*-----------------------------------------------------------------------------
* Mini 68008 BIOS
* Mike Christle 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     $8000
DUART_MR2A      EQU     $8000
DUART_SRA       EQU     $8002
DUART_CSRA      EQU     $8002
DUART_CRA       EQU     $8004
DUART_RHRA      EQU     $8006
DUART_THRA      EQU     $8006
DUART_IPCR      EQU     $8008
DUART_ACR       EQU     $8008
DUART_ISR       EQU     $800A
DUART_IMR       EQU     $800A
DUART_IVR       EQU     $8018
DUART_OPCR      EQU     $801A
DUART_SOPR      EQU     $801C
DUART_ROPR      EQU     $801E

*-----------------------------------------------------------------------------
* 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     $10
CRA_RESET_RCVR  EQU     $20
CRA_RESET_XMTR  EQU     $30
CRA_RESER_ERROR EQU     $40
CRA_RESET_BREAK EQU     $50
CRA_START_BREAK EQU     $60
CRA_STOP_BREAK  EQU     $70
CRA_DISABLE_TX  EQU     $08
CRA_ENABLE_TX   EQU     $04
CRA_DISABLE_RX  EQU     $02
CRA_ENABLE_RX   EQU     $01

ASCII_CR        EQU     13
ASCII_LF        EQU     10

INT_MASK        EQU     ~$0700
SSP_INIT        EQU     $17E00
APP_START       EQU     $10000

*--------------------------------------------------------------------------
* Register Usage
* A0 Temp                       D0 Temp
* A1 Temp                       D1 Temp
* A2 Save                       D2 Temp
* A3 Save                       D3 Temp
* A4 Save                       D4 Save
* A5 App Static Data Address    D5 Save
* A6 BIOS Static Data Address   D6 Save
* A7 Stack Pointer              D7 Save
*--------------------------------------------------------------------------

*--------------------------------------------------------------------------
* BIOS STATIC DATA
*--------------------------------------------------------------------------
BUFR_SIZE       EQU     128
BUFR_SIZE_MASK  EQU     BUFR_SIZE - 1

                ORG     0

TXRDYA_IV       DS      4                 *TxRDY AInterrupt Vector
RXRDYA_IV       DS      4                 *RxRDY A Interrupt Vector
BREAKA_IV       DS      4                 *Delta Break A Interrupt Vector
CTRRDY_IV       DS      4                 *Counter Ready Interrupt Vector
TXRDYB_IV       DS      4                 *TxRDY B Interrupt Vector
RXRDYB_IV       DS      4                 *RxRDY B Interrupt Vector
BREAKB_IV       DS      4                 *Delta Break B Interrupt Vector
INPORT_IV       DS      4                 *In Port Change Interrupt Vector

RXBUFR          DS      BUFR_SIZE
TXBUFR          DS      BUFR_SIZE
CMND_BUFR       DS      BUFR_SIZE
TXTOP           DS      2
TXBOT           DS      2
RXTOP           DS      2
RXBOT           DS      2
IMR_IMAGE       DS      1
ISR_IMAGE       DS      1

*--------------------------------------------------------------------------
                ORG     $0
