*
*    RAMTest                                                Rev: 12 Mar 89
*
*
*    Copyright 1989 by Ross Nelson.
*
*    This program may be freely distributed.
*
*    REGISTERS:
*
*    A6   Pointer to library base
*    A5   End address for RAM testing
*    A4   Start address for RAM testing
*    A3   Current address under test
*    A2   High or low results stack
*    A1   scratch
*    A0   scratch
*
*    D0   scratch
*    D1   scratch
*    D2   What the result word should be
*    D3   What the result word was
*    D4   Inversion control register
*    D5   Indicates the phase of the test pattern
*    D6   Saves original RAM value
*    D7   Counts down number of repeats
*
*
*
     NOPAGE
     NOBLANKS

     INCLUDE "AM:CoreMacros.i"

     INCLUDE "AM:Close.i"
     INCLUDE "AM:Disable.i"
     INCLUDE "AM:Enable.i"
     INCLUDE "AM:GetStdOut.i"
     INCLUDE "AM:Open.i"
     INCLUDE "AM:Write.i"


     DefineSections RAMTest

AllReg  REG  A0-A6/D0-D6


RAMTest:
     MOVEM.L A0/D0,-(SP)      ;|  Save pointers to command line arguments.
     OpenLib exec.library     ;|  Open the exec library.
     BEQ RAMTest_27           ;|
     OpenLib dos.library      ;|  Open the dos library.
     BEQ RAMTest_26           ;|
     GetStdOut                ;|  Get the file handle for standard output.
                              ;|
     MOVEM.L (SP)+,A0/D0      ;|  Restore pointers to command line arguments.
                              ;|
     CMPI.W #3,D0             ;|  IF the command line is too short to be
     BGE RAMTest_1            ;|      valid,
                              ;|  THEN
                              ;||  Write "Format: RAMTest <start address>'
                              ;||   <end address> [<number of repeats>]", etc
     Write D,Format,StdOut    ;||   to standard output.
     BRA RAMTest_25           ;||  Pass to RAMTest_25 to exit.
RAMTest_1:                    ;|  ENDIF
     CMPI.B #' ',(A0)         ;|  Point to first non-space in command line.
     BNE.S RAMTest_2          ;|
     ADDQ.L #1,A0             ;|
     SUBQ.L #1,D0             ;|
     BNE RAMTest_1            ;|
RAMTest_2:                    ;|
     MOVEM.L AllReg,-(A7)     ;|  Open a window for address display.
     Open I,AWSpec,RTAdr,new  ;|
                              ;|  Make the cursor invisible.
     Write D,InitRTAdr,RTAdr  ;|
     MOVEM.L (A7)+,AllReg     ;|
     MOVEA.L A0,A1            ;|  Save the start address in A4 and
     BSR ASCIINumToD1         ;|   at StartAdr.
     ANDI.W #$FFF0,D1         ;|     (Round off to block size)
     MOVE.L D1,StartAdr       ;|
     MOVEA.L D1,A4            ;|
     BSR ASCIINumToD1         ;|  Save the end address in A5 and at EndAdr.
     ORI.W #$000F,D1          ;|     (Round off to block size)
     MOVE.L D1,EndAdr         ;|
     MOVEA.L D1,A5            ;|
     CMPI.B #LF,-1(A1)        ;|  IF the number of repeats was specified,
     BEQ.S RAMTest_3          ;|  THEN
     BSR ASCIINumToD1         ;||  Get the number of repeats.
     BRA.S RAMTest_4          ;||
RAMTest_3:                    ;|  ELSE
     MOVEQ #1,D1              ;||  Make the number of repeats equal one.
RAMTest_4:                    ;|  ENDIF
                              ;|
     MOVE.L D1,RepeatCount    ;|  Save the number of repeats in D7 and at
     MOVE.L D1,D7             ;|   RepeatCount.
     SUBQ.L #1,D7             ;|
RAMTest_5:                    ;|  FOR N = RepeatCount to 0,
     CLR.W ErrorCount         ;||  Clear the error count.
     CLR.L D4                 ;||  Initialize the inversion control register.
     MOVEM.L AllReg,-(A7)     ;||  Write "Starting test of RAM block." to
     Write D,Starting,StdOut  ;||   standard output.
     MOVEM.L (A7)+,AllReg     ;||
     MOVEA.L A4,A3            ;||  Make A3 point to the first RAM address
                              ;||   under test.
