P*-----------------------------------------------------
*          C-128  RAM TEST   by Glen Bredon
*-----------------------------------------------------
*
* This uses both the hires screen and 80 column screen
* to test ram in both 64k banks between $2000 & $FF00.
* It can be used in 40 or 80 column mode, but you will
* see the entire display only if you have two monitors
* attached: one for 40 and one for 80.
*
* Ram is tested by filling with certain bytes, moving
* this to the hires screen (where you can see what is
* happening) then testing that it is still filled with
* that byte.  When an error occurs, the bank and address
* of the error is displayed on the 80 column screen.
* Only the first 200 errors are shown.
*
* Ram is tested at both 1 and 2 mhz speed and this mode
* is shown on the 80 column screen.  During the fast
* cycles you see only a white screen on the hires screen.
*
* When in FAST mode a test is made of the integrity of
* high speed cross bank (maybe) transfers by moving to
* and from the hires screen and checking the result.
* A failure of the move to the hires screen is shown
* by a "<" on the address, and, for a move from the
* hires screen, by a ">".  In the latter case the byte
* being tested is actually the compliment of the one
* shown on the screen!
*
* This program never ends - you have to reset to exit.
*-----------------------------------------------------

          EXP OFF
          TR

* Our zp usage:

BANK      = $63           ;Bank (EOR #1) being tested
BYTE      = $64           ;Byte used for test
SPEEDZ    = $65           ;Speed of test
ERRNUM    = $66           ;Current # of found error
CHAR      = $67           ;Flag for high speed trans test
MODE      = $68           ;Flags random mode
PNTL      = $FA           ;Pointer to memory tested
PNTH      = PNTL+1
BASL      = $FC           ;Pointer to hires screen (etc)
BASH      = BASL+1
PAGE      = $FE           ;First page on rng being tested

* CBM stuff:

ARG       = $6A           ;Floating point acc2 & rnd seed
SEED      = $8B           ; used by included rnd # genr
GRAPHM    = $D8           ;C128 text/graphics flag

WRMVEC    = $302          ;Run/restore return address

BORDER    = $D020
SPEED     = $D030

PRIMM     = $FF7D
CHROUT    = $FFD2
PLOT      = $FFF0

* Our configuration setup:

RAM1      = $FF02
RAM0      = $FF03
RAMHALF   = $FF04         ;Used for accessing kernel

ADD       MAC             ;Used in RND routine
          LDA ARG+]1
          ADC SEED+]1
          STA ARG+]1
          <<<

ROT       MAC             ;Used in RND routine
          LDA SEED+]1
          ROL
          STA ARG+]1
          <<<

          AST 50

          ORG $1300

          ERR START&$FF   ;Demand page boundary

START     CLD             ;Just in case
          CLI
          LDA #START      ;=0
          STA $FF00
          STA WRMVEC
          STA ERRNUM      ;Init 0 errors
          STA PASNUM
          STA PASNUM+1
          LDA #>START     ;Set up STOP-RESTORE reentry
          STA WRMVEC+1
          LDA #%110       ;Set common to $2000 on bottom
          STA $D506
          LDA #%01111111
          STA $D502       ;Emulate Merlin's setup so
          LSR             ; that this can be "BOOTed"
          STA $D503       ; as well as run from Merlin
          LDA #%00001110
          STA $D504
          STA RAM1
          STA $FFF5       ;Enable reboot
          STA RAMHALF
          LDA #142        ;Set uc/gr char set
          JSR CHROUT
          LDA #$93        ;Clear text screen
          JSR CHROUT
          LDX #$20        ;Set bit map mode (B/W)
          STX GRAPHM      ;Editor automatically switches
          LDA $D011
          ORA #$10
          STA $D011       ; but it doesn't do this
          LDX #$1C
          STX BASH
          LDX #4
          LDY #0
          STY BASL        ;Init BASL=0 always
          LDA #$F0