*--------------------------------------------------------------------------

                DL      SSP_INIT        *00 Reset: Initial SSP
                DA      INIT_RESET      *01 Reset: Initial PC
                DA      ERROR_RESET     *02 Bus Error
                DA      ERROR_RESET     *03 Address Error
                DA      ERROR_RESET     *04 Illegal Instruction
                DA      ERROR_RESET     *05 Zero Divide
                DA      ERROR_RESET     *06 CHK Instruction
                DA      ERROR_RESET     *07 TRAPV Instruction
                DA      ERROR_RESET     *08 Privilege Violation
                DA      ERROR_RESET     *09 Trace
                DA      ERROR_RESET     *0A Line 1010 Emulator
                DA      ERROR_RESET     *0B Line 1111 Emulator
                DA      ERROR_RESET     *0C (Unassigned, Reserved)
                DA      ERROR_RESET     *0D (Unassigned, Reserved)
                DA      ERROR_RESET     *0E (Unassigned, Reserved)
                DA      ERROR_RESET     *0F Uninitialized Interrupt Vector
                DA      ERROR_RESET     *10 (Unassigned, Reserved)
                DA      ERROR_RESET     *11 (Unassigned, Reserved)
                DA      ERROR_RESET     *12 (Unassigned, Reserved)
                DA      ERROR_RESET     *13 (Unassigned, Reserved)
                DA      ERROR_RESET     *14 (Unassigned, Reserved)
                DA      ERROR_RESET     *15 (Unassigned, Reserved)
                DA      ERROR_RESET     *16 (Unassigned, Reserved)
                DA      ERROR_RESET     *17 (Unassigned, Reserved)
                DA      ERROR_RESET     *18 Spurious Interrupt
                DA      ERROR_RESET     *19 Level 1 Interrupt Autovector
                DA      ERROR_RESET     *1A Level 2 Interrupt Autovector
                DA      ERROR_RESET     *1B Level 3 Interrupt Autovector
                DA      ERROR_RESET     *1C Level 4 Interrupt Autovector
                DA      ERROR_RESET     *1D Level 5 Interrupt Autovector
                DA      ERROR_RESET     *1E Level 6 Interrupt Autovector
                DA      ERROR_RESET     *1F Level 7 Interrupt Autovector
                DA      BIOS_CALL       *20 TRAP Instruction Vectors
                DA      ERROR_RESET     *21 TRAP Instruction Vectors
                DA      ERROR_RESET     *22 TRAP Instruction Vectors
                DA      ERROR_RESET     *23 TRAP Instruction Vectors
                DA      ERROR_RESET     *24 TRAP Instruction Vectors
                DA      ERROR_RESET     *25 TRAP Instruction Vectors
                DA      ERROR_RESET     *26 TRAP Instruction Vectors
                DA      ERROR_RESET     *27 TRAP Instruction Vectors
                DA      ERROR_RESET     *28 TRAP Instruction Vectors
                DA      ERROR_RESET     *29 TRAP Instruction Vectors
                DA      ERROR_RESET     *2A TRAP Instruction Vectors
                DA      ERROR_RESET     *2B TRAP Instruction Vectors
                DA      ERROR_RESET     *2C TRAP Instruction Vectors
                DA      ERROR_RESET     *2D TRAP Instruction Vectors
                DA      ERROR_RESET     *2E TRAP Instruction Vectors
                DA      ERROR_RESET     *2F TRAP Instruction Vectors
                DA      ERROR_RESET     *30 (Unassigned, Reserved)
                DA      ERROR_RESET     *31 (Unassigned, Reserved)
                DA      ERROR_RESET     *32 (Unassigned, Reserved)
                DA      ERROR_RESET     *33 (Unassigned, Reserved)
                DA      ERROR_RESET     *34 (Unassigned, Reserved)
                DA      ERROR_RESET     *35 (Unassigned, Reserved)
                DA      ERROR_RESET     *36 (Unassigned, Reserved)
                DA      ERROR_RESET     *37 (Unassigned, Reserved)
                DA      ERROR_RESET     *38 (Unassigned, Reserved)
                DA      ERROR_RESET     *39 (Unassigned, Reserved)
                DA      ERROR_RESET     *3A (Unassigned, Reserved)
                DA      ERROR_RESET     *3B (Unassigned, Reserved)
                DA      ERROR_RESET     *3C (Unassigned, Reserved)
                DA      ERROR_RESET     *3D (Unassigned, Reserved)
                DA      ERROR_RESET     *3E (Unassigned, Reserved)
                DA      ERROR_RESET     *3F (Unassigned, Reserved)

*40–FF User Interrupt Vectors

                DA      DUART_INT       *40 68681 DUART INTERRUPT

