;;==========================================================================;; ;; INTV RAM Tests. Performs tests on the Intellicart's Bank Switch modes. ;; ;; Copyright 2000, Joe Zbiciak, im14u2c@primenet.com. ;; ;; http://www.primenet.com/~im14u2c/intv/ ;; ;;==========================================================================;; ;* ======================================================================== *; ;* 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) 2000, Joseph Zbiciak *; ;* ======================================================================== *; ROMW 16 ORG $5000 ; ------------------------------------------------------------------------- ; ; Variables. We hide the 16-bit variables under the stack. ; ; ------------------------------------------------------------------------- ; ; Used by Req'd Width Description ;--------------------------------------------------- RNDLO EQU $2F0 ; RAND 16-bit Random number state RNDHI EQU $2F1 ; RAND 16-bit Random number state SAVLO EQU $2F2 ; RANDSAVE/RSTR 16-bit Saves rand num. seed SAVHI EQU $2F3 ; RANDSAVE/RSTR 16-bit Saves rand num. seed BUSY EQU $2F4 ; ISR/WAIT 16-bit Busy-wait counter WPAGE EQU $2F5 ; BANKTEST 16-bit Current writeout page RPAGE EQU $2F6 ; BANKTEST 16-bit Current readback page DEC_0 EQU $110 ; DEC16/DEC32 8-bit Temp. storage DEC_1 EQU $111 ; DEC16/DEC32 8-bit Temp. storage DEC_2 EQU $112 ; DEC32 8-bit Temp. storage DEC_3 EQU DEC_2+1 ; DEC32 8-bit Must be adj. to DEC_2 TBLNK EQU $132 ; ISR 8-bit Blink counter for timer T_DAY EQU $133 ; ISR 8-bit Day counter T_HRS EQU $134 ; ISR 8-bit Hour counter T_MIN EQU $135 ; ISR 8-bit Minute counter T_SEC EQU $136 ; ISR 8-bit Second counter T_CLN EQU $137 ; ISR 8-bit Colons on or off? PGTMP EQU $138 ; BANKTEST 8-bit Page # temporary MPTMP EQU $139 ; BANKTEST 8-bit Remapping temporary BOS EQU $300 ; STACK 16-bit Bottom of stack. ; ------------------------------------------------------------------------- ; ; Handy Equates. ; ; ------------------------------------------------------------------------- ; ROW_0 EQU $200 ROW_1 EQU ROW_0 + 20 ROW_2 EQU ROW_1 + 20 ROW_3 EQU ROW_2 + 20 ROW_4 EQU ROW_3 + 20 ROW_5 EQU ROW_4 + 20 ROW_6 EQU ROW_5 + 20 ROW_7 EQU ROW_6 + 20 ROW_8 EQU ROW_7 + 20 ROW_9 EQU ROW_8 + 20 ROW_A EQU ROW_9 + 20 ROW_B EQU ROW_A + 20 C_BLK EQU 0 ; Black C_BLU EQU 1 ; Blue C_RED EQU 2 ; Red C_TAN EQU 3 ; Tan C_DGR EQU 4 ; Dark Green C_GRN EQU 5 ; Green C_YEL EQU 6 ; Yellow C_WHT EQU 7 ; White EDLY EQU 1800 ; Number of ticks to hold error message PDLY EQU 30 ; Number of ticks to hold passing message ; ------------------------------------------------------------------------- ; ROMHDR: BYTE $01,$00 ; Movable object data (ignored) WORD $0000 ; RTAB (ignored) WORD MAIN ; Program start address WORD $0000 ; Background graphics WORD ROMHDR ; Card table -- stored above in header. :-) WORD TITLE ; Title string BYTE $C0 ; run code after title, clicks off BYTE $00 ; -> to STIC $32 BYTE $00 ; 0 = color stack, 1 = f/b mode BYTE 0, 0, 0, 0 ; color stack elements 1 - 4 BYTE $00 ; border color ; ------------------------------------------------------------------------- ; ;;==========================================================================;; ;; BANKTBL -- Initial bank mapping table. ;; ;;==========================================================================;; BANKTBL: DECLE $6000 ; Map $6000-$67FF to $0000 in Intellicart DECLE $D000 ; Map $D000-$D7FF to $0000 in Intellicart DECLE $0000 ; End of table ;;==========================================================================;; ;; TITLE / TITLEFIX -- The Title Screen code. ;; ;;==========================================================================;; TITLE: BYTE 100, "I.C. Bank Test", 0 TITLEFIX: BEGIN ; Cyan screen MVII #$09, R0 ; Color 9 is Cyan (pastels.) MVO R0, $28 ; Color stack 0 = Cyan MVO R0, $29 ; Color stack 1 = Cyan MVO R0, $2A ; Color stack 2 = Cyan MVO R0, $2B ; Color stack 3 = Cyan MVO R0, $2C ; Border color = Cyan ; Patch the title string to say '=JRMZ=' instead of Mattel. CLRR R1 ; Black MVII #$23C, R4 ; First 'Mattel' in top-left CALL DRAWSTRING2 ; Write string (ptr in R5) BYTE "Zbiciak", 0 ; Guess who? :-) CLRR R1 ; Black MVII #$2D0, R4 ; Second 'Mattel' in lower-right CALL DRAWSTRING2 ; Write string (ptr in R1) BYTE "2000 =JRMZ=",0 ; Guess who? :-) ; Make all the rest of the text black to match MVII #$243, R3 ; Start after first JRMZ MVII #7, R0 ; Mask = 0xFFF8. That's the 1s complement... COMR R0 ; ...of 7. (Saves an SDBD.) MVII #146, R2 ; We only need to touch 146 words. @@titlelp: MVI@ R3, R1 ; Read a word from the display ANDR R0, R1 ; Mask the foreground color MVO@ R1, R3 ; Write the word back INCR R3 ; Point to next word DECR R2 ; Decrement our loop count BNEQ @@titlelp ; Iterate. ; Done. RETURN ; Return to caller ;;==========================================================================;; ;; MAIN -- main program ;; ;;==========================================================================;; MAIN: PROC ; Fill system memory with zeros. MVII #$260, R1 MVII #$100, R4 CALL FILLZERO ; Set the ISR MVII #ISR, R0 MVO R0, $100 SWAP R0 MVO R0, $101 ; Set our interrupt service routine to 'ISR' MVII #BOS, SP ; Reset our stack. CLRR R0 MVII #$0028, R4 MVO@ R0, R4 ; Black screen. INCR R0 MVO@ R0, R4 ; CS0 == Black CLRR R0 MVO@ R0, R4 ; CS1 == Blue MVO@ R0, R4 ; CS2 == Black MVO@ R0, R4 ; CS3 == Black MVII #BANKTBL, R4 ; Initial bank switch table CALL IC_BANKTBL ; Load the bank table. MVII #ROW_B, R4 MVII #C_BLU, R1 CALL DRAWSTRING2 BYTE "Elapsed", 0 EIS @@test_loop: MVII #$6000, R1 MVII #$6000, R2 CALL BANKTEST MVII #$6000, R1 MVII #$D000, R2 CALL BANKTEST MVII #$D000, R1 MVII #$6000, R2 CALL BANKTEST MVII #$D000, R1 MVII #$D000, R2 CALL BANKTEST B @@test_loop ENDP ;;==========================================================================;; ;; ISR -- The Interrupt Service routine. ;; ;;==========================================================================;; ISR PROC PSHR R5 MVI BUSY, R0 ; Decrement the busy-wait counter. DECR R0 BMI @@zero MVO R0, BUSY @@zero: MVI $21, R0 ; force color-stack mode MVO R5, $20 ; enable display @@done_stat: ; Update the timer clock at the bottom. MVI TBLNK, R0 DECR R0 BMI @@clock_upd MVO R0, TBLNK CMPI #30, R0 BNEQ @@no_colon MVII #$D0, R1 @@do_colon: MVII #ROW_B + 11, R4 MVO@ R1, R4 ADDI #2, R4 MVO@ R1, R4 ADDI #2, R4 MVO@ R1, R4 @@no_colon: PULR PC @@clock_upd: MVII #60, R0 MVO R0, TBLNK MVI T_SEC, R2 INCR R2 MVO R2, T_SEC CMPI #60, R2 BLT @@time_ok CLRR R2 MVO R2, T_SEC MVI T_MIN, R2 INCR R2 MVO R2, T_MIN CMPI #60, R2 BLT @@time_ok CLRR R2 MVO R2, T_MIN MVI T_HRS, R2 INCR R2 MVO R2, T_HRS CMPI #24, R2 BLT @@time_ok MVI T_DAY, R2 INCR R2 MVO R2, T_DAY @@time_ok: MVI T_DAY, R0 MVII #3, R2 MVII #C_BLU, R3 MVII #ROW_B + 9, R4 CALL DEC16A INCR R4 MVI T_HRS, R0 MVII #3, R2 CALL DEC16A INCR R4 MVI T_MIN, R0 MVII #3, R2 CALL DEC16A INCR R4 MVI T_SEC, R0 MVII #3, R2 CALL DEC16A MVII #$D0 + C_BLU, R1 B @@do_colon ENDP ;;==========================================================================;; ;; WAIT -- Do a busy-wait. Number of ticks is in R0. ;; ;;==========================================================================;; WAIT PROC MVO R0, BUSY @@spin: MVI BUSY, R0 DECR R0 BPL @@spin JR R5 ENDP ;;==========================================================================;; ;; CLRSCR -- Clear the screen. ;; ;;==========================================================================;; CLRSCR PROC PSHR R5 MVII #1, R0 CALL WAIT PULR R5 ; Fill display memory with zeros. MVII #$0F0, R1 MVII #$200, R4 B FILLZERO ENDP ;;==========================================================================;; ;; CLRSCR1 -- Clear most of the screen. ;; ;;==========================================================================;; CLRSCR1 PROC PSHR R5 MVII #1, R0 CALL WAIT PULR R5 ; Fill display memory with zeros. MVII #$0F0 - 20, R1 MVII #$200, R4 B FILLZERO ENDP ;;==========================================================================;; ;; HEX16 ;; ;; Display a 4-digit hex number on the screen ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Hex number ;; ;; R1 -- Color mask / screen format word ;; ;; R4 -- Screen offset ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- rotated left by 3 ;; ;; R1 -- unmodified ;; ;; R2 -- trashed ;; ;; R3 -- zeroed ;; ;; R4 -- points just to right of string ;; ;;==========================================================================;; HEX16 PROC ; Rotate R0 left by 3, so that our digit will be in the correct ; position within the screen format word. MOVR R0, R3 SLLC R3, 2 RLC R0, 2 ; First, rotate by two bits... SLLC R3, 1 RLC R0, 1 ; ... and then by one more. MVII #4, R3 ; Iterate through four digits. @@loop: ; Rotate R0 left by 4, so that we can cycle through each digit ; one at a time. MOVR R0, R2 SLLC R2, 2 RLC R0, 2 ; First, rotate by two bits... SLLC R2, 2 RLC R0, 2 ; ... and then by two more. ; Mask out a single hex digit MOVR R0, R2 ANDI #$78, R2 ; Is it A..F? If so, add an offset so that the correct ASCII ; value is selected. Otherwise do nothing special. CMPI #$50, R2 ; $50 is $A shifted left by 3. BLT @@digit ADDI #$38, R2 ; If the digit >= A, add 6 << 3. @@digit: ADDI #$80, R2 ; Generate proper GROM index. XORR R1, R2 ; Merge in the screen format word MVO@ R2, R4 ; Display the digit to the screen. DECR R3 ; Iterate three more times. BNE @@loop JR R5 ; Done! Return. ENDP ;;==========================================================================;; ;; FILLZERO ;; ;; Fills memory with zeros ;; ;; ;; ;; FILLMEM ;; ;; Fills memory with a constant ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Fill value (FILLMEM only) ;; ;; R1 -- Number of words to fill ;; ;; R4 -- Start of fill area ;; ;; R5 -- Return address ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Zeroed if FILLZERO, otherwise untouched. ;; ;; R1 -- Zeroed ;; ;; R4 -- Points to word after fill area ;; ;;==========================================================================;; FILLZERO PROC CLRR R0 ; Start out with R0 zeroed for FILLZERO FILLMEM MVO@ R0, R4 ; Store R0 out at R4, and move along DECR R1 ; Keep going until our count runs out BNEQ FILLMEM JR R5 ; Return to the caller. ENDP ;;==========================================================================;; ;; DRAWSTRING ;; ;; Puts an ASCIIZ string pointed to by R0 onscreen. ;; ;; ;; ;; DRAWSTRING2 ;; ;; Puts an ASCIIZ string after a JSR R5 onscreen. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- String pointer (if DRAWSTRING) ;; ;; R1 -- Screen format word ;; ;; R4 -- Output pointer ;; ;; R5 -- Return address (also, string if DRAWSTRING2). ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Zero if DRAWSTRING2, one if DRAWSTRING ;; ;; R1 -- Untouched EXCEPT bit 15 is cleared. ;; ;; R4 -- Points just after displayed string. ;; ;; R5 -- Points just past end of string. ;; ;; R2 and R3 are not modified. ;; ;;==========================================================================;; DRAWSTRING PROC PSHR R5 ; Save the return address MOVR R0, R5 ; Move our pointer into R5 SETC ; Flag that we'll be returning via PULR PC INCR R7 ; (skip the CLRC) DRAWSTRING2: CLRC ; Flag that we'll be returning via JR R5 SLL R1, 1 RRC R1, 1 ; Put flag into bit 15 of screen format word. MVI@ R5, R0 ; Get first char of string @@tloop: SUBI #32, R0 ; Shift ASCII range to charset SLL R0, 2 ; Move it to position for BTAB word SLL R0, 1 XORR R1, R0 ; Merge with color info MVO@ R0, R4 ; Write to display MVI@ R5, R0 ; Get next character TSTR R0 ; Is it NUL? BNEQ @@tloop ; --> No, keep copying then SLLC R1, 1 ; Recover 'return' flag from screen fmt word, ADCR R0 ; ... and put it in R0. SLR R1, 1 ; Restore screen format word. ADDR R0, R7 ; If flag is set, return by PULR PC, else JR R5 ; ... return by the JR R5. PULR R7 ENDP ;;==========================================================================;; ;; MSG_ERR -- Display "ERR!" ;; ;;==========================================================================;; MSG_ERR PROC PSHR R5 MVII #C_RED, R1 CALL DRAWSTRING2 ERR: BYTE "ERR!", 0 PULR PC ENDP ;;==========================================================================;; ;; MSG_OK -- Display "*OK*" ;; ;;==========================================================================;; MSG_OK PROC PSHR R5 MVII #C_YEL, R1 CALL DRAWSTRING2 OK: BYTE "*OK*", 0 PULR PC ENDP ;;==========================================================================;; ;; MSG_DONE -- Display "*Done*" and wait for tap on the pad. ;; ;;==========================================================================;; MSG_DONE PROC PSHR R5 MVII #$200 + 11*20 + 7, R4 MVII #C_BLU, R1 CALL DRAWSTRING2 BYTE "*Done*", 0 B WAIT_TAP + 1 ; Wait for a tap on the keypad. ENDP ;;==========================================================================;; ;; MSG_MORE -- Display "More..." and wait for tap on the pad. ;; ;;==========================================================================;; MSG_MORE PROC PSHR R5 MVII #$200 + 11*20 + 6, R4 MVII #C_RED, R1 CALL DRAWSTRING2 BYTE "More...", 0 B WAIT_TAP + 1 ; Wait for a tap on the keypad. ENDP ;;==========================================================================;; ;; WAITHAND -- Waits for controller to be pressed/released ;; ;;==========================================================================;; 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 ;;==========================================================================;; ;; WAIT_TAP -- Wait for controller to go through press/release cycle. ;; ;;==========================================================================;; WAIT_TAP PROC PSHR R5 PSHR R0 PSHR R1 PSHR R4 SETC CALL WAITHAND MOVR R0, R2 SWAP R2 ANDR R0, R2 ANDI #$FF, R2 ; Remember what was pressed. CLRC CALL WAITHAND PULR R4 PULR R1 PULR R0 PULR PC ENDP ;;==========================================================================;; ;; RAND ;; ;; Returns random bits in R0. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Number of bits desired ;; ;; R5 -- Return address ;; ;; Random state in RNDLO, RNDHI ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- N random bits. ;; ;; R1, R2, R3, R4 -- Saved and restored ;; ;; R5 -- trashed. ;; ;;==========================================================================;; RAND PROC PSHR R5 ; Save return address and R1..R4 PSHR R4 PSHR R3 PSHR R2 PSHR R1 MVII #1, R1 ; Our initial mask word BEQ @@nobits MVII #$04C1, R5 ; period==(2**32 - 1) polynomial MVII #$1DB7, R4 ; (this is the CRC-32 polynomial) MVI RNDHI, R3 ; Read in our 32-bit random number state MVI RNDLO, R2 TSTR R3 ; If our random number generator is zero BNEQ @@loop ; jumpstart the process by forcing an XOR TSTR R2 ; of our generator polynomal into R2/R3 SETC ; up front. Otherwise, we won't generate BEQ @@forceit ; any random numbers! @@loop: SLLC R2, 1 ; Shift our 32-bit random number left by 1 RLC R3, 1 ; ... by using the carry and an RLC. @@forceit: SLL R1, 1 ; Shift our mask bit left by 1 BNC @@nocarry XORR R4, R2 ; If the carry was set, XOR in our generator XORR R5, R3 ; polynomial. @@nocarry: DECR R0 ; Keep generating bits. BNEQ @@loop MVO R3, RNDHI ; Store our new random number state. MVO R2, RNDLO @@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 R1 ; Retstore our registers and return. PULR R2 PULR R3 PULR R4 PULR PC ENDP ;;==========================================================================;; ;; POW10 ;; ;; Look-up table with powers of 10 as 32-bit numbers (little endian). ;; ;; ;; ;; NPW10 ;; ;; Same as POW10, only -(10**x) instead of 10**x. ;; ;;==========================================================================;; POW10 PROC @@9 WORD 1000000000 AND $FFFF, 1000000000 SHR 16 ; 10**9 @@8 WORD 100000000 AND $FFFF, 100000000 SHR 16 ; 10**8 @@7 WORD 10000000 AND $FFFF, 10000000 SHR 16 ; 10**7 @@6 WORD 1000000 AND $FFFF, 1000000 SHR 16 ; 10**6 @@5 WORD 100000 AND $FFFF, 100000 SHR 16 ; 10**5 @@4 WORD 10000 AND $FFFF, 10000 SHR 16 ; 10**4 @@3 WORD 1000 AND $FFFF, 1000 SHR 16 ; 10**3 @@2 WORD 100 AND $FFFF, 100 SHR 16 ; 10**2 @@1 WORD 10 AND $FFFF, 10 SHR 16 ; 10**1 @@0 WORD 1 AND $FFFF, 1 SHR 16 ; 10**0 ENDP NPW10 PROC @@9 WORD -1000000000 AND $FFFF,-1000000000 SHR 16 ;-10**9 @@8 WORD -100000000 AND $FFFF,-100000000 SHR 16 ;-10**8 @@7 WORD -10000000 AND $FFFF,-10000000 SHR 16 ;-10**7 @@6 WORD -1000000 AND $FFFF,-1000000 SHR 16 ;-10**6 @@5 WORD -100000 AND $FFFF,-100000 SHR 16 ;-10**5 @@4 WORD -10000 AND $FFFF,-10000 SHR 16 ;-10**4 @@3 WORD -1000 AND $FFFF,-1000 SHR 16 ;-10**3 @@2 WORD -100 AND $FFFF,-100 SHR 16 ;-10**2 @@1 WORD -10 AND $FFFF,-10 SHR 16 ;-10**1 @@0 WORD -1 AND $FFFF,-1 SHR 16 ;-10**0 ENDP ;;==========================================================================;; ;; DEC16 ;; ;; Displays a 16-bit decimal number on the screen with leading blanks ;; ;; in a field up to 5 characters wide. Displays all blanks if the number ;; ;; is zero. ;; ;; ;; ;; DEC16A ;; ;; Same as DEC16, only displays leading zeroes. ;; ;; ;; ;; DEC16B ;; ;; Same as DEC16, only leading zeros are controlled by bit 15 of R3. ;; ;; (If set, suppress leading zeros. If clear, show leading zeros.) ;; ;; ;; ;; DEC16C ;; ;; Same as DEC16B, except R1 contains an amount to add to the first digit. ;; ;; ;; ;; DEC16Z ;; ;; Same as DEC16, except displays a single zero if the value is zero. ;; ;; (Note: DEC16Z is actually defined separately along with DEC32Z). ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Number to be displayed in decimal. ;; ;; R1 -- (DEC16C only): Amount to add to initial digit. ;; ;; R2 -- Number of digits to suppress (If R2<=5, it is 5-field_width) ;; ;; R3 -- Color mask / screen format word (XORd with char index) ;; ;; R4 -- Screen offset (lower 8-bits) ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Zeroed ;; ;; R1 -- Trashed ;; ;; R2 -- Remaining digits to suppress (0 if initially <= 5.) ;; ;; R3 -- Color mask, with bit 15 set if no digits displayed. ;; ;; R4 -- Pointer to character just right of string ;; ;; R5 -- Trashed ;; ;; ;; ;; Routine uses DEC16_0, DEC16_1 for temporary storage. ;; ;;==========================================================================;; DEC16 PROC @@so EQU DEC_0 @@fw EQU DEC_1 SETC ; Prepare to set bit 15 of color mask INCR R7 ; Skip the CLRC DEC16A CLRC ; Prepare to clear bit 15 of clrmask SLL R3, 1 RRC R3, 1 ; Set/clear bit 15 of color mask DEC16B CLRR R1 DEC16C PSHR R5 ; Save return address DIS MVI @@so, R5 PSHR R5 MVI @@fw, R5 PSHR R5 EIS MOVR PC, R5 ; (generate PC-relative address) SUBI #$-POW10.4, R5 ; Point to '10000' entry in POW10 MVO R4, @@so ; Save screen offset MVO R2, @@fw ; Save field width MVII #5, R4 ; Iterate 5 (16-bit goes to 65536) MOVR R1, R2 INCR R7 @@digitlp: CLRR R2 ; Start with division result == 0 SDBD MVI@ R5, R1 ; Load power of 10 ADDI #2, R5 ; Point to next smaller power of 10 @@divloop: INCR R2 SUBR R1, R0 ; Divide by repeated subtraction BC @@divloop ADDR R1, R0 ; Loop iterates 1 extra time: Fix it. DECR R2 ; Fix extra iter. Also test if 0 BNEQ @@disp ; If digit != 0, display it. TSTR R3 ; If digit == 0 and no lead 0, skip BMI @@blank @@disp: SLL R3, 1 ; Clear "no leading 0" flag SLR R3, 1 ; MVI @@fw, R1 ; Get field width DECR R1 ; Are we in active field yet? BMI @@ok ; Yes: Go ahead and display MVO R1, @@fw ; No: Save our count-down till field B @@iter ; and don't display the digit. @@blank: MOVR R3, R2 ; Blank character _just_ gets format MVI @@fw, R1 ; Get field width DECR R1 ; Are we in active field yet? BMI @@drawit ; Yes: Go ahead and display MVO R1, @@fw ; No: Save our count-down till field B @@iter ; and don't display the digit. @@ok: ADDI #$10, R2 ; Pseudo-ASCII digits start at 0x10 SLL R2, 2 ; Put pseudo-ASCII char in position ADDR R2, R2 ; ... by shifting left 3 XORR R3, R2 ; Merge with display format @@drawit: MVI @@so, R1 ; Get screen offset XORI #$200, R1 ; Move to screen MVO@ R2, R1 ; Put character on screen INCR R1 ; Move the pointer MVO R1, @@so ; Save the new offset @@iter: DECR R4 ; Count down our digit count BNEQ @@digitlp ; Keep iterating MVI @@so, R4 ; Restore offset MVI @@fw, R2 ; Restore digit suppress count DIS PULR R5 MVO R5, @@fw PULR R5 MVO R5, @@so EIS PULR PC ; Whew! Done! ENDP ;;==========================================================================;; ;; DEC32 ;; ;; Displays a 32 bit number without leading zeros. It performs this feat ;; ;; by calling DEC16 multiple times. ;; ;; ;; ;; DEC32A ;; ;; Same as DEC32, except leading zeros are displayed. ;; ;; ;; ;; DEC32B ;; ;; Same as DEC32, except leading zeros are controlled by bit 15 of R3 ;; ;; (If set, suppress leading zeros. If clear, show leading zeros.) ;; ;; ;; ;; DEC32Z ;; ;; Same as DEC32, except displays a single zero if the value is zero. ;; ;; (Note: DEC32Z is actually defined separately along with DEC16Z). ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Low half of 32-bit number ;; ;; R1 -- High half of 32-bit number ;; ;; R2 -- Number of leading digits to suppress (10 - field width) ;; ;; R3 -- Screen format word ;; ;; R4 -- Screen offset (lower 8-bits) ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Zeroed ;; ;; R1 -- Trashed ;; ;; R2 -- Remaining digits to suppress (0 if initially <= 10.) ;; ;; R3 -- Color mask, with bit 15 set if no digits displayed. ;; ;; R4 -- Pointer to character just right of string ;; ;; R5 -- Trashed ;; ;; ;; ;; Routine uses DEC_0..DEC_3 for temporary storage. ;; ;;==========================================================================;; DEC32 PROC @@so EQU DEC_0 @@fw EQU DEC_1 @@fmt EQU DEC_2 ; and DEC_3. We store 16 bits here. SETC ; Prepare to set bit 15 of color mask INCR R7 ; Skip the CLRC DEC32A CLRC ; Prepare to clear bit 15 of clrmask SLL R3, 1 RRC R3, 1 ; Set/clear bit 15 of color mask DEC32B PSHR R5 ; Save return address MVO R2, @@fw ; Save field width MVO R4, @@so ; Save screen offset MVO R3, @@fmt SWAP R3 MVO R3, @@fmt+1 CLRR R3 PSHR R3 ; Push accumulator (init'd to 0) ; Use division by repeated subtraction to generate a 16-bit ; value which represents the first 5 digits of the 10 digit number. MOVR PC, R5 ; (generate PC-relative address) SUBI #$-NPW10.9, R5 ; Point to -10**9 @@digitlp: CLRR R3 SDBD MVI@ R5, R2 ; Load low half of 32-bit -10**x SDBD MVI@ R5, R4 ; Load high half of 32-bit -10**x @@divlp: SLR R3, 1 @@divlpb: INCR R3 ADDR R2, R0 ; Add the low half ADCR R1 ; Add carry from low half RLC R3, 1 ; See if adding the carry carried ADDR R4, R1 ; Add high half BC @@divlp ; Loop if we had a carry from either SARC R3, 1 ; upper half ADD. (We can't get BC @@divlpb ; a carry from both, though.) ; Subtract off the extra iteration SUBR R2, R0 ; Subtract the low half. ADCR R1 ; Add in the "not-borrow" DECR R1 ; Turn "not-borrow" into "borrow" SUBR R4, R1 ; Subtract the high half. DECR R3 BEQ @@nxtdigit ; Take our count and multiply it by the appropriate power of 10. MOVR R5, R2 MOVR R3, R4 SUBR PC, R2 ADDI #$-NPW10.4, R2 ; Translate 10**x to 10**(x-5) BEQ @@donemult @@mult: ADDR R4, R4 ; To mult by 10, do (x<<1)+(x<<3) MOVR R4, R3 SLL R3, 2 ADDR R3, R4 ADDI #$4, R2 BLT @@mult @@donemult: ADD@ SP, R4 ; Add this to our 16-bit accum. PSHR R4 ; that we keep on top-of-stack @@nxtdigit: CMPI #NPW10.4, R5 BLT @@digitlp MVI @@fw, R2 ; Restore field width MVI @@so, R4 ; Restore screen offset MVI @@fmt+1,R3 ; Restore fmt word SWAP R3, 1 ; ... XOR @@fmt, R3 ; ... MVO R0, @@fmt ; Save low byte of lower 16 bits SWAP R0, 1 ; ... MVO R0, @@fmt+1 ; Save high byte of lower 16 bits PULR R0 ; Get accumulated word for display PSHR R1 ; Save upper bit CALL DEC16B ; Display first five digits ; Now, our 32-bit number should be less than 100000. That ; means R1 should be 0 or 1. We display the last five digits ; as a single 16-bit number by handling that bit separately. MVI @@fmt+1,R0 ; Restore lower 16 bits SWAP R0, 1 ; ... XOR @@fmt, R0 ; ... PULR R1 ; Get upper bit TSTR R1 ; Was it zero? BEQ @@noextra ; Yes: Nothing special to do MVII #6, R1 ; No: Add 6 to the leading digit ADDI #5536, R0 ; ... and "5536" to remaining digits @@noextra: PULR R5 ; Chain the return. B DEC16C ; Display remaining digits. WHEW! ENDP ;;==========================================================================;; ;; DEC32Z ;; ;; Same as DEC32, except a zero is displayed in the final position if ;; ;; the whole number's value is zero. ;; ;; ;; ;; DEC16Z ;; ;; Same as DEC16, except a zero is displayed in the final position if ;; ;; the whole number's value is zero. ;; ;; ;; ;; INPUTS: ;; ;; R0 -- Lower 16-bits of number ;; ;; R1 -- Upper 16-bits of number (if DEC32Z) ;; ;; R2 -- Number of leading digits to suppress ;; ;; (10 - field width for DEC32Z, 5 - field width for DEC16Z). ;; ;; R3 -- Screen format word ;; ;; R4 -- Screen offset (lower 8-bits) ;; ;; ;; ;; OUTPUTS: ;; ;; R0 -- Zeroed ;; ;; R1 -- Trashed ;; ;; R2 -- If number == 0, unchanged. If != 0, remaining digits to suppress ;; ;; R3 -- Color mask, unmodified. ;; ;; R4 -- Pointer to character just right of string ;; ;; R5 -- Trashed ;; ;; ;; ;; DEC16Z uses DEC_0..DEC_1 for temporary storage. ;; ;; DEC32Z uses DEC_0..DEC_3 for temporary storage. ;; ;;==========================================================================;; DEC32Z PROC TSTR R1 ; Is upper half non-zero? BNEQ DEC32 ; Yes: Call DEC32. TSTR R0 ; Is lower half non-zero? BNEQ DEC32 ; Yes: Call DEC32 MVII #10, R1 ; No: Prepare to clear field and draw the B @@dozero ; zero. DEC16Z: TSTR R0 ; Is the number non-zero? BNEQ DEC16 ; Yes: Call DEC16 MVII #5, R1 ; No: Prepare to clear the field and draw 0. @@dozero: SUBR R2, R1 ; Is our field wide enough to display the 0? BLE @@nodisp ; No: Don't display it then. ADDI #$200, R4 ; Yes: Calculate our screen pointer. INCR R7 ; (skip first iteration of loop) @@loop: MVO@ R3, R4 ; Clear the leading digits. DECR R1 BNEQ @@loop XORI #$80, R3 ; Now display a zero. MVO@ R3, R4 XORI #$80, R3 ; Leave R3 unchanged. @@nodisp: JR R5 ; Return to the caller. ENDP ;;==========================================================================;; ;; RANDSAVE -- Save the current random-number seed. ;; ;;==========================================================================;; RANDSAVE PROC PSHR R5 MVI RNDLO, R5 MVO R5, SAVLO MVI RNDHI, R5 MVO R5, SAVHI PULR PC ENDP ;;==========================================================================;; ;; RANDRSTR -- Restore the current random-number seed. ;; ;;==========================================================================;; RANDRSTR PROC PSHR R5 MVI SAVLO, R5 MVO R5, RNDLO MVI SAVHI, R5 MVO R5, RNDHI PULR PC ENDP ;;==========================================================================;; ;; BANKTEST -- Really simple bank test. Fills up all of the Intellicart ;; ;; memory with random data, and then reads it back. ;; ;;==========================================================================;; BANKTEST PROC PSHR R5 ;;--------------------------------------------------------------;; ;; Remember our initial parameters ;; ;;--------------------------------------------------------------;; MVO R1, WPAGE MVO R2, RPAGE ;;--------------------------------------------------------------;; ;; Clear the screen ;; ;;--------------------------------------------------------------;; CALL CLRSCR1 ;;--------------------------------------------------------------;; ;; Put up our status display ;; ;;--------------------------------------------------------------;; MVII #ROW_0, R4 MVII #C_GRN, R1 CALL DRAWSTRING2 ;01234567890123456789; BYTE ">> Bank Switching <<" BYTE ">> Simple Test: <<",0 MVII #ROW_3, R4 MVII #C_WHT, R1 CALL DRAWSTRING2 ;01234567890123456789; BYTE "Writeout page: XXXX" BYTE "Readback page: XXXX" BYTE " " BYTE " Filling at: " BYTE " Reading back: " , 0 MVII #ROW_3 + 16, R4 MVI WPAGE, R0 MVII #C_YEL, R1 CALL HEX16 MVII #ROW_4 + 16, R4 MVI RPAGE, R0 CALL HEX16 ;;--------------------------------------------------------------;; ;; Fill up the Intellicart's memory. Avoid $5000-$5FFF, since ;; ;; that's where this test program lives. ;-) ;; ;;--------------------------------------------------------------;; CALL RANDSAVE ; Save the current random seed. MVI WPAGE, R1 SWAP R1 CLRR R2 MVO R1, PGTMP ; Initialize our page and remapping MVO R2, MPTMP ; counters. @@fill_olp: ; CMPI #$50, R2 ; Skip $5000 - $5FFFF ; BNEQ @@ok_f ; .. by adding $10 if we see $50. ; ADDI #$10, R2 ;@ok_f: ; MVO R2, MPTMP ; Save the mapping for next time ; CALL IC_SETBANK ; Actually flip the page. CLRR R2 MVO R2, $46 MVO R2, $4D MVI MPTMP, R0 ; Get the mapping so we can show it. SWAP R0 ; Put it in the MSBs. MVII #C_TAN, R1 ; Display it.... MVII #ROW_6 + 16, R4 CALL HEX16 MVII #16, R0 CALL RAND MOVR R0, R3 MVII #16, R0 CALL RAND MVI WPAGE, R4 ; Get the page's Inty address @@fill_ilp: INCR R3 XORR R3, R0 MVO@ R0, R4 ; Write them into the bankswitched page. DECR R1 BNEQ @@fill_ilp ; MVI PGTMP, R1 ; Get the page number ; MVI MPTMP, R2 ; Get the page's current mapping. ; ADDI #$08, R2 ; Increment the mapping. ; ANDI #$F8, R2 ; Only keep the 5 MSBs. ; BNEQ @@fill_olp ; If it goes to 0, we're done. ;;--------------------------------------------------------------;; ;; Actually read back the random values and make sure they all ;; ;; match what we originally wrote. ;; ;;--------------------------------------------------------------;; CALL RANDRSTR ; Restore the random seed we saved. MVI RPAGE, R1 SWAP R1 CLRR R2 MVO R1, PGTMP ; Initialize our page and remapping MVO R2, MPTMP ; counters. @@read_olp: ; CMPI #$50, R2 ; Skip $5000 - $5FFFF ; BNEQ @@ok_r ; .. by adding $10 if we see $50. ; ADDI #$10, R2 ;@ok_r: ; MVO R2, MPTMP ; Save the mapping for next time ; CALL IC_SETBANK ; Actually flip the page. CLRR R2 MVO R2, $46 MVO R2, $4D MVI MPTMP, R0 ; Get the mapping so we can show it. SWAP R0 ; Put it in the MSBs. MVII #C_TAN, R1 ; Display it.... MVII #ROW_7 + 16, R4 CALL HEX16 MVII #16, R0 CALL RAND MOVR R0, R3 MVII #16, R0 CALL RAND MVI RPAGE, R4 ; Get the page's Inty address @@read_ilp: INCR R3 XORR R3, R0 MVI@ R4, R2 ; Compare the memory value with rand num. CMPR R0, R2 BNEQ @@fail DECR R1 BNEQ @@read_ilp ; MVI PGTMP, R1 ; Get the page number ; MVI MPTMP, R2 ; Get the page's current mapping. ; ADDI #$08, R2 ; Increment the mapping. ; ANDI #$F8, R2 ; Only keep the 5 MSBs. ; BNEQ @@read_olp ; If it goes to 0, we're done. @@pass: MVII #ROW_8 + 8, R4 CALL MSG_OK MVII #PDLY, R0 CALL WAIT PULR PC @@fail: PSHR R0 PSHR R2 PSHR R4 MVII #ROW_8, R4 MVII #C_RED, R1 CALL DRAWSTRING2 BYTE "A=",0 PULR R0 CALL HEX16 CALL DRAWSTRING2 BYTE " D=",0 PULR R0 CALL HEX16 CALL DRAWSTRING2 BYTE " X=", 0 PULR R0 CALL HEX16 MVII #ROW_9 + 8, R4 CALL MSG_ERR MVII #EDLY, R0 CALL WAIT PULR PC ENDP ;;==========================================================================;; ;; Intellicart Bank Switch Utility Routines ;; ;; Copyright 2000, Joe Zbiciak. ;; ;; ;; ;; This file contains a number of useful routines that you're welcome ;; ;; to use in your own software. Please keep in mind that these routines ;; ;; are licensed under the GNU General Public License, and so if you plan ;; ;; to distribute a program which incorporates these routines, it too must ;; ;; be distributed under the GNU General Public License. ;; ;;==========================================================================;; ;* ======================================================================== *; ;* 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) 2000, Joseph Zbiciak *; ;* ======================================================================== *; ;;==========================================================================;; ;; IC_BANK2REG -- Converts a bank address to an Intellicart reg address. ;; ;; ;; ;; Inputs: ;; ;; R1 -- 5 MSBs of bank address in bits 7..3 ;; ;; R5 -- Return address ;; ;; ;; ;; Outputs: ;; ;; R1 -- Address of Intellicart base control register. ;; ;; R5 -- Trashed. ;; ;; ;; ;;==========================================================================;; IC_BANK2REG PROC PSHR R5 ; Save return address MOVR R1, R5 ; Get Hi/Lo 2K bit from address in R5 ADDR R5, R5 ANDI #$10, R5 SLR R1, 2 ; Put 4 MSBs of page in 4 LSBs of R0 SLR R1, 2 ANDI #$0F, R1 ; Keep only the four LSBs. ADDR R5, R1 ; Merge bits: 76543210 -> xxxx37654 ADDI #$40, R1 ; Point it at Intellicart ctrl regs. PULR PC ; Return. ENDP ;;==========================================================================;; ;; IC_SETBANK -- Sets a bank for a given 2K page of memory. ;; ;; ;; ;; Inputs: ;; ;; R1 -- 5 MSBs of bank address in bits 7..3 ;; ;; R2 -- New bank address to point to in 8 LSBs. ;; ;; R5 -- Return address ;; ;; ;; ;; Outputs: ;; ;; R1 -- Address of Intellicart base control register. ;; ;; R2 -- Trashed. ;; ;; R5 -- Trashed. ;; ;; ;; ;; Example: ;; ;; To remap 0x7800-0x7FFF in the Inty's address space to point to ;; ;; 0x4000-0x47FF in the cart's address space, pass in the following ;; ;; parameters: R1 = 0x0078, R2 = 0x0040. ;; ;; ;; ;;==========================================================================;; IC_SETBANK PROC PSHR R5 ; Save return address. CALL IC_BANK2REG ; Convert bank to ctrl reg address MVO@ R2, R1 ; Write to control register. PULR PC ; Return ENDP ;;==========================================================================;; ;; IC_BANKTBL -- Resets the bank mappings for this cartridge using a ;; ;; table of initial mappings. ;; ;; ;; ;; Inputs: ;; ;; R4 -- Pointer to bank initialization table (format below) ;; ;; R5 -- Return address ;; ;; ;; ;; Outputs: ;; ;; R4 -- Points just past end of table. ;; ;; R5 -- Trashed. ;; ;; ;; ;; Table format: ;; ;; The table is laid out as a series of byte pairs packed into 16-bit ;; ;; words. The current format for each word is like so: ;; ;; ;; ;; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ;; ;; +---+---+---+---+---+---+---+---+-------------------------------+ ;; ;; | BANK NUMBER |n/a|n/a|n/a| INTELLICART BANK ADDR MAPPING | ;; ;; +---+---+---+---+---+---+---+---+-------------------------------+ ;; ;; ;; ;; To end the table, use a word filled with all zeros. ;; ;; ;; ;;==========================================================================;; IC_BANKTBL PROC PSHR R5 PSHR R2 PSHR R1 B @@1st_iter @@loop: CALL IC_SETBANK @@1st_iter: MVI@ R4, R2 MOVR R2, R1 SWAP R1, 1 BNEQ @@loop PULR R1 PULR R2 PULR PC ENDP