RAMTest_6:                    ;||  Start of REPEAT UNTIL
     MOVE.L A3,D0             ;|||  IF the 10 LSBs of the address under test
     TST.B D0                 ;|||      are all zeros,
     BNE RAMTest_7            ;|||
     ANDI.L #$000003FF,D0     ;|||
     BNE.S RAMTest_7          ;|||
                              ;|||  THEN
     MOVEM.L AllReg,-(A7)     ;||||  Write the address to the RAMTest window.
     Write D,AdrEqu,RTAdr     ;||||
     MOVEM.L (A7)+,AllReg     ;||||
     MOVE.L A3,D0             ;||||
     BSR D0toHexASCII         ;||||
     MOVEM.L AllReg,-(A7)     ;||||
     Write D,HexD0,RTAdr      ;||||
     Write D,CrRtn,RTAdr      ;||||
     MOVEM.L (A7)+,AllReg     ;||||
RAMTest_7:                    ;|||  ENDIF
                              ;|||
     MOVEQ #7,D5              ;|||  FOR phase of test pattern = 7 to 0,
RAMTest_8:                    ;||||
RAMTest_9:                    ;||||  FOR inversion control = 0 to -1,
     CMPA.L #RAMTest_14,A3    ;|||||  IF the RAM address to be tested is above
     BLT RAMTest_15           ;|||||   the RAMTest_14 address,
                              ;|||||  THEN
     LEA LoResultsStk(PC),A2  ;||||||  Point to the low results stack.
     Disable                  ;||||||  Disable interrupts.
                              ;||||||  Save the original RAM values.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     LEA LoSaveBuff(PC),A1    ;||||||     Point to the save-buffer.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_10:                   ;|||||||
     MOVE.W (A0)+,(A1)+       ;|||||||     Save the next word.
     DBF D1,RAMTest_10        ;||||||     NEXT count
                              ;||||||  Write the test pattern to the RAM under
                              ;||||||   test.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     MOVE.W #$0101,D0         ;||||||     Put initial pattern in D0.
     EOR.W D4,D0              ;||||||
     ROL.W D5,D0              ;||||||
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_11:                   ;|||||||
     MOVE.W D0,(A0)+          ;|||||||     Write test pattern for the next word.
     ROL.W #1,D0              ;|||||||     Shift the test pattern left one bit.
     DBF D1,RAMTest_11        ;||||||     NEXT count
                              ;||||||  Read back the test pattern onto the stack.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_12:                   ;|||||||
     MOVE.W (A0)+,-(A2)       ;|||||||     Read next word onto the results stack.
     DBF D1,RAMTest_12        ;||||||     NEXT count
                              ;||||||  Restore the original RAM values.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     LEA LoSaveBuff(PC),A1    ;||||||     Point to the save-buffer.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_13:                   ;|||||||
     MOVE.W (A1)+,(A0)+       ;|||||||     Restore next word.
     DBF D1,RAMTest_13        ;||||||     NEXT count
     Enable                   ;||||||  Re-enable interrupts.
     BRA RAMTest_20           ;|||||
LoSaveBuff:                   ;|||||
     DS.W 8                   ;|||||
LoResults:                    ;|||||
     DS.W 10                  ;|||||
LoResultsStk:                 ;|||||
RAMTest_14:                   ;|||||
     DC.L 0,0,0,0,0,0,0,0     ;|||||
RAMTest_15:                   ;|||||  ELSE
     LEA HiResultsStk(PC),A2  ;||||||  Point to the high results stack.
     Disable                  ;||||||  Disable interrupts.
                              ;||||||  Save the original RAM values.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     LEA HiSaveBuff(PC),A1    ;||||||     Point to the save-buffer.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_16:                   ;|||||||
     MOVE.W (A0)+,(A1)+       ;|||||||     Save the next word.
     DBF D1,RAMTest_16        ;||||||     NEXT count
                              ;||||||  Write the test pattern to the RAM under
                              ;||||||   test.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     MOVE.W #$0101,D0         ;||||||     Put initial pattern in D0.
     EOR.W D4,D0              ;||||||
     ROL.W D5,D0              ;||||||
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_17:                   ;|||||||
     MOVE.W D0,(A0)+          ;|||||||     Write test pattern for the next word.
     ROL.W #1,D0              ;|||||||     Shift the test pattern left one bit.
     DBF D1,RAMTest_17        ;||||||     NEXT count
                              ;||||||  Read back the test pattern onto the stack.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_18:                   ;|||||||
     MOVE.W (A0)+,-(A2)       ;|||||||     Read next word onto the results stack.
     DBF D1,RAMTest_18        ;||||||     NEXT count
                              ;||||||  Restore the original RAM values.
     MOVEA.L A3,A0            ;||||||     Point to RAM address.
     LEA HiSaveBuff(PC),A1    ;||||||     Point to the save-buffer.
     MOVEQ #7,D1              ;||||||     FOR count = 7 to 0,
