;* ======================================================================== *;
;*  This program is free software; you can redistribute it and/or modify    *;
;*  it under the terms of the GNU General Public License as published by    *;
;*  the Free Software Foundation; either version 2 of the License, or       *;
;*  (at your option) any later version.                                     *;
;*                                                                          *;
;*  This program is distributed in the hope that it will be useful,         *;
;*  but WITHOUT ANY WARRANTY; without even the implied warranty of          *;
;*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *;
;*  General Public License for more details.                                *;
;*                                                                          *;
;*  You should have received a copy of the GNU General Public License       *;
;*  along with this program; if not, write to the Free Software             *;
;*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *;
;* ======================================================================== *;
;*                  Copyright (c) 1999-2000, Joe Zbiciak                    *;
;* ======================================================================== *;

        ROMW    10

        ORG     $1000

        LISTING "off"
        INCLUDE "../../examples/macro/util.mac"
        INCLUDE "../../examples/macro/stic.mac"
        INCLUDE "../../examples/macro/print.mac"

        ; First, fill 4K EXEC with $0000.
        RPT     $1000 / 8
        DECLE   $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000
        ENDR
        LISTING "on"

        ORG     $1000

DEC_0   EQU     $103
DEC_1   EQU     $104

        JD      EXEC
DUMMY:  JR      R5

;
; HDWRINT
; Hardware Interrupt Routine
; This routine saves the machine state and vectors to the software
; interrupt vector at $100..$101
;

HDWRINT PROC
        PSHR    R0
        GSWD    R0
        PSHR    R0
        PSHR    R1
        PSHR    R2
        NOP
        PSHR    R3
        PSHR    R4
        PSHR    R5
        MVII    #@@return-@@xx, R5
        ADDR    PC,     R5
@@xx:   MVII    #$0100, R4
        SDBD
        MVI@    R4,     R7
@@return:
        PULR    R5
        PULR    R4
        PULR    R3
        PULR    R2
        PULR    R1
        PULR    R0
        RSWD    R0
        PULR    R0
        PULR    R7
        ENDP

MINIISR PROC
        MVO     R0,     $20     ; Enable the display
        MVI     $21,    R0      ; force color-stack
        MVI     $102,   R0
        DECR    R0
        BMI     @@isr_done
        MVO     R0,     $102
@@isr_done
        JR      R5
        ENDP

EXEC    PROC
        MVII    #$1F0,  R4
        MVII    #$00E,  R1
        CALL    FILLZERO

        SDBD
        MVII    #DUMMY, R0
        MVO     R0,     $100    ; Hook dummy routine into ISR vector
        SWAP    R0,     1
        MVO     R0,     $101

        MVII    #$2F0,  R6      ; Set up stack pointer.

        MVII    #$3FF,  R1
        COMR    R1              ; 10-bit ROM mask.
        MOVR    R1,     R0      ; need two copies

        MVII    #$48,   R3      
        SWAP    R3              ; R3 == $4800
        AND@    R3,     R1      ; Check for viable ROM at $4800
        BEQ     @@viablerom
        MVII    #$70,   R3      
        SWAP    R3              ; R3 == $7000
        AND@    R3,     R0      ; Check for viable ROM at $7000
        BNEQ    @@notviablerom
@@viablerom:
        EIS
        MOVR    R3,     PC
@@notviablerom:

        ; Do more thorough initialization
        SDBD
        MVII    #@@cont,R0
        MVO     R0,     $100
        SWAP    R0,     1
        MVO     R0,     $101

        EIS
@@spin: DECR    PC

@@cont:
        MVII    #$2F0,  R6
        MVII    #$5014, R4      ; Rom header address
        PSHR    R4

        MVII    #DUMMY, R0
        MVO     R0,     $100    ; Hook dummy routine into ISR vector
        SWAP    R0,     1
        MVO     R0,     $101

        ;; Zero out STIC registers
        CLRR    R4
        MVII    #$40,   R1
        CALL    FILLZERO

        ;; But make initial display brown.
        MVII    #11,    R0
        MVO     R0,     $28     ; Brown
        MVO     R0,     $2C     ; Brown

        ;; Zero out GRAM
        MVII    #$3000, R4
        MVII    #$800,  R1
        CALL    FILLZERO

        ; Rudimentary title screen
        CALL    CLRSCR
;       PRINT_CSTK r, c, fg, string
                                 ;01234567890123456789
        PRINT_CSTK  3, 1, White,  "SDK-1600 Mini EXEC"
        PRINT_CSTK  4, 6, White,       "presents"
        PRINT_CSTK 10, 1, White,  "Copr @ 0000 <1600>"
        
        ; Locate copyright year in ROM and print it to the display
        MVII    #$500A, R4
        SDBD
        MVI@    R4,     R5      ; read pointer to title screen
        MVI@    R4,     R2      ; read key-clicks byte
        PSHR    R2              ; save it.

        MVI@    R5,     R0
        CMPI    #70,    R0
        BGE     @@yrok
        ADDI    #100,   R0      ; add 100 if year before 1970.
