;; ======================================================================== ;;
;;  INTV RAM Tests.  Tests the bank-switch support on the Intellicart.      ;;
;;  This test is derived from "mem_test".                                   ;;
;;  Copyright 2000, Joe Zbiciak, intvnut AT gmail.com.                      ;;
;;  http://spatula-city.org/~im14u2c/intv/                                  ;;
;; ======================================================================== ;;

;* ======================================================================== *;
;*  TO BUILD IN BIN+CFG FORMAT:                                             *;
;*      as1600 -o banktest.bin -l banktest.lst banktest.asm                 *;
;*                                                                          *;
;*  TO BUILD IN ROM FORMAT:                                                 *;
;*      as1600 -o banktest.rom -l banktest.lst banktest.asm                 *;
;* ======================================================================== *;

;* ======================================================================== *;
;*  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                     *;
;* ======================================================================== *;

        CFGVAR  "name" = "SDK-1600 Intellicart Bankswitched Memory Test"
        CFGVAR  "short_name" = "RAM/BANKSW Test"
        CFGVAR  "author" = "Joe Zbiciak"
        CFGVAR  "year" = 2002
        CFGVAR  "license" = "GPLv2+"
        CFGVAR  "description" = "Memory tester for the Intellicart / CC3."
        CFGVAR  "publisher" = "SDK-1600"

        ROMW    16

; ------------------------------------------------------------------------- ;
;  System Description -- include from library.                              ;
; ------------------------------------------------------------------------- ;
        INCLUDE "../library/gimini.asm"
 
; ------------------------------------------------------------------------- ;
;  Test Configuration.                                                      ;
;  Modify these EQUates to reflect the range/width of memory to test.       ;
; ------------------------------------------------------------------------- ;
RAMLO   EQU     $B000           ; Start of RAM memory range.
RAMHI   EQU     $BFFF           ; End of RAM memory range (inclusive).
RAMAM   EQU     $0FFF           ; RAM Address Mask
BNKLO   EQU     $A000           ; Shadow area that reads the same as the RAM
BNKHI   EQU     $AFFF           ; Shadow area that reads the same as the RAM
RAMW    EQU     $10             ; Ram width in bits, 1 through 16 bits.

;; NOTE:  Mapping RAM into $B800 - $BFFF is generally not a good idea in
;; most programs, as this is a write-only GRAM alias.  It's safe in this
;; program only because we don't care about the contents of GRAM.

; ------------------------------------------------------------------------- ;
;  Mark the memory range as read/write/bankswitched.                        ;
; ------------------------------------------------------------------------- ;
        ORG     BNKLO, BNKLO, "+RWB"
        RMB     $1000

        ORG     BNKHI, BNKHI, "+RWB"
        RMB     $1000

; ------------------------------------------------------------------------- ;
;  Variables.  We hide the 16-bit variables under the stack.                ;
;  Note that some of these variables are used by library routines that are  ;
;  INCLUDEd at the end of the program.                                      ;
; ------------------------------------------------------------------------- ;
                        ; Used by       Req'd Width   Description
                        ;---------------------------------------------------
TESTFXN EQU     $2F2    ; DOTEST        16-bit        Ptr to test function
BUSY    EQU     $2F3    ; ISR/WAIT      16-bit        Busy-wait counter
DEC_0   EQU     $110    ; DEC16         8-bit         Temp. storage
DEC_1   EQU     $111    ; DEC16         8-bit         Temp. storage
ERR0    EQU     $2F4    ; the tests     16-bit        # of errors this test
T_ITER  EQU     $2F5    ; the tests     16-bit        Test number
ERRS    EQU     $2F6    ; the tests     16-bit        Total # of errors
SAVLO   EQU     $2F7    ; RANDSAVE/RSTR 16-bit        Saves rand num. seed
SAVHI   EQU     $2F8    ; RANDSAVE/RSTR 16-bit        Saves rand num. seed
SCRAM   EQU     $2F9    ; the tests     16-bit        Addr. scrambling pattern
CUR_L   EQU     $2FA    ; ISR/tests     16-bit        Current location
CUR_S   EQU     $2FB    ; ISR/tests     16-bit        Current status
TMP0    EQU     $2FC    ; tests         16-bit        Scratch avail to tests
TMP1    EQU     $2FD    ; tests         16-bit        Scratch avail to tests
RNDLO   EQU     $35E    ; RAND          16-bit        Random number state
RNDHI   EQU     $35F    ; RAND          16-bit        Random number state
APAT    EQU     $120    ; the tests     8-bit         Addressing pattern
ARROW   EQU     $130    ; ISR           8-bit         Current row w/ arrows
ABLNK   EQU     $131    ; ISR           8-bit         Blink counter for arrows
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?
HUPD    EQU     $138    ; ISR           8-bit         HEX update counter
BANK    EQU     $139    ; the tests     8-bit         Current 4K bank mapping
RW_COL  EQU     $13A    ; the tests     8-bit         Current 4K bank mapping
BOS     EQU     $300    ; STACK         16-bit        Bottom of stack.
ITMP    EQU     $331