*--------------------------------------------------------------------------
                ORG     $400

ERROR_RESET     RESET
                
INIT_RESET      MOVEA.L #SSP_INIT, A7     *System Stack Pointer
                MOVEA.L #SSP_INIT, A6     *BIOS Static Data Address

                CLR.W   (TXTOP, A6)
                CLR.W   (TXBOT, A6)
                CLR.W   (RXTOP, A6)
                CLR.W   (RXBOT, A6)

*-----------------------------------------------------------------------------
* Init Interrupt Vectors
*-----------------------------------------------------------------------------
                MOVEA.L #$0400, A0
                MOVE.L  A0, (INPORT_IV, A6)
                MOVE.L  A0, (BREAKB_IV, A6)
                MOVE.L  A0, (RXRDYB_IV, A6)
                MOVE.L  A0, (TXRDYB_IV, A6)
                MOVE.L  A0, (CTRRDY_IV, A6)
                MOVE.L  A0, (BREAKA_IV, A6)

                MOVE.L  #RX_INT, (RXRDYA_IV, A6)
                MOVE.L  #TX_INT, (TXRDYA_IV, A6)

*-----------------------------------------------------------------------------
* Reset the 68681 DUART
*-----------------------------------------------------------------------------
                MOVE.B  #CRA_RESET_RCVR, (DUART_CRA).W
                MOVE.B  #CRA_RESET_XMTR, (DUART_CRA).W
                MOVE.B  #CRA_RESET_MRA, (DUART_CRA).W

*-----------------------------------------------------------------------------
* 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
*-----------------------------------------------------------------------------
                MOVE.B  #$13, (DUART_MR1A).W

*-----------------------------------------------------------------------------
* 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
*-----------------------------------------------------------------------------
                MOVE.B  #$07, (DUART_MR2A).W

*-----------------------------------------------------------------------------
* 68681 CSRA
* Bit 7654 = 1011 - Receiver 9600 Baud
* Bit 3210 = 1011 - Transmiter 9600 Baud
*-----------------------------------------------------------------------------
                MOVE.B  #$BB, (DUART_CSRA).W

*-----------------------------------------------------------------------------
* 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 AInterrupt
*-----------------------------------------------------------------------------
                MOVE.B  #$03, (DUART_IMR).W
                MOVE.B  #$03, (IMR_IMAGE, A6)
                MOVE.B  #$40, (DUART_IVR).W

*-----------------------------------------------------------------------------
* Enable UART Receiver
*-----------------------------------------------------------------------------
                MOVE.B  #CRA_ENABLE_RX, (DUART_CRA).W
                MOVE.W  #$2000, SR

*--------------------------------------------------------------------------
* Command Loop
*--------------------------------------------------------------------------
                MOVEA.L #HEADER, A2
                BSR     PUTS

COMMAND_LOOP    MOVEA.L #PROMPT, A2
                BSR     PUTS

                LEA     (CMND_BUFR, A6), A2
                MOVE.W  #BUFR_SIZE, D4
                BSR     GETS

                LEA     (CMND_BUFR, A6), A2
                MOVE.B  (A2)+, D0
                ORI.B   #$20, D0

                CMPI.B  #'d', D0
                BNE.S   COMMAND_LOOP_1
                BSR     DUMP_MEMORY
                BRA.S   COMMAND_LOOP

COMMAND_LOOP_1  CMPI.B  #'f', D0
                BNE.S   COMMAND_LOOP_2
                BSR     FILL_MEMORY
                BRA.S   COMMAND_LOOP

COMMAND_LOOP_2  CMPI.B  #'s', D0
                BNE.S   COMMAND_LOOP_3
                BSR     DOWNLOAD
                BRA.S   COMMAND_LOOP

COMMAND_LOOP_3  CMPI.B  #'j', D0
                BNE.S   COMMAND_LOOP_9
                BSR     JSR_TO
                BRA.S   COMMAND_LOOP