RAMTest_19:                   ;|||||||
     MOVE.W (A1)+,(A0)+       ;|||||||     Restore next word.
     DBF D1,RAMTest_19        ;||||||     NEXT count
     Enable                   ;||||||  Re-enable interrupts.
RAMTest_20:                   ;|||||  ENDIF
                              ;|||||
                              ;|||||  Report any failures.
     MOVE.W #$0101,D2         ;|||||     Figure out what the result word should
     EOR.W D4,D2              ;|||||      be.
     ROL.W D5,D2              ;|||||
     MOVEQ #7,D1              ;|||||     FOR count = 7 to 0,
RAMTest_21:                   ;||||||
     ROR.W #1,D2              ;||||||     Figure out what the next result word
                              ;||||||      should be.
     MOVE.W (A2)+,D3          ;||||||     Check the next result word from the
     CMP.W D2,D3              ;||||||       results stack.
     BEQ RAMTest_22           ;||||||     IF there was a failure,
                              ;||||||     THEN
     MOVEM.L AllReg,-(A7)     ;|||||||     Write "Failed at address $---A3---"
     Write D,FailMsg1,StdOut  ;|||||||
     MOVEM.L (A7)+,AllReg     ;|||||||
     MOVE.L A3,D0             ;|||||||
     ADD.L D1,D0              ;|||||||
     ADD.L D1,D0              ;|||||||
     BSR D0toHexASCII         ;|||||||
     MOVEM.L AllReg,-(A7)     ;|||||||
     Write D,HexD0,StdOut     ;|||||||
     Write D,FailMsg2,StdOut  ;|||||||     Write " ,  $-D2- read back as $-D3-"
     MOVEM.L (A7)+,AllReg     ;|||||||
     MOVE.W D2,D0             ;|||||||
     BSR D0toHexASCII         ;|||||||
     MOVEM.L AllReg,-(A7)     ;|||||||
     Write D,HexD0+4,StdOut,4 ;|||||||
     Write D,FailMsg3,StdOut  ;|||||||
     MOVEM.L (A7)+,AllReg     ;|||||||
     MOVE.W D3,D0             ;|||||||
     BSR D0toHexASCII         ;|||||||
     MOVEM.L AllReg,-(A7)     ;|||||||
     Write D,HexD0+4,StdOut,4 ;|||||||
     MOVEM.L (A7)+,AllReg     ;|||||||
     ADDQ.B #1,ErrorCount     ;|||||||     Increment the error count.
     BPL.S RAMTest_22         ;|||||||     IF there were 128 errors,
                              ;|||||||     THEN
                              ;||||||||     Write "Aborting RAMTest.  Too many
     Write D,Aborting,StdOut  ;||||||||      errors were found."
     BRA.S RAMTest_24         ;||||||||     Pass to RAMTest_24 to abort.
                              ;|||||||     ENDIF
RAMTest_22:                   ;||||||     ENDIF
                              ;||||||
     DBF D1,RAMTest_21        ;|||||     NEXT count
                              ;|||||
     NOT.W D4                 ;||||  NEXT inversion control
     BNE RAMTest_9            ;||||
     DBF D5,RAMTest_8         ;|||  NEXT phase of test pattern
                              ;|||
     ADDQ.L #8,A3             ;|||  Make A3 point to the next RAM section
     ADDQ.L #8,A3             ;|||   to be tested.
                              ;|||
     CMPA.L A3,A5             ;||  REPEAT UNTIL the end address has been
     BGE RAMTest_6            ;||   tested.
     MOVEM.L AllReg,-(A7)     ;||
     TST.W ErrorCount         ;||  IF there were no errors,
     BNE.S RAMTest_23         ;||  THEN
                              ;|||  Write "No errors were found." to the
     Write D,NoErrors,StdOut  ;|||   standard output.
RAMTest_23:                   ;||   ENDIF
                              ;||  Write "Finished test of RAM block." to
     Write D,Finished,StdOut  ;||   standard output.
     MOVEM.L (A7)+,AllReg     ;||
     DBF D7,RAMTest_5         ;|  NEXT N
RAMTest_24:                   ;|
     Close RTAdr              ;|
RAMTest_25:                   ;|
     CloseLib dos.library     ;|  Close the dos library.
RAMTest_26:                   ;|
     CloseLib exec.library    ;|  Close the exec library.