:RCL      STA (BASL),Y    ;Set up color matrix 1
          INY
          BNE :RCL
          INC BASH
          DEX
          BNE :RCL
          STX PNTL        ;Init PNTL=0 always
          STX BORDER      ;Set black border

*-------------------------------
* Main program loop (forever):
*-------------------------------

LOOP      SED
          LDA PASNUM      ;Count passes in BCD
          CLC
          ADC #1
          STA PASNUM
          LDA PASNUM+1
          ADC #0
          STA PASNUM+1
          CLD
          LDA #%00000000
          STA MODE        ;Clear RND mode
          JSR TEST
          LDA #%10101010
          JSR TEST
          LDA #%01010101
          JSR TEST
          LDA #%00110011
          JSR TEST
          LDA #%11001100
          JSR TEST
          LDA #%10011001
          JSR TEST
          LDA #%01100110
          JSR TEST
          LDA #%11110000
          JSR TEST
          LDA #%00001111
          JSR TEST
          LDA #%11111111
          JSR TEST
          SEC
          ROR MODE        ;Set RND mode
          JSR TEST        ;Do the RND test
          JMP LOOP        ;Loop forever!

*----------------------------------------------------
* Routine to test all tested memory with byte in ACC.
*----------------------------------------------------

TEST      STA BYTE        ;Byte to write to memory
          LDA #1
          STA SPEEDZ      ;Init slow/fast flag to fast
:NS       STA RAMHALF
          BIT MODE
          BPL :LS         ;Branch if not random mode
          JSR PRIMM
          DFB 19          ;Home
          TXT 'filling memory with random data.'
          DFB 27,'q',0    ;Clear to end of line
          LDA #1          ;Fill at top speed even in
          STA SPEED       ; slow mode
          LDX #3
]LUP      LDA SEED+1,X    ;Save seed so we can go through
          STA SEEDSV,X    ; same sequence during test
          DEX
          BPL ]LUP
          STA RAM0        ;Put random data through all
          LDA #$20        ; memory before testing
          STA PNTH
          LDX #>$FF00-$2000
          LDY #0
]LUP      JSR RND
          STA (PNTL),Y
          INY
          BNE ]LUP
          INC PNTH
          DEX
          BNE ]LUP
          STA RAM1        ;Fill ram 1 also
          LDA #$20
          STA PNTH
          LDX #>$FF00-$2000
]LUP      JSR RND
          STA (PNTL),Y
          INY
          BNE ]LUP
          INC PNTH
          DEX
          BNE ]LUP
          LDX #3          ;Retrieve seed for testing
]LUP      LDA SEEDSV,X
          STA SEED+1,X
          DEX
          BPL ]LUP
          STA RAMHALF
:LS       LDA SPEEDZ
          STA SPEED       ;Set slow/fast mode
          LDA #1
          STA BANK        ;Init bank (1=bank 0)
:NB       LDA #>$2000     ;Start at page $20
:JT       STA PAGE
          JSR TESTRNG     ;Test $20 pages with curr byte
          LDA PAGE        ;Next page
          CLC
          ADC #$20
          BNE :JT         ;Ignore $E000-$FFFF
          DEC BANK
          BEQ :NB         ;Do bank0 = RAM 1
          DEC SPEEDZ
          BNE :RET
          JMP :NS         ;Redo in slow mode
:RET      RTS             ;Back for next go through

*----------------------------------------------------
* Routine to test $20 pages starting at PAGE in bank
* held in BANK (note BANK=0 is really RAM 1).
*----------------------------------------------------