@@yrok: 
        ADDI    #1900,  R0      ; 1900 + year at $500A
        PSHR    R5              ; save title screen pointer

        MVII    #7,     R3
        MVII    #4,     R1
        MVII    #disp_ptr(10,8), R4
        CALL    EDECZ  

        PULR    R5              ; restore pointer to title string.
        MVII    #disp_ptr(7,10), R4 ; point to middle of screen

        ; find length of title string
        CLRR    R1
        CLRR    R0
@@tllp  INCR    R1
        CMP@    R5,     R0      ; look for NUL
        BNEQ    @@tllp

        PSHR    R5              ; remember end of string

        SUBR    R1,     R5      ; rewind title pointer
        SLR     R1              ; 
        SUBR    R1,     R4      ; rewind cursor according to length of string
        
        MOVR    R5,     R0      ; pointer to string
        MVII    #7,     R1      ; white
        CALL    PRINT.R         ; put it onscreen
        

        ; Now let the display be enabled.
        MVII    #MINIISR, R0
        MVO     R0,     $100    ; Hook dummy routine into ISR vector
        SWAP    R0,     1
        MVO     R0,     $101

        CALL    WAIT
        DECLE   1               ; let a tick go by

        ; Decide whether to run code after title screen.

        PULR    R4              ; get pointer to post-title code
        PULR    R2              ; get key-clicks byte
        SWAP    R2,     2
        BPL     @@no_t_code

        SDBD
        MVII    #@@no_t_code, R5
        MOVR    R4,     PC      ; Jump to code after title.     
@@no_t_code:

        ; Now wait for controller press at title screen.
        CALL    WAIT_TAP


        ; Jump to the START address in the std ROM header location instead.

        MVII    #@@spin,R5      ; Set return address a DECR P.
        MVI     $2F0,   R4
        SUBI    #$10,   R4      ; R4 = $5004 now
        SDBD
        MVI@    R4,     PC      ; Jump to program start address.

        ENDP

WAIT    PROC
        MVI@    R5,     R0
@@1:
        MVO     R0,     $102
        CLRR    R0
@@spin  CMP     $102,   R0
        BNEQ    @@spin
        JR      R5
        ENDP

WAIT_TAP PROC
        PSHR    R5
        CLRC
        CALL    WAITHAND
        SETC
        CALL    WAITHAND
        PULR    R5
        CLRC
        B       WAITHAND
        ENDP

WAITHAND        PROC
        B       @@waithand
@@waitpress:
        BNEQ    @@waitdone
@@waithand:
        MVII    #100,   R1      ; Debounce factor
@@waitloop:
        MVII    #$1FE,  R4
        SDBD
        MVI@    R4,     R0
        COMR    R0
        BC      @@waitpress
        BNEQ    @@waithand
@@waitdone:
        DECR    R1
        BNEQ    @@waitloop
        JR      R5
        ENDP


                        ; Used by       Req'd Width     Description
                        ;-----------------------------------------------------
RNDLO   EQU     $35E    ; RAND          16-bit          Random number state
;RNDHI  EQU     $321    ; RAND          16-bit          Random number state

;; ======================================================================== ;;
;;  RAND                                                                    ;;
;;      Returns random bits in R0.                                          ;;
;; ======================================================================== ;;
RAND    PROC
        PSHR    R5
@@1:    TSTR    R0
        BEQ     @@exit
        PSHR    R1
        PSHR    R2

        MVII    #1,     R1      ; Our initial mask word
        MVII    #$1021, R5      ; CRC-16 polynomial
        MVI     RNDLO,  R2

        TSTR    R2              ; If our random number generator is zero 
        SETC                    ; jumpstart the process by forcing an XOR 
        BEQ     @@forceit       ; 
        
@@loop:
        SLLC    R2,     1       ; rotate left 1
@@forceit:
        SLL     R1,     1       ; Shift our mask bit left by 1
        BNC     @@nocarry
        XORR    R5,     R2      ; If the carry was set, XOR in generator poly
@@nocarry:
        DECR    R0              ; Keep generating bits.
        BNEQ    @@loop

        MVO     R2,     RNDLO   ; Store our new random number state.

@@nobits:
        DECR    R1              ; Turn our mask bit into a mask word
        ANDR    R1,     R2      ; Mask the bits we actually want.
        MOVR    R2,     R0      ; Return our result in R0

        PULR    R2
        PULR    R1              ; Restore our registers and return.

@@exit: PULR    PC
        ENDP

        INCLUDE "../../examples/library/fillmem.asm"
        INCLUDE "../../examples/library/print.asm"
        INCLUDE "../../examples/library/dividivu.asm"


;* ======================================================================== *;
;*  ERAND:  Try to mimic EXEC's RAND with my own.                           *;
;* ======================================================================== *;
        ORG     $169E

ERAND   PROC
        PSHR    R5
        PSHR    R2              ; save R2
        MOVR    R0,     R2      ; remember top of range
        BEQ     @@zero
        PSHR    R1              ; save R1

        ; count bits in range
        CLRR    R1
