;*******************************************************************************
; NO RAM RAM TESTER - Version 0.1
;*******************************************************************************
; Date:          Location:                         Author:
;  2020-10-04     Drummondville, Québec, Canada     denis.bisson@denisbisson.org
;*******************************************************************************
; Purpose:
;  Testing the RAM MEMORY of a COCO 2 assuming it might not be usable.
;
;  In other words, this code will test the RAM, report errors but all this
;  without actually using any bit of the RAM memory for its execution.
;  Program boots from the ROM and run using exclusively the CPU registers.
;
;  It does not assume it can rely on any RAM memory location so there is no
;  stack used in this. So there no single subroutine calls with "BSR", "JSR",
;  etc. Obviously, there are no variables neither. So far all this, don't
;  expect nice and cute graphics! Also, don't be surprise to see a lot
;
;  Program is made to be assembled and store to EPROM that we will install
;  in place of the "COLOR BASIC" ROM and mapped at address 0xA000.
;
;  It will send diagnostic information via RS-232 serial port of the COCO at
;  the ludicrous speed of 600 bps to respect the initial spirit of the COCO.
;
;  It first do a sequence of "SMART TEST" where it will test patterns at
;  specific addresses. These smart tests consist of using data where only one
;  bit is at 1 or only one bit is at 0. Then, it test them at pertinent
;  addresses to quickly report to use an overview of if the RAM is working
;  good or not.
;
;  After, a "FULL TEST" is done and we will cycle in this. These tests
;  consits in writing a repetitive patterns of 353 bytes though all the
;  memory and re-read each memory location to validate content is correct.
;  One the test is complete, it will restart again but with an offset of 1
;  from previously in the 353 bytes source. We repeat that in cycle so it
;  can be considered a kind of burn in test.
;
;  For both of these tests, we're not writing a byte and then re-read it
;  immediately after. No. We are doing all our writing in the destination
;  area and then we reread them back after and validate the data read back.
;  This amplifies a lot the possible problem and error detection of a writing
;  corrupting previously written data.
;
;  Finally, here is an exemple of report the application may report. In the
;  following example, the DRAM wired on the bit d2 has been removed from the
;  board showing the application may run anyway and diagnostic the problem
;  with bit d2.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;=============
;RAM TEST v0.2
;=============
;
;Smart test begins...
;A:0008 W:80 R:02 B:X-----X-
;Smart test completed.
;
;Full test begins.
;Full test begins.
;Full test begins.
;Full test begins.
;A:00ED W:37 R:B5 B:X-----X-
;Full test begins.
;Full test begins.
;Full test begins.
;

;*******************************************************************************
; Notes:
;  This is a tool. This is not a magic thing that will transform a neophyte
;  into an electronic master. So it's to help a knowledgeable technician to
;  identify a defective RAM from a board that would not start at all other
;  way by itself if one bit of memory is defective. It hopes to avoid
;  technician to "guess" which RAM is defective by providing a close to sure
;  way to determine what is defective.
;
;  And if the application finds no problem with RAM, we know we have to search
;  somewhere else.
;*******************************************************************************
; Logs:
;  2020-09-30 -Version 0.1
;             -First release.
;             -Tested with COCO 2 with 64 KB.
;             -Tested with COCO 2 with 16 KB.
;
;  2020-10-01 -Version 0.2
;             -Intensive usage of MACRO to make source code shorter.
;
;  2020-10-03 -Version 0.3
;             -Define for compilation by memory size.
;
;  2020-10-04 -Version 0.4
;             -Check jumpers for memory size and initialize SAM chip accordingly.
;*******************************************************************************



;-------------------------------------------------------------------------------
; Section with DEFINE
;-------------------------------------------------------------------------------

;Type of compilation
ASSEMBLE_FOR_ROM    EQU                 1                   ;Set to 1 to assemble for ROM file mapped at 0xA000

RAMSIZE8K           EQU                 0                   ;Set to 1 if we want to test for 8K (Useful to test with program in RAM on a 16K machine)
RAMSIZE16K          EQU                 0                   ;Set to 1 if we want to test for 16K
RAMSIZE24K          EQU                 0                   ;Set to 1 if we want to test for 24K (Useful to test with program in RAM on a 64K machine)
RAMSIZE32K          EQU                 1                   ;Set to 1 if we want to test for 32K