TESTRNG   STA RAMHALF     ;Set for calling kernel
          LDA #19         ;Home
          JSR CHROUT
          LDA BANK
          EOR #'1'
          JSR CHROUT      ;Show current bank
          LDA PAGE
          STA PNTH        ;Set up pointer for test range
          LDX #0          ;On a page boundary
          JSR PRNTAX      ;Print start address
          LDA #'-'
          JSR CHROUT
          LDA BANK
          EOR #'1'
          JSR CHROUT
          LDA PAGE
          EOR #$E0        ;Clear carry iff doing $E0--
          CMP #1
          EOR #$E0
          ADC #>$1EFF
          LDX #<$FFFF
          JSR PRNTAX      ;Print end address
          LDA #' '
          STA CHAR
          JSR PRIMM
          TXT '  testing byte: '00
          BIT MODE
          BPL :NOTRND
          JSR PRIMM
          TXT ' random '00
          JMP :LSP
:NOTRND   LDX #8
          LDY BYTE        ;Print binary form of byte
:SHWBYTE  TYA             ; being tested
          ASL             ;Shift bit into carry
          TAY             ;Save rest for next iteration
          LDA #'0'
          ADC #0          ;Convert bit (carry) into ascii
          JSR CHROUT      ; and print it
          DEX
          BNE :SHWBYTE    ;Next bit
:LSP      LDA SPEEDZ      ;Show speed mode
          BNE :FAST
          JSR PRIMM
          TXT '  slow'00
          JMP :OV
:FAST     JSR PRIMM
          TXT '  fast'00
:OV       JSR PRIMM
          TXT ' mode.  pass #'00
          LDA PASNUM+1
          LDX PASNUM
          JSR PRNTAX
          LDX BANK
          STA RAM1,X      ;Turn on current ram bank
          JSR NUMPAGS     ;Page count
          LDY #0
          LDA BYTE
          BIT MODE
          BPL :NORND
          JMP :RNDTEST
:NORND    STA (PNTL),Y    ;Fill memory range with byte
          CMP (PNTL),Y    ;Immediate fast test
          BEQ :1
          JSR :ERR
:1        INY
          BNE :NORND
          INC PNTH
          DEX
          BNE :NORND
          LDA PAGE        ;Reset pointer to range
          STA PNTH
          LDA #>$2000     ;Point BASL,H to gr screen
          STA BASH
          LDX BANK
]LUP      STA RAM1,X
          LDA (PNTL),Y    ;Get byte from memory
          STA RAM0
          STA (BASL),Y    ;Show it on screen
          INY
          BNE ]LUP
          INC PNTH
          INC BASH
          LDA PNTH
          CMP #$FF
          BEQ :SKIP
          LDA BASH
          CMP #$40
          BLT ]LUP
:SKIP     LDA PAGE
          STA PNTH        ;Reset range pointer
          LDX BANK
          STA RAM1,X      ;Turn on current bank
          JSR NUMPAGS     ;Count for $20 pages
          LDA BYTE
]LUP      CMP (PNTL),Y    ;Is it still there?
          BEQ :2
          JSR :ERR
:2        INY             ;Yes - continue testing
          BNE ]LUP
          INC PNTH
          DEX
          BNE ]LUP
          LDA SPEEDZ
          BEQ :RET
          STA RAM0
          LDX #$20        ;Check cross bank transfer
          STX BASH        ; integrity for FAST
          JSR NUMPAGS
          LDA #'<'
          STA CHAR
]LUP      LDA BYTE
          CMP (BASL),Y
          BEQ :3
          JSR :ERR
:3        EOR #$FF        ;Reverse all bits for other
          STA (BASL),Y    ; direction test
          INY
          BNE ]LUP
          INC BASH
          INC PNTH
          DEX
          BNE ]LUP
          LDA #'>'
          STA CHAR        ;Indicate direction
          LDA PAGE
          STA PNTH
          LDX #$20
          STX BASH
          LDX BANK
]LUP      STA RAM0        ;High speed test other directn
          LDA (BASL),Y    ;Note that we are testing the
          STA RAM1,X      ; compliment of the byte shown
          STA (PNTL),Y
          INY
          BNE ]LUP
          INC BASH
          INC PNTH
          LDA PNTH
          CMP #$FF
          BEQ :JNP
          LDA BASH
          CMP #$40
          BLT ]LUP