COMMAND_LOOP_9  CMPI.B  #'?', D0
                BNE.S   COMMAND_LOOP
                MOVEA.W #MENU_STR, A2
                BSR     PUTS
                BRA.S   COMMAND_LOOP

MENU_STR        DB      "D ADRS COUNT       - Dump Memory ", ASCII_CR
                DB      "F ADRS VALUE COUNT - Fill Memory ", ASCII_CR
                DB      "J ADRS             - JSR To Adrs ", ASCII_CR
                DB      "S2xxx              - Download Hex Record ", ASCII_CR
                DB      "?                  - Menu ", ASCII_CR, 0
HEADER          DB      "Mini 68008 BIOS", ASCII_CR, 0
PROMPT          DB      ">", 0

*--------------------------------------------------------------------------
* DUART Interrupt Service Routine
*--------------------------------------------------------------------------
DUART_INT       MOVEM.L D0-D1/A0, -(A7)

                MOVE.B  (DUART_ISR).W, D0
                AND.B   (IMR_IMAGE, A6), D0
                MOVE.B  D0, (ISR_IMAGE, A6)

                BTST.L  #CTRRDY_INT_BIT, D0
                BEQ.S   DUART_INT_1
                MOVEA.L (CTRRDY_IV, A6), A0
                JSR     (A0)

DUART_INT_1     BTST.B  #INPORT_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_2
                MOVEA.L (INPORT_IV, A6), A0
                JSR     (A0)

DUART_INT_2     BTST.B  #RXRDYA_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_3
                MOVEA.L (RXRDYA_IV, A6), A0
                JSR     (A0)

DUART_INT_3     BTST.B  #RXRDYB_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_4
                MOVEA.L (RXRDYB_IV, A6), A0
                JSR     (A0)

DUART_INT_4     BTST.B  #TXRDYA_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_5
                MOVEA.L (TXRDYA_IV, A6), A0
                JSR     (A0)

DUART_INT_5     BTST.B  #TXRDYB_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_6
                MOVEA.L (TXRDYB_IV, A6), A0
                JSR     (A0)

DUART_INT_6     BTST.B  #BREAKB_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_7
                MOVEA.L (BREAKB_IV, A6), A0
                JSR     (A0)

DUART_INT_7     BTST.B  #BREAKA_INT_BIT, (ISR_IMAGE, A6)
                BEQ.S   DUART_INT_X
                MOVEA.L (BREAKA_IV, A6), A0
                JSR     (A0)

DUART_INT_X     MOVEM.L (A7)+, D0-D1/A0
                RTE

*--------------------------------------------------------------------------
* TX_INT
*--------------------------------------------------------------------------
TX_INT          MOVE.W  (TXBOT, A6), D0
                CMP.W   (TXTOP, A6), D0
                BNE.S   TX_INT_1

                MOVE.B  #CRA_DISABLE_TX, (DUART_CRA).W
                BRA.S   TX_INT_X

TX_INT_1        LEA     (TXBUFR, A6), A0
                MOVE.B  (0, A0, D0.W), (DUART_THRA).W

                ADDQ.W  #1, D0
                ANDI.W  #BUFR_SIZE_MASK, D0
                MOVE.W  D0, (TXBOT, A6)

TX_INT_X        RTS

*--------------------------------------------------------------------------
* PUTC
*
* D2.B = Char
*--------------------------------------------------------------------------
PUTC            MOVE.W  (TXTOP, A6), D1
                MOVE.W  D1, D0
                ADDQ.W  #1, D1
                ANDI.W  #BUFR_SIZE_MASK, D1

PUTC_1          CMP.W   (TXBOT, A6), D1
                BEQ.S   PUTC_1

                LEA     (TXBUFR, A6), A0
                MOVE.B  D2, (0, A0, D0.W) 
                MOVE.W  D1, (TXTOP, A6)
                MOVE.B  #CRA_ENABLE_TX, (DUART_CRA).W
                RTS