INTENTIONAL_ERROR   EQU                 0                   ;Set to 1 to intentionnaly generate error in RAM test. Used for debug and tune functions.

                    IF RAMSIZE8K
MEMTESTSIZE         EQU                 (8*1024)           ;Size of memory to test
                    ENDIF
                    IF RAMSIZE16K
MEMTESTSIZE         EQU                 (16*1024)           ;Size of memory to test
                    ENDIF
                    IF RAMSIZE24K
MEMTESTSIZE         EQU                 (24*1024)           ;Size of memory to test
                    ENDIF
                    IF RAMSIZE32K
MEMTESTSIZE         EQU                 (32*1024)           ;Size of memory to test
                    ENDIF

;Memory mapped stuff
DA                  EQU                 $FF20               ;Bit 1 of this power is the output for RS-232 serial port
PIA1                EQU                 $FF20               ;Peripheral Input Adapter #1
SAMREG              EQU                 $FFC0               ;Sam Control Register
RAMSTART            EQU                 $0000               ;RAM memory starts at 0 on the COCO.
ENDSMARTTABLEMARKER EQU                 $FFFF               ;Use in the SMART test to indicate end of address list.

;RS-232 serial port
XDELAYFOR1STARTBIT  EQU                 207                 ;Constants use in RS-232 delay loop
XDELAYFOR1DATABIT   EQU                 210
XDELAYFOR1STOPBIT   EQU                 207
CHAR_Space          EQU                 $20                 ;Constants for special characters in serial communication
CHAR_CarriageReturn EQU                 $0D
CHAR_Terminaison    EQU                 $00                 ;To indicate the end of a string
CHAR_A              EQU                 'A'
CHAR_B              EQU                 'B'
CHAR_C              EQU                 'C'
CHAR_D              EQU                 'D'
CHAR_E              EQU                 'E'
CHAR_I              EQU                 'I'
CHAR_P              EQU                 'P'
CHAR_R              EQU                 'R'
CHAR_S              EQU                 'S'
CHAR_T              EQU                 'T'
CHAR_W              EQU                 'W'
CHAR_X              EQU                 'X'
CHAR_COLON          EQU                 ':'

;Constant related with actual RAM test
MaskBit0            EQU                 #$01                ;Constants use in bit test for RS-232 send macro
MaskBit1            EQU                 #$02
MaskBit2            EQU                 #$04
MaskBit3            EQU                 #$08
MaskBit4            EQU                 #$10
MaskBit5            EQU                 #$20
MaskBit6            EQU                 #$40
MaskBit7            EQU                 #$80

SmartData01         EQU                 #$01                ;Constants use in SMART test
SmartData02         EQU                 #$02
SmartData04         EQU                 #$04
SmartData08         EQU                 #$08
SmartData10         EQU                 #$10
SmartData20         EQU                 #$20
SmartData40         EQU                 #$40
SmartData80         EQU                 #$80
SmartDataFE         EQU                 #$FE
SmartDataFD         EQU                 #$FD
SmartDataFB         EQU                 #$FB
SmartDataF7         EQU                 #$F7
SmartDataEF         EQU                 #$EF
SmartDataDF         EQU                 #$DF
SmartDataBF         EQU                 #$BF
SmartData7F         EQU                 #$7F


;-------------------------------------------------------------------------------
; Section with MACRO definitions (Macro names always start with "MAC_")
;-------------------------------------------------------------------------------

;Macros related with RS-232 serial port

;Macro to wait the amount of loop using the parameter
;We loose "B" and keep all the others.
MAC_DelayB          macro
                    ldb                 #\1
4                   nop
                    decb
                    bne                 4B
                    endm

;Macro to set SPACE (0) in RS-232 serial port
;We loose "B" and keep all the others.
MAC_SetSpace        macro
                    ldb                 #$00
                    stb                 DA
                    endm

;Macro to set MARK (1) in RS-232 serial port
;We loose "B" and keep all the others.
MAC_SetMark         macro
                    ldb                 #$02
                    stb                 DA
                    endm

