kopia lustrzana https://github.com/maccasoft/z80-tools
752 wiersze
28 KiB
NASM
752 wiersze
28 KiB
NASM
;==================================================================================
|
|
; Contents of this file are copyright Grant Searle
|
|
; HEX routines from Joel Owens.
|
|
;
|
|
; You have permission to use this for NON COMMERCIAL USE ONLY
|
|
; If you wish to use it elsewhere, please include an acknowledgement to myself.
|
|
;
|
|
; http://searle.hostei.com/grant/index.html
|
|
;
|
|
; eMail: home.micros01@btinternet.com
|
|
;
|
|
; If the above don't work, please perform an Internet search to see if I have
|
|
; updated the web page hosting service.
|
|
;
|
|
;==================================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; Z80 Monitor Rom
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
; General Equates
|
|
;------------------------------------------------------------------------------
|
|
|
|
CR .EQU 0DH
|
|
LF .EQU 0AH
|
|
ESC .EQU 1BH
|
|
CTRLC .EQU 03H
|
|
CLS .EQU 0CH
|
|
|
|
; CF registers
|
|
CF_DATA .EQU 10H
|
|
CF_FEATURES .EQU 11H
|
|
CF_ERROR .EQU 11H
|
|
CF_SECCOUNT .EQU 12H
|
|
CF_SECTOR .EQU 13H
|
|
CF_CYL_LOW .EQU 14H
|
|
CF_CYL_HI .EQU 15H
|
|
CF_HEAD .EQU 16H
|
|
CF_STATUS .EQU 17H
|
|
CF_COMMAND .EQU 17H
|
|
CF_LBA0 .EQU 13H
|
|
CF_LBA1 .EQU 14H
|
|
CF_LBA2 .EQU 15H
|
|
CF_LBA3 .EQU 16H
|
|
|
|
;CF Features
|
|
CF_8BIT .EQU 1
|
|
CF_NOCACHE .EQU 82H
|
|
;CF Commands
|
|
CF_READ_SEC .EQU 20H
|
|
CF_WRITE_SEC .EQU 30H
|
|
CF_SET_FEAT .EQU 0EFH
|
|
|
|
;BASIC cold and warm entry points
|
|
BASCLD .EQU 2000H
|
|
BASWRM .EQU 2003H
|
|
|
|
LOADADDR .EQU 0D000H ; CP/M load address
|
|
NUMSECS .EQU 24 ; Number of 512 sectors to be loaded
|
|
|
|
SIOA_D .EQU 81H
|
|
SIOA_C .EQU 80H
|
|
SIOB_D .EQU 83H
|
|
SIOB_C .EQU 82H
|
|
|
|
;------------------------------------------------------------------------------
|
|
; START OF MONITOR ROM
|
|
;------------------------------------------------------------------------------
|
|
|
|
.ORG 00H ; MONITOR ROM RESET VECTOR
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Reset
|
|
;------------------------------------------------------------------------------
|
|
|
|
RST00 DI ; Disable INTerrupts
|
|
JP INIT ; Initialize Hardware and go
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; TX a character over RS232 wait for TXDONE first.
|
|
;------------------------------------------------------------------------------
|
|
|
|
RST08 JP CONOUT
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; RX a character from buffer wait until char ready.
|
|
;------------------------------------------------------------------------------
|
|
|
|
RST10 JP CONIN
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Check input buffer status
|
|
;------------------------------------------------------------------------------
|
|
|
|
RST18 JP CKINCHAR
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Interrupt vector
|
|
;------------------------------------------------------------------------------
|
|
|
|
.ORG 38H
|
|
|
|
RETI
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
NOP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Console input routine
|
|
; Use the "primaryIO" flag to determine which input port to monitor.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CONIN
|
|
LD A, (PRIMARYIO)
|
|
CP 00H
|
|
JR NZ, CONINB
|
|
|
|
CONINA
|
|
XOR A
|
|
OUT (SIOA_C), A
|
|
WAITINA IN A, (SIOA_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 01H ; Rotates RX status into Carry Flag,
|
|
JR Z, WAITINA
|
|
IN A, (SIOA_D)
|
|
RET ; Char ready in A
|
|
|
|
CONINB
|
|
XOR A
|
|
OUT (SIOB_C), A
|
|
WAITINB IN A, (SIOB_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 01H ; Rotates RX status into Carry Flag,
|
|
JR Z, WAITINB
|
|
IN A, (SIOB_D)
|
|
RET ; Char ready in A
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Console output routine
|
|
; Use the "primaryIO" flag to determine which output port to send a character.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CONOUT
|
|
PUSH AF ; Store character
|
|
LD A, (PRIMARYIO)
|
|
CP 00H
|
|
JR NZ, CONOUTB1
|
|
JR CONOUTA1
|
|
|
|
CONOUTA
|
|
PUSH AF
|
|
CONOUTA1 XOR A ; See if SIO channel A is finished transmitting
|
|
OUT (SIOA_C), A
|
|
WAITOUTA IN A, (SIOA_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 04H
|
|
JR Z, WAITOUTA ; Loop until SIO flag signals ready
|
|
POP AF ; RETrieve character
|
|
OUT (SIOA_D), A ; OUTput the character
|
|
RET
|
|
|
|
CONOUTB
|
|
PUSH AF
|
|
CONOUTB1 XOR A ; See if SIO channel B is finished transmitting
|
|
OUT (SIOB_C), A
|
|
WAITOUTB IN A, (SIOB_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 04H
|
|
JR Z, WAITOUTB ; Loop until SIO flag signals ready
|
|
POP AF ; RETrieve character
|
|
OUT (SIOB_D), A ; OUTput the character
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Check if there is a character in the input buffer
|
|
; Use the "primaryIO" flag to determine which port to check.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CKINCHAR
|
|
LD A, (PRIMARYIO)
|
|
CP 00H
|
|
JR NZ, CKINCHARB
|
|
|
|
CKINCHARA XOR A ; See if SIO channel A is finished transmitting
|
|
OUT (SIOA_C), A
|
|
IN A, (SIOA_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 01H
|
|
RET
|
|
|
|
CKINCHARB XOR A
|
|
OUT (SIOB_C), A
|
|
IN A, (SIOB_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
|
|
AND 01H
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Filtered Character I/O
|
|
;------------------------------------------------------------------------------
|
|
|
|
RDCHR
|
|
RST 10H
|
|
CP LF
|
|
JR Z, RDCHR ; Ignore LF
|
|
CP ESC
|
|
JR NZ, RDCHR1
|
|
LD A, CTRLC ; Change ESC to CTRL-C
|
|
RDCHR1 RET
|
|
|
|
WRCHR CP CR
|
|
JR Z, WRCRLF ; When CR, write CRLF
|
|
CP CLS
|
|
JR Z, WR ; Allow write of "CLS"
|
|
CP ' ' ; Don't write out any other control codes
|
|
JR C, NOWR ; ie. < space
|
|
WR RST 08H
|
|
NOWR RET
|
|
|
|
WRCRLF LD A, CR
|
|
RST 08H
|
|
LD A, LF
|
|
RST 08H
|
|
LD A, CR
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Initialise hardware and start main loop
|
|
;------------------------------------------------------------------------------
|
|
INIT
|
|
LD SP, STACK ; Set the Stack Pointer
|
|
|
|
; Initialise SIO A
|
|
|
|
LD A, 00H
|
|
OUT (SIOA_C), A
|
|
LD A, 18H
|
|
OUT (SIOA_C), A
|
|
|
|
LD A, 04H
|
|
OUT (SIOA_C), A
|
|
LD A, 0C4H
|
|
OUT (SIOA_C), A
|
|
|
|
LD A, 01H
|
|
OUT (SIOA_C), A
|
|
LD A, 00H
|
|
OUT (SIOA_C), A
|
|
|
|
LD A, 03H
|
|
OUT (SIOA_C), A
|
|
LD A, 0E1H
|
|
OUT (SIOA_C), A
|
|
|
|
LD A, 05H
|
|
OUT (SIOA_C), A
|
|
LD A, 0EAH
|
|
OUT (SIOA_C), A
|
|
|
|
; Initialise SIO B
|
|
|
|
LD A, 00H
|
|
OUT (SIOB_C), A
|
|
LD A, 18H
|
|
OUT (SIOB_C), A
|
|
|
|
LD A, 04H
|
|
OUT (SIOB_C), A
|
|
LD A, 0C4H
|
|
OUT (SIOB_C), A
|
|
|
|
LD A, 01H
|
|
OUT (SIOB_C), A
|
|
LD A, 00H
|
|
OUT (SIOB_C), A
|
|
|
|
LD A, 02H
|
|
OUT (SIOB_C), A
|
|
LD A, 00H
|
|
OUT (SIOB_C), A
|
|
|
|
LD A, 03H
|
|
OUT (SIOB_C), A
|
|
LD A, 0E1H
|
|
OUT (SIOB_C), A
|
|
|
|
LD A, 05H
|
|
OUT (SIOB_C), A
|
|
LD A, 0EAH
|
|
OUT (SIOB_C), A
|
|
|
|
; Set primary console and clear screen
|
|
|
|
LD A, 00H
|
|
LD (PRIMARYIO), A
|
|
LD A, CLS
|
|
RST 08H
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Monitor
|
|
;------------------------------------------------------------------------------
|
|
|
|
CALL TXCRLF ; TXCRLF
|
|
LD HL, SIGNON ; Print SIGNON message
|
|
CALL PRINT
|
|
|
|
; Command loop
|
|
|
|
MAIN
|
|
LD HL, MAIN ; Save entry point for Monitor
|
|
PUSH HL ; This is the return address
|
|
MAIN0 CALL TXCRLF ; Entry point for Monitor, Normal
|
|
LD A, '>' ; Get a ">"
|
|
RST 08H ; print it
|
|
|
|
MAIN1 CALL RDCHR ; Get a character from the input port
|
|
CP ' ' ; <spc> or less?
|
|
JR C, MAIN1 ; Go back
|
|
|
|
CP ':' ; ":"?
|
|
JP Z, LOAD ; First character of a HEX load
|
|
|
|
CALL WRCHR ; Print char on console
|
|
|
|
CP '?'
|
|
JP Z, HELP
|
|
|
|
AND 5FH ; Make character uppercase
|
|
|
|
CP 'R'
|
|
JP Z, RST00
|
|
|
|
CP 'B'
|
|
JP Z, BASIC
|
|
|
|
CP 'G'
|
|
JP Z, GOTO
|
|
|
|
CP 'X'
|
|
JP Z, CPMLOAD
|
|
|
|
LD A, '?' ; Get a "?"
|
|
RST 08H ; Print it
|
|
JR MAIN0
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Print string of characters to Serial A until byte=$00, WITH CR, LF
|
|
;------------------------------------------------------------------------------
|
|
|
|
PRINT
|
|
LD A, (HL) ; Get character
|
|
OR A ; Is it $00 ?
|
|
RET Z ; Then RETurn on terminator
|
|
RST 08H ; Print it
|
|
INC HL ; Next Character
|
|
JR PRINT ; Continue until $00
|
|
|
|
TXCRLF
|
|
LD A, 0DH ;
|
|
RST 08H ; Print character
|
|
LD A, 0AH ;
|
|
RST 08H ; Print character
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Get a character from the console, must be $20-$7F to be valid (no control characters)
|
|
; <Ctrl-c> and <SPACE> breaks with the Zero Flag set
|
|
;------------------------------------------------------------------------------
|
|
|
|
GETCHR
|
|
CALL RDCHR ; RX a Character
|
|
CP 03H ; <ctrl-c> User break?
|
|
RET Z
|
|
CP 20H ; <space> or better?
|
|
JR C, GETCHR ; Do it again until we get something usable
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Gets two ASCII characters from the console (assuming them to be HEX 0-9 A-F)
|
|
; Moves them into B and C, converts them into a byte value in A and updates a
|
|
; Checksum value in E
|
|
;------------------------------------------------------------------------------
|
|
|
|
GET2
|
|
CALL GETCHR ; Get us a valid character to work with
|
|
LD B, A ; Load it in B
|
|
CALL GETCHR ; Get us another character
|
|
LD C, A ; load it in C
|
|
CALL BCTOA ; Convert ASCII to byte
|
|
LD C, A ; Build the checksum
|
|
LD A, E
|
|
SUB C ; The checksum should always equal zero when checked
|
|
LD E, A ; Save the checksum back where it came from
|
|
LD A, C ; Retrieve the byte and go back
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Gets four Hex characters from the console, converts them to values in HL
|
|
;------------------------------------------------------------------------------
|
|
|
|
GETHL
|
|
LD HL, 00H ; Gets xxxx but sets Carry Flag on any Terminator
|
|
CALL ECHO ; RX a Character
|
|
CP 0DH ; <CR>?
|
|
JR NZ, GETX2 ; other key
|
|
SETCY SCF ; Set Carry Flag
|
|
RET ; and Return to main program
|
|
|
|
;------------------------------------------------------------------------------
|
|
; This routine converts last four hex characters (0-9 A-F) user types into a value in HL
|
|
; Rotates the old out and replaces with the new until the user hits a terminating character
|
|
;------------------------------------------------------------------------------
|
|
|
|
GETX
|
|
LD HL, 00H ; CLEAR HL
|
|
GETX1 CALL ECHO ; RX a character from the console
|
|
CP 0DH ; <CR>
|
|
RET Z ; quit
|
|
CP 2CH ; <,> can be used to safely quit for multiple entries
|
|
RET Z ; (Like filling both DE and HL from the user)
|
|
GETX2 CP 03H ; Likewise, a <ctrl-C> will terminate clean, too, but
|
|
JR Z, SETCY ; It also sets the Carry Flag for testing later.
|
|
ADD HL, HL ; Otherwise, rotate the previous low nibble to high
|
|
ADD HL, HL ; rather slowly
|
|
ADD HL, HL ; until we get to the top
|
|
ADD HL, HL ; and then we can continue on.
|
|
SUB 30H ; Convert ASCII to byte value
|
|
CP 0AH ; Are we in the 0-9 range?
|
|
JR C, GETX3 ; Then we just need to sub $30, but if it is A-F
|
|
SUB 07H ; We need to take off 7 more to get the value down to
|
|
GETX3 AND 0FH ; to the right hex value
|
|
ADD A, L ; Add the high nibble to the low
|
|
LD L, A ; Move the byte back to A
|
|
JR GETX1 ; and go back for next character until he terminates
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Convert ASCII characters in B C registers to a byte value in A
|
|
;------------------------------------------------------------------------------
|
|
|
|
BCTOA LD A, B ; Move the hi order byte to A
|
|
SUB 30H ; Take it down from Ascii
|
|
CP 0AH ; Are we in the 0-9 range here?
|
|
JR C, BCTOA1 ; If so, get the next nybble
|
|
SUB 07H ; But if A-F, take it down some more
|
|
BCTOA1 RLCA ; Rotate the nybble from low to high
|
|
RLCA ; One bit at a time
|
|
RLCA ; Until we
|
|
RLCA ; Get there with it
|
|
LD B, A ; Save the converted high nybble
|
|
LD A, C ; Now get the low order byte
|
|
SUB 30H ; Convert it down from Ascii
|
|
CP 0AH ; 0-9 at this point?
|
|
JR C, BCTOA2 ; Good enough then, but
|
|
SUB 07H ; Take off 7 more if it's A-F
|
|
BCTOA2 ADD A, B ; Add in the high order nybble
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Get a character and echo it back to the user
|
|
;------------------------------------------------------------------------------
|
|
|
|
ECHO
|
|
CALL RDCHR
|
|
CALL WRCHR
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; GOTO command
|
|
;------------------------------------------------------------------------------
|
|
|
|
GOTO
|
|
CALL GETHL ; ENTRY POINT FOR <G>oto addr. Get XXXX from user.
|
|
RET C ; Return if invalid
|
|
LD A, (PRIMARYIO)
|
|
PUSH HL
|
|
RET ; Jump to HL address value
|
|
|
|
;------------------------------------------------------------------------------
|
|
; LOAD Intel Hex format file from the console.
|
|
; [Intel Hex Format is:
|
|
; 1) Colon (Frame 0)
|
|
; 2) Record Length Field (Frames 1 and 2)
|
|
; 3) Load Address Field (Frames 3,4,5,6)
|
|
; 4) Record Type Field (Frames 7 and 8)
|
|
; 5) Data Field (Frames 9 to 9+2*(Record Length)-1
|
|
; 6) Checksum Field - Sum of all byte values from Record Length to and
|
|
; including Checksum Field = 0 ]
|
|
;------------------------------------------------------------------------------
|
|
|
|
LOAD
|
|
LD E, 0 ; First two Characters is the Record Length Field
|
|
CALL GET2 ; Get us two characters into BC, convert it to a byte <A>
|
|
LD D, A ; Load Record Length count into D
|
|
CALL GET2 ; Get next two characters, Memory Load Address <H>
|
|
LD H, A ; put value in H register.
|
|
CALL GET2 ; Get next two characters, Memory Load Address <L>
|
|
LD L, A ; put value in L register.
|
|
CALL GET2 ; Get next two characters, Record Field Type
|
|
CP 01H ; Record Field Type 00 is Data, 01 is End of File
|
|
JR NZ, LOAD2 ; Must be the end of that file
|
|
CALL GET2 ; Get next two characters, assemble into byte
|
|
LD A, E ; Recall the Checksum byte
|
|
AND A ; Is it Zero?
|
|
JR Z, LOAD00 ; Print footer reached message
|
|
JR LOADERR ; Checksums don't add up, Error out
|
|
|
|
LOAD2 LD A, D ; Retrieve line character counter
|
|
AND A ; Are we done with this line?
|
|
JR Z, LOAD3 ; Get two more ascii characters, build a byte and checksum
|
|
CALL GET2 ; Get next two chars, convert to byte in A, checksum it
|
|
LD (HL), A ; Move converted byte in A to memory location
|
|
INC HL ; Increment pointer to next memory location
|
|
LD A, '.' ; Print out a "." for every byte loaded
|
|
RST 08H ;
|
|
DEC D ; Decrement line character counter
|
|
JR LOAD2 ; and keep loading into memory until line is complete
|
|
|
|
LOAD3 CALL GET2 ; Get two chars, build byte and checksum
|
|
LD A, E ; Check the checksum value
|
|
AND A ; Is it zero?
|
|
RET Z
|
|
|
|
LOADERR LD HL, CKSUMERR ; Get "Checksum Error" message
|
|
CALL PRINT ; Print Message from (HL) and terminate the load
|
|
RET
|
|
|
|
LOAD00 LD HL, LDETXT ; Print load complete message
|
|
CALL PRINT
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Display Help command
|
|
;------------------------------------------------------------------------------
|
|
|
|
HELP
|
|
LD HL, HLPTXT ; Print Help message
|
|
CALL PRINT
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Start BASIC command
|
|
;------------------------------------------------------------------------------
|
|
|
|
BASIC
|
|
LD HL, BASTXT
|
|
CALL PRINT
|
|
CALL GETCHR
|
|
RET Z ; Cancel if CTRL-C
|
|
AND 5FH ; uppercase
|
|
CP 'C'
|
|
JP Z, BAS1
|
|
CP 'W'
|
|
JP Z, BAS2
|
|
RET
|
|
|
|
BASTXT
|
|
.BYTE 0DH, 0AH
|
|
.TEXT "Cold or Warm ?"
|
|
.BYTE 00H
|
|
|
|
BAS1 LD A, CLS
|
|
RST 08
|
|
JP BASCLD
|
|
|
|
BAS2 CALL TXCRLF
|
|
CALL TXCRLF
|
|
JP BASWRM
|
|
|
|
;------------------------------------------------------------------------------
|
|
; CP/M load command
|
|
;------------------------------------------------------------------------------
|
|
|
|
CPMLOAD
|
|
LD HL, CPMTXT
|
|
CALL PRINT
|
|
CALL GETCHR
|
|
RET Z ; Cancel if CTRL-C
|
|
AND 5FH ; uppercase
|
|
CP 'Y'
|
|
JP Z, CPMLOAD2
|
|
RET
|
|
|
|
CPMTXT .BYTE 0DH, 0AH
|
|
.TEXT "Boot CP/M?"
|
|
.BYTE 00H
|
|
|
|
CPMTXT2 .BYTE 0DH, 0AH
|
|
.TEXT "Loading CP/M..."
|
|
.BYTE 0DH, 0AH, 00H
|
|
|
|
CPMLOAD2
|
|
LD HL, CPMTXT2
|
|
CALL PRINT
|
|
|
|
CALL CFWAIT
|
|
LD A, CF_8BIT ; Set IDE to be 8bit
|
|
OUT (CF_FEATURES), A
|
|
LD A, CF_SET_FEAT
|
|
OUT (CF_COMMAND), A
|
|
|
|
CALL CFWAIT
|
|
LD A, CF_NOCACHE ; No write cache
|
|
OUT (CF_FEATURES), A
|
|
LD A, CF_SET_FEAT
|
|
OUT (CF_COMMAND), A
|
|
|
|
LD B, NUMSECS
|
|
|
|
LD A, 0
|
|
LD (SECNO), A
|
|
LD HL, LOADADDR
|
|
LD (DMAADDR), HL
|
|
|
|
PROCESSSECTORS
|
|
CALL CFWAIT
|
|
|
|
LD A, (SECNO)
|
|
OUT (CF_LBA0), A
|
|
LD A, 0
|
|
OUT (CF_LBA1), A
|
|
OUT (CF_LBA2), A
|
|
LD A, 0E0H
|
|
OUT (CF_LBA3), A
|
|
LD A, 1
|
|
OUT (CF_SECCOUNT), A
|
|
|
|
CALL READ
|
|
|
|
LD DE, 0200H
|
|
LD HL, (DMAADDR)
|
|
ADD HL, DE
|
|
LD (DMAADDR), HL
|
|
LD A, (SECNO)
|
|
INC A
|
|
LD (SECNO), A
|
|
|
|
DJNZ PROCESSSECTORS
|
|
|
|
; Start CP/M using entry at top of BIOS
|
|
; The current active console stream ID is pushed onto the stack
|
|
; to allow the CBIOS to pick it up
|
|
; 0 = SIO A, 1 = SIO B
|
|
|
|
LD A, (PRIMARYIO)
|
|
PUSH AF
|
|
LD HL, (0FFFEH)
|
|
JP (HL)
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; Read physical sector from host
|
|
|
|
READ
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH HL
|
|
|
|
CALL CFWAIT
|
|
|
|
LD A, CF_READ_SEC
|
|
OUT (CF_COMMAND), A
|
|
|
|
CALL CFWAIT
|
|
|
|
LD C, 4
|
|
LD HL, (DMAADDR)
|
|
RD4SECS
|
|
LD B, 128
|
|
RDBYTE
|
|
NOP
|
|
NOP
|
|
IN A, (CF_DATA)
|
|
LD (HL), A
|
|
INC HL
|
|
DEC B
|
|
JR NZ, RDBYTE
|
|
DEC C
|
|
JR NZ, RD4SECS
|
|
|
|
POP HL
|
|
POP BC
|
|
POP AF
|
|
|
|
RET
|
|
|
|
|
|
; Wait for disk to be ready (busy=0,ready=1)
|
|
|
|
CFWAIT
|
|
TSTBUSY IN A, (CF_STATUS)
|
|
AND 80H
|
|
JR NZ, TSTBUSY
|
|
TSTREADY IN A, (CF_STATUS)
|
|
AND 40H
|
|
JR Z, TSTREADY
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
SIGNON .BYTE "Z80 SBC Boot ROM 1.1"
|
|
.BYTE " by G. Searle"
|
|
.BYTE 0DH, 0AH
|
|
.BYTE "Type ? for options"
|
|
.BYTE 0DH, 0AH, 00H
|
|
|
|
CKSUMERR .BYTE "Checksum error"
|
|
.BYTE 0DH, 0AH, 00H
|
|
|
|
LDETXT .TEXT "Load complete."
|
|
.BYTE 0DH, 0AH, 00H
|
|
|
|
HLPTXT .BYTE 0DH, 0AH
|
|
.TEXT "R - Reset"
|
|
.BYTE 0DH, 0AH
|
|
.TEXT "BC or BW - ROM BASIC Cold or Warm"
|
|
.BYTE 0DH, 0AH
|
|
.TEXT "X - Boot CP/M (load $D000-$FFFF from disk)"
|
|
.BYTE 0DH, 0AH
|
|
.TEXT ":nnnnnn... - Load Intel-Hex file record"
|
|
.BYTE 0DH, 0AH
|
|
.BYTE 00H
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
.ORG 4000H
|
|
|
|
PRIMARYIO .DS 1
|
|
SECNO .DS 1
|
|
DMAADDR .DS 2
|
|
|
|
STACKSPACE .DS 32
|
|
STACK .EQU $ ; Stack top
|
|
|
|
.END
|