Navigate This Site...

Design Doc: Generic Direct-Address Storage Device

Background

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.

Address Map

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

Procedures

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.

Example Code

: 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 ;