;Macro to send a start bit. Clear the line and wait the time of 1 bit.
;We loose "B" and keep all the others.
MAC_SendStartBit    macro
                    MAC_SetSpace
                    MAC_DelayB          XDELAYFOR1STARTBIT
                    endm

;Macro to send a stop bit. Set the line and wait the time of 1 bit.
;We loose "B" and keep all the others.
MAC_SendStopBit     macro
                    MAC_SetMark
                    MAC_DelayB          XDELAYFOR1STOPBIT
                    endm

;Macro to send the bit to isolate using the mask in parameter.
;We assumed here "B" is holding the byte to send.
;We loose "B" and keep all the others.
MAC_SendBit         macro
                    andb                #\1
                    beq                 1F
                    MAC_SetMark
                    bra                 2F
1                   MAC_SetSpace
2                   MAC_DelayB          XDELAYFOR1DATABIT
                    endm

;Macro that is the actual hardware related routine to send the the byte holds in DP.
;By "actual hardware" we mean the function that send the start bit, the 8 data bits and the stop bits.
;We assumed here "B" is holding the byte to send.
;We loose "B" and keep all the others.
MAC_SendByte        macro
                    MAC_SendStartBit
                    tfr                 dp,b
                    MAC_SendBit         MaskBit0
                    tfr                 dp,b
                    MAC_SendBit         MaskBit1
                    tfr                 dp,b
                    MAC_SendBit         MaskBit2
                    tfr                 dp,b
                    MAC_SendBit         MaskBit3
                    tfr                 dp,b
                    MAC_SendBit         MaskBit4
                    tfr                 dp,b
                    MAC_SendBit         MaskBit5
                    tfr                 dp,b
                    MAC_SendBit         MaskBit6
                    tfr                 dp,b
                    MAC_SendBit         MaskBit7
                    MAC_SendStopBit
                    endm

;Macro to send the content of B via serial port.
;We loose DP, B and U and keep all the others.
MAC_SendByteB       macro
                    tfr                 b,dp
                    leau                ((1F-*)-3),pc
                    jmp                 SendByte
1
                    endm

;Macro to send the content of "B" via RS-232 serial port.
;We assumed here "B" is holding the byte to send.
;We loose DP, B and U and keep all the others.
MAC_SendThisChar    macro
                    ldb                 #\1
                    MAC_SendByteB
                    endm

;Macro to send the 'ADDR:'
;We loose DP, B and U and keep all the others.
MAC_SendStrAddr     macro
                    MAC_SendThisChar    CHAR_A
                    MAC_SendThisChar    CHAR_COLON
                    endm

;Macro to send the 'EXPECT:'
;We loose DP, B and U and keep all the others.
MAC_SendStrExpect   macro
                    MAC_SendThisChar    CHAR_W
                    MAC_SendThisChar    CHAR_COLON
                    endm

;Macro to send the 'READ:'
;We loose DP, B and U and keep all the others.
MAC_SendStrRead     macro
                    MAC_SendThisChar    CHAR_R
                    MAC_SendThisChar    CHAR_COLON
                    endm

;Macro to send the 'BITS:'
;We loose DP, B and U and keep all the others.
MAC_SendStrBits     macro
                    MAC_SendThisChar    CHAR_B
                    MAC_SendThisChar    CHAR_COLON
                    endm

;Macro to send the two spaces
;We loose DP, B and U and keep all the others.
MAC_SendTwoSpaces   macro
                    MAC_SendThisChar    CHAR_Space
                    endm

;Macro that will send the character ASCII value of the low nibble of the content of "B".
;So if B is holding 0xB7, it will send "0x37" since "0x37" is the ASCII code of "7".
;So if B is holding 0x3A, it will send "0x41" since "0x41" is the ASCII code of "A".
;We loose DP, B and U and keep all the others.
MAC_SendLowNibbleB   macro
                    andb                #$0F
                    addb                #$30
                    cmpb                #$39
                    bls                 1F
                    addb                #$07
1                   tfr                 b,dp
                    MAC_SendByte
                    endm

;Macro to send the two ASCII characters to represent
;the hex value of the content of "A".
;We loose DP, B and U and keep all the others.
MAC_SendHexByteA    macro
                    leau                ((1F-*)-3),pc
                    jmp                 SendHexByte
