;----------------------------------------------------------------------------- ; Mini Z80 BIOS ; Mike Christle (c) 2016 ;----------------------------------------------------------------------------- ; TERMS OF USE: MIT License ;----------------------------------------------------------------------------- ; Permission is hereby granted, free of charge, to any person obtaining a ; copy of this software and associated documentation files (the "Software"), ; to deal in the Software without restriction, including without limitation ; the rights to use, copy, modify, merge, publish, distribute, sublicense, ; and/or sell copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ; DEALINGS IN THE SOFTWARE. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; 68681 DUART Register Port Addresses ;----------------------------------------------------------------------------- DUART_MR1A EQU 0 DUART_MR2A EQU 0 DUART_SRA EQU 1 DUART_CSRA EQU 1 DUART_CRA EQU 2 DUART_RHRA EQU 3 DUART_THRA EQU 3 DUART_IPCR EQU 4 DUART_ACR EQU 4 DUART_ISR EQU 5 DUART_IMR EQU 5 DUART_IVR EQU 12 DUART_OPCR EQU 13 DUART_SOPR EQU 14 DUART_ROPR EQU 15 ;----------------------------------------------------------------------------- ; 68681 Interrupt Service Register Constants ;----------------------------------------------------------------------------- INPORT_INT_BIT EQU 7 BREAKB_INT_BIT EQU 6 RXRDYB_INT_BIT EQU 5 TXRDYB_INT_BIT EQU 4 CTRRDY_INT_BIT EQU 3 BREAKA_INT_BIT EQU 2 RXRDYA_INT_BIT EQU 1 TXRDYA_INT_BIT EQU 0 ;----------------------------------------------------------------------------- ; 68681 Command Register Constants ; Bit 7 - 0 ; Bit 654 - Commands ; Bit 3 - Disable Transmiter ; Bit 2 - Enable Transmiter ; Bit 1 - Disable Receiver ; Bit 0 - Enable Receiver ;----------------------------------------------------------------------------- CRA_RESET_MRA EQU 10H CRA_RESET_RCVR EQU 20H CRA_RESET_XMTR EQU 30H CRA_RESET_ERRORS EQU 40H CRA_RESET_BREAK EQU 50H CRA_START_BREAK EQU 60H CRA_STOP_BREAK EQU 70H CRA_DISABLE_XMTR EQU 08H CRA_ENABLE_XMTR EQU 04H CRA_DISABLE_RCVR EQU 02H CRA_ENABLE_RCVR EQU 01H ASCII_CR EQU 13 ASCII_LF EQU 10 ;----------------------------------------------------------------------------- ; RAM ;----------------------------------------------------------------------------- APP_START EQU 8000H STACK_INIT EQU 0FE00H ORG STACK_INIT BUFFER_SIZE EQU 80H BUFFER_SIZE_MASK EQU BUFFER_SIZE - 1 TxBufr DS BUFFER_SIZE RxBufr DS BUFFER_SIZE CmndBufr DS BUFFER_SIZE TxTop DS 1 TxBot DS 1 RxTop DS 1 RxBot DS 1 ISR_IMAGE DS 1 IMR_IMAGE DS 1 ORG 0FFF0H TXRDYA_IV DS 2 ;TxRDY AInterrupt Vector RXRDYA_IV DS 2 ;RxRDY A Interrupt Vector BREAKA_IV DS 2 ;Delta Break A Interrupt Vector CTRRDY_IV DS 2 ;Counter Ready Interrupt Vector TXRDYB_IV DS 2 ;TxRDY B Interrupt Vector RXRDYB_IV DS 2 ;RxRDY B Interrupt Vector BREAKB_IV DS 2 ;Delta Break B Interrupt Vector INPORT_IV DS 2 ;In Port Change Interrupt Vector ;----------------------------------------------------------------------------- ORG 00H JP SYSTEM_RESET ORG 08H JP (HL) ORG 10H JP SYSTEM_RESET ORG 18H JP SYSTEM_RESET ORG 20H JP SYSTEM_RESET ORG 28H JP SYSTEM_RESET ORG 30H JP SYSTEM_RESET ;----------------------------------------------------------------------------- ; 68681 DUART Interrupt Service Routine ;----------------------------------------------------------------------------- ORG 38H EX AF, AF' EXX IN A, (DUART_ISR) LD B, A LD A, (IMR_IMAGE) AND B LD (ISR_IMAGE), A BIT RXRDYA_INT_BIT, A JR Z, INT_VECTOR_1 LD HL, (RXRDYA_IV) CALL INT_VECTOR_10 INT_VECTOR_1 LD A, (ISR_IMAGE) BIT TXRDYA_INT_BIT, A JR Z, INT_VECTOR_2 LD HL, (TXRDYA_IV) CALL INT_VECTOR_10 INT_VECTOR_2 LD A, (ISR_IMAGE) BIT BREAKA_INT_BIT, A JR Z, INT_VECTOR_3 LD HL, (BREAKA_IV) CALL INT_VECTOR_10 INT_VECTOR_3 LD A, (ISR_IMAGE) BIT CTRRDY_INT_BIT, A JR Z, INT_VECTOR_4 LD HL, (CTRRDY_IV) CALL INT_VECTOR_10 INT_VECTOR_4 LD A, (ISR_IMAGE) BIT TXRDYB_INT_BIT, A JR Z, INT_VECTOR_5 LD HL, (TXRDYB_IV) CALL INT_VECTOR_10 INT_VECTOR_5 LD A, (ISR_IMAGE) BIT RXRDYB_INT_BIT, A JR Z, INT_VECTOR_6 LD HL, (RXRDYB_IV) CALL INT_VECTOR_10 INT_VECTOR_6 LD A, (ISR_IMAGE) BIT BREAKB_INT_BIT, A JR Z, INT_VECTOR_7 LD HL, (BREAKB_IV) CALL INT_VECTOR_10 INT_VECTOR_7 LD A, (ISR_IMAGE) BIT INPORT_INT_BIT, A JR Z, INT_VECTOR_8 LD HL, (INPORT_IV) CALL INT_VECTOR_10 INT_VECTOR_8 EXX EX AF, AF' EI RETI INT_VECTOR_10 JP (HL) ;----------------------------------------------------------------------------- ; System Initialization ;----------------------------------------------------------------------------- SYSTEM_RESET DI ;Disable interrupts LD SP, STACK_INIT ;Init stack pointer IM 0 ;Auto-Vector Interrupts LD A, 0 LD (TxTop), A LD (TxBot), A LD (RxTop), A LD (RxBot), A ;----------------------------------------------------------------------------- ; Init Interrupt Vectors ;----------------------------------------------------------------------------- LD HL, SYSTEM_RESET LD (InPort_IV), HL LD (BreakB_IV), HL LD (RxRdyB_IV), HL LD (TxRdyB_IV), HL LD (CtrRdy_IV), HL LD (BreakA_IV), HL LD HL, RX_ISR LD (RxRdyA_IV), HL LD HL, TX_ISR LD (TxRdyA_IV), HL ;----------------------------------------------------------------------------- ; Initialize the 68681 DUART ;----------------------------------------------------------------------------- LD A, CRA_RESET_RCVR OUT (DUART_CRA), A LD A, CRA_RESET_XMTR OUT (DUART_CRA), A LD A, CRA_RESET_MRA OUT (DUART_CRA), A LD A, 0FFH OUT (DUART_IVR), A ;----------------------------------------------------------------------------- ; 68681 MR1A ; Bit 7 = 0 - No RTS Control ; Bit 6 = 0 - RxDRY Causes Interrupt ; Bit 5 = 0 - Char Error Mode ; Bit 432 = 100 - No Parity ; Bit 10 = 11 - 8 Data Bits ;----------------------------------------------------------------------------- LD A, 13H OUT (DUART_MR1A), A ;----------------------------------------------------------------------------- ; 68681 MR2A ; Bit 76 = 00 - Normal Mode ; Bit 5 = 0 - No TxRTS Control ; Bit 4 = 0 - No TxCTS Control ; Bit 3210 = 0111 - 1 Stop Bit ;----------------------------------------------------------------------------- LD A, 07H OUT (DUART_MR2A), A ;----------------------------------------------------------------------------- ; 68681 CSRA ; Bit 7654 = 1011 - Receiver 9600 Baud ; Bit 3210 = 1011 - Transmiter 9600 Baud ;----------------------------------------------------------------------------- LD A, 0BBH OUT (DUART_CSRA), A ;----------------------------------------------------------------------------- ; 68681 IMR ; Bit 7 = 0 - In Port Change Interrupt ; Bit 6 = 0 - Delta Break B Interrupt ; Bit 5 = 0 - RxRDY B Interrupt ; Bit 4 = 0 - TxRDY B Interrupt ; Bit 3 = 0 - Counter Ready Interrupt ; Bit 2 = 0 - Delta Break A Interrupt ; Bit 1 = 1 - RxRDY A Interrupt ; Bit 0 = 1 - TxRDY A Interrupt ;----------------------------------------------------------------------------- LD A, 0FFH OUT (DUART_IMR), A LD (IMR_IMAGE), A ;----------------------------------------------------------------------------- ; Enable UART Receiver ;----------------------------------------------------------------------------- LD A, CRA_ENABLE_RCVR OUT (DUART_CRA), A ;----------------------------------------------------------------------------- ; Command loop ;----------------------------------------------------------------------------- EI LD DE, HeaderMsg CALL PUTS CMND_LOOP LD DE, PromptMsg CALL PUTS LD DE, CmndBufr LD C, BUFFER_SIZE CALL GETS LD A, (CmndBufr) OR 20H CP 'd' JR NZ, CMND_LOOP_1 CALL DUMP_MEM JR CMND_LOOP CMND_LOOP_1 CP 's' JR NZ, CMND_LOOP_2 CALL APP_START JR CMND_LOOP CMND_LOOP_2 CP ':' JR NZ, CMND_LOOP_3 CALL DOWNLOAD JR CMND_LOOP CMND_LOOP_3 CP 'f' JR NZ, CMND_LOOP CALL FILL_MEM JR CMND_LOOP HeaderMsg DB "Mini Z80", ASCII_CR, 0 PromptMsg DB "> ", 0 ;----------------------------------------------------------------------------- ; DUART Receive Interrupt Service Routine ;----------------------------------------------------------------------------- RX_ISR LD A, (RxTop) LD B, A LD HL, RxBufr ADD A, L LD L, A IN A, (DUART_RHRA) LD (HL), A LD A, B INC A AND BUFFER_SIZE_MASK LD (RxTop), A RX_ISR_X RET ;----------------------------------------------------------------------------- ; DUART Transmit Interrupt Service Routine ;----------------------------------------------------------------------------- TX_ISR LD A, (TxBot) LD HL, TxTop CP (HL) JR NZ, TX_ISR_1 LD A, CRA_DISABLE_XMTR OUT (DUART_CRA), A JP TX_ISR_X TX_ISR_1 LD B, A LD HL, TxBufr ADD A, L LD L, A LD A, (HL) OUT (DUART_THRA), A LD A, B INC A AND BUFFER_SIZE_MASK LD (TxBot), A TX_ISR_X RET ;----------------------------------------------------------------------------- ; GETC ; Output A = Char ; z = 1 if buffer empty ;----------------------------------------------------------------------------- GETC PUSH HL PUSH BC LD A, (RxBot) LD B, A LD HL, RxTop SUB (HL) JR Z, GETC_X LD A, B LD HL, RxBufr ADD A, L LD L, A LD A, B INC A AND BUFFER_SIZE_MASK DI LD (RxBot), A LD A, (HL) EI BIT 7, H GETC_X POP BC POP HL RET ;----------------------------------------------------------------------------- ; GETS ; Exits on CR or buffer full ; Terminates buffer with 0. ; Input DE = Address of buffer ; C = Buffer size ;----------------------------------------------------------------------------- GETS DEC C JR Z, GETS_X GETS_1 CALL GETC JR Z, GETS_1 CP ASCII_CR JR Z, GETS_X LD (DE), A INC DE JR GETS GETS_X XOR A LD (DE), A RET ;----------------------------------------------------------------------------- ; PUTC ; Waits if buffer full ; Input A = Char ;----------------------------------------------------------------------------- PUTC PUSH HL PUSH BC PUSH AF LD A, (TxTop) LD BC, TxBufr ADD A, C LD C, A LD A, (TxTop) INC A AND BUFFER_SIZE_MASK LD HL, TxBot PUTC_1 CP (HL) JR Z, PUTC_1 DI LD (TxTop), A POP AF LD (BC), A EI LD A, CRA_ENABLE_XMTR OUT (DUART_CRA), A POP BC POP HL RET ;----------------------------------------------------------------------------- ; PUTS ; Input DE = Address of null terminated string ;----------------------------------------------------------------------------- PUTS LD A, (DE) CP 0 JR Z, PUTS_X CALL PUTC INC DE JR PUTS PUTS_X RET ;----------------------------------------------------------------------------- ; Dump Memory ; B - Line Counter ; C - Byte Counter ; DE - Memory Address ;----------------------------------------------------------------------------- DUMP_MEM LD DE, APP_START LD B, 8 DUMP_MEM_1 LD C, 16 LD A, D CALL PRINT_HEX LD A, E CALL PRINT_HEX DUMP_MEM_2 LD A, ' ' CALL PUTC LD A, (DE) INC DE CALL PRINT_HEX DEC C JR NZ, DUMP_MEM_2 LD A, ASCII_CR CALL PUTC DEC B JR NZ, DUMP_MEM_1 DUMP_MEM_X RET ;----------------------------------------------------------------------------- ; Print a Hex Digit ; Input A = Value ;----------------------------------------------------------------------------- PRINT_HEX PUSH HL PUSH AF SRL A SRL A SRL A SRL A LD HL, HEX_DIGITS ADD A, L LD L, A LD A, (HL) CALL PUTC POP AF AND 0FH LD HL, HEX_DIGITS ADD A, L LD L, A LD A, (HL) CALL PUTC POP HL RET HEX_DIGITS DB "0123456789ABCDEF" ;----------------------------------------------------------------------------- ; FILL_MEM ;----------------------------------------------------------------------------- FILL_MEM LD DE, APP_START LD A, 0 FILL_MEM_1 LD (DE), A INC DE INC A JR NZ, FILL_MEM_1 RET ;----------------------------------------------------------------------------- ; DOWNLOAD ; HL - Load address ; BC - CMDBUF pointer ; D - Byte count ; E - Checksum ;----------------------------------------------------------------------------- DOWNLOAD LD BC, CmndBufr ;Setup record pointer INC BC ;Skip ':' CALL HTOI ;Get the record length LD D, A LD E, A ;Init the checksum CALL HTOI ;Get offset high byte LD H, A ADD A, E ;Update the checksum LD E, A CALL HTOI ;Get offset low byte LD L, A ADD A, E ;Update the checksum LD E, A CALL HTOI ;Get record type AND A ;Check data record type JR NZ, DOWNLOAD_2 ;Ignore non-data records DOWNLOAD_1 CALL HTOI ;Get a data byte LD (HL), A ;Store in memory INC HL ;Increment pointer ADD A, E ;Update the checksum LD E, A DEC D ;Decrement data count JR NZ, DOWNLOAD_1 ;Loop until count zero CALL HTOI ;Get checksum byte ADD A, E ;Update the checksum JR Z, DOWNLOAD_2 ;Continue if checksum is zero LD HL, DOWNLOAD_ERR_MSG CALL PUTS ;Output error message DOWNLOAD_2 RET DOWNLOAD_ERR_MSG DB "Error - Bad checksum", ASCII_CR, 0 ;----------------------------------------------------------------------------- ; HTOI Hex to Integer ; Input BC - Pointer to string ; Output BC - Points to next character ; A - Value ;----------------------------------------------------------------------------- HTOI PUSH DE LD A, (BC) ;Get a character from buffer INC BC ;Increment buffer pointer SUB '0' ;Subtract '0' CP 10 ;Compare to 10 JR C, HTOI_1 ;Skip if less than 10 SUB 7 ;Subtract 7 for letters HTOI_1 SLA A ;Shift left SLA A ;Shift left SLA A ;Shift left SLA A ;Shift left LD D, A ;Save in D LD A, (BC) ;Get a character from buffer INC BC ;Increment buffer pointer SUB '0' ;Subtract '0' CP 10 ;Compare to 10 JR C, HTOI_2 ;Skip if less than 10 SUB 7 ;Subtract 7 for letters HTOI_2 OR D ;Combine nibbles together POP DE RET ;----------------------------------------------------------------------------- ; Link Interrupt Service Routine ; A = Vector Number ; DE = ISR Address ;----------------------------------------------------------------------------- LINK_ISR PUSH HL LD HL, 0FFF0H ADD A, L LD L, A LD (HL), E INC HL LD (HL), D POP HL RET ;----------------------------------------------------------------------------- ; BIOS Interface Vectors ;----------------------------------------------------------------------------- ORG 1F00H VECTOR_TABLE DW GETC DW PUTC DW GETS DW PUTS DW PRINT_HEX DW LINK_ISR