|
|
@@ -0,0 +1,91 @@ |
|
|
|
# Using block devices |
|
|
|
|
|
|
|
The `blockdev.asm` part manage what we call "block devices", an abstraction over |
|
|
|
something that we can read a byte to, write a byte to and seek into (select at |
|
|
|
which offset we will read/write to next). |
|
|
|
|
|
|
|
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 |
|
|
|
.dw aciaGetC, aciaPutC, 0 |
|
|
|
[...] |
|
|
|
|
|
|
|
That tells `blockdev` that we're going to set up one device, that its GetC and |
|
|
|
PutC are the ones defined by `acia.asm` and that it has no Seek. |
|
|
|
|
|
|
|
blockdev routines defined as zero are dummies (we don't actually call `0x0000`). |
|
|
|
|
|
|
|
## Routine definitions |
|
|
|
|
|
|
|
Parts that implement GetC, PutC and Seek do so in a loosely-coupled manner, but |
|
|
|
they should try to adhere to the convention, that is: |
|
|
|
|
|
|
|
**GetC**: Get a character at current position, advance the position by 1, then |
|
|
|
return the fetched character in register `A`. If no input is |
|
|
|
available, block until it is (in other words, we always get a valid |
|
|
|
character). |
|
|
|
|
|
|
|
**PutC**: The opposite of GetC. Write the character in `A` at current position |
|
|
|
and advance. If it can't write, block until it can. |
|
|
|
|
|
|
|
**Seek**: Set current position (word) to value in register `HL`. |
|
|
|
|
|
|
|
## Shell usage |
|
|
|
|
|
|
|
`blockdev.asm` supplies 2 shell commands that you can graft to your shell thus: |
|
|
|
|
|
|
|
[...] |
|
|
|
SHELL_EXTRA_CMD_COUNT .equ 2 |
|
|
|
#include "shell.asm" |
|
|
|
; extra commands |
|
|
|
.dw blkBselCmd, blkSeekCmd |
|
|
|
[...] |
|
|
|
|
|
|
|
### bsel |
|
|
|
|
|
|
|
`bsel` select the active block device. For now, this only affects `load`. 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. |
|
|
|
|
|
|
|
### 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. |
|
|
|
|
|
|
|
### 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 |
|
|
|
> load 4 [device 0 is selected initially] |
|
|
|
[enter "abcd"] |
|
|
|
> peek 4 |
|
|
|
61626364 |
|
|
|
> mptr c000 |
|
|
|
C000 |
|
|
|
> peek 4 |
|
|
|
[RAM garbage] |
|
|
|
> bsel 1 |
|
|
|
> load 4 |
|
|
|
[returns immediately] |
|
|
|
> peek 4 |
|
|
|
61626364 |
|
|
|
> seek 0002 |
|
|
|
> load 2 |
|
|
|
> peek 4 |
|
|
|
63646364 |
|
|
|
|
|
|
|
Awesome, right? |