:JNP      JSR NUMPAGS
          LDA PAGE
          STA PNTH
          LDA BYTE
          EOR #$FF        ;Now test if the high speed
]LUP      CMP (PNTL),Y    ; transfer worked correctly
          BEQ :4
          JSR :ERR
:4        INY
          BNE ]LUP
          INC PNTH
          DEX
          BNE ]LUP
:RET      RTS

:ERR      PHA
          TXA
          PHA
          TYA
          PHA
          LDA $FF00       ;Save memory status
          PHA
          STA RAMHALF
          LDA #7
          JSR CHROUT      ;Ring bell on each error
          LDX ERRNUM
          BNE :SKP
          JSR PRIMM
          HEX 0D0D
          TXT 'errors:'00
:SKP      CPX #20*10
          BGE :BACK       ;Ignore after screen fills up
          TYA             ;Save adrs low of error
          PHA
          INC ERRNUM
          TXA             ;= old ERRNUM
          LDX #3          ;Start at row 4
]LUP      SEC
          SBC #80/8
          INX
          BCS ]LUP
          ADC #80/8
          ASL             ;*8
          ASL
          ASL
          TAY             ;Column
          CLC             ;Set cursor position
          JSR PLOT
          LDA BANK
          EOR #'1'
          JSR CHROUT      ;Show bank of error
          PLA             ; and address
          TAX
          LDA PNTH
          JSR PRNTAX
          LDA CHAR        ;Print space or show dir of the
          JSR CHROUT      ; high speed transfer failure
:BACK     PLA
          STA $FF00       ;Replace memory status
          PLA             ; and registers
          TAY
          PLA
          TAX
          PLA
          RTS

:RNDTEST  LDA #'*'        ;Use asterisk to mark errors
          STA CHAR        ; from rnd test
          LDY #0
          JSR NUMPAGS
]LUP      JSR RND
          CMP (PNTL),Y
          BEQ :5
          JSR :ERR
:5        INY
          BNE ]LUP
          INC PNTH
          DEX
          BNE ]LUP
          RTS

NUMPAGS   LDA #$DF        ;Routine to load X with $20
          CMP PAGE        ; unless PAGE=$E0, in which
          LDA #$1F        ; case X gets $1F, to avoid
          ADC #0          ; writing to $FF--
          TAX
          RTS

PRNTAX    JSR PRBYTE      ;Print byte in A
          TXA             ; then in X
PRBYTE    PHA             ;Save to do low nibble
          LSR             ;Isolate high nibble
          LSR
          LSR
          LSR
          JSR PRNIB       ;Print high nibble
          PLA             ;Recall byte
          AND #$F         ;Isolate low nibble
PRNIB     ORA #'0'        ;Convert nibble to ascii
          CMP #'9'+1
          BLT :DEC
          ADC #'a'-'9'-2
:DEC      JMP CHROUT      ;Show nibble & return

*-----------------------------------------
* A good and fast random # generator.
* The BASIC RND does not deserve the name.
* Rnd # held in SEED (32 bits), ARG used
* for scratch pad.  Preserves X, Y
* Returns msb in A.
*-----------------------------------------

RND       LDA SEED+4
          ASL
          STA ARG+4
          ROT 3
          ROT 2
          ROT 1
          SEC
          ROL ARG+4
          ROL ARG+3
          ROL ARG+2
          ROL ARG+1
          CLC
          ADD 4
          PHA
          ADD 3
          PHA
          ADD 2
          ADD 1
          CLC
          LDA ARG+2
          ADC SEED+4
          STA SEED+2
          LDA ARG+1
          ADC SEED+3
          STA SEED+1
          PLA
          STA SEED+3
          PLA
          STA SEED+4
          LDA SEED+1      ;Most signif byte
          RTS

SEEDSV    DS 4
PASNUM    DA 0

          ERR ^$1C00