; ------------------------------------------------------------------------- ;
;  Handy Equates.                                                           ;
; ------------------------------------------------------------------------- ;
ROW_0   EQU     MEMMAP.backtab
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

MASK    EQU     (1 SHL RAMW)-1  ; All 1s mask equal to RAM's width.
RAMSZ   EQU     RAMHI-RAMLO+1   ; Number of words of RAM.
HCNT    EQU     3               ; Number of ticks between "hex updates"
EDLY    EQU     30              ; Number of ticks to hold error addr up.
PDLY    EQU     45              ; Number of ticks to hold each full page

W_COL   EQU     C_DGR
R_COL   EQU     C_TAN


        ORG     $5000
;------------------------------------------------------------------------------
; EXEC-friendly ROM header.
;------------------------------------------------------------------------------
ROMHDR: BIDECLE ZERO            ; MOB picture base   (points to NULL list)
        BIDECLE ZERO            ; Process table      (points to NULL list)
        BIDECLE MAIN            ; Program start address
        BIDECLE ZERO            ; Bkgnd picture base (points to NULL list)
        BIDECLE ONES            ; GRAM pictures      (points to NULL list)
        BIDECLE TITLE           ; Cartridge title/date
        DECLE   $03C0           ; No ECS title, run code after title,
                                ; ... no clicks
ZERO:   DECLE   $0000           ; Screen border control
        DECLE   $0000           ; 0 = color stack, 1 = f/b mode
        DECLE   C_BLK, C_BLK    ; Initial color stack 0 and 1: Black
        DECLE   C_BLK, C_BLK    ; Initial color stack 2 and 3: Black
        DECLE   C_BLK           ; Initial border color: Black
ONES:   DECLE   1
;------------------------------------------------------------------------------


;; ======================================================================== ;;
;;  TITLE / TITLEFIX -- The Title Screen code.                              ;;
;; ======================================================================== ;;
TITLE:      BYTE    101, "RAM/BANKSW Test", 0 

TITLEFIX:   PROC

            BEGIN

            MVII    #$100,    R4    ;\
            SDBD                    ; |__ remember old ISR address
            MVI@    R4,       R1    ; |
            MVO     R1,       ITMP  ;/

            MVII    #@@isr,   R0    ; \
            SUBI    #2,       R4    ;  |
            MVO@    R0,       R4    ;  |-- Make title screen cyan
            SWAP    R0              ;  |   via short ISR.
            MVO@    R0,       R4    ; /

            ; Patch the title string to say '=JRMZ=' instead of Mattel.
            CALL    PRINT.FLS       ; Write string (ptr in R5)
            DECLE   C_BLK, $23C     ; Black,  Point to 'Mattel' in top-left
            BYTE    "Zbiciak "      ; Guess who?  :-)
            BYTE    "Electronics",0

            CALL    PRINT.FLS       ; Write string (ptr in R1)
            DECLE   C_BLK, $2D0     ; Black,  Point to 'Mattel' in lower-right
            BYTE    "2001 =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 compl...
            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

@@isr:
            ; Cyan screen
            MVII    #C_CYN, R0      ; Cyan title screen
            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

            MVI     ITMP,   PC

            ENDP

;; ======================================================================== ;;
;;  MAIN -- main program                                                    ;;
;; ======================================================================== ;;
MAIN:   PROC

        XOR     RNDLO,  R1
        XOR     RNDHI,  R2
        ADDR    R3,     R1
        XORR    R4,     R2
        MVII    #$260/4,R3
        MVII    #$100,  R4
@@rndlp:
        XOR@    R4,     R1
        ADD@    R4,     R2
        ADD@    R4,     R1
        XOR@    R4,     R2
        DECR    R3
        BNEQ    @@rndlp

        MVO     R1,     RNDLO
        MVO     R2,     RNDHI

        JSRD    R5,     ISRSPIN


        DIS
        CLRR    R0              ; R0 == 0 == C_BLK
        MVII    #$0028, R4
        MVO@    R0,     R4      ; Black screen.
        INCR    R0              ; R0 == 1 == C_BLU
        MVO@    R0,     R4      ; CS0 == Black
        CLRR    R0
        MVO@    R0,     R4      ; CS1 == Blue
        MVO@    R0,     R4      ; CS2 == Black
        MVO@    R0,     R4      ; CS3 == Black


        ; Fill system memory with zeros.
        MVI     RNDLO,  R2
        MVI     RNDHI,  R3
        MVII    #$260,  R1
        MVII    #$100,  R4
        CALL    FILLZERO
        MVO     R2,     RNDLO
        MVO     R3,     RNDHI

        ; 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.

        EIS
        MVII    #1,     R0
        MVO     R0,     APAT    ; Start "RANDOM", will get toggled to LINEAR.

@@test_loop:
        MVI     T_ITER, R0      ; Increment the test iteration number
        INCR    R0
        MVO     R0,     T_ITER

        MVI     APAT,   R0      ; Get our current addressing mode 
        XORI    #1,     R0      ; Toggle RANDOM or LINEAR.
        MVO     R0,     APAT    ;

        BNEQ    @@do_tests      ; don't increment bank if we just 
                                ; switched to RANDOM

        MVI     BANK,   R0
        ADDI    #7,     R0
        CMPI    #$41,   R0      ; Make sure we don't span over $5000-$5FFF
        BLT     @@bank_ok
        CMPI    #$5F,   R0
        BGT     @@bank_ok
        MVII    #$60,   R0