@@cl    INCR    R1
        SLR     R0
        BNEQ    @@cl

@@rl:   MOVR    R1,     R0      ; call inner 'rand' for right # of bits.
        CALL    RAND
        CMPR    R2,     R0
        BGE     @@rl

        PULR    R1
@@zero: PULR    R2
        PULR    PC
        ENDP

        


;* ======================================================================== *;
;*  EDECZ:  Try to mimic EXEC's number-print routine with my own.           *;
;*  R0 = number (0000 to 9999)                                              *;
;*  R1 = number of digits to display                                        *;
;*  R3 = format word                                                        *;
;*  R4 = display pointer                                                    *;
;* ======================================================================== *;
P10     DECLE   1000, 100, 10, 1  ; can't do 10000 due to 10-bit ROM.
        ORG     $18AD
EDECZ:  PROC
        PSHR    R1
        PSHR    R2
        PSHR    R4
        MVII    #P10+4, R2
        SUBR    R1,     R2

@@digit PSHR    R3
        ADDI    #$80-8, R3      ; start at '0', offset to negate first incr.

@@div   ADDI    #8,     R3      ; increment through the digits
        SUB@    R2,     R0      ; repeatedly subtract power of 10
        BGE     @@div
        ADD@    R2,     R0      ; add back once when we go too far.

        MVO@    R3,     R4      ; display the digit.
        PULR    R3              ; restore format word

        INCR    R2              ; move to next lower power of 10
        DECR    R1              ; decr digit count
        BNEQ    @@digit         ; display as needed.

        PULR    R4
        PULR    R2
        PULR    R1
        JR	R5
        ENDP

;* ======================================================================== *;
;*  EMPY:   Try to mimic EXEC's multiply routine                            *;
;*          R2 = R0 * R1.   Destroys R0, R1.                                *;
;* ======================================================================== *;
        ORG     $1DDC
EMPY    PROC
        MOVR    R1,     R2
        XORR    R0,     R2
        PSHR    R2              ; track sign of result as XOR input signs

        CLRR    R2              ; clear result

        TSTR    R0
        BPL     @@r0_ok         ; make R0 positive
        NEGR    R0
@@r0_ok:
        TSTR    R1
        BPL     @@ml            ; make R1 positive
        NEGR    R1

        B       @@ml

@@c     ADDR    R0,     R2
@@nc    SLL     R0

@@ml:   CLRC    
        RRC     R1
        BC      @@c
        BNEQ    @@nc

        ADD@    SP,     R1
        BPL     @@leave
        NEGR    R2

@@leave JR      R5
        ENDP
        

;* ======================================================================== *;
;*  EDIV:   Try to mimic EXEC's divide & round routine.                     *;
;*          R0 = R1 / R2, destroying R2.                                    *;
;* ======================================================================== *;
        ORG     $1DF8
EDIVR   MOVR    R2,     R0      ; make a temp copy
        SAR     R0,     1       ; divide by two
        ADDR    R0,     R1      ; add to numer (effectively adding .5 to rslt)
        
;* ======================================================================== *;
;*  EDIV:   Try to mimic EXEC's divide routine.                             *;
;*          R0 = R1 / R2, destroying R2.                                    *;
;* ======================================================================== *;
EDIV    PROC
        PSHR    R5
        PSHR    R1
        PSHR    R3

        MOVR    R1,     R0
        MOVR    R2,     R1
        CALL    DIVI.1
        DECLE   0
        MOVR    R3,     R0

        PULR    R3
        PULR    R1
        PULR    PC
        ENDP

;* ======================================================================== *;
;*  This program is free software; you can redistribute it and/or modify    *;
;*  it under the terms of the GNU General Public License as published by    *;
;*  the Free Software Foundation; either version 2 of the License, or       *;
;*  (at your option) any later version.                                     *;
;*                                                                          *;
;*  This program is distributed in the hope that it will be useful,         *;
;*  but WITHOUT ANY WARRANTY; without even the implied warranty of          *;
;*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *;
;*  General Public License for more details.                                *;
;*                                                                          *;
;*  You should have received a copy of the GNU General Public License       *;
;*  along with this program; if not, write to the Free Software             *;
;*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *;
;* ======================================================================== *;
;*                Copyright (c) 1999-2002, Joseph Zbiciak                   *;
;* ======================================================================== *;


;05000H Moving object graphics address, used for exec-assisted animation.
;       Also used by the "SUCKY" feature on the ECS.
;05002H Pointer to "periodically called routine" table.
;05004H Start program address (after title screen).
;05006H Pointer to background graphics (?)
;05008H ??
;0500AH Pointer to title screen and copyright date, first word is the
;       year, then follows the title in ASCII terminated by a 0.
;       The code after may be called for additions to the title screen.
;0500CH if bit #7 set, run code directly after title string null word.
;0500DH moved into 00032H (block out h/v card rows)
;0500EH graphics mode
;0500FH + cs_element = colour
;05013H border colour


