2019-04-17 00:37:29 +10:00
|
|
|
# Using block devices
|
|
|
|
|
|
|
|
The `blockdev.asm` part manage what we call "block devices", an abstraction over
|
2019-10-05 02:05:05 +10:00
|
|
|
something that we can read a byte to, write a byte to, optionally at arbitrary
|
|
|
|
offsets.
|
2019-04-17 00:37:29 +10:00
|
|
|
|
|
|
|
A Collapse OS system can define up to `0xff` devices. Those definitions are made
|
|
|
|
in the glue code, so they are static.
|
|
|
|
|
|
|
|
Definition of block devices happen at include time. It would look like:
|
|
|
|
|
|
|
|
[...]
|
|
|
|
BLOCKDEV_COUNT .equ 1
|
|
|
|
#include "blockdev.asm"
|
|
|
|
; List of devices
|
2019-10-31 07:59:35 +11:00
|
|
|
.dw sdcGetB, sdcPutB
|
2019-04-17 00:37:29 +10:00
|
|
|
[...]
|
|
|
|
|
2019-10-31 07:59:35 +11:00
|
|
|
That tells `blockdev` that we're going to set up one device, that its GetB and
|
|
|
|
PutB are the ones defined by `sdc.asm`.
|
2019-04-17 00:37:29 +10:00
|
|
|
|
2019-10-05 02:05:05 +10:00
|
|
|
If your block device is read-only or write-only, use dummy routines. `unsetZ`
|
2019-10-05 03:52:14 +10:00
|
|
|
is a good choice since it will return with the `Z` flag unset, indicating an
|
2019-10-05 02:05:05 +10:00
|
|
|
error (dummy methods aren't supposed to be called).
|
|
|
|
|
|
|
|
Each defined block device, in addition to its routine definition, holds a
|
|
|
|
seek pointer. This seek pointer is used in shell commands described below.
|
2019-04-17 00:37:29 +10:00
|
|
|
|
|
|
|
## Routine definitions
|
|
|
|
|
2019-10-31 07:59:35 +11:00
|
|
|
Parts that implement GetB and PutB do so in a loosely-coupled manner, but
|
2019-04-17 00:37:29 +10:00
|
|
|
they should try to adhere to the convention, that is:
|
|
|
|
|
2019-10-31 07:59:35 +11:00
|
|
|
**GetB**: Get the byte at position specified by `HL`. If it supports 32-bit
|
2019-10-05 02:05:05 +10:00
|
|
|
addressing, `DE` contains the high-order bytes. Return the result in
|
2019-10-05 03:52:14 +10:00
|
|
|
`A`. If there's an error (for example, address out of range), unset
|
|
|
|
`Z`. This routine is not expected to block. We expect the result to be
|
2019-10-05 02:05:05 +10:00
|
|
|
immediate.
|
2019-04-17 00:37:29 +10:00
|
|
|
|
2019-10-31 07:59:35 +11:00
|
|
|
**PutB**: The opposite of GetB. Write the character in `A` at specified
|
2019-10-05 03:52:14 +10:00
|
|
|
position. `Z` unset on error.
|
2019-10-05 02:05:05 +10:00
|
|
|
|
2019-04-17 00:37:29 +10:00
|
|
|
## Shell usage
|
|
|
|
|
2019-06-03 01:23:24 +10:00
|
|
|
`blockdev.asm` supplies 4 shell commands that you can graft to your shell thus:
|
2019-04-17 00:37:29 +10:00
|
|
|
|
|
|
|
[...]
|
2019-06-03 01:23:24 +10:00
|
|
|
SHELL_EXTRA_CMD_COUNT .equ 4
|
2019-04-17 00:37:29 +10:00
|
|
|
#include "shell.asm"
|
|
|
|
; extra commands
|
2019-06-03 01:23:24 +10:00
|
|
|
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
|
2019-04-17 00:37:29 +10:00
|
|
|
[...]
|
|
|
|
|
|
|
|
### bsel
|
|
|
|
|
2019-10-05 02:05:05 +10:00
|
|
|
`bsel` select the active block device. This specify a target for `load` and
|
|
|
|
`save`. Some applications also use the active blockdev. It receives one
|
|
|
|
argument, the device index. `bsel 0` selects the first defined device, `bsel 1`,
|
|
|
|
the second, etc. Error `0x04` when argument is out of bounds.
|
2019-04-17 00:37:29 +10:00
|
|
|
|
|
|
|
### seek
|
|
|
|
|
|
|
|
`seek` receives one word argument and sets the pointer for the currently active
|
|
|
|
device to the specified address. Example: `seek 1234`.
|
|
|
|
|
|
|
|
The device position is device-specific: if you seek on a device, then switch
|
|
|
|
to another device and seek again, your previous position isn't lost. You will
|
|
|
|
still be on the same position when you come back.
|
|
|
|
|
2019-06-03 01:23:24 +10:00
|
|
|
### load
|
|
|
|
|
|
|
|
`load` works a bit like `poke` except that it reads its data from the currently
|
|
|
|
active blockdev at its current position. If it hits the end of the blockdev
|
|
|
|
before it could load its specified number of bytes, it stops. It only raises an
|
|
|
|
error if it couldn't load any byte.
|
|
|
|
|
2019-10-05 02:05:05 +10:00
|
|
|
It moves the device's position to the byte after the last loaded byte.
|
|
|
|
|
2019-06-03 01:23:24 +10:00
|
|
|
### save
|
|
|
|
|
|
|
|
`save` is the opposite of `load`. It writes the specified number of bytes from
|
|
|
|
memory to the active blockdev at its current position.
|
|
|
|
|
2019-10-05 02:05:05 +10:00
|
|
|
It moves the device's position to the byte after the last written byte.
|
|
|
|
|
2019-04-17 00:37:29 +10:00
|
|
|
### Example
|
|
|
|
|
|
|
|
Let's try an example: You glue yourself a Collapse OS with ACIA as its first
|
|
|
|
device and a mmap starting at `0xd000` as your second device. Here's what you
|
|
|
|
could do to copy memory around:
|
|
|
|
|
|
|
|
> mptr d000
|
|
|
|
D000
|
2019-06-03 01:23:24 +10:00
|
|
|
> poke 4
|
2019-04-17 00:37:29 +10:00
|
|
|
[enter "abcd"]
|
|
|
|
> peek 4
|
|
|
|
61626364
|
|
|
|
> mptr c000
|
|
|
|
C000
|
|
|
|
> peek 4
|
|
|
|
[RAM garbage]
|
|
|
|
> bsel 1
|
|
|
|
> load 4
|
|
|
|
[returns immediately]
|
|
|
|
> peek 4
|
|
|
|
61626364
|
2019-06-03 01:23:24 +10:00
|
|
|
> seek 00 0002
|
2019-04-17 00:37:29 +10:00
|
|
|
> load 2
|
|
|
|
> peek 4
|
|
|
|
63646364
|
|
|
|
|
|
|
|
Awesome, right?
|