@@bank_ok:
        MVO     R0,     BANK

@@do_tests:
        CALL    MAINSCRN

        MVII    #(RAMLO SHR 8) AND $FF, R1
        MVII    #(RAMHI SHR 8) AND $FF, R0
        MVI     BANK,   R2
        CALL    IC_SETBANKS

        MVII    #(BNKLO SHR 8) AND $FF, R1
        MVII    #(BNKHI SHR 8) AND $FF, R0
        MVI     BANK,   R2
        CALL    IC_SETBANKS

        MVII    #1,     R0

@@loop:
        CALL    SET_ARRO
        PSHR    R0
        MVII    #@@ret, R5
        MOVR    R0,     R4
        ADDR    R0,     R4
        ADDI    #LINFXN-2, R4
        MVI     APAT,   R2
        TSTR    R2
        BEQ     @@dispat
        ADDI    #RNDFXN-LINFXN, R4
@@dispat:
        CLRR    R3
        MVO     R3,     ERR0    ; Clear error count for test
        SDBD
        MVI@    R4,     PC      ; Call the test.
@@ret:
        PULR    R0
        INCR    R0
        CMPI    #6,     R0
        BLT     @@loop

        CLRR    R0
        CALL    SET_ARRO
;       CALL    MSG_DONE
        MVII    #PDLY,  R0
        CALL    WAIT

        B       @@test_loop

        ENDP

LINFXN  PROC
        WORD    FILL_L
        WORD    WLK1_L
        WORD    WLK0_L
        WORD    CHKR_L
        WORD    RAND_L
        ENDP

RNDFXN  PROC
        WORD    FILL_R
        WORD    WLK1_R
        WORD    WLK0_R
        WORD    CHKR_R
        WORD    RAND_R
        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     STIC.mode, R0   ; force color-stack mode
        MVO     R5, STIC.viden  ; enable display

        ; Blink the "Current Test" arrows, if enabled.
        MVI     ARROW,  R0
        TSTR    R0
        BEQ     @@noarrow

        MVI     ABLNK,  R1
        DECR    R1
        BMI     @@redisp        ; Timer expired, re-display arrows
        MVO     R1,     ABLNK
        SUBI    #20,    R1      ; Are we at the "delete arrow" threshold?
        BNEQ    @@do_stat       ; No:  Do nothing.
        MVII    #C_BLU, R1      ; Undisplay by displaying in blue.
        B       @@undisp

@@redisp:
        MVII    #40,    R1
        MVO     R1,     ABLNK   ; Reset blink counter to 60
        MVII    #C_GRN, R1      ; R1 == GREEN 

@@undisp:
        MVII    #ROW_4+1,R4     ; Offset down to Row #1 for first test.
        ADDR    R0,     R4      ; Point to correct row.

        XORI    #$20F0, R1      ; R1 == '>' in desired color.
        MVO@    R1,     R4      ; Output the left part of arrow
        XORI    #$2010, R1      ; R1 == '<' in desired color.
        ADDI    #10,    R4
        MVO@    R1,     R4      ; Output the right part of arrow
        MVII    #$2000, R0
        MVO@    R0,     R4

@@do_stat:
        ; Update the memory location/pass counter/error thingy
        MVI     ARROW,  R4
        ADDI    #ROW_4+14, R4
        MVI     CUR_L,  R0

        MVI     CUR_S,  R1
        DECR    R1
        BMI     @@no_stat
        BEQ     @@pass_count

        MVI     HUPD,   R1
        DECR    R1
        BPL     @@no_hupd

        MVI     RW_COL, R1
        CALL    HEX16

        MVII    #HCNT,  R1
@@no_hupd:
        MVO     R1,     HUPD
        B       @@done_stat


@@pass_count:
        MVII    #C_TAN, R3
        MVII    #1,     R2
        CALL    DEC16Z

@@noarrow:
@@no_stat:
@@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       ; 5 - 3 ==> 2 digit field
        MVII    #C_BLU, R3
        MVII    #ROW_B + 9, R4
        CALL    DEC16A           ; display leading zeros

        INCR    R4

        MVI     T_HRS,  R0
        MVII    #3,     R2       ; 5 - 3 ==> 2 digit field
        CALL    DEC16A           ; display leading zeros

        INCR    R4

        MVI     T_MIN,  R0
        MVII    #3,     R2       ; 5 - 3 ==> 2 digit field
        CALL    DEC16A           ; display leading zeros

        INCR    R4

        MVI     T_SEC,  R0
        MVII    #3,     R2       ; 5 - 3 ==> 2 digit field
        CALL    DEC16A           ; display leading zeros

        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

;; ======================================================================== ;;
;;  MSG_ERR  -- Display "ERR!"                                              ;;
;; ======================================================================== ;;
MSG_ERR PROC
        PSHR    R5
        MVII    #C_RED, R1
        CALL    PRINT.S    