*--------------------------------------------------------------------------
* PUTS
*
* A2 = Pointer to NULL terminated string
*--------------------------------------------------------------------------
PUTS            MOVE.B  (A2)+, D2
                BEQ.S   PUTS_X

                BSR.S   PUTC
                BRA.S   PUTS

PUTS_X          RTS

*--------------------------------------------------------------------------
* RX_INT
*--------------------------------------------------------------------------
RX_INT          MOVE.B  (DUART_RHRA).W, D1
                LEA     (RXBUFR, A6), A0
                MOVE.W  (RXTOP, A6), D0
                ADDA.W  D0, A0

                ADDQ.W  #1, D0
                ANDI.W  #BUFR_SIZE_MASK, D0
                CMP.W   (RXBOT, A6), D0
                BEQ.S   RX_INT_X

                MOVE.B  D1, (A0)
                MOVE.W  D0, (RXTOP, A6)

RX_INT_X        RTS

*--------------------------------------------------------------------------
* GETC
*
* D2.B = Char, 0 If Buffer Empty
* Z = 1          If Buffer Empty
*--------------------------------------------------------------------------
GETC            CLR.L   D2
                MOVE.W  (RXBOT, A6), D1
                CMP.W   (RXTOP, A6), D1
                BEQ.S   GETC_X

                LEA     (RXBUFR, A6), A0
                MOVE.B  (0, A0, D1.W), D2
                ADDQ.W  #1, D1
                ANDI.W  #BUFR_SIZE_MASK, D1
                MOVE.W  D1, (RXBOT, A6)
                ADDQ.L  #1, D1

GETC_X          RTS

*--------------------------------------------------------------------------
* GETS
*
* A2 = Pointer to buffer
* D4 = Buffer size
* Terminated on CR
*--------------------------------------------------------------------------
GETS            SUBQ.W  #1, D4
                BEQ.S   GETS_X

GETS_1          BSR.S   GETC
                BEQ.S   GETS_1

                CMP.B   #ASCII_CR, D2
                BEQ.S   GETS_X

                MOVE.B  D2, (A2)+
                BRA.S   GETS

GETS_X          CLR.B   (A2)
                RTS

*--------------------------------------------------------------------------
* JSR To Address
*--------------------------------------------------------------------------
JSR_TO          LEA     (CMND_BUFR + 1, A6), A2
                BSR     PARSE_PARM
                MOVEA.L D0, A0
                JSR     (A0)
                RTS

*--------------------------------------------------------------------------
* DOWNLOAD S2 RECORD
*
* All other S-Records are ignored
* D6 - Byte Counter
* D7 - Checksum
* A2 - Input Buffer Address
* A3 - Destination Address
*--------------------------------------------------------------------------
DOWNLOAD        LEA     (CMND_BUFR + 1, A6), A2
                MOVE.B  (A2)+, D0
                CMP.B   #'2', D0
                BNE     DOWNLOAD_X

                MOVE.W  #2, D4
                BSR     HEX2INT   *Byte count
                MOVE.L  D0, D6
                MOVE.L  D0, D7
                SUBQ.W  #4, D6

                MOVE.W  #6, D4
                BSR     HEX2INT   *Address
                MOVEA.L D0, A3
                ADD.B   D0, D7
                LSR.L   #8, D0
                ADD.B   D0, D7
                LSR.L   #8, D0
                ADD.B   D0, D7

DOWNLOAD_1      TST.W   D6
                BEQ.S   DOWNLOAD_2

                MOVE.W  #2, D4
                BSR     HEX2INT   *Data byte
                MOVE.B  D0, (A3)+
                ADD.B   D0, D7
                SUBQ.W  #1, D6
                BRA.S   DOWNLOAD_1