1
                    endm

;Macro to send the four ASCII character to represent the hex value of the content of "D".
;We loose DP, A, B X and U and keep all the others.
MAC_SendHexWordD    macro
                    MAC_SendHexByteA
                    tfr                 x,d
                    tfr                 b,a
                    MAC_SendHexByteA
                    endm

;Macro to send the null-terminated string pointed by "X" which receive its value via the single parameter.
;We loose DP, B, X and U and keep all the others.
MAC_SendThisString  macro
                    ldx                 #\1
                    leau                ((1F-*)-3),pc
                    jmp                 SendString
1
                    endm

;Macro used in sending the bit result of comparaison between the expected and actual values.
;Will send a "-" for matching bit and "X" for changing bit.
;We loose DP, B, A and U and keep all the others.
MAC_SendBitCompareA macro
                    ldb                 #'-'
                    lsla
                    bcc                 1F
                    ldb                 #'X'
1                   MAC_SendByteB
                    endm

;Macro used during the write portion of the SMART test.
;We loose B, X is increment by 1 and keep all the others.
MAC_SmartWrite      macro
                    ldb                 #\1
                    stb                 ,x+
                    endm

;Macro used during the read portion of the SMART test.
;We loose... We loose a lot! Let's we lose everything and "X" is increment by 1!
MAC_SmartCompare    macro
                    lda                 ,x+
                    cmpa                #\1
                    lbeq                2F

;If we keep going here, it's because we have a mismatch!!!
                    tfr                 d,y                 ;Let's preserve "A" which represent what we read from DRAM so we don't reread it.

                    MAC_SendStrAddr                         ;Column #1 = The address of the error, let's show it.
                    tfr                 x,d
                    MAC_SendHexWordD
                    MAC_SendTwoSpaces

                    MAC_SendStrExpect
                    lda                 #\1                 ;Recuperate what we initially wrote.
                    MAC_SendHexByteA                        ;Column #2 = The byte we initially wrote and that was expected.
                    MAC_SendTwoSpaces

                    MAC_SendStrRead
                    tfr                 y,d                 ;Recuperate was read back.
                    MAC_SendHexByteA                        ;Column #3 = The byte we read back from DRAM.
                    MAC_SendTwoSpaces

                    MAC_SendStrBits
                    tfr                 y,d
                    eora                #\1                 ;In "A", the matching bit now have "0" and the mismatch are "1"
                    MAC_SendBitCompareA                     ;Send bit 7
                    MAC_SendBitCompareA                     ;Send bit 6
                    MAC_SendBitCompareA                     ;Send bit 5
                    MAC_SendBitCompareA                     ;Send bit 4
                    MAC_SendBitCompareA                     ;Send bit 3
                    MAC_SendBitCompareA                     ;Send bit 2
                    MAC_SendBitCompareA                     ;Send bit 1
                    MAC_SendBitCompareA                     ;Send bit 0

                    MAC_SendThisChar    CHAR_CarriageReturn

;Back in normal flow, either from a match or a mismatch
2
                    endm


;-------------------------------------------------------------------------------
; Section with actual code, where it starts!
; (Finally! After all these defines and macros!)
;-------------------------------------------------------------------------------

                    IF ASSEMBLE_FOR_ROM
                    org                 $A000
                    ELSIF RAMSIZE24K
                    org                 $6000
                    ELSE
                    org                 $2000
                    ENDIF

ResetVector         orcc                #$50                ;Make sure interrupt are disabled.