ERR:    BYTE    "ERR!", 0
        PULR    PC
        ENDP

;; ======================================================================== ;;
;;  MSG_OK   -- Display "*OK*"                                              ;;
;; ======================================================================== ;;
MSG_OK  PROC
        PSHR    R5
        MVII    #C_YEL, R1
        CALL    PRINT.S    
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    PRINT.S    
        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    PRINT.S    
        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

;; ======================================================================== ;;
;;  DISPERRS -- Displays current error count.                               ;;
;; ======================================================================== ;;
DISPERRS    PROC
        PSHR    R5
        MVII    #C_TAN, R1      ; Tan  
        MVII    #ROW_3, R4      ; Row 2, Col 0
        CALL    PRINT.S    
        BYTE    "Total Errors: ", 0

        MVI     ERRS,   R0
        TSTR    R0
        BNEQ    @@errs
        MVII    #C_YEL, R1
        CALL    PRINT.S    
        BYTE    "None.", 0
        PULR    PC
@@errs:
        MVII    #C_RED, R3
        CLRR    R2
        PULR    R5
        J       DEC16A
        ENDP

;; ======================================================================== ;;
;;  SET_ARRO -- Put arrows next to the current test.  Test # in R0.         ;;
;; ======================================================================== ;;
SET_ARRO    PROC
        PSHR    R5
        PSHR    R0
        PSHR    R1

        CLRR    R5
    
        MVI     ARROW,  R1
        MVO     R5,     ARROW   ; Disable current arrow (if any)

        TSTR    R1              ; Do we have a current blinking arrow?
        BEQ     @@no_cur_arrow  ; No.. do nothing.
        ADDI    #ROW_4+1,R1     ; Yes... erase it.
        MVO@    R5,     R1
        ADDI    #11,    R1
        MVO@    R5,     R1
        INCR    R1
        MVO@    R5,     R1

@@no_cur_arrow:
        TSTR    R0              ; Do we have a new arrow?
        BEQ     @@no_new_arrow  ; No... do nthing

        SLL     R0,     2       ; Yes... find its location on the screen,
        MOVR    R0,     R1      ; ... and store it so the ISR can do the
        SLL     R0,     2       ; ... right thing.
        ADDR    R0,     R1      ; R1 = ARROW * 20

        CLRR    R0
        MVO     R0,     ABLNK   ; Reset the blink timer. (non-interruptible)
        MVO     R1,     ARROW   ; Set the arrow pointer. (non-interruptible)

@@no_new_arrow:
        PULR    R1
        PULR    R0
        PULR    PC              ; Return.
        ENDP


;; ======================================================================== ;;
;;  MAINSCRN -- Displays the main memory-test screen.                       ;;
;; ======================================================================== ;;
MAINSCRN    PROC
        PSHR    R5

        MVII    #1,     R0
        CALL    WAIT


        ;                   1111111111
        ;         01234567890123456789
        ;       +----------------------+
        ;$200  0| > RAM Test: #_____ < |
        ;$214  1|                      |
        ;$228  2| BANK: #### A: LINEAR |
        ;$23C  3| Total Errors: #####  |  
        ;$250  4|                      |
        ;$264  5|   Fill Const  XXXX   |
        ;$278  6|   Walking 1s  XXXX   |
        ;$28C  7|   Walking 0s  XXXX   |
        ;$2A0  8|   CheckerBrd  XXXX   |
        ;$2B4  9|   Rand Value  XXXX   |
        ;$2C8 10|                      |
        ;$2DC 11| Elapsed: 00:00:00:00 |
        ;       +----------------------+

        CALL    PRINT.FLS    
        DECLE   C_BLU, ROW_B
        BYTE    "Elapsed:", 0

        CALL    PRINT.FLS  
        DECLE   C_GRN, ROW_0
        BYTE    "> RAM Test: #      <", 0

        SUBI    #7,     R4
        MVI     T_ITER, R0
        CLRR    R2
        MOVR    R1,     R3
        CALL    DEC16A          ; Display Iters per Test

        CALL    PRINT.FLS    
        DECLE   C_TAN, ROW_2
        BYTE    "BANK:      A: ", 0

        MVII    #RANDOM,R0
        MVI     APAT,   R2
        TSTR    R2
        BNEQ    @@random
        ADDI    #LINEAR-RANDOM, R0
@@random
        MVII    #C_YEL, R1
        CALL    PRINT.R    

        MVII    #ROW_2 + 6, R4  ; Row 2, Col 5
        MVII    #C_YEL, R1
        MVI     BANK,   R0
        SWAP    R0
        CALL    HEX16

        CALL    DISPERRS

        JSR     R5,     @@do_loop

        BYTE    "Fill Const", 0
        BYTE    "Walking 1s", 0
        BYTE    "Walking 0s", 0
        BYTE    "CheckerBrd", 0
        BYTE    "Rand Value", 0

@@do_loop:
        MVII    #5,     R2
        MVII    #C_WHT, R1      ; White
        MVII    #ROW_5 + 2, R4  ; Row 5, Col 2
