When first powering the Kestrel-2 up, it will drop into a Forth environment. This environment allows the user to create new programs and to interact with the computer. However, because RAM is volatile, it will come up in a factory reset state every time. Some means is required of saving and restoring programs for later use. Forth provides the BLOCK abstraction to accomplish this, which directly addresses a block-storage device. Therefore, the Kestrel-2 needs a direct-address storage device (more generically, a generic block storage device).
This design is driven solely by the needs of Forth. Forth's interaction with I/O devices is typically fully synchronous, and strongly prefers polling. As a result, the GDASD specification does not provide for interrupts or other tools to assist in asynchronous I/O. Therefore, alternative designs and standards are required to provide these features.
| From | Description | To |
|---|---|---|
| $0000 | undefined; this space may potentially be used by other peripheral functions. | $00F9 |
| $00FA | MaxAddress. This read-only register provides the disk's largest address that may be stored in the DiskAddress field. For a 64MB device, this will be $FFFF. For a 32MB device, $7FFF. Etc. | $00FB |
| $00FC | DiskAddress. This specifies which disk block to read from or write to. Each block is 1KiB in size; 65536 different values are allowed, thus providing a maximum storage capacity of 64MB. | $00FD |
| $00FE | Command. There are only two valid commands defined at this time. $00 indicates an idle condition, where the disk controller is not doing anything. $01 commences a write operation. $02 commences a read operation. $03-$FF are undefined, and may lead to unpredictable behavior; never use them. This byte must be the last byte written, since it is what commences the I/O operation indicated. |   |
| $00FF | unused |   |
| $0100 | unused; this space may potentially be used by other peripheral functions. | $03FF |
| $0400 | Disk buffer storage area. This buffer must be loaded with data before commencing a write operation. | $07FF |
| $0800 | unused; this space may potentially be used by other peripheral functions. | $FFFF |
Writing to the disk is performed by first writing your data to the disk buffer at $0400. Then, a write to $00FC is performed, including the disk block to write to, and the disk-write command ($01) itself. While the write is in progress, the Command register will remain $01. When it finally completes, it will be reset to $00 automatically.
Reading is performed in the reverse order. First, the control information is written to $00FC, including the block to read from, and the read command ($02). When the Command register changes to $00, then the data will have been read into the buffer at $0400. It may then be read safely.
: wr serbus-c! ; : rd 16 + serbus-c! ; : wr.w dup wr 2/ 2/ 2/ 2/ 2/ 2/ 2/ 2/ wr ; : frame 1 serbus-device! execute 0 serbus-device! ; : check 1 rd $FE wr 0 serbus-c!@ ; : wait begin ['] check frame 0= until ; : data 1024 begin over @ wr.w 2 /string dup 0= until 2drop ; : buf! 2 wr $0400 wr.w data ; : out 1 wr $FC wr wr.w $01 wr ; : store ( blknum bufaddr -- ) wait ['] buf! frame ['] out frame ; : inp 1 wr $FC wr wr.w $02 wr ; : data 1024 begin serbus-c@ >r over r> swap c! 1 /string dup 0= until 2drop ; : buf@ 2 rd $0400 wr.w data ; : retrieve ( bufaddr blknum -- ) wait ['] inp frame wait ['] buf frame ;