;When booting from ROM, we need to do some basic initialization of the PIA to read the jumpers.
;To save time, let's use the same initialization the COCO does normally.
;Following has been copied from "Color Basic Unravelled II" (REVISED:12/26/99 WALTER K ZYDHEK)
                    IF ASSEMBLE_FOR_ROM
                    LDX                 #PIA1               ;POINT X TO PIA1
                    CLR                 -3,X                ;CLEAR PIA0 CONTROL REGISTER A
                    CLR                 -1,X                ;CLEAR PIA0 CONTROL REGISTER B
                    CLR                 -4,X                ;SET PIA0 SIDE A TO INPUT
                    LDD                 #$FF34
                    STA                 -2,X                 ;* SET PIA0 SIDE B TO OUTPUT
                    STB                 -3,X                 ;* ENABLE PIA0 PERIPHERAL REGISTERS, DISABLE PIA0
                    STB                 -1,X                 ;* MPU INTERRUPTS, SET CA2, CA1 TO OUTPUTS
                    CLR                 1,X                  ;CLEAR CONTROL REGISTER A ON PIA1
                    CLR                 3,X                  ;CLEAR CONTROL REGISTER B ON PIA1
                    DECA                                     ;A REG NOW HAS $FE
                    STA                 ,X                   ;BITS 1-7 ARE OUTPUTS, BIT 0 IS INPUT ON PIA1 SIDE A
                    LDA                 #$F8                 ;=
                    STA                 2,X                  ;= BITS 0-2 ARE INPUTS, BITS 3-7 ARE OUTPUTS ON B SIDE
                    STB                 1,X                  ;* ENABLE PERIPHERAL REGISTERS, DISABLE PIA1 MPU
                    STB                 3,X                  ;* INTERRUPTS AND SET CA2, CB2 AS OUTPUTS
                    CLR                 2,X                  ;SET 6847 MODE TO ALPHA-NUMERIC
                    LDB                 #$02                 ;*
                    STB                 ,X                   ;* MAKE RS232 OUTPUT MARKING
                    ENDIF

                    MAC_SendThisString  MsgPresentation

;Let's check the RAM SIZE jumpers, set SAM correctly and inform user of their position.
                    MAC_SendThisString  MsgJumper
                    LDX                 #PIA1                ;Put us back in the context of a cold start with ROM...
                    LDA                 #$FE                 ;Put us back in the context of a cold start with ROM...
                    LDB                 #$04                 ;USE AS A MASK TO CHECK RAMSZ INPUT
                    STA                 -2,X                 ;SET RAMSZ STROBE HIGH
                    BITB                2,X                  ;CHECK RAMSZ INPUT
                    BNE                 WillBe16Or64        ;BRANCH IF JUMPER -is not- SET FOR 4K RAMS
                    MAC_SendThisString  MsgJumper4K
                    STA                 SAMREG+26           ;Write to EVEN address to clear M0 in SAM
                    STA                 SAMREG+28           ;Write to EVEN address to clear M1 in SAM
                    BRA                 AfterJumpers

WillBe16Or64        CLR                 -2,X                ;SET RAMSZ STROBE LOW
                    BITB                2,X                 ;CHECK RAMSZ INPUT
                    BEQ                 JMPR64K             ;BRANCH IF JUMPER SET FOR 64K RAMS

                    MAC_SendThisString  MsgJumper16K
                    STA                 SAMREG+27           ;Write to ODD address to set M0 in SAM
                    STA                 SAMREG+28           ;Write to EVEN address to clear M1 in SAM
                    BRA                 AfterJumpers

JMPR64K             MAC_SendThisString  MsgJumper64K
                    STA                 SAMREG+26           ;Write to EVEN address to clear M0 in SAM
                    STA                 SAMREG+29           ;Write to ODD address to set M1 in SAM
AfterJumpers        MAC_SendThisString  MsgJumperEnd


;Write part...
                    MAC_SendThisString  MsgSmartTestStart
                    lds                 #SMART_WRITE_TABLE
KeepSmartWrite      ldx                 ,s++
                    cmpx                #ENDSMARTTABLEMARKER
                    beq                 SmartWriteCompleted
                    MAC_SmartWrite      SmartData01
                    MAC_SmartWrite      SmartData02
                    MAC_SmartWrite      SmartData04
                    MAC_SmartWrite      SmartData08
                    MAC_SmartWrite      SmartData10
                    MAC_SmartWrite      SmartData20
                    MAC_SmartWrite      SmartData40
                    IF                  INTENTIONAL_ERROR
                    MAC_SmartWrite      SmartData02
                    ELSE
                    MAC_SmartWrite      SmartData80
                    ENDIF
                    MAC_SmartWrite      SmartDataFE
                    MAC_SmartWrite      SmartDataFD
                    MAC_SmartWrite      SmartDataFB
                    MAC_SmartWrite      SmartDataF7
                    MAC_SmartWrite      SmartDataEF
                    MAC_SmartWrite      SmartDataDF
                    MAC_SmartWrite      SmartDataBF
                    MAC_SmartWrite      SmartData7F
                    bra                 KeepSmartWrite