@@loop:
        PSHR    R2
        MOVR    R5,     R0
        CALL    PRINT.R    
        CLRR    R2
        ADDI    #2,     R4
        MVO@    R2,     R4
        MVO@    R2,     R4
        MVO@    R2,     R4
        MVO@    R2,     R4
        ADDI    #4,     R4
        PULR    R2
        DECR    R2
        BNEQ    @@loop
        
        PULR    PC
        ENDP

RANDOM: BYTE    "RANDOM", 0
LINEAR: BYTE    "LINEAR", 0

;; ======================================================================== ;;
;;  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

;; ======================================================================== ;;
;;  FAULT  -- Do error report from one of the following tests.              ;;
;; ======================================================================== ;;
FAULT   PROC
        PSHR    R5
        INCR    R3              ; Incr the error count for this function.
        PSHR    R0
        PSHR    R1
        PSHR    R2
        PSHR    R3
        PSHR    R4

        MVI     CUR_S,  R0
        NEGR    R0
        MVO     R0,     CUR_S   ; Disable address display

        DECR    R4
        MOVR    R4,     R0
        MVII    #C_RED, R1
        MVI     ARROW,  R4
        ADDI    #ROW_4 + 14, R4 ; Get correct row for ERR.
        CALL    HEX16

        MVII    #C_RED + 8, R1
        MVO@    R1,     R4      ; Put a red ! after location.

        MVI     ERRS,   R0
        INCR    R0
        MVO     R0,     ERRS
        CALL    DISPERRS        ; Update the error display

        MVII    #EDLY,  R0
        CALL    WAIT            ; Hold this info for 1/2 second.

        MVI     CUR_S,  R0
        NEGR    R0
        MVO     R0,     CUR_S   ; Re-enable address display

        MVI     ERR0,   R0
        INCR    R0
        MVO     R0,     ERR0

        PULR    R4
        PULR    R3
        PULR    R2
        PULR    R1
        PULR    R0
        PULR    PC              ; Continue the test.
        ENDP

;; ======================================================================== ;;
;;  FINISH -- Do final status report from one of following tests.           ;;
;; ======================================================================== ;;
FINISH  PROC
        CLRR    R0
        MVO     R0,     CUR_S

        MVI     ARROW,  R4      ; Get current row
        ADDI    #ROW_4 + 14, R4 ; Display OK or ERR final status
        PULR    R5              ; Get return address.
        MVI     ERR0,   R3
        TSTR    R3
        BNEQ    MSG_ERR         ; Return through MSG_ERR
        B       MSG_OK          ; Return through MSG_OK
        ENDP


;; ======================================================================== ;;
;;  FILL_L -- Fill Memory Test, Linear. Fills with all 0/1, reads it back   ;;
;; ======================================================================== ;;
FILL_L  PROC
        PSHR    R5

        MVII    #1,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Pass Number"
        
        CLRR    R1
        MVII    #4,     R2
@@oloop:
        MVII    #4,     R0
        SUBR    R2,     R0
        INCR    R0

        MVO     R0,     CUR_L

        MVII    #RAMLO, R4
        MVII    #RAMSZ, R0

        SARC    R0,     1
        BNC     @@f_nobit0
        MVO@    R1,     R4      ; Store 0s or 1s

@@f_nobit0:
        BEQ     @@f_done
        SARC    R0,     1
        BNC     @@f_nobit1
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s

@@f_nobit1:
        BEQ     @@f_done
        SARC    R0,     1
        BNC     @@f_nobit2
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s

        B       @@f_nobit2

@@f_iloop8:     
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        NOP                     ; interruptible! (for STIC)
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s
        MVO@    R1,     R4      ; Store 0s or 1s

        DECR    R0
@@f_nobit2:
        BNEQ    @@f_iloop8

@@f_done:

@@r_oloop:
        MVII    #RAMLO, R4
        MVII    #RAMSZ, R0

        SARC    R0,     1
        BNC     @@r_nobit0
        CMP@    R4,     R1
        BEQ     @@r_ok0
        CALL    FAULT  
@@r_ok0 TSTR    R0
        BEQ     @@r_done

@@r_iloop2:     
        CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@r_ok1
        CALL    FAULT  

@@r_ok1 CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@r_ok2
        CALL    FAULT  

@@r_ok2 DECR    R0
@@r_nobit0:
        BNEQ    @@r_iloop2

@@r_done:

@@s_oloop:
        MVII    #BNKLO, R4
        MVII    #RAMSZ, R0

        SARC    R0,     1
        BNC     @@s_nobit0
        CMP@    R4,     R1
        BEQ     @@s_ok0
        CALL    FAULT  
@@s_ok0 TSTR    R0
        BEQ     @@s_done

@@s_iloop2:     
        CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@s_ok1
        CALL    FAULT  

@@s_ok1 CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@s_ok2
        CALL    FAULT  

@@s_ok2 DECR    R0
@@s_nobit0:
        BNEQ    @@s_iloop2

@@s_done:

        XORI    #MASK,  R1      ; Do it again with all 1's
        BNEQ    @@oloop

        DECR    R2              ; Repeat for 4 iterations.
        BNEQ    @@oloop

        B       FINISH
        ENDP

