;
; Commonly used assembly routines
;

; 8259 Constants
I8259A  EQU     000H            ; 8259 port 1
I8259B  EQU     001H            ; 8259 port 2

;
; LCD Constants
;
LCDINST EQU     002H            ; LCD instruction I/O port
LCDDATA EQU     003H            ; LCD data I/O port
LCLEAR  EQU     001H            ; LCD clear instruction
LRESET  EQU     038H            ; LCD reset to normal instruction
LHALF1  EQU     080H            ; LCD move cursor to char 1
LHALF2  EQU     0c0H            ; LCD move cursor to char 9
PAUSE   EQU     0aH             ; a UNIX newline
STACKTOP        EQU     00000H  ; top of stack (wraps to 0ffff)

; PIC Constants
PIC     EQU     004H            ; PIC I/O port

;
; Set up useful stuff, jump to main program
;
        LD      SP, STACKTOP
        CALL    LCDINIT
        JP      MAIN            ; get past library routines

;
; Catch reset if it happens and try to print it on the LCD
;

        ORG     0038H           ; Catch a reset
        LD      HL, GOTRESETSTR
        CALL    LCDPRINT
        HALT

GOTRESETSTR     DB      "Got RST 38H", PAUSE, 0


;
; LCD Init routine
; In: nothing
;
LCDINIT
#ifdef NOPRINT
        RET
#endif

        PUSH    BC
        PUSH    HL

        LD      HL, LISTRING
        LD      B, LISTRLEN

        JP      OUTBLOOP

;
; LCD string bytes output routine
; In:
;     B    - length divided by two, (e.g. # of bytes to output, not
;           including the I/O addresses)
;     HL   - address of bytes
;
OUTBYTES
        PUSH    BC
        PUSH    HL

OUTBLOOP
        LD      C, (HL)
        INC     HL
        OUTI
        JR      NZ, OUTBLOOP

        ; Probably need a delay here at 1 MHz.
        ; Are we supposed to check busy bit and wait until not busy?

        POP     HL
        POP     BC

        RET

;
; Clear LCD display
; In: nothing
;
LCDCLR
        PUSH    BC
        PUSH    HL

        LD      HL, LCSTRING
        LD      B, LCSTRLEN     ; falls through into byte output loop
        JP      OUTBLOOP

;
; LCD Initialization string
;
LISTRLEN        EQU     10
LISTRING
        DB      LCDINST, LRESET
        DB      LCDINST, LRESET
        DB      LCDINST, 006H
        DB      LCDINST, 00eH
        DB      LCDINST, LCLEAR
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1

LCSTRLEN        EQU     5
LCSTRING
        DB      LCDINST, LCLEAR
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1
        DB      LCDINST, LHALF1

;
; LCD String output routine
; In:
;     HL   - Address of null-terminated string
;
LCDPRINT
#ifdef NOPRINT
        RET
#endif

        PUSH    AF
        PUSH    BC
        PUSH    DE
        PUSH    HL

        LD      A, LCLEAR
        OUT     (LCDINST), A            ; do a clear

#ifndef SLOWCLOCK
        LD      B, 250          ; 250 cycles of wait
LCDPCLOOP
        DJNZ    LCDPCLOOP
#endif /* SLOWCLOCK */

        LD      C, LCDDATA
        LD      D, 25           ; when 1->0, switch to 2nd display

LCDPLOOP
        DEC     D
        JP      NZ, LCDNOSWITCH

        LD      A, LHALF2       ; set LCD to address 0xc0
        OUT     (LCDINST), A

#ifndef SLOWCLOCK
        LD      B, 20           ; 20 cycles of wait for write to LCD
LCDP2LOOP
        DJNZ    LCDP2LOOP       ; fall through
#endif /* SLOWCLOCK */

LCDNOSWITCH

        LD      A, (HL)
        CP      0
        JP      Z, LCDPDONE

        CP      PAUSE
        JP      NZ, LCDPDOIT

;       LD      A, 0dh          ; return
;       OUT     (PIC), A

#ifndef SLOWCLOCK
        ; wait for two seconds here!
        LD      D, 2            ; 2 * 256 * 256 cycles is close to 1 sec
LCDP1SL1
        LD      A, 0            ; 256 * 256 cycles
LCDP1SL2
        LD      B, 0            ; 256 cycles
LCDP1SL3
        DJNZ    LCDP1SL3

        DEC     A
        JP      NZ, LCDP1SL2

        DEC     D
        JP      NZ, LCDP1SL1
#endif /* SLOWCLOCK */

        LD      A, LCLEAR
        OUT     (LCDINST), A    ; do a clear

;       LD      A, 0ah          ; linefeed
;       OUT     (PIC), A

#ifndef SLOWCLOCK
        LD      B, 250          ; 250 cycles of wait
LCDPNLOOP
        DJNZ    LCDPNLOOP
#endif /* SLOWCLOCK */

        LD      A, LHALF1
        OUT     (LCDINST), A    ; go to address 0x80

#ifndef SLOWCLOCK
        LD      B, 20           ; 20 cycles of wait for write
LCDP1LOOP
        DJNZ    LCDP1LOOP
#endif /* SLOWCLOCK */

        LD      D, 9            ; reset half counter
        JP      LCDPNEXT        ; continue with next character

LCDPDOIT
        OUT     (LCDDATA), A    ; output that guy
;       OUT     (PIC), A

#ifndef SLOWCLOCK
        LD      B, 20           ; 20 cycles of wait for write
LCDPWLOOP
        DJNZ    LCDPWLOOP
#endif /* SLOWCLOCK */

LCDPNEXT
        INC     HL              ; next char
        JP      LCDPLOOP

LCDPDONE

        POP     HL
        POP     DE
        POP     BC
        POP     AF

        RET


;
; Wait for seconds routine
; In:   
;     A    - number of seconds to wait
;
WAITSECS
        PUSH    AF
        PUSH    BC
        RLCA            ; multiply A by 2

LCDP1SLP1
        LD      C, 0            ; 256 * 256 cycles
LCDP1SLP2
        LD      B, 0            ; 256 cycles
LCDP1SLP3
        DJNZ    LCDP1SLP3

        DEC     C
        JP      NZ, LCDP1SLP2

        DEC     A
        JP      NZ, LCDP1SLP1

        POP     BC
        POP     AF

        RET


;
; put the hex string representation of A into the location at IX
; IX becomes IX + 2
;
PHEXBYTE
        PUSH    AF
        PUSH    BC

        LD      B, A
        AND     0f0H
        SRL     A
        SRL     A
        SRL     A
        SRL     A
        CP      0aH
        JP      C, DIG1LESS
        ADD     A, "a" - 10
        JP      DIG1DONE
DIG1LESS
        ADD     A, "0"
DIG1DONE

        LD      (IX), A
        INC     IX
        LD      A, B
        AND     0fH
        CP      0aH
        JP      C, DIG2LESS
        ADD     A, "a" - 10
        JP      DIG2DONE
DIG2LESS
        ADD     A, "0"
DIG2DONE
        LD      (IX), A
        INC     IX

        POP     BC
        POP     AF
        RET

;
; put the hex string representation of HL into the location at IX
; IX becomes IX + 4
;
PHEXWORD

        PUSH    AF
        LD      A, H
        CALL    PHEXBYTE
        LD      A, L
        CALL    PHEXBYTE
        POP     AF
        RET