RAMTest_27:                   ;|
     CLR.L D0                 ;|  Exit the program with return code of zero.
     RTS                      ;|


AWSpec:

  DC.B 'CON:400/15/158/21/RAMTest',0

AWSpecEnd:

     CNOP 0,2

StartAdr:
     DS.L 1

EndAdr:
     DS.L 1

RepeatCount:
     DS.L 1

HiSaveBuff:
     DS.W 8
HiResults:
     DS.W 10
HiResultsStk:

ErrorCount:
     DS.W 1

CR   EQU $0D
LF   EQU $0A

Format:
     DC.B LF,'Format: RAMTest <start address>'
     DC.B ' <end address> [<number of repeats>]',LF
     DC.B '  Numbers are given in decimal,'
     DC.B ' unless preceded by a "$" for hexadecimal.',LF
     DC.B '  EXAMPLE:  RAMTest $200000 $27FFFF 1',LF
FormatEnd:

Starting:
     DC.B LF,'Starting test of RAM block.'
StartingEnd:

NoErrors:
     DC.B LF,'No errors were found.'
NoErrorsEnd:

Finished:
     DC.B LF,'Finished test of RAM block.',LF
FinishedEnd:

Aborting:
     DC.B LF,'Aborting RAMTest.  Too many errors were found.',LF
AbortingEnd:

FailMsg1:
     DC.B LF,'Failed at address $'
FailMsg1End:

FailMsg2:
     DC.B ' ,  $'
FailMsg2End:

FailMsg3:
     DC.B ' read back as $'
FailMsg3End:

LineFeed:
     DC.B LF
LineFeedEnd:

CrRtn:
     DC.B CR
CrRtnEnd:

InitRTAdr:
     DC.B $9B,'0 p'
InitRTAdrEnd:

AdrEqu:
     DC.B ' Adr = $'
AdrEquEnd:

HexD0:
     DC.B '********'
HexD0End:


     CNOP 0,2

*****************************************************************************
*
*    ASCIINumToD1          SUBROUTINE                       11 Feb 89
*
*    NAME:
*         ASCIINumToD1 - Convert an ASCII coded string to a decimal,
*                          hexadecimal, or binary number.
*
*    FUNCTION:
*         This subroutine converts an ASCII coded numeric string to a number
*          in the D1.L register. The start of the string must be given in A1.
*
*         The string must be terminated by a space, a null, or any ASCII
*          code from $00 to $20.
*
*         The maximum length of the string must be specified in D0.L .
*
*         If the number begins with a minus sign (-), the result will be a
*         negative signed number. If a decimal point is encountered, the
*         D2.B register will indicate how many digits are to the right of
*         the decimal point.
*
*         If the number begins with a "$", it will be evaluated as a
*         hexadecimal value. If it begins with a "%", it will be evaluated
*         as a binary value.
*
*         The bits in D3 will be set for the following conditions:
*
*             D3 bit 0 = The number is negative.
*             D3 bit 1 = The number contains a decimal point.
*             D3 bit 2 = The number is hexadecimal.
*             D3 bit 3 = The number is binary.
*
*         The A1, D0, D4, and D5 registers will be trashed.
*

     CNOP 0,2

ASCIINumToD1:
     CLR.L D1                 ;|  Initialize D1, D2 and D3.
     CLR.L D2                 ;|
     CLR.L D3                 ;|
ASCIINumToD1_1:               ;|
     CLR.L D4                 ;|  Read the (next) character.
     MOVE.B (A1)+,D4          ;|
     CMPI.B #$20,D4           ;|  IF there are still more characters,
     BLS ASCIINumToD1_12      ;|
     BCLR #7,D4               ;|  THEN
     CMP.B #'-',D4            ;||  IF the character is a minus sign,
     BNE ASCIINumToD1_2       ;||  THEN
     BSET #0,D3               ;|||  Indicate negative sign in D3 bit 0.
ASCIINumToD1_2:               ;||  ENDIF
     CMP.B #'.',D4            ;||  IF the character is a decimal point,
     BNE ASCIINumToD1_3       ;||  THEN
     BSET #1,D3               ;|||  Indicate the decimal point in D3 bit 1.
ASCIINumToD1_3:               ;||  ENDIF
     CMP.B #'$',D4            ;||  IF the character is a "$",
     BNE ASCIINumToD1_4       ;||  THEN
     BSET #2,D3               ;|||  Indicate hexadecimal in D3 bit 2.
ASCIINumToD1_4:               ;||  ENDIF
     CMP.B #'%',D4            ;||  IF the character is a "%",
     BNE ASCIINumToD1_5       ;||  THEN
     BSET #3,D3               ;|||  Indicate binary in D3 bit 3.
