retroforth/vm/nga-c-native-x86/x86/ata.retro

92 lines
2 KiB
Forth
Raw Normal View History

# ATA (Hard Disk) Driver
This implements a basic PIO mode ATA driver.
The code here works (at least under qemu), but is *very*
dangerous to use. It will allow you to read or write a
sector to/from a dedicated `ata:Sector` buffer. No checks
are made to validate the sector number. Using these (esp.
`ata:write`) is likely to cause data loss.
# Settings
~~~
#10000 'ata:Delay var-n
~~~
# Constants
~~~
0x20 'ata:READ const
0x30 'ata:WRITE const
0xE7 'ata:FLUSH-CACHE const
(port (name (access_modes
(---- (----------------------- (------------
0x1F0 'ata:PRIMARY const
0x1F0 'ata:DATA const (rw
0x1F1 'ata:ERROR const (r
0x1F1 'ata:FEATURES const (w
0x1F2 'ata:SECTOR-COUNT const (rw
0x1F3 'ata:SECTOR-NUMBER const (rw
0x1F4 'ata:CYLINDER-LOW const (rw
0x1F5 'ata:CYLINDER-HIGH const (rw
0x1F6 'ata:DRIVE const (rw
0x1F6 'ata:HEAD const (rw
0x1F7 'ata:STATUS const (r
0x1F7 'ata:COMMAND const (w
0x3F6 'ata:PRIMARY-DCR-AS const
~~~
# Common
~~~
:ata:clear-bsy (-)
[ ata:COMMAND pio:in-byte 0x80 and n:zero? ] until ;
:ata:set-sector (n-)
0xE0 ata:HEAD pio:out-byte
0x00 ata:FEATURES pio:out-byte
0x01 ata:SECTOR-COUNT pio:out-byte
dup ata:SECTOR-NUMBER pio:out-byte
dup #8 shift ata:CYLINDER-LOW pio:out-byte
#16 shift ata:CYLINDER-HIGH pio:out-byte ;
~~~
# Reading a Sector
~~~
:mask 0xFF and ;
:delay @ata:Delay [ ] times ;
:ata:read-word
ata:PRIMARY pio:in-word ;
:store-word
[ mask over store n:inc ] sip #8 shift over store n:inc ;
:ata:read (an-)
ata:set-sector
ata:READ ata:COMMAND pio:out-byte
delay
#256 [ ata:read-word store-word ] times drop ;
~~~
# Writing a Sector
~~~
:ata:write-word
ata:PRIMARY pio:out-word ;
:fetch-word
fetch-next [ fetch-next #-8 shift ] dip + ;
:ata:write (an-)
ata:set-sector
ata:WRITE ata:COMMAND pio:out-byte
delay
#256 [ fetch-word ata:write-word ] times drop
ata:FLUSH-CACHE ata:COMMAND pio:out-byte ata:clear-bsy ;
~~~