**************************************** * MiniMemoryTester * * * * Dagen Brock * * 2015-09-16 * **************************************** ******************************************************************** * Some notes * * * * Large portions of this program are written in one of the two cpu * * modes: m=1 (short) x=0 (long) or m=0 (long) x=0 (long) * * The 8-bit test modes, in particular, are written with a short * * accumulator, but long index registers. This way it can easily * * scan a bank of memory using the X register from 0000 to FFFF. * * Likewise, when running 16-bit test modes, we write 16 bit values * * using a long accumulator, and still using long index registers. * * However, we also increment or decrement by two, since it writes * * two bytes at a time with a long accumulator. * * * * This program favors configurability and reusable code, over * * speed. There's also not much thought to stability, but I wanted * * to allow the user to try to test their RAM as they see fit. * * * ******************************************************************** org $2000 ; start at $2000 (all ProDOS8 system files) typ $ff ; set P8 type ($ff = "SYS") for output file dsk mmtsystem ; tell compiler what name for output file put applerom Init jsr Intro ;UltimateMicro intro clc xce ;enable full 65816 sep #$30 LDA #$A0 ;USE A BLANK SPACE TO JSR $C300 ;TURN ON THE VIDEO FIRMWARE lda $C034 ; save border color sta BorderColor jsr DetectRam * ENABLE THIS TO SEE WHAT BANKS THE DETECTION ALGORITHM FOUND * jsr PrintMemoryMap * jsr RDKEY lda BankExpansionLowest sta StartBank lda BankExpansionHighest sta EndBank lda #MainMenuDefs ldx #>MainMenuDefs jsr Menu_InitMenu * Main Menu loop begin2 * Main :menuLoop jsr DrawMenuBackground jsr DrawRomMessage jsr DrawRamMessages jsr LogWelcomeMessage jsr LogRamMessages jsr LogPromoMessage :menuDrawOptionsLoop jsr MenuUpdateConfig ;always update this before draw in case of change lda #MainMenuDefs ldy #>MainMenuDefs jsr Menu_DrawOptions :menuNoDrawLoop jsr MenuCheckKeyColor bcc :menuNoDrawLoop ;hmm? :keyHit cmp #KEY_ENTER ;8D bne :check1 :enter jsr Menu_HandleSelection bra :menuDrawOptionsLoop ;because an option might have changed :check1 cmp #KEY_UPARROW ;8B beq :prevItem cmp #KEY_LTARROW ;88 beq :prevItem cmp #KEY_DNARROW ;8A beq :nextItem cmp #KEY_RTARROW ;95 beq :nextItem :unknownKey bra :menuNoDrawLoop :prevItem jsr Menu_PrevItem jsr Menu_UndrawSelectedAll ;hack for blinky cursor stz _ticker bra :menuNoDrawLoop :nextItem jsr Menu_NextItem jsr Menu_UndrawSelectedAll ;hack for blinky cursor stz _ticker bra :menuNoDrawLoop * * Main Menu loop end ^^^ * Prints all the mousetext background DrawMenuBackground jsr HOME lda #MainMenuStrs ldy #>MainMenuStrs ldx #00 ; horiz pos jsr PrintStringsX rts * Prints "Apple IIgs ROM 0x" DrawRomMessage PRINTXY #54;#05;Mesg_Rom lda GSROM jsr PRBYTE rts * Prints "Built-In RAM xxxK" * "Expansion RAM yyyyK" DrawRamMessages lda GSROM cmp #3 bne :rom0or1 :rom3 PRINTXY #54;#06;Mesg_InternalRam1024 bra :drawExpansionMessage :rom0or1 PRINTXY #54;#06;Mesg_InternalRam256 :drawExpansionMessage PRINTXY #54;#07;Mesg_ExpansionRam ldx #BankExpansionRamKB ldy #>BankExpansionRamKB jsr PrintInt lda #"K" jsr COUT rts LogWelcomeMessage jsr WinConsole LOG Mesg_Welcome jsr WinFull rts LogPromoMessage jsr WinConsole LOG Mesg_Promo jsr WinFull rts LogRamMessages jsr WinConsole LOG Mesg_DetectedBanks lda BankExpansionLowest jsr PRBYTE lda #Mesg_ToBank ldy #>Mesg_ToBank jsr PrintString lda BankExpansionHighest jsr PRBYTE jsr CROUT jsr WinFull rts LogTestDone jsr WinConsole LOG Mesg_Done jsr WinFull rts * * ####### ### ### ### * # ###### #### ##### ###### ##### ### ### ### * # # # # # # # ### ### ### * # ##### #### # ##### # # # # # * # # # # # ##### * # # # # # # # # ### ### ### * # ###### #### # ###### # # ### ### ### * * TestInit PRINTXY #$34;#$E;_clearstring ;clear something on screen? jsr WinConsole LOG Mesg_Starting jsr WinFull sei ; disable interrupts stz _testErrors stz _testIteration inc _testIteration ;actually, set to 1. let test passes be indicated in natural numbers. see, i'm not such a bad guy. stz _testIteration+1 stz _testState stz TwoPassWalkState jsr TestTwoPassMakeSeed TestMasterLoop clc xce rep #$10 ;long x/y ldy StartAddr ldx EndAddr stz CurBank jsr TestPrintIteration jsr TestPrintErrors ;just to get it drawn :NextBank jsr TestSetState ;sets read/write/both jsr TestForceUpdateStatus ;print last tested address before we advance banks jsr TestGetNextBank ;sets initial bank when CurBank = 0 jsr TestPatchBanks ;patches code for whatever CurBank is set to jsr TestPastFinalBank bcs :NextIteration jsr TestPrintState jsr TestGetStartAddress jsr TestForceUpdateStatus ;print last tested address before we advance banks stz _updateTick stz _updateTick+1 :TestLoop ;THIS IS IT! lda $C000 bmi TestKeyHandler KeyHandled jsr TestMemoryLocation jsr TestUpdateStatus jsr TestAdvanceLocation bcc :TestLoop bcs :NextBank :NextIteration inc _testIteration ;see if we've done enough tests lda TestIterations beq :infiniteIterations ;0=infinite cmp _testIteration bcc :testComplete :infiniteIterations lda TestTwoPass beq :notwopass stz _testState ;hack to reset for two pass, will switch it back to write when it sees zero. i hope. (update: WORKS! BOOM!) :notwopass jmp TestMasterLoop TestAbort jsr TestForceUpdateStatus ;print last test address :testComplete sep #$10 jsr LogTestDone rts Mesg_Done asc "DONE WITH TEST",$8D,00 TestKeyHandler sta $C010 jsr ToLower cmp #"q" beq TestAbort cmp #KEY_ESC beq TestAbort cmp #"p" beq :pause jmp KeyHandled :pause :nokey lda $C000 bpl :nokey sta $C010 jmp KeyHandled * This should just flip-flop, no matter what, on TwoPass mode... otherwise W/R (BOTH in one pass) mx %10 TestSetState lda TestTwoPass ;read pass then write pass? bne :twopass lda #TESTSTATE_BOTH ;r&w sta _testState rts :twopass lda _testState beq :setWrite ;0 check for initial value cmp #TESTSTATE_READ beq :setWrite lda #TESTSTATE_READ sta _testState rts :setWrite lda #TESTSTATE_WRITE ;otherwise, start with write pass sta _testState rts * Prints whether "Reading", "Writing", or "W/R" (Both) TestPrintState PushAll sep #$10 lda _testState :check1 cmp #TESTSTATE_WRITE bne :check2 PRINTXY #53;#12;Mesg_Writing bra :done :check2 cmp #TESTSTATE_READ bne :check3 PRINTXY #53;#12;Mesg_Reading bra :done :check3 cmp #TESTSTATE_BOTH bne :done PRINTXY #53;#12;Mesg_WR :done clc xce rep #$10 PopAll rts * Prints current test pass string TestPrintIteration PushAll sep #$10 PRINTXY #53;#10;Mesg_TestPass ldx #_testIteration ldy #>_testIteration jsr PrintInt clc xce rep #$10 PopAll rts * Prints current test error counts string TestPrintErrors PushAll sep #$10 PRINTXY #53;#11;Mesg_Errors ldx #_testErrors ldy #>_testErrors jsr PrintInt clc xce rep #$10 PopAll rts * Makes alert noise when enabled, otherwise immediately returns TestNoiseError lda TestErrorSound beq :nonoise jsr ErrorNoise jsr ErrorNoise jsr ErrorNoise :nonoise rts * Pauses on test error (when enabled, otherwise immediately returns) TestPauseError lda TestErrorPause ;is this option enabled? beq :no PushAll sep #$10 PRINTXY #55;#14;Mesg_TestError1 ;draw messages PRINTXY #55;#15;Mesg_TestError2 sta $C010 :pause lda $C000 ;wait for key bpl :pause sta $C010 PRINTXY #55;#14;Mesg_Blank ;undraw messages PRINTXY #55;#15;Mesg_Blank clc xce rep #$10 PopAll :no rts * Print a console error detailing the spot in memory where the error occured TestLogError PushAll php sta _stash+12 ;8 or 16 bit? YES! sty _stash+10 ;ReadRepeat stx _stash+2 ;address - legacy rep #$30 ;need longA lda TestReadRepeat inc ;n++ sec sbc _stash+10 ;-Y sta _stash+10 ;ReadRepeat+1-(ReadRepeat-TestPass)=TestPass sep #$30 inc _testErrors bne :noRoll inc _testErrors+1 :noRoll jsr WinConsole LOG Mesg_F1 ;Error Count ldx #_testErrors ldy #>_testErrors jsr PrintInt PRINTSTRING Mesg_F2 ;Test Pass ldx #_testIteration ldy #>_testIteration jsr PrintInt PRINTSTRING Mesg_F3 ;Read Pass ldx #_stash+10 ldy #>_stash+10 jsr PrintInt PRINTSTRING Mesg_F4 ;Address lda CurBank jsr PRBYTE lda #"/" jsr COUT lda _stash+3 ldx _stash+2 jsr PRNTAX PRINTSTRING Mesg_F5 ;Wrote lda TestSize16Bit bne :16bitwrote :8bitwrote lda HexPattern jsr PRBYTE bra :printread :16bitwrote lda HexPattern ldx HexPattern+1 jsr PRNTAX :printread PRINTSTRING Mesg_F6 ;Read lda TestSize16Bit bne :16bitread :8bitread lda _stash+12 jsr PRBYTE bra :nextline :16bitread lda _stash+12 ldx _stash+12+1 jsr PRNTAX :nextline bra :skipit LOG Mesg_E3 lda _stash+1 jsr PRBYTE lda #" " jsr COUT lda #"%" jsr COUT lda _stash+1 jsr PRBIN PRINTSTRING Mesg_E4 lda _stash jsr PRBYTE lda #" " jsr COUT lda #"%" jsr COUT lda _stash jsr PRBIN :skipit jsr WinFull clc xce rep $10 ;take me out? but make sure to mx% plp ;M can be 0 or 1 depending on test size PopAll rts *Mesg_Error0 asc "Error: Bad Read Pass 0000 Location: 00/1234" *Mesg_Error0 asc "Wrote: $00 %12345678 Read: $00 %12345678" TestRollBack lda TestDirection eor #$01 sta TestDirection jsr TestAdvanceLocation lda TestDirection eor #$01 sta TestDirection rts TestForceUpdateStatus PushAll stx _stash bra :print TestUpdateStatus ldy _updateTick cpy #_updateInterval bcc :noprint PushAll stx _stash ; save real X ldy #$0000 sty _updateTick :print sep #$10 ;in case? there was a sec xce combo here GOXY #66;#12 lda CurBank jsr PRBYTE lda #"/" jsr COUT lda _stash+1 ldx _stash jsr PRNTAX clc xce rep #$10 PopAll :noprint ldy _updateTick iny sty _updateTick rts _updateTick dw #0 _updateInterval = #$0200 ;327 works well TestMemoryLocation lda _testState cmp #TESTSTATE_BOTH bne TestMemoryLocationTwoPass lda TestSize16Bit bne :test16 :test8 lda TestType cmp #TT_BITPATTERN bne :checkrand jmp Test_8BitPatternWR :checkrand cmp #TT_RANDOM bne :checkwalk0 jmp Test_8RandomWR :checkwalk0 cmp #TT_BITWALK0 bne :checkwalk1 jmp Test_8BitWalk0WR :checkwalk1 cmp #TT_BITWALK1 bne :UNHANDLED jmp Test_8BitWalk1WR :test16 rep #$30 ;full 16-bit for long M lda TestType and #$00ff cmp #TT_BITPATTERN bne :check16rand jmp Test_16BitPatternWR :check16rand cmp #TT_RANDOM bne :check16walk0 jmp Test_16RandomWR :check16walk0 cmp #TT_BITWALK0 bne :check16walk1 jmp Test_16BitWalk0WR :check16walk1 cmp #TT_BITWALK1 bne :UNHANDLED jmp Test_16BitWalk1WR :UNHANDLED sep #$30 rep #$10 rts *********************** ************************* TWO PASS !! **************************** ******************************** ************************************ ***************************************** TestMemoryLocationTwoPass lda TestSize16Bit bne :test16 :test8 lda TestType ;8-bit tests cmp #TT_BITPATTERN bne :checkrand jmp Test_8BitPatternTP :checkrand cmp #TT_RANDOM bne :checkwalk0 jmp Test_8RandomTP :checkwalk0 cmp #TT_BITWALK0 bne :checkwalk1 jmp Test_8BitWalk0TP :checkwalk1 cmp #TT_BITWALK1 bne :UNHANDLED jmp Test_8BitWalk1TP :test16 rep #$30 ;full 16-bit for long M lda TestType and #$00ff cmp #TT_BITPATTERN bne :check16rand jmp Test_16BitPatternTP :check16rand cmp #TT_RANDOM bne :check16walk0 jmp Test_16RandomTP :check16walk0 cmp #TT_BITWALK0 bne :check16walk1 jmp Test_16BitWalk0TP :check16walk1 cmp #TT_BITWALK1 bne :UNHANDLED jmp Test_16BitWalk1TP :UNHANDLED sep #$30 rep #$10 rts ******************************** * * * TWO PASS TESTS * * * ******************************** mx %10 Test_8BitWalk0TP phx lda TwoPassWalkState tax lda _walkTbl8B0,x sta HexPattern plx jmp Test_8BitPatternTP _walkTbl8B0 db #%01111111 db #%10111111 db #%11011111 db #%11101111 db #%11110111 db #%11111011 db #%11111101 db #%11111110 mx %10 Test_8BitWalk1TP phx lda TwoPassWalkState tax lda _walkTbl8B1,x sta HexPattern plx jmp Test_8BitPatternTP _walkTbl8B1 db #%10000000 db #%01000000 db #%00100000 db #%00010000 db #%00001000 db #%00000100 db #%00000010 db #%00000001 Test_8RandomTP jsr GetRandByte ;should match with seeds? sta HexPattern jmp Test_8BitPatternTP TwoPassWalkState dw 0 ;use to track in two pass mode (I treat this like a byte in places) TwoPassSeed dw #$0000 ;we store the pass at the beginning of each write round, and restore it for the read round Test_8BitPatternTP lda _testState cmp #TESTSTATE_READ beq :read :write ldy TestWriteRepeat _writeloop2 lda HexPattern stal $020000,x BANKPATCH10 = *-1 dey bne _writeloop2 jsr CORRUPTOR rts :read ldy TestReadRepeat _readloop3 ldal $020000,x BANKPATCH11 = *-1 cmp HexPattern bne :readerror dey bne _readloop3 rts :readerror jsr TestLogError jsr TestPrintErrors jsr TestNoiseError jsr TestPauseError rts mx %00 mx %00 * 16-bit two-pass tests Test_16BitWalk1TP phx lda TwoPassWalkState and #$00ff asl tax lda _walkTbl16B1,x sta HexPattern plx jsr Test_16BitPatternTP sep #$20 rts mx %00 _walkTbl16B1 dw #%1000000000000000 dw #%0100000000000000 dw #%0010000000000000 dw #%0001000000000000 dw #%0000100000000000 dw #%0000010000000000 dw #%0000001000000000 dw #%0000000100000000 dw #%0000000010000000 dw #%0000000001000000 dw #%0000000000100000 dw #%0000000000010000 dw #%0000000000001000 dw #%0000000000000100 dw #%0000000000000010 dw #%0000000000000001 Test_16BitWalk0TP phx lda TwoPassWalkState and #$00ff asl tax lda _walkTbl16B0,x sta HexPattern plx jsr Test_16BitPatternTP sep #$20 rts mx %00 _walkTbl16B0 dw #%0111111111111111 dw #%1011111111111111 dw #%1101111111111111 dw #%1110111111111111 dw #%1111011111111111 dw #%1111101111111111 dw #%1111110111111111 dw #%1111111011111111 dw #%1111111101111111 dw #%1111111110111111 dw #%1111111111011111 dw #%1111111111101111 dw #%1111111111110111 dw #%1111111111111011 dw #%1111111111111101 dw #%1111111111111110 Test_16RandomTP jsr GetRandByte16 sta HexPattern jsr Test_16BitPatternTP sep #$20 rts mx %00 *Test_16BitPatternWR jsr Test_16Bit sep #$20 rts mx %00 Test_16BitPatternTP lda _testState cmp #TESTSTATE_READ beq :read16 :write16 ldy TestWriteRepeat _writeloop3 lda HexPattern stal $020000,x BANKPATCH12 = *-1 dey bne _writeloop3 PushAll sep #$20 jsr CORRUPTOR clc xce rep #$30 PopAll sep #$20 rts mx %00 :read16 ldy TestReadRepeat _readloop4 ldal $020000,x BANKPATCH13 = *-1 cmp HexPattern bne :readerror dey bne _readloop4 sep $20 rts :readerror sep $20 jsr TestLogError jsr TestPrintErrors jsr TestNoiseError jsr TestPauseError rts mx %10 ;still shortM longX * 8-bit W/R TESTS Test_8BitWalk0WR lda #%01111111 sta HexPattern jsr Test_8BitPatternWR lda #%10111111 sta HexPattern jsr Test_8BitPatternWR lda #%11011111 sta HexPattern jsr Test_8BitPatternWR lda #%11101111 sta HexPattern jsr Test_8BitPatternWR lda #%11110111 sta HexPattern jsr Test_8BitPatternWR lda #%11111011 sta HexPattern jsr Test_8BitPatternWR lda #%11111101 sta HexPattern jsr Test_8BitPatternWR lda #%11111110 sta HexPattern jmp Test_8BitPatternWR Test_8BitWalk1WR lda #%10000000 sta HexPattern jsr Test_8BitPatternWR lda #%01000000 sta HexPattern jsr Test_8BitPatternWR lda #%00100000 sta HexPattern jsr Test_8BitPatternWR lda #%00010000 sta HexPattern jsr Test_8BitPatternWR lda #%00001000 sta HexPattern jsr Test_8BitPatternWR lda #%00000100 sta HexPattern jsr Test_8BitPatternWR lda #%00000010 sta HexPattern jsr Test_8BitPatternWR lda #%00000001 sta HexPattern jmp Test_8BitPatternWR Test_8RandomWR jsr GetRandByte sta HexPattern jmp Test_8BitPatternWR Test_8BitPatternWR ldy TestWriteRepeat _writeloop lda HexPattern stal $020000,x BANKPATCH01 = *-1 lda TestAdjacentWrite beq _noAdjacentWrite stal $02FFFF,x ;-1 BANKPATCH02 = *-1 stal $020001,x ;+1 BANKPATCH03 = *-1 _noAdjacentWrite dey bne _writeloop jsr CORRUPTOR ldy TestReadRepeat _readloop2 ldal $020000,x BANKPATCH04 = *-1 cmp HexPattern bne :readerror dey bne _readloop2 rts :readerror jsr TestLogError jsr TestPrintErrors jsr TestNoiseError jsr TestPauseError rts * 16-bit W/R TESTS mx %00 Test_16BitWalk0WR lda #%0111111111111111 sta HexPattern jsr Test_16Bit lda #%1011111111111111 sta HexPattern jsr Test_16Bit lda #%1101111111111111 sta HexPattern jsr Test_16Bit lda #%1110111111111111 sta HexPattern jsr Test_16Bit lda #%1111011111111111 sta HexPattern jsr Test_16Bit lda #%1111101111111111 sta HexPattern jsr Test_16Bit lda #%1111110111111111 sta HexPattern jsr Test_16Bit lda #%1111111011111111 sta HexPattern jsr Test_16Bit lda #%1111111101111111 sta HexPattern jsr Test_16Bit lda #%1111111110111111 sta HexPattern jsr Test_16Bit lda #%1111111111011111 sta HexPattern jsr Test_16Bit lda #%1111111111101111 sta HexPattern jsr Test_16Bit lda #%1111111111110111 sta HexPattern jsr Test_16Bit lda #%1111111111111011 sta HexPattern jsr Test_16Bit lda #%1111111111111101 sta HexPattern jsr Test_16Bit lda #%1111111111111110 sta HexPattern jsr Test_16Bit sep #$20 rts mx %00 Test_16BitWalk1WR lda #%1000000000000000 sta HexPattern jsr Test_16Bit lda #%0100000000000000 sta HexPattern jsr Test_16Bit lda #%0010000000000000 sta HexPattern jsr Test_16Bit lda #%0001000000000000 sta HexPattern jsr Test_16Bit lda #%0000100000000000 sta HexPattern jsr Test_16Bit lda #%0000010000000000 sta HexPattern jsr Test_16Bit lda #%0000001000000000 sta HexPattern jsr Test_16Bit lda #%0000000100000000 sta HexPattern jsr Test_16Bit lda #%0000000010000000 sta HexPattern jsr Test_16Bit lda #%0000000001000000 sta HexPattern jsr Test_16Bit lda #%0000000000100000 sta HexPattern jsr Test_16Bit lda #%0000000000010000 sta HexPattern jsr Test_16Bit lda #%0000000000001000 sta HexPattern jsr Test_16Bit lda #%0000000000000100 sta HexPattern jsr Test_16Bit lda #%0000000000000010 sta HexPattern jsr Test_16Bit lda #%0000000000000001 sta HexPattern jsr Test_16Bit sep #$20 rts mx %00 Test_16RandomWR jsr GetRandByte16 sta HexPattern jsr Test_16Bit sep #$20 rts mx %00 Test_16BitPatternWR jsr Test_16Bit sep #$20 rts mx %00 * the real test function for 16-bit Test_16Bit ldy TestWriteRepeat _writeloop16 lda HexPattern stal $020000,x BANKPATCH05 = *-1 lda TestAdjacentWrite beq _noAdjacentWrite16 _adjacentWrite16 stal $02FFFE,x ;-1 BANKPATCH06 = *-1 stal $020002,x ;+1 BANKPATCH07 = *-1 _noAdjacentWrite16 dey bne _writeloop16 sep #$20 ;????????????????? jsr CORRUPTOR clc xce rep #$30 ;???????????????????? ldy TestRefreshPause beq :nopause :outer dey bne :outer :nopause ldy TestReadRepeat _readloop16 ldal $020000,x BANKPATCH08 = *-1 cmp HexPattern bne _readerror16 dey bne _readloop16 rts _readerror16 sep #$20 jsr TestLogError jsr TestPrintErrors jsr TestNoiseError jsr TestPauseError clc xce rep #$30 rts mx %10 TestAdvanceLocation lda TestDirection bne :dn :up lda TestSize16Bit beq :up8 :up16 inx beq :hitBankBoundry :up8 inx beq :hitBankBoundry ;rollover cpx EndAddr ;sets carry if we are past/done bcs :done rts :dn lda TestSize16Bit beq :dn8 :dn16 cpx #0 beq :hitBankBoundry dex ; cpx #0 beq :hitBankBoundryTest ;we still need to test in this case. side effect of odd start/ends bra :testStartAddr :dn8 cpx #0 beq :hitBankBoundry dex :testStartAddr cpx StartAddr bcc :done :hitBankBoundryTest clc rts :done :hitBankBoundry sec rts TestGetStartAddress lda TestDirection bne :dn :up ldx StartAddr rts :dn ldx EndAddr :addressSet rts TestPastFinalBank lda TestDirection bne :descending :ascending lda EndBank cmp CurBank ;is EndBank < CurBank ? bcc :yes ;past final bank bcs :no :descending lda CurBank cmp StartBank ;is CurBank < StartBank ? bcc :yes bcs :no :yes sec rts :no clc rts TestTwoPassRestoreSeed lda TwoPassSeed+1 ;if we are on a read pass, restore our seed sta _seed16a sta _seed lda TwoPassSeed sta _seed16b rts TestTwoPassMakeSeed jsr GetRandByte ;update our two-pass seed (even if we aren't in random mode. too lazy to check.) sta TwoPassSeed ; sta _seed16b sta _seed jsr GetRandByte ; sta TwoPassSeed+1 ; sta _seed16a rts * TWO PASS has lots of exceptions where it doesn't advance the bank right away TestGetNextBank lda CurBank bne :notInitialBank ;can't be bank 00 so we must be starting a new test jmp SetInitialBank ;will RTS back - THIS IS THE SAME FOR ALL TESTS :notInitialBank lda TestTwoPass ;see if we are doing two-passes of the bank bne :TwoPass ;nope, no additional logic needed jmp SetNextBank ;regular way to advance the bank :TwoPass jsr TwoPassBankLogics bcs SetNextBank rts * Just sets the CurBank to either the StartAddr or EndAddr, depending on direction SetInitialBank lda TestDirection bne :descending :ascending lda StartBank bra :storeInitialBank :descending lda EndBank :storeInitialBank sta CurBank rts * INCs or DECs CurBank, depending on direction. No value checking at all. SetNextBank lda TestDirection bne :descending inc CurBank rts :descending dec CurBank rts * This is really TestGetNextBank for TwoPass!!! * Set CARRY on return to advance bank TwoPassBankLogics lda _testState cmp #TESTSTATE_READ ;don't change bank on read pass of two-pass. (we read during this pass) bne :checkWrite lda TestType :checkReadPattern cmp #TT_BITPATTERN bne :checkReadRandom clc rts :checkReadRandom cmp #TT_RANDOM bne :checkReadBitwalk0 jsr TestTwoPassRestoreSeed ;for RANDOM, restore our write seed clc rts :checkReadBitwalk0 cmp #TT_BITWALK0 bne :checkReadBitwalk1 clc rts :checkReadBitwalk1 cmp #TT_BITWALK1 bne :unknown clc rts :checkWrite ;we're in write mode. lda TestType :checkWritePattern cmp #TT_BITPATTERN bne :checkWriteRandom sec rts :checkWriteRandom cmp #TT_RANDOM bne :checkWriteBitwalk0 jsr TestTwoPassMakeSeed ;for RANDOM, make a write seed sec rts :checkWriteBitwalk0 cmp #TT_BITWALK0 bne :checkWriteBitwalk1 jmp TestUpdateWalkState ;for BITWALK0, update walkpass and SEC when loops :checkWriteBitwalk1 cmp #TT_BITWALK1 bne :unknown jmp TestUpdateWalkState ;for BITWALK1, update walkpass and SEC when loops :unknown sec ;unknown - advance? should not occur. rts * sets carry when last test complete TestUpdateWalkState inc TwoPassWalkState ;walkstate++ lda TestSize16Bit bne :walk16 :walk8 lda TwoPassWalkState cmp #8 beq :resetWalkState clc rts :walk16 lda TwoPassWalkState cmp #16 beq :resetWalkState clc rts :resetWalkState ;walkstate=0 stz TwoPassWalkState sec rts TestPatchBanks lda CurBank sta BANKPATCH01 sta BANKPATCH02 sta BANKPATCH03 sta BANKPATCH04 sta BANKPATCHXX ;corruptor! sta BANKPATCH05 sta BANKPATCH06 sta BANKPATCH07 sta BANKPATCH08 sta BANKPATCH10 ;two pass start here sta BANKPATCH11 sta BANKPATCH12 sta BANKPATCH13 rts CORRUPTOR lda $C000 bpl _nokey and #11101111 cmp #"c" jsr GetRandTrash ;careful... this is 8-bit code. make sure M=1 ;lda #$55 stal $020000,x BANKPATCHXX = *-1 sta $C010 ; clear it or we can't test WaitOnError _nokey nop rts mx %11 _testIteration ds 8 _testErrors ds 8 _testState ds 2 ;1=read 2=write 3=both (read & write) TESTSTATE_READ = 1 TESTSTATE_WRITE = 2 TESTSTATE_BOTH = 3 UpdateScanInterval equ #$1000 Mesg_Welcome asc "Mini Memory Tester v1.0 - Copyright (c) 2015 by Dagen Brock",00 Mesg_Promo asc " Go to www.ultimateapple2.com for RAM cards and more for your Apple II!",$8D,$8D asc " Latest versions of this program at github.com/digarok/mmt",00 Mesg_InternalRam256 asc "Built-In RAM 256K",00 Mesg_InternalRam1024 asc "Built-In RAM 1024K",00 Mesg_ExpansionRam asc "Expansion RAM ",00 Mesg_Rom asc "Apple IIgs ROM ",00 Mesg_UserManual asc "USE ARROW KEYS TO MOVE - USE ENTER TO SELECT/EDIT",00 Mesg_Starting asc $8D,"Starting Test",$8D,"Press P to pause, ESC to stop.",$8D,$8D,00 Mesg_Waiting asc " Waiting: ",00 Mesg_Writing asc " Writing: ",00 Mesg_Reading asc " Reading: ",00 Mesg_WR asc "Write&Read: ",00 Mesg_Errors asc " Errors: ",$00 Mesg_TestPass asc " Test Pass: ",00 Mesg_Blank asc " ",00 Mesg_DetectedBanks asc "Setting default start/end banks to detected memory expansion: $",00 Mesg_ToBank asc " to $",00 Mesg_TestError1 asc "Error: Press any",00 Mesg_TestError2 asc "key to continue.",00 * Error message strings Mesg_E1 asc "Bad Read - Pass ",00 Mesg_E2 asc " Location: ",00 Mesg_E3 asc "Wrote: $",00 Mesg_E4 asc " ",$1B,'SU',$18," Read: $",00 Mesg_Arrow asc $1B,'SU',$18,00 Mesg_F1 asc "ERR #",00 Mesg_F2 asc " Pass #",00 Mesg_F3 asc " Rep #",00 Mesg_F4 asc " Addr. $",00 Mesg_F5 asc " Wrote $",00 Mesg_F6 asc " ",$1B,'U',$18," Read $",00 mx %10 ;i think? * called with short M, long X PrintTestError sep $30 inc _testErrors bne :noRoll inc _testErrors+1 :noRoll PRINTXY #55;#11;Mesg_Errors ldx _testErrors lda _testErrors+1 jsr PRNTAX jsr WinConsole LOG Mesg_E1 ldx _testIteration lda _testIteration+1 jsr PRNTAX PRINTSTRING Mesg_E2 lda CurBank jsr PRBYTE lda #"/" jsr COUT lda _stash+3 ldx _stash+2 jsr PRNTAX lda #$8D jsr COUT LOG Mesg_E3 lda _stash+1 jsr PRBYTE lda #" " jsr COUT lda #"%" jsr COUT lda _stash+1 jsr PRBIN PRINTSTRING Mesg_E4 lda _stash jsr PRBYTE lda #" " jsr COUT lda #"%" jsr COUT lda _stash jsr PRBIN jsr WinFull clc xce rep $10 rts *Mesg_Error0 asc "Error: Bad Read Pass 0000 Location: 00/1234" *Mesg_Error0 asc "Wrote: $00 %12345678 Read: $00 %12345678" mx %11 PRBIN pha phx ldx #8 :loop asl pha bcc :zero :one lda #"1" jsr COUT bra :ok :zero lda #"0" jsr COUT :ok pla dex bne :loop plx pla rts Pauser PRINTXY #55;#13;Mesg_Waiting ldy #60 ldx TestRefreshPause beq :donepause jsr PrintTimerVal ; inaugural print before waiting 1 sec :secondloop :wait ldal $e1c019 bpl :wait :wait2 ldal $e1c019 bmi :wait2 dey bne :secondloop dex beq :donepause jsr PrintTimerVal ldy #60 bra :secondloop :donepause PRINTXY #55;#13;Mesg_Blank rts PrintTimerVal phx phy txa GOXY #65;#13 ply plx txa jsr PRBYTE rts * possible EOR values *$1d (29) *$2b (43) *$2d (45) *$4d (77) *$5f (95) *$63 (99) *$65 (101) *$69 (105) *$71 (113) *$87 (135) *$8d (141) *$a9 (169) *$c3 (195) *$cf (207) *$e7 (231) *$f5 (245) * This is ridiculously poorly implemented. Don't care. mx $00 GetRandByte16 PushAll ShortMX lda _seed16a beq :doEor asl bcc :noEor :doEor eor #$a9 :noEor sta _seed16a lda _seed16b beq :doEorB asl bcc :noEorB :doEorB eor #$5f :noEorB sta _seed16b Full16 PopAll lda _seed16a rts _seed16a db 03 _seed16b db 40 mx %11 GetRandByte ; USE ONLY WITH CORRUPTOR lda _seed beq :doEor asl bcc :noEor :doEor eor #$2b :noEor sta _seed rts _seed db 0 GetRandTrash ; USE ONLY WITH CORRUPTOR lda _randomTrashByte beq :doEor asl bcc :noEor :doEor eor #$1d :noEor sta _randomTrashByte rts _randomTrashByte db 0 * * #### ###### ##### ##### # # # #### #### * # # # # # ## # # # # * #### ##### # # # # # # # #### * # # # # # # # # # ### # * # # # # # # # ## # # # # * #### ###### # # # # # #### #### *@todo better defaults * 00 - Byte : Selected Value * 01 - Byte : Number of values * 02... - Words : Table of Addresses of possible values TestTypeTbl TestType db 00 ; actual CONST val db 04 ; number of possible values da TestType_BitPattern,TestType_BitWalk1,TestType_BitWalk0,TestType_Random,00,00 TestType_BitPattern asc "bit pattern",$00 TestType_BitWalk1 asc " bit walk 1",$00 TestType_BitWalk0 asc " bit walk 0",$00 TestType_Random asc " random ",$00 TT_BITPATTERN = 0 TT_BITWALK1 = 1 TT_BITWALK0 = 2 TT_RANDOM = 3 TestDirectionTbl TestDirection db 0 db 2 da _testDirectionUp,_testDirectionDown,00,00 _testDirectionUp asc "up",$00 _testDirectionDown asc "dn",$00 TestSizeTbl TestSize16Bit db 01 ;0=no ... 8bit, 1=yes ... 16 bit db 02 da _TestSize_0,_TestSize_1 _TestSize_0 asc " 8-bit",$00 _TestSize_1 asc "16-bit",$00 MenuStr_BeginTestJSR da TestInit ; MUST PRECEDE MENU STRING! Yes, it's magicly inferred. (-2) MenuStr_BeginTest asc " BEGIN TEST " MenuStr_BeginTestL equ #*-MenuStr_BeginTest MenuStr_BeginTestE db 00 StartBank db #$06 EndBank db #$1F CurBank db #0 StartAddr dw #$0000 EndAddr dw #$FFFF HexPattern dw #$0000 TestTwoPass dw #0 ; bool is byte, but might change in future? :P TestAdjacentWrite dw #0 ; bool is byte, but might change in future? :P TestRefreshPause dw #$00 ; int TestReadRepeat dw #$01 ; int TestWriteRepeat dw #$01 ; int TestIterations dw #$00 ; int TestErrorPause dw #0 ;bool TestErrorSound dw #0 ;bool * * # # ###### # # # # * ## ## # ## # # # * # ## # ##### # # # # # * # # # # # # # # * # # # # ## # # * # # ###### # # #### MainMenuDefs :StartBank hex 19,05 ; x,y db Menu_TypeHex ; 1=hex input db 01 ; memory size (bytes) da StartBank ; variable storage :EndBank hex 22,05 ; x,y db Menu_TypeHex ; 1=hex input db 01 ; memory size (bytes) da EndBank ; variable storage :StartAddr hex 19,06 ; x,y db Menu_TypeHexByteOrder ; 1=hex input db 02 ; memory size (bytes) da StartAddr ; variable storage :EndAddr hex 20,06 ; x,y db Menu_TypeHexByteOrder ; 1=hex input db 02 ; memory size (bytes) da EndAddr ; variable storage :TestType hex 19,07 ; x,y db Menu_TypeList ; 3=list input db 11 ; max len size (bytes), 3=option list da TestTypeTbl ; params definition & storage :TestSize hex 28,07 ; x,y db Menu_TypeList ; 3=list input db 6 ; max len size (bytes), 3=option list da TestSizeTbl ; params definition & storage :HexPattern hex 19,08 ; x,y db Menu_TypeHex ; 3=list input _hexpatternsize db 02 ; max len size (bytes), 3=option list <- can change when 8 bit?? da HexPattern ; params definition & storage :BinPattern hex 19,09 ; x,y db Menu_TypeBin ; 5?=bin _binpatternsize db 02 ; max len size (bytes), 3=option list <- can change when 8 bit?? da HexPattern ; params definition & storage <- uses same space as above!! just different representation :Direction hex 19,0A db Menu_TypeList db 2 da TestDirectionTbl :TestErrorSound hex 12,0B ; x,y db Menu_TypeBool ; 1=hex input db 2 ; could be 8-bit or 16-bit bool da TestErrorSound ; variable storage :TestErrorPause hex 28,0B ; x,y db Menu_TypeBool ; 1=hex input db 2 ; could be 8-bit or 16-bit bool da TestErrorPause ; variable storage :AdjacentWrite hex 12,0C ; x,y db Menu_TypeBool ; 1=hex input db 01 ; memory size (bytes) da TestAdjacentWrite ; variable storage :TwoPass hex 28,0C db Menu_TypeBool db 2 ; could be 8-bit or 16-bit bool da TestTwoPass :ReadRepeat hex 12,0D ; x,y db Menu_TypeInt ; 1=hex input db 03 ; display/entry width. ints are 16-bit internally da TestReadRepeat ; variable storage :WriteRepeat hex 28,0D ; x,y db Menu_TypeInt ; 1=hex input db 03 ; display/entry width. ints are 16-bit internally da TestWriteRepeat ; variable storage :TestIterations hex 12,0E ; x,y db Menu_TypeInt ; 1=hex input db 03 ; display/entry width. ints are 16-bit internally da TestIterations ; variable storage :TestRefreshPause hex 28,0E ; x,y db Menu_TypeInt ; 1=hex input db 03 ; display/entry width. ints are 16-bit internally da TestRefreshPause ; variable storage :BeginTest hex 3A,0E ; x,y db Menu_TypeAction ; 2=action db MenuStr_BeginTestL ; menu string length da MenuStr_BeginTest ; string storage MainMenuLen equ *-MainMenuDefs MainMenuItems equ MainMenuLen/6 MainMenuEnd dw 0000 Menu_ItemSelected db 0 * special helper functions to update some input sizes when * the user switches between 8 and 16 bit testing modes * ... also disable AdjacentWrite if TwoPass MenuUpdateConfig lda TestSize16Bit bne :is16bit :is8bit jsr MenuFixMax8 jmp MenuSet8Bit :is16bit jsr MenuFixMax16 jmp MenuSet16Bit MenuSet16Bit lda #2 bra MenuSetBits MenuSet8Bit jsr MenuClearPatterns ;clear leftover chars because strings are shorter now lda #1 MenuSetBits sta _hexpatternsize sta _binpatternsize :checkTwoPass lda TestTwoPass ;now check TwoPass/AdjacentWrite conflict cmp _lastTwoPass ;i wish this was simpler code beq :checkAdjacentWrite ;some computer science dude could probably help me out here sta _lastTwoPass stz TestAdjacentWrite stz _lastAdjacentWrite bra :done :checkAdjacentWrite lda TestAdjacentWrite cmp _lastAdjacentWrite beq :done sta _lastAdjacentWrite stz TestTwoPass stz _lastTwoPass :done rts _lastTwoPass db 0 _lastAdjacentWrite db 0 MenuFixMax16 Full16 lda EndAddr cmp #$FFFF bne :noneed dec EndAddr :noneed ShortMX rts MenuFixMax8 Full16 lda EndAddr cmp #$FFFE bne :noneed inc EndAddr :noneed ShortMX rts * hack to allow for smaller portion of screen to update MenuClearPatterns PRINTXY #$17;#$8;_clearstring PRINTXY #$17;#$9;_clearstring rts _clearstring asc " ",$00 MainMenuStrs asc " ______________________________________________________________________________",$8D,$00 asc $1B,'ZV_@ZVWVWVWV_',"Mini Memory Tester v1.0",'ZVWVWVWVWVWVWVWVWVWVW_',"UltimateMicro",'ZWVWVWVW_',$18,$00 asc $1B,'ZLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL_',$18,00 asc $1B,'ZZ \GGGGGGGGGGGGG_',"Test Settings",'ZGGGGGGGGGGGGG\ _'," ",'Z \GGGGGGGG_',"Info",'ZGGGGGGGG\ _'," ",'_',$18,00 asc $1B,'ZZ'," ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Start/End Bank : / ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Start/End Address : / ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Test Type : ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Hex Pattern : ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Bin Pattern : ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Test Direction : ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Error Sound Wait on Error ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Adjacent Wr. Two-Pass W/R ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Read Repeat Write Repeat ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZZ'," Iterations Refresh Pause ",'_'," ",'Z'," ([ BEGIN TEST ]) ",'_'," ",'_',$18,00 asc $1B,'ZZ'," ",'_'," ",'Z'," ",'_'," ",'_',$18,00 asc $1B,'ZLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL_',$18,00 asc $1B,'Z'," ",'_',$18,00 asc $1B,'Z'," ",'_',$18,00 asc $1B,'Z'," ",'_',$18,00 asc $1B,'Z'," ",'_',$18,00 asc $1B,'Z'," ",'_',$18,00 asc $1B,'Z'," _",'_',$18,00 asc $1B,'Z',"_____________________________________________________________________________",'_',$18,00 hex 00,00 * Creates a 256 byte map of each bank, "BankRam" * The map shows whether it's Built-in RAM, ROM, Expansion RAM, etc. DetectRam lda #BankRAMFastBuiltIn ;these are universal to all IIgs sta BankMap+$00 ;bank 00 sta BankMap+$01 ;bank 01 lda #BankRAMSlowBuiltIn ; sta BankMap+$e0 ;bank e0 sta BankMap+$e1 ;bank e1 lda #BankROMUsed sta BankMap+$FE ;bank FE sta BankMap+$FF ;bank FF lda GSROM cmp #3 ;check for ROM3 IIgs bne :rom0or1 :rom3 lda #BankRAMFastBuiltIn ldx #$02 ;bank 02 :builtinram sta BankMap,x ;bank 02 inx cpx #$10 ;stop after bank 0F bcc :builtinram lda #BankROMUsed ;ROM 3 is 256KB, so 4 banks (2 additional) sta BankMap+$FC ; sta BankMap+$FD ; ldx #$FB ;ROM3 starts scan at bank FC txy bra :writeloop :rom0or1 ;no additional mappings lda #$02 ;ROM1 end bank FE sta :endbankscan+1 ;but change our min scan bank sta :endbankscan2+1 ;but change our min scan bank ldx #$FE ;ROM0/1 starts scan at bank FE txy :writeloop txa ;we'll store the bank number sta :writer+3 ;overwrite bank address eor #$FF ;INVERT :writer stal $000000 ;should overwrite first byte dex cpx #$EF bne :endbankscan ldx #$DF ;skip to bank DF (skip banks E0-EF) :endbankscan cpx #$10 ;ROM3 end bank (default) bcs :writeloop ;blt tyx ;restore start bank :detectloopread txa sta :reader+3 eor #$FF sta :compare+1 :reader ldal $000000 :compare cmp #$00 bne :notused inc BankExpansionRam ;TotalMB++ lda #BankRAMFastExpansion ;store mapping sta BankMap,x :continue dex cpx #$EF bne :endbankscan2 ldx #$DF ;skip to bank F0 (skip banks E0-EF) :endbankscan2 cpx #$10 ;ROM3 end bank (default) bcs :detectloopread ;blt * This part looks for the lowest and highest banks to pre-populate * the Start Bank and End Bank for the tests. ;let's find low/high to simplify things ldx #$ff :lowloop lda BankMap,x cmp #BankRAMFastExpansion beq :isRam dex cpx #$ff bne :lowloop bra :checkhigh :isRam stx BankExpansionLowest dex bra :lowloop :checkhigh ldx #$00 :highloop lda BankMap,x cmp #BankRAMFastExpansion beq :isRam2 inx bne :highloop bra :done :isRam2 stx BankExpansionHighest inx bra :highloop :done bra :findKB :notused lda #BankNoRAM sta BankMap,x bra :continue :findKB lda BankExpansionRam ;number of banks clc xce rep #$30 mx %00 and #$00FF ;clear artifacts? can't remember state of B asl ;*2 asl ;*4 asl ;*8 asl ;*16 asl ;*32 asl ;*64 sta BankExpansionRamKB lda GSROM ;now check (hardcode really) build-in ram cmp #3 bne :notrom3 :rom3 lda #1024 sta BankBuiltInRamKB bra :exit :notrom3 lda #256 sta BankBuiltInRamKB :exit sep #$30 rts PrintMemoryMap jsr CROUT ldx #$0 ldy #$0 :loop lda BankMap,x phy phx jsr PRBYTE lda #" " jsr COUT plx ply iny cpy #16 bne :noty jsr CROUT ldy #0 :noty inx bne :loop rts * Takes address in X/Y and prints out Int stored there PrintInt stx :loc+1 inx stx :loc2+1 sty :loc+2 sty :loc2+2 :loc ldx $2000 ;overwrite :loc2 ldy $2000 ;overwrite jsr BINtoBCD phx tya jsr PRBYTE pla jsr PRBYTE rts Quit jsr MLI ; first actual command, call ProDOS vector dfb $65 ; with "quit" request ($65) da QuitParm bcs Error brk $00 ; shouldn't ever here! QuitParm dfb 4 ; number of parameters dfb 0 ; standard quit type da $0000 ; not needed when using standard quit dfb 0 ; not used da $0000 ; not used Error brk $00 ; shouldn't be here either put misc put strings.s put menu.s ; BankROMUsed = 1 BankROMReserved = 2 BankRAMSlowBuiltIn = 3 BankRAMFastBuiltIn = 4 BankRAMFastExpansion = 5 BankNoRAM = 0 BorderColor db 0 BankExpansionRamKB ds 2 BankBuiltInRamKB ds 2 BankExpansionRam ds 1 BankExpansionLowest ds 1 BankExpansionHighest ds 1 ds \ BankMap ds 256 ;page-align maps just to make them easier to see _stash ds 256 ds \