DOWNLOAD_2      MOVE.W  #2, D4
                BSR     HEX2INT   *Checksum
                ADD.B   D0, D7
                ADDQ.B  #1, D7
                BEQ.S   DOWNLOAD_X

                MOVE.B  #'X', D2
                BSR     PUTC
DOWNLOAD_X      RTS

*--------------------------------------------------------------------------
* HEX2INT
*
* A2 = Pointer to string
* D4 = Max digits
* D0 = Result
*--------------------------------------------------------------------------
HEX2INT         CLR.L   D0

HEX2INT_1       MOVE.B  (A2)+, D1
                ORI.B   #$20, D1
                SUBI.B  #'0', D1
                BMI.S   HEX2INT_X

                CMP.B   #9, D1
                BLE.S   HEX2INT_2

                SUBI.B  #39, D1
                BMI.S   HEX2INT_X

                CMP.B   #15, D1
                BGT.S   HEX2INT_X

HEX2INT_2       LSL.L   #4, D0
                OR.B    D1, D0
                SUBQ.W  #1, D4
                BNE.S   HEX2INT_1

HEX2INT_X       RTS

*--------------------------------------------------------------------------
* PARSE_PARM
* A2 - Input Address
* D0 - Value
*--------------------------------------------------------------------------
PARSE_PARM      MOVE.W  #' ', D0

PARSE_PARM_1    CMP.B   (A2), D0
                BNE.S   PARSE_PARM_2
                ADDQ.L  #1, A2
                BRA.S   PARSE_PARM_1

PARSE_PARM_2    MOVE.W  #8, D4
                BSR     HEX2INT
                RTS

*--------------------------------------------------------------------------
* FILL_MEMORY
* F ADRS VALUE COUNT
*
* A3 - Address
* D7 - Value
* D6 - Count
*--------------------------------------------------------------------------
FILL_MEMORY     LEA     (CMND_BUFR + 1, A6), A2
                BSR     PARSE_PARM
                MOVEA.L D0, A3
                BSR     PARSE_PARM
                MOVE.W  D0, D7
                BSR     PARSE_PARM
                MOVE.W  D0, D6

FILL_MEMORY_1   MOVE.B  D7, (A3)+
                SUBQ.W  #1, D6
                BNE.S   FILL_MEMORY_1

                RTS

*--------------------------------------------------------------------------
* DUMP_MEMORY
* D ADRS LINE_COUNT
*
* A2 - Address pointer
* D7 - Line counter
* D6 - Word counter
*--------------------------------------------------------------------------
DUMP_MEMORY     LEA     (CMND_BUFR + 1, A6), A2
                BSR     PARSE_PARM
                MOVEA.L D0, A3
                BSR     PARSE_PARM
                MOVE.W  D0, D7
                SUBQ.W  #1, D7

DUMP_MEMORY_1   MOVE.L  A3, D4
                MOVE.W  #3, D5
                BSR     PRINT_HEX

                MOVE.W  #15, D6

DUMP_MEMORY_2   MOVE.B  #' ', D2
                BSR     PUTC
                MOVE.B  (A3)+, D4
                MOVE.W  #1, D5
                BSR     PRINT_HEX
                DBF     D6, DUMP_MEMORY_2

                MOVE.B  #ASCII_CR, D2
                BSR     PUTC
                DBF     D7, DUMP_MEMORY_1

                RTS

*--------------------------------------------------------------------------
* PRINT_DEC
* D3.L = Value to print
*--------------------------------------------------------------------------
PRINT_DEC       MOVEM.W D2/D4, -(A7)
                CLR.W   D4
                TST.L   D3
                BPL.S   PRINT_DEC_1

                NEG.L   D3
                MOVE.B  #'-', D2
                BSR     PUTC

PRINT_DEC_1     DIVU.W  #10000, D3
                BNE.S   PRINT_DEC_2

                SWAP    D3
                BSR.S   PRINT_DEC_10
                BRA.S   PRINT_DEC_3