ASCIINumToD1_5:               ;||  ENDIF
     BTST #6,D4               ;||  Convert any lower case letters to upper case.
     BEQ ASCIINumToD1_6       ;||
     BCLR #5,D4               ;||
ASCIINumToD1_6:               ;||
     SUB.B #'0',D4            ;||  :  IF it is not a digit between 0 and 9 or
     BMI ASCIINumToD1_1       ;||  :      a hexadecimal digit from A to F,
     CMP.B #9,D4              ;||  :  THEN
     BLE ASCIINumToD1_7       ;||  :|  Loop back to ASCIINumToD1_1.
     BTST #2,D3               ;||  :  ELSE
     BEQ ASCIINumToD1_1       ;||  :|  Convert the ASCII digit to a number
     CMP.B #16,D4             ;||  :|   from $0 to $F.
     BLE ASCIINumToD1_1       ;||  :  ENDIF
     SUBQ.B #7,D4             ;||  :
     CMP.B #$F,D4             ;||  :
     BGT ASCIINumToD1_1       ;||  :
ASCIINumToD1_7:               ;||  :
     BTST #3,D3               ;||  IF the number is binary,
     BEQ ASCIINumToD1_8       ;||  THEN
     LSL.L #1,D1              ;|||  Multiply D1.L by 2.
     BRA ASCIINumToD1_10      ;|||
ASCIINumToD1_8:               ;||  ELSE
     BTST #2,D3               ;|||  IF the number is hexadecimal,
     BEQ ASCIINumToD1_9       ;|||  THEN
     LSL.L #4,D1              ;||||  Multiply D1.L by 16.
     BRA ASCIINumToD1_10      ;||||
ASCIINumToD1_9:               ;|||  ELSE
     MOVE.L D1,D5             ;||||  Multiply D1.L by 10.
     LSL.L #3,D1              ;||||
     LSL.L #1,D5              ;||||
     ADD.L D5,D1              ;||||
                              ;|||  ENDIF
ASCIINumToD1_10:              ;||  ENDIF
     ADD.L D4,D1              ;||  Add the digit to D1.
     BTST #1,D3               ;||  IF the digit is to the right of the decimal
     BEQ ASCIINumToD1_11      ;||      point,
                              ;||  THEN
     ADDQ.B #1,D2             ;|||  Incriment D2.B .
ASCIINumToD1_11:              ;||  ENDIF
     BRA ASCIINumToD1_1       ;||  Loop back to ASCIINumToD1_1 for the next
                              ;||   character.
ASCIINumToD1_12:              ;|  ENDIF
     BTST #0,D3               ;|  IF there was a minus sign,
     BEQ ASCIINumToD1_13      ;|  THEN
     NEG.L D1                 ;||  Negate the number.
ASCIINumToD1_13:              ;|  ENDIF
     RTS                      ;|  Return from ASCIINumToD1.


*****************************************************************************

     CNOP 0,2

*****************************************************************************
*
*    D0toHexASCII          SUBROUTINE                       21 Jan 89
*
*    NAME:
*         D0toHexASCII - Convert a number in D0 to an ASCII hexadecimal
*                         string at HexD0.
*
*    FUNCTION:
*         This subroutine converts a number in D0 to an ASCII hexadecimal
*          string.  The string will be stored at the location in RAM
*          labeled HexD0.
*
*


     CNOP 0,2

D0toHexASCII:
     MOVEM.L AllReg,-(A7)     ;|  Save all registers.
     LEA HexD0+8(PC),A0       ;|  Point to the 8th digit location in HexD0.
     MOVEQ #7,D2              ;|  FOR N = 7 to 0,
D0toHexASC_1:                 ;||
     MOVE.B D0,D1             ;||  Take the next 4 lowest bits from D0.
     ROR.L #4,D0              ;||
     ANDI.B #$0F,D1           ;||
     ADDI.B #'0',D1           ;||  Convert them to ASCII hexadecimal.
     CMPI.B #'9',D1           ;||
     BLS.S D0toHexASC_2       ;||
     ADDQ.B #7,D1             ;||
D0toHexASC_2:                 ;||
     MOVE.B D1,-(A0)          ;||  Save hex ASCII code at HexD0.
     DBF D2,D0toHexASC_1      ;|  NEXT N
     MOVEM.L (A7)+,AllReg     ;|  Restore all registers.
     RTS                      ;|  Return from D0toHexASCII.


*****************************************************************************


     END