SmartWriteCompleted

;Read part...
                    lds                 #SMART_WRITE_TABLE
KeepSmartRead       ldx                 ,s++
                    cmpx                #ENDSMARTTABLEMARKER
                    lbeq                SmartReadCompleted
                    MAC_SmartCompare    SmartData01
                    MAC_SmartCompare    SmartData02
                    MAC_SmartCompare    SmartData04
                    MAC_SmartCompare    SmartData08
                    MAC_SmartCompare    SmartData10
                    MAC_SmartCompare    SmartData20
                    MAC_SmartCompare    SmartData40
                    MAC_SmartCompare    SmartData80
                    MAC_SmartCompare    SmartDataFE
                    MAC_SmartCompare    SmartDataFD
                    MAC_SmartCompare    SmartDataFB
                    MAC_SmartCompare    SmartDataF7
                    MAC_SmartCompare    SmartDataEF
                    MAC_SmartCompare    SmartDataDF
                    MAC_SmartCompare    SmartDataBF
                    MAC_SmartCompare    SmartData7F
                    lbra                KeepSmartRead
SmartReadCompleted

                    MAC_SendThisString  MsgSmartTestEnd

                    lds                 #ReferenceStart

;Write part...
CycleTest           MAC_SendThisString  MsgFullTestStart

                    ldx                 #RAMSTART
WriteOtherBunch     lda                 ,s+
                    sta                 ,x+
                    cmps                #ReferenceEnd
                    blo                 NotEndReference
                    lds                 #ReferenceStart
NotEndReference     cmpx                #(RAMSTART+MEMTESTSIZE)
                    blo                 WriteOtherBunch

;Read part...
                    leas                ((ReferenceEnd-ReferenceStart)-((MEMTESTSIZE)%(ReferenceEnd-ReferenceStart))),s
                    cmps                #ReferenceEnd
                    blo                 1F
                    leas                -(ReferenceEnd-ReferenceStart),s
1
                    ldx                 #RAMSTART
ReadOtherBunch      lda                 ,x

                    IF INTENTIONAL_ERROR
                    cmpa                #$37
                    bne                 Not37
                    lda                 #$B5
                    ENDIF
Not37
                    cmpa                ,s
                    lbeq                MatchValue

;If we keep going here, it's because we have a mismatch!!!
                    tfr                 d,y                 ;Let's preserve "A" which represent what we read from DRAM so we don't reread it.
                                                            ;It's preferable to preserve what's have been read from DRAM instead to re-read it a second time.

                    MAC_SendStrAddr                         ;Column #1 = The address of the error, let's show it.
                    tfr                 x,d
                    MAC_SendHexWordD
                    MAC_SendTwoSpaces

                    MAC_SendStrExpect
                    lda                 ,s                  ;Recuperate what we initially wrote.
                    MAC_SendHexByteA                        ;Column #2 = The byte we initially wrote and that was expected.
                    MAC_SendTwoSpaces

                    MAC_SendStrRead
                    tfr                 y,d                 ;Recuperate was read back.
                    MAC_SendHexByteA                        ;Column #3 = The byte we read back from DRAM.
                    MAC_SendTwoSpaces

                    MAC_SendStrBits
                    tfr                 y,d
                    eora                ,s                  ;In "A", the matching bit now have "0" and the mismatch are "1"
                    MAC_SendBitCompareA                     ;Send bit 7
                    MAC_SendBitCompareA                     ;Send bit 6
                    MAC_SendBitCompareA                     ;Send bit 5
                    MAC_SendBitCompareA                     ;Send bit 4
                    MAC_SendBitCompareA                     ;Send bit 3
                    MAC_SendBitCompareA                     ;Send bit 2
                    MAC_SendBitCompareA                     ;Send bit 1
                    MAC_SendBitCompareA                     ;Send bit 0

                    MAC_SendThisChar    CHAR_CarriageReturn