;; ======================================================================== ;;
;;  FILL_R -- Fill Memory Test, Random.  Fills with all 0/1, reads it back  ;;
;; ======================================================================== ;;
FILL_R  PROC
        PSHR    R5
        
        MVII    #1,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Pass Number"

        CLRR    R1
        MVII    #4,     R2
        MVII    #$10,   R0
        CALL    RAND
        ANDI    #RAMAM, R0
        MVO     R0,     SCRAM
        
@@oloop:

        MVII    #4,     R0
        SUBR    R2,     R0
        INCR    R0

        MVO     R0,     CUR_L

        MVII    #RAMLO, R4
        MVII    #RAMSZ, R0

@@f_iloop:      
        MOVR    R4,     R5
        XOR     SCRAM,  R4 
        MVO@    R1,     R4      ; Store 0s or 1s
        MOVR    R5,     R4
        INCR    R4
        DECR    R0
        BNEQ    @@f_iloop

@@f_done:

@@r_oloop:
        MVII    #RAMLO, R4
        MVII    #RAMSZ, R0

@@r_iloop2:     
        MOVR    R4,     R5
        XOR     SCRAM,  R4 
        CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@r_ok
        PSHR    R5
        CALL    FAULT  
        PULR    R5

@@r_ok: MOVR    R5,     R4
        INCR    R4
        DECR    R0
@@r_nobit0:
        BNEQ    @@r_iloop2

@@r_done:

@@s_oloop:
        MVII    #BNKLO, R4
        MVII    #RAMSZ, R0

@@s_iloop2:     
        MOVR    R4,     R5
        XOR     SCRAM,  R4 
        CMP@    R4,     R1      ; Read back 0s or 1s
        BEQ     @@s_ok
        PSHR    R5
        CALL    FAULT  
        PULR    R5

@@s_ok: MOVR    R5,     R4
        INCR    R4
        DECR    R0
@@s_nobit0:
        BNEQ    @@s_iloop2

@@s_done:

        XORI    #MASK,  R1      ; Do it again with all 1's
        BNEQ    @@oloop

        DECR    R2              ; Repeat for 4 iterations.
        BNEQ    @@oloop

        B       FINISH

        ENDP

;; ======================================================================== ;;
;;  WLK1_L -- Walking 1 Test, Linear.                                       ;;
;; ======================================================================== ;;
WLK1_L  PROC
        PSHR    R5              ; Save return address

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"
        
        MVII    #(MASK + 1) SHR 1, R1   ; Init R1 to leftmost 1 in mask

        MVO     R1,     TMP1    ; Save this initial 'walking 1'.

        ;; Fill memory with walking-1 pattern.
        MVII    #RAMLO, R4      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
@@f_loop:
        MVO     R4,     CUR_L
        MVO@    R1,     R4
        SLR     R1
        BNEQ    @@f_nz
        MVI     TMP1,   R1
@@f_nz:
        DECR    R0
        BNEQ    @@f_loop
        
        
        ;; Read back memory with walking-1 pattern.
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     TMP1,   R1
@@r_loop:
        MVO     R2,     CUR_L
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        SLR     R1              ; Walk the 1 to the right
        BNEQ    @@r_nz          ; Did the constant go to 0?
        MVI     TMP1,   R1      ; Yes:  Re-initialize it.
@@r_nz:
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH

        ENDP

;; ======================================================================== ;;
;;  WLK1_R -- Walking 1 Test, Random.                                       ;;
;; ======================================================================== ;;
WLK1_R  PROC

        PSHR    R5

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        MVII    #$10,   R0
        CALL    RAND
        ANDI    #RAMAM, R0
        MVO     R0,     SCRAM   ; Initialize our address "scrambler"
        
        MVII    #(MASK + 1) SHR 1, R1   ; Init R1 to leftmost 1 in mask

        MVO     R1,     TMP1    ; Save this initial 'walking 1'.

        ;; Fill memory with walking-1 pattern.
        MVII    #W_COL, R0
        MVO     R0,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     SCRAM,  R3
@@f_loop:
        XORR    R3,     R2
        MVO     R2,     CUR_L
        MVO@    R1,     R2
        XORR    R3,     R2
        SLR     R1
        BNEQ    @@f_nz
        MVI     TMP1,   R1
@@f_nz:
        INCR    R2
        DECR    R0
        BNEQ    @@f_loop
        
        
        ;; Read back memory with walking-1 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
@@r_loop:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        MVO     R2,     CUR_L
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        SLR     R1              ; Walk the 1 to the right
        BNEQ    @@r_nz          ; Did the constant go to 0?
        MVI     TMP1,   R1      ; Yes:  Re-initialize it.
@@r_nz:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH

        ENDP

;; ======================================================================== ;;
;;  WLK0_L -- Walking 0 Test, Linear.                                       ;;
;; ======================================================================== ;;
WLK0_L  PROC

        PSHR    R5              ; Save return address

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"
        
        MVII    #(MASK + 1) SHR 1, R1   ; Init R1 to leftmost 1 in mask

        MVO     R1,     TMP1    ; Save this initial 'walking 1'.

        ;; Fill memory with walking-1 pattern.
        MVII    #W_COL, R0
        MVO     R0,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R4      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
