You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1308 lines
24 KiB

; N8VEM PPI IDE test program for checkout of IDE drive connected to the 8255 PPI
;
; Written by Max Scane July 2009
; Based on work by Paul Stoffregen (www.pjrc.com)
;
; Note: due to a known anomaly in the 8255, some signals ( all active low signals) on the IDE bus require an inverter (74LS04 or 74LS14)
; between the 8255 and the IDE drive.
; This is due to the 8255 returning all signals to 0 (low) when a mode change is performed (for read and write to IDE data bus).
;
; This test program will allow you to check out an attached IDE drive using the basic commands:
;
; u - Spin up the drive
; d - Spin down the drive
; s - Read and print out drive status
; i - Execute drive ID command and print result correctly
; r - Read the current LBA into the sector buffer and print status
; w - Write the sector buffer to the current LBA and print status
; l - Change the current LBA
; h - Dump the current sector buffer in hexdump format
; f - format drive for CP/M use (fill with 0xE5)
; e - Display drive error information
; x - Return to CP/M
; n - read and hexdump next LBA
; ? - Display command menu help
; p - set PPI port
;
;
;
;
; - Updated December 2014 MS - changed IO routines to support different PPI ports.
; - Updated July 2021 Andrew Lynch - Minor cosmetic updates
;********************* HARDWARE IO ADR ************************************
;
; Offsets to the various PPI registers
IDELSB: EQU 0 ; LSB
IDEMSB: EQU 1 ; MSB
IDECTL: EQU 2 ; Control Signals
PIOCONT: EQU 3 ; CONTROL BYTE PIO 82C55
; PPI control bytes for read and write to IDE drive
rd_ide_8255: EQU 10010010b ; ide_8255_ctl out, ide_8255_lsb/msb input
wr_ide_8255: EQU 10000000b ; all three ports output
;IDE control lines for use with ide_8255_ctl. Change these 8
;constants to reflect where each signal of the 8255 each of the
;IDE control signals is connected. All the control signals must
;be on the same port, but these 8 lines let you connect them to
;whichever pins on that port.
ide_a0_line: EQU 01H ;direct from 8255 to IDE interface
ide_a1_line: EQU 02H ;direct from 8255 to IDE interface
ide_a2_line: EQU 04H ;direct from 8255 to IDE interface
ide_cs0_line: EQU 08H ;inverter between 8255 and IDE interface
ide_cs1_line: EQU 10H ;inverter between 8255 and IDE interface
ide_wr_line: EQU 20H ;inverter between 8255 and IDE interface
ide_rd_line: EQU 40H ;inverter between 8255 and IDE interface
ide_rst_line: EQU 80H ;inverter between 8255 and IDE interface
;------------------------------------------------------------------
; More symbolic constants... these should not be changed, unless of
; course the IDE drive interface changes, perhaps when drives get
; to 128G and the PC industry will do yet another kludge.
;some symbolic constants for the ide registers, which makes the
;code more readable than always specifying the address pins
ide_data: EQU ide_cs0_line
ide_err: EQU ide_cs0_line + ide_a0_line
ide_sec_cnt: EQU ide_cs0_line + ide_a1_line
ide_sector: EQU ide_cs0_line + ide_a1_line + ide_a0_line
ide_cyl_lsb: EQU ide_cs0_line + ide_a2_line
ide_cyl_msb: EQU ide_cs0_line + ide_a2_line + ide_a0_line
ide_head: EQU ide_cs0_line + ide_a2_line + ide_a1_line
ide_command: EQU ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line
ide_status: EQU ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line
ide_control: EQU ide_cs1_line + ide_a2_line + ide_a1_line
ide_astatus: EQU ide_cs1_line + ide_a2_line + ide_a1_line + ide_a0_line
;IDE Command Constants. These should never change.
ide_cmd_recal: EQU 10H
ide_cmd_read: EQU 20H
ide_cmd_write: EQU 30H
ide_cmd_init: EQU 91H
ide_cmd_id: EQU 0ECH
ide_cmd_spindown: EQU 0E0H
ide_cmd_spinup: EQU 0E1H
CR: EQU 0Dh
LF: EQU 0Ah
BELL: EQU 07H
org 100H
start:
; save stack pointer so that we can return to calling program
ld (savsp),sp
ld sp,stack
call set_ppi_rd ; setup PPI chip to known state
ld hl,lba1 ; zero LBA variables
call clrlba
ld hl,lba2
call clrlba
ld hl,lba3
call clrlba
call print
db "PPI IDE test program v0.6a",CR,LF,0
call prstatus
call prlba
call ide_init
call prstatus
call crlf
menu:
call print ; display prompt
db "Enter command (u,d,s,i,r,w,l,h,f,e,n,p,?,x) > ",0
call cin ; get command from console in reg A
push af
call crlf
pop af
mnu1:
cp 'd' ; spin down command
jr nz,mnu2
call spindown
jr menu
mnu2:
cp 'u' ; spinup command
jr nz,mnu3
call spinup
jr menu
mnu3:
cp 's' ;print IDE status reg contents
jr nz,mnu4
call prstatus
jr menu
mnu4:
cp 'i'
jr nz,mnu5 ; drive ID command
call drive_id
jr menu
mnu5:
cp 'r'
jr nz,mnu6 ; read command
call prlba ; print out the current LBA
call read_sector ; read current LBA
call prstatus
jr menu
mnu6:
cp 'w'
jr nz,mnu7 ; write command
call prlba ; print out the current LBA
call write_sector ; write current LBA
call prstatus
jr menu
mnu7:
cp 'l'
jr nz,mnu8 ; LBA command
call prlba ; print out the current LBA
mnu7a:
call print
db "Enter new LBA: ",0
ld de,lba1 ; get LBA in lba1
call getlba
jp nc,menu ; valid, finished
call print
db "Invalid LBA",CR,LF,0
jr mnu7a ; try again
mnu8:
cp 'h'
jr nz,mnu9 ; hexdump command
call hexdump ; hexdump the current sector buffer
jp menu
mnu9:
cp 'f'
jr nz,mnua ; drive format
call format
jp menu
mnua:
cp 'e'
jr nz,mnub ; get error register
call get_err
push af
call print
db "Error register is: ",0
pop af
call prhex
call crlf
ld a,ide_head
call ide_read
ld a,c
call prhex
ld a,ide_cyl_msb
call ide_read
ld a,c
call prhex
ld a,ide_cyl_lsb
call ide_read
ld a,c
call prhex
ld a,ide_sector
call ide_read
ld a,c
call prhex
call crlf
ld a,ide_sec_cnt
call ide_read
ld a,c
call prhex
call crlf
jp menu
mnub:
cp 'n'
jr nz,mnuc
ld hl,lba1
call inclba
call prlba
call read_sector
call hexdump
jp menu
mnuc:
cp 'p'
jr nz,mnux
call crlf
call print
db "Please enter new PPI base port: ",0
; get a hex number
ld (ppibase),a ; save it
call crlf
jp menu
mnux:
cp 'x' ; exit command
jp nz,mnuhlp
ld sp,(savsp)
ret
mnuhlp:
call print
db "Commands available:",CR,LF,LF
db "u - Spin Up drive",CR,LF
db "d - Spin Down drive",CR,LF
db "s - Print drive Status",CR,LF
db "i - Query drive using ID command",CR,LF
db "r - Read a sector addressed by the lba variable",CR,LF
db "w - Write a sector adresses by the lba variable",CR,LF
db "l - Change the current LBA variable",CR,LF
db "h - Hexdump the current buffer",CR,LF
db "f - Format the drive for CP/M use (fill with 0xE5)",CR,LF
db "e - Display drive Error information",CR,LF
db "p - Change base IO port",CR,LF
db "? - Display command menu help",CR,LF
db "x - eXit from this utility",CR,LF,LF,0
jp menu
format:
call print
db "Warning - this command will write data to the drive",CR,LF,LF
db "All existing data will be over written",CR,LF,LF
db "Is that what you want to do ? ",0
call cin ; get answer
cp 'y'
jr z,fmt1 ; if yes then continue
call print
db " Command aborted",CR,LF,0
ret
fmt1:
ld a,0E5h
call fillbuf ; setup sector buffer
fmt2:
call print
db CR,LF,"Enter starting LBA: ",0
ld de,lba2 ; starting LBA
call getlba
jr nc,fmt3
call print
db "Invalid LBA",CR,LF,0
jr fmt2 ; try again
fmt3:
call crlf
fmt4:
call print
db "Enter ending LBA: ",0
ld de,lba3 ; ending LBA
call getlba
jr nc,fmt5
call print
db "Invalid LBA",CR,LF,0
jr fmt4 ; try again
fmt5:
call crlf
call print ; say what is going to happen
db "Format will start at LBA ",0
ld a,(lba2+3)
call prhex
ld a,(lba2+2)
call prhex
ld a,(lba2+1)
call prhex
ld a,(lba2)
call prhex
call print
db " and finish at LBA ",0
ld a,(lba3+3)
call prhex
ld a,(lba3+2)
call prhex
ld a,(lba3+1)
call prhex
ld a,(lba3)
call prhex
call crlf
call print
db "Type y to continue or any other key to abort ",0
call cin
cp 'y'
jp nz,fmtx
call crlf
; add the actual format code here
; get starting LBA
; get ending LBA
; fill buffer with E5
ld hl,lba2
ld de,lba1
call cpylba ; copy start LBA to LBA
call inclba
fmt6:
push hl
call print ; display progress
db "Writing LBN: ",0
ld a,(lba1+3)
call prhex
ld a,(lba1+2)
call prhex
ld a,(lba1+1)
call prhex
ld a,(lba1)
call prhex
ld a,CR
call cout
pop hl
; do some stuff to format here
call write_sector
; need to check status after each call and check for errors
;
ld hl,lba1 ; LBA for disk operation
call inclba
ld hl,lba1
ld de,lba3
call cplba
jp nz,fmt6
call crlf
fmtx:
call print ; finished
db "Format complete",CR,LF,0
ret
getlba: ; get an LBA value from the console and validate it
push de ; save LBA variable
ld c,0ah ; bdos read console buffer
ld de,conbuf
call 5 ; get edited string
call crlf
; ok we now have an ascii string representing the LBA. now we have to validate it
pop de
ld hl,conbuf
inc hl
ld b,(hl) ; get character count
glba1:
inc hl ; HL = address of buffer
ld a,(hl) ; get next character
call ishex
ret c ; return with carry set if any char is invalid
; ok we are here when we have a valid character (0-9,A-F,a-f) need to convert to binary
; character is still in A
cp 3AH ; test for 0-9
jp m,glba4
cp 47H ; test for A-F
jp m,glba3
cp 67H ; test for a-f
jp m,glba2
glba2:
sub 20H ; character is a-f
glba3:
sub 07h ; character is A-F
glba4:
sub 030H ; character is 0-9
ld (hl),a ; save back in buffer as binary
djnz glba1 ; continue checking the buffer
; need to pack bytes into the destination LBA which is in de and points to the LSB
glba5:
; - need to change the endian-ness
push de
ex de,hl ; clear LBA ready
; push de ; address of LBA
; pop hl ; address of input buffer
ld a,0 ; zero existing LBA variable
ld (hl),a
inc hl
ld (hl),a
inc hl
ld (hl),a
inc hl
ld (hl),a
ex de,hl ; de now positioned at end of LBA
pop de ; restore LBA
; de still contains dest address
; now pack and store LBA
ld hl,conbuf+1 ; get character count
ld b,(hl)
inc hl ; point to first character in buffer
glba6:
push de ; save starting address for next subsequent rotations
ld a,(hl) ; get next char from buffer
inc hl ; next character
ex de,hl ; switch to LBA
rld ; shift nibble into LBA
inc hl
rld
inc hl
rld
inc hl
rld
ex de,hl ; back to console buffer
pop de ; restore address of LBA
djnz glba6 ; process next character
scf
ccf ; exit with carry clear = success
ret
ishex:
cp 30h ; check if less than character 0
jp m,nothex
cp 3Ah ; check for > 9
jp m,ishx1 ; ok, character is 1-9
cp 41h ; check for character less than A
jp m,nothex
cp 47H ; check for characters > F
jp m,ishx1
cp 61H ; check for characters < a
jp m,nothex
cp 67H ; check for character > f
jp m,ishx1
nothex:
scf ; set carry to indicate fail
ret
ishx1:
scf
ccf
ret
fillbuf:
; fill sector buffer with character specified in A
ld hl,buffer
ld b,0
fb1:
ld (hl),a ;store character in buffer
inc hl
ld (hl),a
inc hl
djnz fb1
ret
hexdump:
call print ; print heading
db "Current sector buffer contents:",CR,LF,LF,0
ld b,32 ; line counter
ld hl,buffer ; address of buffer to dump
hxd1:
push bc ; save loop counter
push hl ; save address pointer
push hl
ld a,h
call prhex ; print hi byte of address
pop hl
push hl
ld a,l
call prhex ; print lo byte of address
ld a,' '
call cout
pop hl
ld b,16 ; how many characters do we display
hxd2:
push bc
ld a,(hl) ; get byte from buffer
inc hl
push hl
call prhex ; display it in hex
ld a,' '
call cout
pop hl
pop bc
djnz hxd2
pop hl
ld b,16 ; how many characters do we display
hxd3:
push bc
ld a,(hl) ; get byte from buffer
inc hl
push hl
call prascii ; display it in ASCII
pop hl
pop bc
djnz hxd3
push hl
call crlf
pop hl
pop bc
ld a,b ; check for screen pause
cp 16
jp nz,hxd4
push hl
push bc
call cin ; wait for a character
pop bc
pop hl
hxd4:
djnz hxd1 ; continue if not at end of buffer
call crlf
call crlf
ret
prascii:
cp 20H
jp m,pra1 ; anything less than 20H is non-printable
cp 7fH ; anything greater than 7E is non-printable
jp m,pra2
pra1:
ld a,'.'
pra2:
call cout
ret
;
;
;
; -------------------------------------------------------------------------
;
; LBA manipulation routines;
;
cpylba:
; copy LBA to LBA
; source = HL, Destination = DE
ld bc,04H
ldir
ret
; -------------------------------------------------------------------------
inclba:
ld a,(hl) ; first byte
add a,1
ld (hl),a
ret nc
inc hl ;second byte
ld a,(hl)
add a,1
ld (hl),a
ret nc
inc hl ; third byte
ld a,(hl)
add a,1
ld (hl),a
ret nc
inc hl ; fourth byte (MSB)
ld a,(hl)
add a,1
ld (hl),a
ret
; -------------------------------------------------------------------------
cplba: ; compare LBA
; addresses by HL and DE
ld a,(hl) ; start at LSB
inc hl
ex de,hl
cp (hl)
ret nz
inc hl
ex de,hl
ld a,(hl)
inc hl
ex de,hl
cp (hl)
ret nz
inc hl
ex de,hl
ld a,(hl)
inc hl
ex de,hl
cp (hl)
ret nz
inc hl
ex de,hl
ld a,(hl)
inc hl
ex de,hl
cp (hl)
ret
ret nz
inc hl
ex de,hl
ret
; -------------------------------------------------------------------------
prlba:
call print
db "Current LBA = ",0
ld a,(lba1+3)
call prhex
ld a,(lba1+2)
call prhex
ld a,(lba1+1)
call prhex
ld a,(lba1)
call prhex
call crlf
call crlf
ret
clrlba:
ld a,0
ld b,4
clr32b1:
ld (hl),a
inc hl
djnz clr32b1
ret
; -------------------------------------------------------------------------
prstatus:
call print
db "status = ",0
ld a,ide_status ;read IDE status register
call ide_read
ld a,c ; returned value
call prhex
call crlf
ret
print:
pop hl ; get address of text
ld a,(hl) ; get next character
inc hl
push hl
cp 0
ret z ; end of text found
call cout ; output character
jp print
; -------------------------------------------------------------------------
prhex: ; proint hexadecimal digit in A
push af
srl a ; move high nibble to low
srl a
srl a
srl a
call hexnib ; convert to ASCII Hex
call cout ; send character to output device
pop af
call hexnib
call cout ; send character to output device
ret
hexnib:
and 0fh ; strip high order nibble
add a,30H ; add ASCII ofset
cp 3ah ; correction necessary?
ret m
add a,7 ; correction for A to F
ret
; -------------------------------------------------------------------------
cout:
ld e,a
ld c,02h ; Console output byte call
call 5
ret
; -------------------------------------------------------------------------
cin:
ld c,01h ; BDOS console function
call 5
ret
; -------------------------------------------------------------------------
crlf:
ld a,CR
call cout
ld a,LF
call cout
ret
;------------------------------------------------------------------
; Routines that talk with the IDE drive, these should be called by
; the main program.
;read a sector, specified by the 4 bytes in "lba",
;Return, acc is zero on success, non-zero for an error
read_sector:
call ide_wait_not_busy ;make sure drive is ready
call wr_lba ;tell it which sector we want
ld a, ide_command
ld c, ide_cmd_read
call ide_write ; ask the drive to read it
call ide_wait_drq ;wait until it's got the data
bit 0,a
jp nz, get_err
ld hl, buffer
call read_data ;grab the data
ld a,0
ret
;when an error occurs, we get acc.0 set from a call to ide_drq
;or ide_wait_not_busy (which read the drive's status register). If
;that error bit is set, we should jump here to read the drive's
;explanation of the error, to be returned to the user. If for
;some reason the error code is zero (shouldn't happen), we'll
;return 255, so that the main program can always depend on a
;return of zero to indicate success.
get_err:
ld a,ide_err
call ide_read
ld a,c
jp z,gerr2
ret
gerr2:
ld a, 255
ret
;write a sector, specified by the 4 bytes in "lba",
;whatever is in the buffer gets written to the drive!
;Return, acc is zero on success, non-zero for an error
write_sector:
call ide_wait_not_busy ;make sure drive is ready
call wr_lba ;tell it which sector we want
ld a, ide_command
ld c, ide_cmd_write
call ide_write ;tell drive to write a sector
call ide_wait_drq ;wait unit it wants the data
bit 0,a ; check for error returned
jp nz,get_err
ld hl, buffer
call write_data ;give the data to the drive
call ide_wait_not_busy ;wait until the write is complete
bit 0,a
jp nz,get_err
ld a,0
ret
;do the identify drive command, and return with the buffer
;filled with info about the drive
drive_id:
call ide_wait_not_busy
ld a,ide_head
ld c,10100000b
call ide_write ;select the master device
call ide_wait_ready
ld a,ide_command
ld c,0ech
call ide_write ;issue the command
call ide_wait_drq
ld hl, buffer
call read_data
ret
;tell the drive to spin up
spinup:
ld c,ide_cmd_spinup
ld a,ide_command
call ide_write
call ide_wait_not_busy
ret
;tell the drive to spin down
spindown:
call ide_wait_not_busy
ld c,ide_cmd_spindown
ld a,ide_command
call ide_write
call ide_wait_not_busy
ret
;initialize the IDE drive
ide_init:
ld a, ide_head
ld b, 0
ld c, 10100000b ;select the master device
call ide_write
init1:
ld a, ide_status
call ide_read
ld a, c
;should probably check for a timeout here
bit 6,a ; wait for RDY bit to be set
jp z,init1
bit 7,a
jp nz,init1 ;wait for BSY bit to be clear
ret
; IDE Status Register:
; bit 7: Busy 1=busy, 0=not busy
; bit 6: Ready 1=ready for command, 0=not ready yet
; bit 5: DF 1=fault occured inside drive
; bit 4: DSC 1=seek complete
; bit 3: DRQ 1=data request ready, 0=not ready to xfer yet
; bit 2: CORR 1=correctable error occured
; bit 1: IDX vendor specific
; bit 0: ERR 1=error occured
;------------------------------------------------------------------
; Not quite as low, low level I/O. These routines talk to the drive,
; using the low level I/O. Normally a main program should not call
; directly to these.
;Read a block of 512 bytes (one sector) from the drive
;and store it in memory @ HL
read_data:
ld b, 0
rdblk2:
push bc
push hl
ld a, ide_data
call ide_read
pop hl
ld a, c
ld (hl), a
inc hl
ld a, b
ld (hl), a
inc hl
pop bc
djnz rdblk2
ret
;Write a block of 512 bytes (at HL) to the drive
write_data:
ld b,0
wrblk2:
push bc
ld a,(hl)
ld c, a ; LSB
inc hl
ld a,(hl)
ld b, a ; MSB
inc hl
push hl
ld a, ide_data
call ide_write
pop hl
pop bc
djnz wrblk2
ret
;write the logical block address to the drive's registers
wr_lba:
ld a,(lba1+3) ; MSB
and 0fh
or 0e0h
ld c,a
ld a,ide_head
call ide_write
ld a,(lba1+2)
ld c,a
ld a,ide_cyl_msb
call ide_write
ld a,(lba1+1)
ld c,a
ld a,ide_cyl_lsb
call ide_write
ld a,(lba1+0) ; LSB
ld c,a
ld a,ide_sector
call ide_write
ld c,1
ld a,ide_sec_cnt
call ide_write
ret
ide_wait_not_busy:
ld a,ide_status ;wait for RDY bit to be set
call ide_read
bit 7,c
jp nz,ide_wait_not_busy
;should probably check for a timeout here
ret
ide_wait_ready:
ld a,ide_status ;wait for RDY bit to be set
call ide_read
bit 6,c ; test for XXX
jp z,ide_wait_ready
bit 7,c
jp nz,ide_wait_ready
;should probably check for a timeout here
ret
;Wait for the drive to be ready to transfer data.
;Returns the drive's status in Acc
ide_wait_drq:
ld a,ide_status ;wait for DRQ bit to be set
call ide_read
bit 7,c
jp nz,ide_wait_drq ; check for busy
bit 3,c ; wait for DRQ
jp z,ide_wait_drq
;should probably check for a timeout here
ret
;-----------------------------------------------------------------------------
; Low Level I/O to the drive. These are the routines that talk
; directly to the drive, via the 8255 chip. Normally a main
; program would not call to these.
;Do a read bus cycle to the drive, using the 8255.
;input acc = IDE register address
;output C = lower byte read from IDE drive
;output B = upper byte read from IDE drive
ide_read:
push af ; save register value
push bc
call set_ppi_rd ; setup for a read cycle
pop bc
pop af ; restore register value
call wrppictl ; write to control sigs
or ide_rd_line ; assert RD pin
call wrppictl ; write to control sigs
push af ; save register value
call rdppilsb ; read LSB register into A
ld c,a ; save in reg C
call rdppimsb ; read MSB register into A
ld b,a ; save in reg C
pop af ; restore register value
xor ide_rd_line ; de-assert RD signal
call wrppictl ; write to control sigs
ld a,0
call wrppictl ; write to control sigs
ret
;Do a write bus cycle to the drive, via the 8255
;input acc = IDE register address
;input register C = LSB to write
;input register B = MSB to write
;
ide_write:
push af ; save IDE register value
push bc
call set_ppi_wr ; setup for a write cycle
pop bc
ld a,c ; get value to be written
call wrppilsb
ld a,b ; get value to be written
call wrppimsb
pop af ; get saved IDE register
call wrppictl ; write to control sigs
or ide_wr_line ; assert write pin
call wrppictl ; write to control sigs
xor ide_wr_line ; de assert WR pin
call wrppictl ; write to control sigs
ld a,0
call wrppictl ; write to control sigs
ret
;-------------------------------------------------------------------------------------------
ide_hard_reset:
call set_ppi_rd
ld a,ide_rst_line
call wrppictl ; write to control register
ld bc,0
rstdly:
djnz rstdly
ld a,0
call wrppictl ; write to control registers
ret
;-----------------------------------------------------------------------------------
; PPI setup routine to configure the appropriate PPI mode
;
;------------------------------------------------------------------------------------
set_ppi_rd:
ld a,(ppibase)
add a,PIOCONT ; select Control register
ld c,a
ld a,rd_ide_8255 ;configure 8255 chip, read mode
out (c),a
ret
set_ppi_wr:
ld a,(ppibase)
add a,PIOCONT ; select Control register
ld c,a
ld a,wr_ide_8255 ;configure 8255 chip, write mode
out (c),a
ret
;------------------------------------------------------------------------------------
rdppilsb: ; read LSB
; returns data in A
push bc
ld a,(ppibase)
add a,IDELSB ; select Control register
ld c,a
in a,(c)
pop bc
ret
wrppilsb: ; write LSB
; data to be written in A
push bc
push af
ld a,(ppibase)
add a,IDELSB ; select Control register
ld c,a
pop af
out (c),a
pop bc
ret
;--------------------------------------------------------------------------
rdppimsb: ; read MSB
; returns data in A
push bc
ld a,(ppibase)
add a,IDEMSB ; select MSB Register
ld c,a
in a,(c)
pop bc
ret
wrppimsb: ; write LSB
; data to be written in A
push bc
push af
ld a,(ppibase)
add a,IDEMSB ; select MSB Register
ld c,a
pop af
out (c),a
pop bc
ret
;--------------------------------------------------------------------------
wrppictl: ; write to control signals
; data to be written in A
push bc
push af
ld a,(ppibase)
add a,IDECTL ; select CTL Register
ld c,a
pop af
out (c),a
pop bc
ret
;--------------------------------------------------------------------------
; Storage area follows
savsp: ds 2 ; saved stack pointer
lba1: ds 4 ; LBA used for read/write operations
lba2: ds 4 ; Start LBA for format
lba3: ds 4 ; End LBA for format
ppibase: db 60h ; base address of PPI chip to be used, default to Z80 SBC / Z80 MBC
;ppibase db 44h ; base address of PPI chip to be used
org 0b00h
buffer: ds 512 ; sector buffer for IDE transfers
conbuf:
db 8 ; maximum chars
db 0 ; count
ds 8 ; size of buffer
ds 100
stack:
end