;Back in normal flow, either from a match or a mismatch
MatchValue          leas                1,s                 ;Increment our source.
                    leax                1,x                 ;Increment our destination.

                    cmps                #ReferenceEnd       ;Checking if we need to wraparound in our source patterns.
                    blo                 KeepRef4Read
                    lds                 #ReferenceStart
KeepRef4Read
                    cmpx                #(RAMSTART+MEMTESTSIZE) ;Checking if we've completed reading the whole RAM to test.
                    lblo                ReadOtherBunch

;Now we need to replace our pattern source pointer to where it was at the beginning of the cycle.
                    leas                ((ReferenceEnd-ReferenceStart)-((MEMTESTSIZE)%(ReferenceEnd-ReferenceStart))),s
                    cmps                #ReferenceEnd
                    blo                 1F
                    leas                -(ReferenceEnd-ReferenceStart),s
1

;To restartn a new cycle, we'll use data from one position further in our reference pattern source data.
                    leas                1,s
                    cmps                #ReferenceEnd
                    blo                 1F
                    lds                 #ReferenceStart
1

                   lbra                CycleTest

SendHexByte         tfr                 a,b
                    lsrb
                    lsrb
                    lsrb
                    lsrb
                    MAC_SendLowNibbleB
                    tfr                 a,b
                    MAC_SendLowNibbleB
                    jmp                 ,u

; In: DP=The byte to send
;      U=The return address to jump in
; Kept: DP A X Y U S
; Lost: B
;
SendByte            MAC_SendByte
                    jmp                 ,u

;   In: Y=The null terminated string to send.
;       S=The return address to jump in
; Kept: DP A X S
; Lost: B Y U
;
SendString          ldb                 ,x+
                    lbeq                NoMoreChar
                    tfr                 b,dp
                    MAC_SendByte
                    lbra                SendString
NoMoreChar          jmp                 ,u


ReferenceStart      fcb                 $00,$01,$02,$04,$08,$10,$20,$40,$80,$FF,$AA,$55,$F0,$0F,$A5,$EE
                    fcb                 $23,$35,$28,$DE,$19,$71,$C0,$87,$94,$5C,$3E,$6D,$F1,$9C,$A9,$05
                    fcb                 $60,$4E,$4F,$52,$41,$4D,$60,$60,$52,$41,$4D,$54,$45,$53,$54,$60 ;" NORAM  RAMTEST "
                    fcb                 $B2,$A6,$C4,$12,$93,$4A,$DF,$E3,$D1,$44,$7B,$A3,$22,$B4,$E6,$11
                    fcb                 $1C,$67,$B1,$D5,$B5,$1F,$92,$F2,$C2,$61,$E0,$D2,$90,$82,$03,$C9
                    fcb                 $FD,$D3,$33,$09,$14,$32,$9D,$51,$EF,$0A,$43,$50,$D0,$70,$B6,$06
                    fcb                 $0D,$9E,$18,$66,$89,$1A,$7D,$76,$C3,$25,$42,$31,$8F,$5A,$F7,$AF
                    fcb                 $D7,$47,$73,$A2,$8D,$84,$B0,$62,$3D,$CC,$15,$E5,$BE,$E2,$C6,$E4
                    fcb                 $2A,$38,$2B,$81,$C7,$2D,$AD,$0E,$FC,$65,$96,$74,$58,$36,$7E,$F5
                    fcb                 $5E,$4B,$2E,$F4,$1D,$57,$46,$30,$91,$E1,$63,$A7,$D4,$A1,$56,$72
                    fcb                 $BD,$0B,$13,$64,$8E,$3F,$2C,$24,$B9,$F8,$FE,$C5,$A0,$85,$95,$9F
                    fcb                 $7A,$9A,$39,$2F,$EA,$E9,$3C,$DA,$CE,$1B,$21,$D6,$6F,$6C,$83,$77
                    fcb                 $BF,$98,$97,$C1,$99,$07,$A8,$A4,$5F,$5B,$FB,$0C,$BC,$3B,$E7,$69
                    fcb                 $3A,$CB,$48,$B3,$6A,$DC,$27,$E8,$8C,$88,$DD,$CA,$BB,$17,$EC,$79
                    fcb                 $D8,$26,$F9,$86,$4C,$F6,$6E,$29,$8B,$EB,$FA,$78,$5D,$37,$DB,$34
                    fcb                 $AC,$CD,$BA,$68,$75,$7F,$49,$AE,$59,$9B,$8A,$ED,$7C,$C8,$D9,$AB
                    fcb                 $16,$FB,$6B,$CF,$58,$3E,$E1,$DE,$AD,$BE,$EF,$C0,$C0,$02,$68,$09
                    fcb                 $31,$DA,$8D,$CE,$B8,$6F,$CF,$3B,$11,$8E,$8D,$CB,$AC,$B7,$2F,$5E
                    fcb                 $F6,$D5,$CE,$A5,$01,$53,$F7,$B5,$A9,$02,$DD,$79,$A9,$03,$88,$85
                    fcb                 $D9,$9A,$F7,$01,$08,$82,$87,$18,$89,$96,$1A,$BA,$3D,$AE,$1F,$92
                    fcb                 $F8,$B5,$7E,$DE,$ED,$F3,$81,$B2,$F6,$64,$BE,$5F,$E0,$90,$22,$66
                    fcb                 $F1,$01,$7A,$77,$02,$9C,$48,$C6,$94,$8D,$92,$13,$A4,$5E,$A5,$36
                    fcb                 $6A