@@f_loop:
        MVO     R4,     CUR_L
        XORI    #MASK,  R1
        MVO@    R1,     R4
        XORI    #MASK,  R1
        SLR     R1
        BNEQ    @@f_nz
        MVI     TMP1,   R1
@@f_nz:
        DECR    R0
        BNEQ    @@f_loop
        
        
        ;; Read back memory with walking-1 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
@@r_loop:
        MVO     R2,     CUR_L
        XORI    #MASK,  R1
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        XORI    #MASK,  R1
        SLR     R1              ; Walk the 1 to the right
        BNEQ    @@r_nz          ; Did the constant go to 0?
        MVI     TMP1,   R1      ; Yes:  Re-initialize it.
@@r_nz:
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH
        ENDP

;; ======================================================================== ;;
;;  WLK0_R -- Walking 0 Test, Random.                                       ;;
;; ======================================================================== ;;
WLK0_R  PROC

        PSHR    R5

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        MVII    #$10,   R0
        CALL    RAND
        ANDI    #RAMAM, R0
        MVO     R0,     SCRAM   ; Initialize our address "scrambler"
        
        MVII    #(MASK + 1) SHR 1, R1   ; Init R1 to leftmost 1 in mask

        MVO     R1,     TMP1    ; Save this initial 'walking 1'.

        ;; Fill memory with walking-0 pattern.
        MVII    #W_COL, R0
        MVO     R0,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     SCRAM,  R3
@@f_loop:
        XORR    R3,     R2
        MVO     R2,     CUR_L
        XORI    #MASK,  R1
        MVO@    R1,     R2
        XORR    R3,     R2
        XORI    #MASK,  R1
        SLR     R1
        BNEQ    @@f_nz
        MVI     TMP1,   R1
@@f_nz:
        INCR    R2
        DECR    R0
        BNEQ    @@f_loop
        
        
        ;; Read back memory with walking-0 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     TMP1,   R1
@@r_loop:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        XORI    #MASK,  R1
        MVO     R2,     CUR_L
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        XORI    #MASK,  R1
        SLR     R1              ; Walk the 1 to the right
        BNEQ    @@r_nz          ; Did the constant go to 0?
        MVI     TMP1,   R1      ; Yes:  Re-initialize it.
@@r_nz:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH

        ENDP

CKPAT   PROC
        DECLE   $5555
        DECLE   $5A5A
        DECLE   $3333
        DECLE   $3C3C
        DECLE   $0F0F
        DECLE   $0FF0
        DECLE   $00FF
        DECLE   $FFFF
        DECLE   $0000
        ENDP

;; ======================================================================== ;;
;;  CHKR_L -- Checkerboard Pattern, Linear.                                 ;;
;; ======================================================================== ;;
CHKR_L  PROC
        PSHR    R5              ; Save return address

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        MVII    #CKPAT, R0
        MVO     R0,     TMP0
        
@@o_loop:

        ;; Get current checker pattern
        MVI     TMP0,   R4
        MVI@    R4,     R0
        ANDI    #MASK,  R0
        BEQ     @@done
        MOVR    R0,     R1
        XORI    #MASK,  R1
        MVO     R0,     TMP1
        MVO     R4,     TMP0

        ;; Fill memory with checker pattern.
        MVII    #W_COL, R2
        MVO     R2,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R2      ; Init outer loop counter.

@@f_loop:
        MVO     R3,     CUR_L
        MVO@    R0,     R3
        MVO@    R1,     R3
        MVO@    R0,     R3
        XORI    #MASK,  R0
        XORI    #MASK,  R1
        INCR    R3
        DECR    R2
        BNEQ    @@f_loop
        
        
        ;; Read back memory with checker pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     TMP1,   R1
@@r_loop:
        MVO     R2,     CUR_L
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        XORI    #MASK,  R1
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       @@o_loop
@@done: B       FINISH

        ENDP

;; ======================================================================== ;;
;;  CHKR_R -- Checkerboard Pattern, Random.                                 ;;
;; ======================================================================== ;;
CHKR_R  PROC

        PSHR    R5

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        MVII    #$10,   R0
        CALL    RAND
        ANDI    #RAMAM, R0
        MVO     R0,     SCRAM   ; Initialize our address "scrambler"
        
        MVII    #CKPAT, R0
        MVO     R0,     TMP0
        
@@o_loop:
        ;; Get current checker pattern
        MVI     TMP0,   R4
        MVI@    R4,     R0
        ANDI    #MASK,  R0
        BEQ     @@done
        MOVR    R0,     R1
        XORI    #MASK,  R1
        MVO     R0,     TMP1
        MVO     R4,     TMP0

        ;; Fill memory with checker pattern.
        MVII    #W_COL, R2
        MVO     R2,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R2      ; Init outer loop counter.
        MVI     SCRAM,  R4