PRINT_DEC_2     SWAP    D3
                MOVE.L  D3, -(A7)
                CLR.L   D3
                MOVE.W  (A7)+, D3
                BSR.S   PRINT_DEC_10
                CLR.L   D3
                MOVE.W  (A7)+, D3
                BSR.S   PRINT_DEC_20

PRINT_DEC_3     MOVEM.W (A7)+, D2/D4
                RTS

*--------------------------------------------------------------------------
PRINT_DEC_10    DIVU.W  #10, D3
                SWAP    D3
                MOVE.B  D3, -(A7)
                ADDQ.W  #1, D4
                CLR.W   D3
                SWAP    D3
                BNE.S   PRINT_DEC_10

PRINT_DEC_11    MOVE.B  (A7)+, D2
                MOVE.B  (DIGIT_TABLE, PC, D2.W), D2
                BSR     PUTC
                SUBQ.W  #1, D4
                BNE.S   PRINT_DEC_11
                RTS

*--------------------------------------------------------------------------
PRINT_DEC_20    MOVE.W  #3, D0

PRINT_DEC_21    DIVU.W  #10, D3
                SWAP    D3
                MOVE.B  D3, -(A7)
                ADDQ.W  #1, D4
                CLR.W   D3
                SWAP    D3
                DBF     D0, PRINT_DEC_21

PRINT_DEC_22    MOVE.B  (A7)+, D2
                MOVE.B  (DIGIT_TABLE, PC, D2.W), D2
                BSR     PUTC
                SUBQ.W  #1, D4
                BNE.S   PRINT_DEC_22
                RTS

*--------------------------------------------------------------------------
DIGIT_TABLE     DB      "0123456789ABCDEF"

*--------------------------------------------------------------------------
* PRINT_HEX
*
* D4 = Value
* D5 = Number of bytes
*--------------------------------------------------------------------------
PRINT_HEX       LSL.W   #3, D5
                ROR.L   D5, D4
                LSR.W   #2, D5
                SUBQ.W  #1, D5

PRINT_HEX_1     ROL.L   #4, D4
                MOVE.W  D4, D2
                ANDI.W  #15, D2
                MOVE.B  (DIGIT_TABLE, PC, D2.W), D2
                BSR     PUTC
                DBF     D5, PRINT_HEX_1
                RTS

*--------------------------------------------------------------------------
* Enable Interrupt Service Routine
*
* D1 = Vector Number
* A1 = ISR Address
*--------------------------------------------------------------------------
ENABLE_ISR      MOVE.W  D1, D0
                LSL.W   #2, D0
                LEA     (TXRDYA_IV, A6, D0.W), A0
                MOVE.L  A1, (A0)
                MOVE.B  #1, D0
                LSL.B   D1, D0
                OR.B    D0, (IMR_IMAGE, A6)
                MOVE.B  (IMR_IMAGE, A6), (DUART_IMR).W
                RTS

*--------------------------------------------------------------------------
* Disable Interrupt Service Routine
*
* D1 = Vector Number
*--------------------------------------------------------------------------
DISABLE_ISR     MOVE.B  #1, D0
                LSL.B   D1, D0
                NOT.B   D0
                AND.B   D0, (IMR_IMAGE, A6)
                MOVE.B  (IMR_IMAGE, A6), (DUART_IMR).W
                RTS

*--------------------------------------------------------------------------
* BIOS_CALL
* D0 = Function Number
*--------------------------------------------------------------------------
BIOS_CALL       MOVEA.L #BIOS_CALL_TABLE, A0
                LSL.W   #2, D0
                MOVEA.L (0, A0, D0.W), A0
                JSR     (A0)
                RTE

BIOS_CALL_TABLE DA      GETC
                DA      PUTC
                DA      GETS
                DA      PUTS
                DA      PRINT_HEX
                DA      PRINT_DEC
                DA      ENABLE_ISR
                DA      DISABLE_ISR

*--------------------------------------------------------------------------