ReferenceEnd        fcb                 $17,$E8,$5A,$44,$00,$29,$66,$6A,$59,$60,$FF,$C5,$17,$0D,$B6,$3E


SMART_WRITE_TABLE   fdb                 $0000
                    fdb                 $0020
                    fdb                 $0040
                    fdb                 $0080
                    fdb                 $0100
                    fdb                 $0200
                    fdb                 $0400
                    fdb                 $0800
                    IF RAMSIZE8K
                    fdb                 $1000 ;4K
                    ENDIF
                    IF RAMSIZE16K
                    fdb                 $1000 ;4K
                    ENDIF
                    IF RAMSIZE24K
                    fdb                 $1000 ;4K
                    fdb                 $2000 ;8K
                    fdb                 $4000 ;16K
                    ENDIF
                    IF RAMSIZE32K
                    fdb                 $1000 ;4K
                    fdb                 $2000 ;8K
                    fdb                 $4000 ;16K
                    ENDIF
                    fdb                 ENDSMARTTABLEMARKER

MsgPresentation     fcc                 CHAR_CarriageReturn,CHAR_CarriageReturn
                    fcc                 "=============",CHAR_CarriageReturn
                    fcc                 "RAM TEST v0.4",CHAR_CarriageReturn
                    IF RAMSIZE8K
                    fcc                 " TESTING 8K ",CHAR_CarriageReturn
                    ENDIF
                    IF RAMSIZE16K
                    fcc                 " TESTING 16K ",CHAR_CarriageReturn
                    ENDIF
                    IF RAMSIZE24K
                    fcc                 " TESTING 24K ",CHAR_CarriageReturn
                    ENDIF
                    IF RAMSIZE32K
                    fcc                 " TESTING 32K ",CHAR_CarriageReturn
                    ENDIF
                    fcc                 "=============",CHAR_CarriageReturn,CHAR_CarriageReturn,CHAR_Terminaison

MsgSmartTestStart   fcc                 "Smart test begins...",CHAR_CarriageReturn,CHAR_Terminaison
MsgSmartTestEnd     fcc                 "Smart test completed.",CHAR_CarriageReturn,CHAR_CarriageReturn,CHAR_Terminaison
MsgFullTestStart    fcc                 "Full test begins.",CHAR_CarriageReturn,CHAR_Terminaison
LastPrgLocation     fcb                 CHAR_Terminaison
MsgJumper           fcc                 "Jumpers for ",CHAR_Terminaison
MsgJumper4K         fcc                 "4",CHAR_Terminaison
MsgJumper16K        fcc                 "16",CHAR_Terminaison
MsgJumper64K        fcc                 "64",CHAR_Terminaison
MsgJumperEnd        fcc                 "K.",CHAR_CarriageReturn,CHAR_CarriageReturn,CHAR_Terminaison

                    IF ASSEMBLE_FOR_ROM
                    org                 $BFF0
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    fdb                 ResetVector
                    ENDIF

                    end