@@f_loop:
        XORR    R4,     R3
        MVO     R3,     CUR_L
        MVO@    R0,     R3
        MVO@    R1,     R3
        MVO@    R0,     R3
        XORR    R4,     R3
        XORI    #MASK,  R0
        XORI    #MASK,  R1

        INCR    R3
        DECR    R2
        BNEQ    @@f_loop
        
        
        ;; Read back memory with walking-0 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R0      ; Init outer loop counter.
        MVI     TMP1,   R1
@@r_loop:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        MVO     R2,     CUR_L
        CMP@    R2,     R1      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R1      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        XORI    #MASK,  R1
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R0              ; Count down the loop.
        BNEQ    @@r_loop

        B       @@o_loop

@@done: B       FINISH

        ENDP

;; ======================================================================== ;;
;;  RAND_L -- Random Value, Linear.                                         ;;
;; ======================================================================== ;;
RAND_L  PROC

        PSHR    R5

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        ;; Save our current random state
        CALL    RANDSAVE

        ;; Fill memory with random numbers.    
        MVII    #W_COL, R0
        MVO     R0,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #RAMSZ, R1      ; Init outer loop counter.
@@f_loop:
        MVO     R2,     CUR_L
        MVII    #RAMW,  R0
        CALL    RAND
        MVO@    R0,     R2
        INCR    R2
        DECR    R1
        BNEQ    @@f_loop

        ;; Restore our current random state
        CALL    RANDRSTR
        
        ;; Read back memory with walking-1 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R1      ; Init outer loop counter.
@@r_loop:
        MVO     R2,     CUR_L
        MVII    #RAMW,  R0
        CALL    RAND
        CMP@    R2,     R0      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R0      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R1              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH

        ENDP

;; ======================================================================== ;;
;;  RAND_R -- Random Value, Random.                                         ;;
;; ======================================================================== ;;
RAND_R  PROC

        PSHR    R5

        MVII    #2,     R0
        MVO     R0,     CUR_S   ; Set our status to "Show Address"

        MVII    #$10,   R0
        CALL    RAND
        ANDI    #RAMAM, R0
        MVO     R0,     SCRAM   ; Initialize our address "scrambler"
        
        ;; Save our current random state
        CALL    RANDSAVE

        ;; Fill memory with random numbers.    
        MVII    #W_COL, R0
        MVO     R0,     RW_COL  ; Make status "write" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #RAMSZ, R1      ; Init outer loop counter.
        MVI     SCRAM,  R3
@@f_loop:
        XORR    R3,     R2
        MVO     R2,     CUR_L
        MVII    #RAMW,  R0
        CALL    RAND
        MVO@    R0,     R2
        XORR    R3,     R2
        INCR    R2
        DECR    R1
        BNEQ    @@f_loop
        

        ;; Restore our current random state
        CALL    RANDRSTR
        
        ;; Read back memory with walking-1 pattern.
        MVII    #R_COL, R0
        MVO     R0,     RW_COL  ; Make status "read" colored
        MVII    #RAMLO, R2      ; Init pointer to start of RAM
        MVII    #BNKLO, R3      ; Init pointer to start of RAM
        MVII    #RAMSZ, R1      ; Init outer loop counter.
@@r_loop:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        MVO     R2,     CUR_L
        MVII    #RAMW,  R0
        CALL    RAND
        CMP@    R2,     R0      ; Read from primary address
        BNEQ    @@r_fault       ; Fault if value differs
        CMP@    R3,     R0      ; Read from "shadowed" address
        BEQ     @@r_ok          ; Fault if value differs
        MOVR    R3,     R4      ; Report fault address from "Shadow addr"
        INCR    PC              ; (skip next MOVR)
@@r_fault:
        MOVR    R2,     R4      ; Report fault address from "primary addr"
        INCR    R4
        CALL    FAULT
@@r_ok:
        XOR     SCRAM,  R2
        XOR     SCRAM,  R3
        INCR    R2              ; Move our pointers forward
        INCR    R3              ; Move our pointers forward
        DECR    R1              ; Count down the loop.
        BNEQ    @@r_loop

        B       FINISH
        ENDP

;; ======================================================================== ;;
;;  ISRSPIN                                                                 ;;
;;      Sets ISR to the value in R5, and spins waiting for interrupts.      ;;
;;      Note:  Call this with interrupts disabled! (eg. JSRD)               ;;
;;                                                                          ;;
;;  INPUTS:                                                                 ;;
;;      R5 -- ISR function address                                          ;;
;;                                                                          ;;
;;  OUTPUTS:                                                                ;;
;;      ISR vector set to value in R5.                                      ;;
;;      Does not return.                                                    ;;
;; ======================================================================== ;;
ISRSPIN PROC
        MVII    #$2F0,  R6
        MOVR    R5,     R0
        MVO     R0,     $100
        SWAP    R0
        MVO     R0,     $101

        EIS
@@spinloop:
        DECR    PC
        ENDP


; ------------------------------------------------------------------------- ;
;  Library Includes.                                                        ;
; ------------------------------------------------------------------------- ;
        INCLUDE "../library/ic_banksw.asm"
        INCLUDE "../library/rand.asm"
        INCLUDE "../library/dec16only.asm"
        INCLUDE "../library/print.asm"
        INCLUDE "../library/fillmem.asm"
        INCLUDE "../library/hex16.asm"
