From 6d1966d5002cf34d27785dc438f3448100ccc3fc Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Sat, 15 Aug 2026 00:44:13 -0400 Subject: [PATCH] Interrupt system implemented, some new programs. --- .gitignore | 3 + Programs/Libraries/print.asm | 22 +- Programs/gameOfLife/16x16LifeModern.asm | 266 +++++++++++++++++ Programs/makefile | 4 +- Programs/primeSieve/16bitSegmentedSieve.asm | 7 +- .../primeSieve/16bitSegmentedSieveModern.asm | 224 ++++++++++++++ Programs/primeSieve/8bitSieve.asm | 6 +- Programs/testPrograms/deviceTest.asm | 44 +++ .../testPrograms/diagnostics/alignOutside.asm | 11 + .../testPrograms/diagnostics/bareAlign.asm | 10 + .../testPrograms/diagnostics/bareInclude.asm | 10 + Programs/testPrograms/diagnostics/bareSWI.asm | 10 + .../diagnostics/duplicateLabel.asm | 14 + .../diagnostics/duplicateVector.asm | 20 ++ .../diagnostics/unknownVector.asm | 10 + Programs/testPrograms/dispatchTest.asm | 77 +++++ Programs/testPrograms/faultResumeTest.asm | 52 ++++ Programs/testPrograms/faultTest.asm | 15 + Programs/testPrograms/interruptExample.asm | 72 +++++ Programs/testPrograms/interruptFlagTest.asm | 45 +++ Programs/testPrograms/maskTest.asm | 44 +++ Programs/testPrograms/moveQTest.asm | 41 +++ Programs/testPrograms/paddingTest.asm | 43 +++ Programs/testPrograms/stackPointerTest.asm | 36 +++ Programs/testPrograms/swiFaultTest.asm | 30 ++ Programs/testPrograms/vectorTest.asm | 94 ++++++ README.md | 12 +- Source/Assembler/Assembler.c | 13 +- Source/Assembler/Assm-util.c | 55 +++- Source/Assembler/Assm-util.h | 20 ++ Source/Assembler/assembly.c | 10 + Source/Assembler/assembly.h | 44 +++ Source/Assembler/firstPass.c | 92 +++++- Source/Assembler/secondPass.c | 277 +++++++++++++++++- Source/Assembler/secondPass.h | 21 ++ Source/Emulator/bootstrap.c | 46 ++- Source/Emulator/cpu.c | 233 +++++++++++++-- Source/Emulator/cpu.h | 27 ++ Source/Emulator/emulator.c | 24 +- Source/Emulator/io.c | 39 +++ Source/Emulator/io.h | 16 + Source/Emulator/utility.c | 26 +- SplitBit Assembler Manual.md | 164 ++++++++++- SplitBit Programming Manual.md | 136 ++++++++- Tests/expected/16bitFibonacci.out | 1 + Tests/expected/16bitSegmentedSieve.out | 1 + Tests/expected/16bitSegmentedSieveModern.out | 3 + Tests/expected/16x16Life.out | 1 + Tests/expected/16x16LifeModern.out | 226 ++++++++++++++ Tests/expected/32bitFibonacci.out | 1 + Tests/expected/8bitFibonacci.out | 1 + Tests/expected/8bitSieve.out | 1 + Tests/expected/dataPointerTest.out | 1 + Tests/expected/deviceTest.out | 5 + Tests/expected/dispatchTest.out | 6 + Tests/expected/faultResumeTest.out | 4 + Tests/expected/faultTest.out | 3 + Tests/expected/hello.out | 1 + Tests/expected/inputTest.out | 1 + Tests/expected/inputTestOld.out | 1 + Tests/expected/int16print.out | 1 + Tests/expected/interruptExample.out | 5 + Tests/expected/interruptFlagTest.out | 3 + Tests/expected/maskTest.out | 5 + Tests/expected/mathTest.out | 1 + Tests/expected/moveQTest.out | 3 + Tests/expected/paddingTest.out | 3 + Tests/expected/pointerTableTest.out | 1 + Tests/expected/printHello.out | 1 + Tests/expected/printTest.out | 1 + Tests/expected/replCalculator.out | 1 + Tests/expected/stackPointerTest.out | 3 + Tests/expected/staticTableTest.out | 1 + Tests/expected/swiFaultTest.out | 4 + Tests/expected/twoPointerCopy.out | 1 + Tests/expected/vectorTest.out | 5 + Tests/manifest | 62 ++++ Tests/run.sh | 9 +- makefile | 34 ++- 79 files changed, 2778 insertions(+), 88 deletions(-) create mode 100644 Programs/gameOfLife/16x16LifeModern.asm create mode 100644 Programs/primeSieve/16bitSegmentedSieveModern.asm create mode 100644 Programs/testPrograms/deviceTest.asm create mode 100644 Programs/testPrograms/diagnostics/alignOutside.asm create mode 100644 Programs/testPrograms/diagnostics/bareAlign.asm create mode 100644 Programs/testPrograms/diagnostics/bareInclude.asm create mode 100644 Programs/testPrograms/diagnostics/bareSWI.asm create mode 100644 Programs/testPrograms/diagnostics/duplicateLabel.asm create mode 100644 Programs/testPrograms/diagnostics/duplicateVector.asm create mode 100644 Programs/testPrograms/diagnostics/unknownVector.asm create mode 100644 Programs/testPrograms/dispatchTest.asm create mode 100644 Programs/testPrograms/faultResumeTest.asm create mode 100644 Programs/testPrograms/faultTest.asm create mode 100644 Programs/testPrograms/interruptExample.asm create mode 100644 Programs/testPrograms/interruptFlagTest.asm create mode 100644 Programs/testPrograms/maskTest.asm create mode 100644 Programs/testPrograms/moveQTest.asm create mode 100644 Programs/testPrograms/paddingTest.asm create mode 100644 Programs/testPrograms/stackPointerTest.asm create mode 100644 Programs/testPrograms/swiFaultTest.asm create mode 100644 Programs/testPrograms/vectorTest.asm create mode 100644 Tests/expected/16bitSegmentedSieveModern.out create mode 100644 Tests/expected/16x16LifeModern.out create mode 100644 Tests/expected/deviceTest.out create mode 100644 Tests/expected/dispatchTest.out create mode 100644 Tests/expected/faultResumeTest.out create mode 100644 Tests/expected/faultTest.out create mode 100644 Tests/expected/interruptExample.out create mode 100644 Tests/expected/interruptFlagTest.out create mode 100644 Tests/expected/maskTest.out create mode 100644 Tests/expected/moveQTest.out create mode 100644 Tests/expected/paddingTest.out create mode 100644 Tests/expected/stackPointerTest.out create mode 100644 Tests/expected/swiFaultTest.out create mode 100644 Tests/expected/vectorTest.out diff --git a/.gitignore b/.gitignore index 979d941..4a9604e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ Tests/build/ +Programs/build/ Object/ Assembler SplitBit CLAUDE.md +resume +codexResume.sh diff --git a/Programs/Libraries/print.asm b/Programs/Libraries/print.asm index 56475ac..47587b3 100644 --- a/Programs/Libraries/print.asm +++ b/Programs/Libraries/print.asm @@ -132,21 +132,7 @@ DecimalValue: 0x00 ; The tens place. 0x00 ; The hundreds place. -; For convenience, I'll pad this out so programs using this library store their data in a fresh page of memory. - -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +; This library used to pad its data out to a whole page, so that anything including it +; started on a page boundary. That cost every program 253 bytes of zeroes to give one +; program a guarantee it could not ask for out loud. A program that needs a boundary now +; writes #Align in front of the thing that needs it. diff --git a/Programs/gameOfLife/16x16LifeModern.asm b/Programs/gameOfLife/16x16LifeModern.asm new file mode 100644 index 0000000..30e0c86 --- /dev/null +++ b/Programs/gameOfLife/16x16LifeModern.asm @@ -0,0 +1,266 @@ +; Conway's Game of Life rewritten for SplitBit's four-Data-Pointer ISA. +; +; The representation and display match 16x16Life.asm: a visible 16x16 field, +; a dead border, and interleaved current/next bytes. DP0 walks the board, DP1 +; and DP2 address the loop counters, and volatile DP3 walks the neighborhood. + +#Include print.asm + +#Program + +start: + CALL seedGlider + SETD.0 ClearScreen + CALL printString + +generationLoop: + CALL renderBoard + CALL evolveBoard + CALL commitBoard + CALL frameDelay + BRI generationLoop + +seedGlider: + SETD.0 Board + DPUP.0 0d42 + INIA 0x01 + STA.0 + SETD.0 Board + DPUP.0 0d80 + STA.0 + SETD.0 Board + DPUP.0 0d112 + STA.0 + DPUP.0 0d02 + STA.0 + DPUP.0 0d02 + STA.0 + RET + +renderBoard: + SETD.0 CursorHome + CALL printString + SETD.1 RowCount + SETD.2 ColCount + INIA 0d16 + STA.1 + SETD.0 Board + DPUP.0 0d38 + +renderRow: + INIA 0d16 + STA.2 +renderCell: + LDA.0 + BRA renderDead + INIB 0x23 + OUTB 0x00 + BRI renderCellDone +renderDead: + INIB 0x20 + OUTB 0x00 +renderCellDone: + DPUP.0 0d02 + LDA.2 + DECA + STA.2 + BRA renderRowDone + BRI renderCell + +renderRowDone: + CALL lineFeed + DPUP.0 0d04 + LDA.1 + DECA + STA.1 + BRA renderDone + BRI renderRow +renderDone: + RET + +evolveBoard: + SETD.1 RowCount + SETD.2 ColCount + INIA 0d16 + STA.1 + SETD.0 Board + DPUP.0 0d38 + +evolveRow: + INIA 0d16 + STA.2 +evolveCellLoop: + CALL evolveCell + DPUP.0 0d02 + LDA.2 + DECA + STA.2 + BRA evolveRowDone + BRI evolveCellLoop + +evolveRowDone: + DPUP.0 0d04 + LDA.1 + DECA + STA.1 + BRA evolveDone + BRI evolveRow +evolveDone: + RET + +evolveCell: + CALL countNeighbors + MVQB ; B is the neighbor count from here down. + + ; Three neighbors always produces a live cell. + INIA 0d03 + CCF + SUB + BRQ makeAlive + + ; Two neighbors preserve the current state. + INIA 0d02 + CCF + SUB + BRQ preserveCell + +makeDead: + RSTA + INCD.0 + STA.0 + DECD.0 + RET + +preserveCell: + LDA.0 + BRA makeDead + +makeAlive: + INIA 0x01 + INCD.0 + STA.0 + DECD.0 + RET + +; Return the eight-neighbor sum in Q. One Stack round-trip copies DP0 into +; volatile DP3; MVQA then keeps the running total entirely in registers. +countNeighbors: + PSHD.0 + POPD.3 + RSTA + DPDN.3 0d38 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d02 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d02 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d32 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d04 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d32 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d02 + + LDB.3 + CCF + ADD + MVQA + DPUP.3 0d02 + + LDB.3 + CCF + ADD + RET + +commitBoard: + SETD.1 RowCount + SETD.2 ColCount + INIA 0d18 + STA.1 + SETD.0 Board + +commitRow: + INIA 0d18 + STA.2 +commitCell: + INCD.0 + LDA.0 + DECD.0 + STA.0 + DPUP.0 0d02 + LDA.2 + DECA + STA.2 + BRA commitRowDone + BRI commitCell + +commitRowDone: + LDA.1 + DECA + STA.1 + BRA commitDone + BRI commitRow +commitDone: + RET + +frameDelay: + INIA 0xFF +delayOuter: + INIB 0xFF +delayInner: + DECB + BRB delayInnerDone + BRI delayInner +delayInnerDone: + DECA + BRA delayDone + BRI delayOuter +delayDone: + RET + +#Data + +RowCount: + 0x00 +ColCount: + 0x00 + +ClearScreen: + 0x1B + "[2J" +CursorHome: + 0x1B + "[H" + +; 18 by 18 cells with the current and next states interleaved, so 648 bytes. The +; original leaves this implicit and leans on Data Memory being zero, which works but +; means the assembler believes the board is one byte long: anything placed after it +; would land inside it, and nothing would say so. Reserving the region states how far +; it reaches, so a label added below here is safe. +Board: + #Reserve 0d648 diff --git a/Programs/makefile b/Programs/makefile index c7d1458..1770e89 100644 --- a/Programs/makefile +++ b/Programs/makefile @@ -28,7 +28,9 @@ PROGRAMS = \ Fibonacci/32bitFibonacci.asm \ primeSieve/8bitSieve.asm \ primeSieve/16bitSegmentedSieve.asm \ - gameOfLife/16x16Life.asm + primeSieve/16bitSegmentedSieveModern.asm \ + gameOfLife/16x16Life.asm \ + gameOfLife/16x16LifeModern.asm BINARIES = $(PROGRAMS:%.asm=$(BUILD)/%.bin) DEPENDENCIES = $(BINARIES:.bin=.d) diff --git a/Programs/primeSieve/16bitSegmentedSieve.asm b/Programs/primeSieve/16bitSegmentedSieve.asm index 26a1427..94576bf 100644 --- a/Programs/primeSieve/16bitSegmentedSieve.asm +++ b/Programs/primeSieve/16bitSegmentedSieve.asm @@ -157,7 +157,12 @@ printCandidateHex: #Data -; print.asm deliberately pads its data to one page, so this begins at 0x0100. +; This has to begin on a page boundary, and now says so itself rather than relying on +; whatever happens to have been assembled before it. The marking loop treats a carry out +; of the low byte as the end of the page, which only finds the right boundary if the +; window starts on one. + + #Align 0x100 Segment: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 diff --git a/Programs/primeSieve/16bitSegmentedSieveModern.asm b/Programs/primeSieve/16bitSegmentedSieveModern.asm new file mode 100644 index 0000000..b1c0ae1 --- /dev/null +++ b/Programs/primeSieve/16bitSegmentedSieveModern.asm @@ -0,0 +1,224 @@ +; The 16-bit segmented sieve rewritten for SplitBit's four-Data-Pointer ISA. +; +; This deliberately implements the same algorithm and emits the same text as +; 16bitSegmentedSieve.asm, making the two versions useful as a direct comparison. +; DP0 walks PrimeStates, DP1 holds Page, DP2 walks Segment, and volatile DP3 +; marks multiples. CALL preserves the first three pointers automatically. + +#Include print.asm + +#Program + +start: + RSTA + SETD.1 Page + STA.1 + +nextPage: + SETD.2 Segment + RSTA + RSTB +clearSegment: + STB.2 + INCD.2 + INCA + BRA segmentCleared + BRI clearSegment + +segmentCleared: + ; Zero and one are not prime. + LDA.1 + BRA excludeZeroAndOne + BRI markSegment +excludeZeroAndOne: + SETD.2 Segment + INIA 0x01 + STA.2 + INCD.2 + STA.2 + +markSegment: + SETD.0 PrimeStates + INIA 0d54 +primeLoop: + CALL processPrime + DPUP.0 0d03 + DECA + BRA scanSegment + BRI primeLoop + +scanSegment: + SETD.2 Segment + RSTA +scanLoop: + LDB.2 + BRB emitPrime +scanNext: + INCD.2 + INCA + BRA advancePage + BRI scanLoop + +emitPrime: + CALL printCandidateHex + BRI scanNext + +advancePage: + LDA.1 + INCA + STA.1 + BRA finished + BRI nextPage + +finished: + CALL lineFeed + HALT + +; DP0 points at a PrimeStates entry. CALL restores it on return. +processPrime: + INCD.0 + LDA.0 + LDB.1 + XOR + BRQ primeIsActive + RET + +primeIsActive: + ; B is the prime and A its current offset. + DECD.0 + LDB.0 + DPUP.0 0d02 + LDA.0 + + ; DP3 = Segment + offset. Only this one initial pointer copy needs the Stack. + SETD.3 Segment + PSHB + PSHD.3 + POPB + CCF + ADD + PSHQ + POPD.3 + POPB + +markPrimeLoop: + INIA 0x01 + STA.3 + + ; Add the prime to DP3's low byte. A carry crosses into the next window. + PSHD.3 + POPA + CCF + ADD + PSHQ + POPD.3 + BRC primeFinished + BRI markPrimeLoop + +primeFinished: + ; DP0 is on the offset byte; advance the saved high byte and save Q as + ; the wrapped offset for the following page. + DECD.0 + LDA.0 + INCA + STA.0 + INCD.0 + STQ.0 + RET + +printCandidateHex: + PSHA + LDA.1 + CALL printByteHex + POPA + CALL printByteHex + CALL blankSpace + RET + +#Data + +; Segment has to begin on a page boundary, and now says so itself rather than relying on +; whatever happens to have been assembled before it. The marking loop adds the prime to +; the low byte of DP3 and treats the carry out as the end of the page, so it only finds +; the right boundary if the window starts on one. +; +; The whole window is written out here so that Page and PrimeStates begin after it. + + #Align 0x100 +Segment: + 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + +Page: + 0x00 + +PrimeStates: + 0x02 0x00 0x04 + 0x03 0x00 0x09 + 0x05 0x00 0x19 + 0x07 0x00 0x31 + 0x0B 0x00 0x79 + 0x0D 0x00 0xA9 + 0x11 0x01 0x21 + 0x13 0x01 0x69 + 0x17 0x02 0x11 + 0x1D 0x03 0x49 + 0x1F 0x03 0xC1 + 0x25 0x05 0x59 + 0x29 0x06 0x91 + 0x2B 0x07 0x39 + 0x2F 0x08 0xA1 + 0x35 0x0A 0xF9 + 0x3B 0x0D 0x99 + 0x3D 0x0E 0x89 + 0x43 0x11 0x89 + 0x47 0x13 0xB1 + 0x49 0x14 0xD1 + 0x4F 0x18 0x61 + 0x53 0x1A 0xE9 + 0x59 0x1E 0xF1 + 0x61 0x24 0xC1 + 0x65 0x27 0xD9 + 0x67 0x29 0x71 + 0x6B 0x2C 0xB9 + 0x6D 0x2E 0x69 + 0x71 0x31 0xE1 + 0x7F 0x3F 0x01 + 0x83 0x43 0x09 + 0x89 0x49 0x51 + 0x8B 0x4B 0x79 + 0x95 0x56 0xB9 + 0x97 0x59 0x11 + 0x9D 0x60 0x49 + 0xA3 0x67 0xC9 + 0xA7 0x6C 0xF1 + 0xAD 0x74 0xE9 + 0xB3 0x7D 0x29 + 0xB5 0x7F 0xF9 + 0xBF 0x8E 0x81 + 0xC1 0x91 0x81 + 0xC5 0x97 0x99 + 0xC7 0x9A 0xB1 + 0xD3 0xAD 0xE9 + 0xDF 0xC2 0x41 + 0xE3 0xC9 0x49 + 0xE5 0xCC 0xD9 + 0xE9 0xD4 0x11 + 0xEF 0xDF 0x21 + 0xF1 0xE2 0xE1 + 0xFB 0xF6 0x19 diff --git a/Programs/primeSieve/8bitSieve.asm b/Programs/primeSieve/8bitSieve.asm index 78cf61d..9eafb1b 100644 --- a/Programs/primeSieve/8bitSieve.asm +++ b/Programs/primeSieve/8bitSieve.asm @@ -43,7 +43,11 @@ start: #Data -; The table of our prime candidates. +; The table of our prime candidates. It has to begin on a page boundary: marking walks +; the pointer's low byte and treats the carry out as running off the end of the table, +; which only finds the right end if the table starts on one. + + #Align 0x100 DataTop: 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 diff --git a/Programs/testPrograms/deviceTest.asm b/Programs/testPrograms/deviceTest.asm new file mode 100644 index 0000000..ce4093c --- /dev/null +++ b/Programs/testPrograms/deviceTest.asm @@ -0,0 +1,44 @@ +; Tests a hardware interrupt delivered to a handler named in the Vector Segment. +; +; A device is named by the port it is plugged into, because that is what decides which +; vector it arrives through. The test device on port 0x10 puts its line up when anything +; is written to it. +; +; The device is asked for attention while the Interrupt Flag is down, so the line waits. +; SIF lets it through, and the handler runs before the next instruction does. +; +; Correct output is: +; O printed with the line up and the flag down +; K printed by the handler +; ! printed after RETI came back + +#Program + +start: + CIF ; Hold devices off. + INIA 0d1 + OUTA 0x10 ; The device asks. Its line goes up and stays up. + + INIA 0d79 ; 'O' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + SIF ; Let it through. It is answered on the very next step. + + INIA 0d33 ; '!'. Reached only because RETI came back here. + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT + +deviceHandler: + INIA 0d75 ; 'K' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + RETI + +#Vectors + + Device 0x10 deviceHandler diff --git a/Programs/testPrograms/diagnostics/alignOutside.asm b/Programs/testPrograms/diagnostics/alignOutside.asm new file mode 100644 index 0000000..a907c19 --- /dev/null +++ b/Programs/testPrograms/diagnostics/alignOutside.asm @@ -0,0 +1,11 @@ +; #Align before either segment has been opened. +; +; The directive moves a cursor along, and outside a segment there is no cursor for +; it to move, so this has to be an error rather than quietly doing nothing. + + #Align 0x100 + +#Program + +start: + HALT diff --git a/Programs/testPrograms/diagnostics/bareAlign.asm b/Programs/testPrograms/diagnostics/bareAlign.asm new file mode 100644 index 0000000..bb4e324 --- /dev/null +++ b/Programs/testPrograms/diagnostics/bareAlign.asm @@ -0,0 +1,10 @@ +; #Align with no number after it. +; +; Without this check the next token is taken as the alignment, which would silently +; align to whatever the following instruction happened to be worth. + +#Program + +start: + HALT + #Align diff --git a/Programs/testPrograms/diagnostics/bareInclude.asm b/Programs/testPrograms/diagnostics/bareInclude.asm new file mode 100644 index 0000000..e0c184c --- /dev/null +++ b/Programs/testPrograms/diagnostics/bareInclude.asm @@ -0,0 +1,10 @@ +; Deliberately broken, to check that the assembler still catches it. +; The file ends straight after the keyword, so there is no name to read. This +; used to walk into whatever the array happened to hold and crash. + +#Program + +start: + HALT + +#Include diff --git a/Programs/testPrograms/diagnostics/bareSWI.asm b/Programs/testPrograms/diagnostics/bareSWI.asm new file mode 100644 index 0000000..41f1fdd --- /dev/null +++ b/Programs/testPrograms/diagnostics/bareSWI.asm @@ -0,0 +1,10 @@ +; SWI with nothing after it. +; +; Without the operand check this assembles, and SWI quietly takes the next +; instruction as its vector number. Everything after it then shifts by a byte. + +#Program + +start: + SWI + HALT diff --git a/Programs/testPrograms/diagnostics/duplicateLabel.asm b/Programs/testPrograms/diagnostics/duplicateLabel.asm new file mode 100644 index 0000000..0af7430 --- /dev/null +++ b/Programs/testPrograms/diagnostics/duplicateLabel.asm @@ -0,0 +1,14 @@ +; Deliberately broken, to check that the assembler still catches it. +; The same name is defined twice, which used to be accepted silently, with every +; reference quietly resolving to whichever definition came first. + +#Program + +start: + BRI twice + +twice: + HALT + +twice: + HALT diff --git a/Programs/testPrograms/diagnostics/duplicateVector.asm b/Programs/testPrograms/diagnostics/duplicateVector.asm new file mode 100644 index 0000000..7dcea04 --- /dev/null +++ b/Programs/testPrograms/diagnostics/duplicateVector.asm @@ -0,0 +1,20 @@ +; Two handlers claiming the same vector. +; +; Device lines name a port directly, so two of them can collide even though the +; assembler numbers the named vectors itself. + +#Program + +start: + HALT + +firstHandler: + RETI + +secondHandler: + RETI + +#Vectors + + Device 0x10 firstHandler + Device 0x10 secondHandler diff --git a/Programs/testPrograms/diagnostics/unknownVector.asm b/Programs/testPrograms/diagnostics/unknownVector.asm new file mode 100644 index 0000000..6fbc176 --- /dev/null +++ b/Programs/testPrograms/diagnostics/unknownVector.asm @@ -0,0 +1,10 @@ +; SWI names something that was never given a handler. +; +; A vector name is not a label, so the usual "undefined label" error would be +; misleading. It has to say that the name needs a #Vectors entry. + +#Program + +start: + SWI neverDeclared + HALT diff --git a/Programs/testPrograms/dispatchTest.asm b/Programs/testPrograms/dispatchTest.asm new file mode 100644 index 0000000..db91ed0 --- /dev/null +++ b/Programs/testPrograms/dispatchTest.asm @@ -0,0 +1,77 @@ +; Tests BRD, the only branch whose destination is not written into the program. +; +; A table of addresses in the Data Segment is walked with one Data Pointer, each +; entry is pulled out with LDD, and BRD jumps to it. That is dispatch: choosing +; where to go from data rather than from a branch the assembler laid down. +; +; Correct output is: +; one +; two +; three +; done + +#Program + +start: + SETD.0 Handlers ; DP0 walks the table of handler addresses. + INIB 0d3 ; Three of them. + +dispatchLoop: + LDD.1.0 ; DP1 becomes the address of the next handler. + BRD.1 ; Go there. The handler branches back to itself. + +; Each handler prints its name and returns to the loop by hand. There is no CALL +; here on purpose, so that what BRD does is the only thing under test. +handlerOne: + SETD.2 One + CALL printDP2 + BRI nextHandler + +handlerTwo: + SETD.2 Two + CALL printDP2 + BRI nextHandler + +handlerThree: + SETD.2 Three + CALL printDP2 + BRI nextHandler + +nextHandler: + DPUP.0 0d02 ; Step over the two byte table entry. + DECB + BRB finished + BRI dispatchLoop + +finished: + SETD.2 Done + CALL printDP2 + HALT + +printDP2: + LDA.2 + BRA printDone + OUTA 0x00 + INCD.2 + BRI printDP2 + printDone: + INIA 0x0A + OUTA 0x00 + RET + +#Data + +One: +"one" +Two: +"two" +Three: +"three" +Done: +"done" + +; The dispatch table. Each name becomes the address of that handler. +Handlers: +handlerOne +handlerTwo +handlerThree diff --git a/Programs/testPrograms/faultResumeTest.asm b/Programs/testPrograms/faultResumeTest.asm new file mode 100644 index 0000000..a4d2b4f --- /dev/null +++ b/Programs/testPrograms/faultResumeTest.asm @@ -0,0 +1,52 @@ +; Tests a fault handler that steps over the byte it could not decode and carries on. +; +; The frame holds the address of the offending byte rather than the one after it, so a +; handler can see exactly what failed. The cost is that returning with a bare RETI meets +; the same byte again, which is why this handler moves the saved address on by one +; first. MVSD is what lets it reach the frame at all. +; +; 0xFE is not an instruction. Writing it as a literal is the only way past the +; assembler, which is what makes a program containing one buildable. +; +; Correct output is: +; O printed before the byte that fails +; K printed after the handler stepped over it + +#Program + +start: + INIA 0d79 ; 'O' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + 0xFE ; Not an instruction. The handler steps over this. + + INIA 0d75 ; 'K'. Reached only because the handler moved the address on. + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT + +faultHandler: + ; The frame sits above the Stack Pointer, which points at the next free slot. The + ; address to resume at went on first, so it is furthest up: high byte 13 above the + ; Stack Pointer, low byte 14 above. + MVSD.0 + DPUP.0 0d14 + LDA.0 + INCA ; Step past the one byte that failed. + STA.0 + BRC carried ; The low byte wrapped, so the high byte needs the carry. + RETI + +carried: + DPDN.0 0d01 + LDA.0 + INCA + STA.0 + RETI + +#Vectors + + BadOpcode faultHandler diff --git a/Programs/testPrograms/faultTest.asm b/Programs/testPrograms/faultTest.asm new file mode 100644 index 0000000..03c11e0 --- /dev/null +++ b/Programs/testPrograms/faultTest.asm @@ -0,0 +1,15 @@ +; Tests that the CPU stops when it meets a byte it cannot decode. +; +; 0xFE is not an instruction. Placing it in the Program Segment as a literal gets +; it past the assembler, which is the only way to build a program containing one. +; +; The CPU should raise the Fault Flag, halt, and leave the Program Counter pointing +; at the offending byte rather than stepping over it and carrying on. The emulator +; then reports what it was and where, and exits non zero. + +#Program + +start: + INIA 0d65 ; Something harmless first, so the fault is not at address zero. + 0xFE ; Not an instruction. + HALT ; Never reached. diff --git a/Programs/testPrograms/interruptExample.asm b/Programs/testPrograms/interruptExample.asm new file mode 100644 index 0000000..62957da --- /dev/null +++ b/Programs/testPrograms/interruptExample.asm @@ -0,0 +1,72 @@ +; The worked example from the SplitBit Assembler Manual, kept here so that the manual +; cannot quietly stop being true. If this test changes, the manual changes with it. +; +; Correct output is: +; ready +; trap +; device + +; Interrupt handling from all three directions. + +#Program + +start: + CIF ; Hold devices off while we set up. + SETD.0 Greeting + CALL printString + + SWI announce ; A trap of our own, reached by name. + + INIA 0d1 + OUTA 0x10 ; Ask the test device for attention. Its line goes up. + SIF ; Let it through. It is answered before the next instruction. + + HALT + +; A trap. It is entered with a full frame, so it may use any register it likes +; without agreeing anything with the code it interrupted. +announce: + SETD.0 Trapped + CALL printString + RETI + +; The device handler. Reached because the device sits on port 0x10. +deviceReady: + SETD.0 Device + CALL printString + RETI + +; The fault handler. It reports and stops, rather than trying to carry on. +reportFault: + SETD.0 Broken + CALL printString + HALT + +printString: ; Expects DP0 to be set to the beginning of the string. + LDA.0 + BRA printDone + OUTA 0x00 + INCD.0 + BRI printString + printDone: + INIA 0x0A + OUTA 0x00 + RET + +#Data + +Greeting: +"ready" +Trapped: +"trap" +Device: +"device" +Broken: +"bad opcode" + +#Vectors + + Boot start ; Begin here rather than at the first byte. + BadOpcode reportFault + announce announce ; A name of our own. The assembler numbers it. + Device 0x10 deviceReady ; Named by the port, because that is what decides it. diff --git a/Programs/testPrograms/interruptFlagTest.asm b/Programs/testPrograms/interruptFlagTest.asm new file mode 100644 index 0000000..dc46193 --- /dev/null +++ b/Programs/testPrograms/interruptFlagTest.asm @@ -0,0 +1,45 @@ +; Tests SIF and CIF, the Interrupt Flag. +; +; Nothing reads the Interrupt Flag yet, so what this proves is that the two +; instructions decode, execute, and leave everything else exactly as they found +; it. The Carry Flag is the part worth checking, because it lives in the same +; Status register and a careless mask would take it out. +; +; Correct output is: +; OKC + +#Program + +start: + ; Load two registers, run the new instructions across them, and prove that + ; nothing moved. + INIA 0d79 ; 'O' + INIB 0d75 ; 'K' + SIF + CIF + SIF + OUTA 0x00 ; Still 'O'. + OUTB 0x00 ; Still 'K'. + + ; Now set the Carry Flag, and work the Interrupt Flag around it. + CCF + INIA 0xFF + INIB 0x01 + ADD ; Q = 0, and the Carry Flag is set. + SIF + CIF + BRC carryHeld + + ; Falling through here means one flag trampled the other. + INIA 0d88 ; 'X' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT + +carryHeld: + INIA 0d67 ; 'C' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT diff --git a/Programs/testPrograms/maskTest.asm b/Programs/testPrograms/maskTest.asm new file mode 100644 index 0000000..349846e --- /dev/null +++ b/Programs/testPrograms/maskTest.asm @@ -0,0 +1,44 @@ +; Tests that the Interrupt Flag holds a device off, and that the device is still +; waiting once the flag goes back up. +; +; The test device on port 0x10 puts its own line up when anything is written to it. A +; device on port N interrupts on N, so this one arrives on hardware vector 16. +; +; Nothing is installed at that vector, so answering it is a fault. That is the point: +; the fault is proof the line was answered, and where it appears in the output is proof +; of when. The letters are printed to mark how far the program got. +; +; Correct output is: +; M the device has asked, and the flag is down, so nothing has happened +; S still nothing, several instructions later +; then a fault naming hardware vector 16, raised after SIF and not before. + +#Program + +start: + CIF ; Hold devices off. + INIA 0d1 + OUTA 0x10 ; The device asks for attention. Its line goes up and stays up. + + INIA 0d77 ; 'M', printed with the line still up and the flag still down. + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + NOP ; Several instructions pass and the line is still not answered. + NOP + NOP + + INIA 0d83 ; 'S' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + SIF ; Now let it through. The line is answered on the very next step. + + ; Never reached. + INIA 0d88 ; 'X' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT diff --git a/Programs/testPrograms/moveQTest.asm b/Programs/testPrograms/moveQTest.asm new file mode 100644 index 0000000..18937e3 --- /dev/null +++ b/Programs/testPrograms/moveQTest.asm @@ -0,0 +1,41 @@ +; Tests MVQA and MVQB. +; +; Every ALU result lands in Q, and Q is not an ALU operand. Without these two +; instructions the only way to use a result in the next sum is to store it into +; Data Memory and load it back, which costs two instructions and a Data Pointer +; that has to be pointing somewhere sensible. +; +; Correct output is: +; AAA + +#Program + +start: + CCF + INIA 0d60 + INIB 0d5 + ADD ; Q = 65, which is 'A'. + MVQA ; A = 65 + OUTA 0x00 + MVQB ; And B, from the same result. + OUTB 0x00 + + ; A running total kept entirely in registers, which is the thing that was not + ; possible before. Nothing here touches Data Memory at all. + CCF + RSTA + INIB 0d1 + ADD ; Q = 1 + MVQA + ADD ; Q = 2 + MVQA + ADD ; Q = 3 + MVQA + INIB 0d62 + ADD ; Q = 65 again + MVQA + OUTA 0x00 + + INIA 0x0A + OUTA 0x00 + HALT diff --git a/Programs/testPrograms/paddingTest.asm b/Programs/testPrograms/paddingTest.asm new file mode 100644 index 0000000..df1058f --- /dev/null +++ b/Programs/testPrograms/paddingTest.asm @@ -0,0 +1,43 @@ +; Tests #Align and #Reserve by printing the addresses they produce. +; +; Both directives only move the cursor along, so what they do is entirely visible in +; where the labels after them land. The program pushes each pointer and prints the two +; bytes of its address, which is the only way a SplitBit program can look at one. +; +; Aligned is asked for on a page boundary, so its low byte has to be 0x00. Reserved +; follows one byte of data and a reservation of 0x30, so it lands 0x31 further on. +; +; Correct output is: +; 00 31 + +#Include print.asm + +#Program + +start: + ; The aligned label. Only the low byte is interesting: a page boundary means zero. + SETD.0 Aligned + PSHD.0 ; High byte, then low, so the low byte comes off first. + POPA + POPB + CALL printByteHex + CALL blankSpace + + ; The reserved region. Reserved sits one byte of data plus 0x30 reserved bytes past + ; Aligned, so its low byte says how far the reservation moved the cursor. + SETD.0 Reserved + PSHD.0 + POPA + POPB + CALL printByteHex + CALL lineFeed + HALT + +#Data + + #Align 0x100 +Aligned: + 0x41 ; One byte of real data, so the cursor is one past the boundary. + #Reserve 0x30 +Reserved: + 0x42 diff --git a/Programs/testPrograms/stackPointerTest.asm b/Programs/testPrograms/stackPointerTest.asm new file mode 100644 index 0000000..f28cb7c --- /dev/null +++ b/Programs/testPrograms/stackPointerTest.asm @@ -0,0 +1,36 @@ +; Tests MVSD, which copies the Stack Pointer into a Data Pointer. +; +; The Stack Pointer still cannot be written, so this does not let a program move the +; Stack. It lets a program find it, which is what reading anything already on the Stack +; requires. Without it, the manual's claim that a Data Pointer can be aimed at the Stack +; is not something a program can actually act on: there is no way to learn where the +; Stack is without already knowing. +; +; An interrupt handler needs this to reach its own frame, which is how a fault handler +; steps over the byte that failed and carries on. +; +; Correct output is: +; OK + +#Program + +start: + ; Push two bytes, then go looking for them. + INIA 0d79 ; 'O' + PSHA + INIA 0d75 ; 'K' + PSHA + + ; The Stack Pointer points at the next free slot, so the byte pushed last sits one + ; above it, and the one before that sits two above. + MVSD.0 + DPUP.0 0d01 + LDA.0 ; 'K', the last one pushed. + INCD.0 + LDB.0 ; 'O', the one before it. + + OUTB 0x00 + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT diff --git a/Programs/testPrograms/swiFaultTest.asm b/Programs/testPrograms/swiFaultTest.asm new file mode 100644 index 0000000..c476d98 --- /dev/null +++ b/Programs/testPrograms/swiFaultTest.asm @@ -0,0 +1,30 @@ +; Tests a software interrupt that names a vector with nothing installed in it. +; +; Until the assembler can lay down a vector table, every entry reads as zero, and zero +; means no handler. Dispatching through one has to stop the machine and say which +; vector was empty, rather than jumping to the bottom of Program Memory and running +; whatever happens to be sitting there. +; +; The letter is printed first so that it is obvious the program ran at all, and that it +; stopped exactly where it should have. +; +; Correct output is: +; O +; a fault naming software vector 20, and a non zero exit. + +#Program + +start: + INIA 0d79 ; 'O' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + SWI 0d20 ; Nothing is installed here. + + ; Never reached. If the machine ever prints this, the empty vector was taken. + INIA 0d88 ; 'X' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT diff --git a/Programs/testPrograms/vectorTest.asm b/Programs/testPrograms/vectorTest.asm new file mode 100644 index 0000000..7da4bd7 --- /dev/null +++ b/Programs/testPrograms/vectorTest.asm @@ -0,0 +1,94 @@ +; Tests the Vector Segment: a Boot Vector pointing somewhere other than the start of the +; program, and a software interrupt the program names for itself. +; +; The decoy sits at address 0x0000, where execution would begin if the Boot Vector were +; not obeyed. It prints an X, so if an X ever appears the vector was ignored. +; +; The handler tramples every register it can reach. Everything printed afterwards comes +; out of the frame, which is the point: an interrupt gives back what it borrowed, and +; unlike a subroutine that includes Q and Data Pointer 3. +; +; Correct output is: +; OK! +; good +; AFTER + +#Program + +decoy: + INIA 0d88 ; 'X'. Never reached. + OUTA 0x00 + HALT + +realStart: + CCF + INIA 0d79 ; 'O' + INIB 0d75 ; 'K' + SETD.0 Good ; DP0 is preserved across a CALL as well. + SETD.3 After ; DP3 is not, but an interrupt has to give it back anyway. + + SWI stampTrap + + OUTA 0x00 ; 'O' + OUTB 0x00 ; 'K' + BRC carryLost + INIA 0d33 ; '!', so the Status register came back too. + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + + CALL printDP0 + CALL printDP3 + HALT + +carryLost: + INIA 0d63 ; '?' + OUTA 0x00 + INIA 0x0A + OUTA 0x00 + HALT + +; The handler. Nothing it does to a register should survive. +stampRegisters: + INIA 0xFF + INIB 0x01 + ADD ; Q is stamped, and the Carry Flag is set. + SETD.0 Bad + SETD.3 Bad + RETI + +printDP0: + LDA.0 + BRA done0 + OUTA 0x00 + INCD.0 + BRI printDP0 + done0: + INIA 0x0A + OUTA 0x00 + RET + +printDP3: + LDA.3 + BRA done3 + OUTA 0x00 + INCD.3 + BRI printDP3 + done3: + INIA 0x0A + OUTA 0x00 + RET + +#Data + +Good: +"good" +Bad: +"bad" +After: +"AFTER" + +#Vectors + + Boot realStart + stampTrap stampRegisters diff --git a/README.md b/README.md index ea4a7f1..e794fa1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ cd SplitBit-Emulator ``` make ``` +The sources are ISO C, and build clean under -std=c11 -pedantic with -Wall -Wextra. Beyond ISO C they need POSIX.1-2008, which the makefile asks for by name, and getopt_long for the long form of the command line options. 3) Assemble a program: ``` ./Assembler Programs/hello.asm @@ -37,11 +38,14 @@ make ./SplitBit [options] [binary file] ``` #### Options: -- -d, --debug: Enable debug mode to single step through cycles. Each keypress advances one instruction. +- -d, --debug: Enable debug mode to single step through cycles. Each key press advances one instruction. - -c, --cycles N: Stop after N cycles rather than running until the program halts. Useful for programs that never halt, and for getting the same output from a run every time. - -f, --fast: Run as fast as the host machine allows, ignoring the emulated cycle rate. - -h, --help: Show help and usage information. +#### Notes: +- If the CPU reads a byte that is not an instruction, it goes to the fault handler the program installed. If it installed none, it raises the Fault Flag and halts, and the emulator reports the byte and the address it was found at and exits with a non zero status. The same happens if a program or a device asks for a handler that was never installed. + ### Usage: ``` ./Assembler [options] [assembly file] @@ -88,6 +92,12 @@ Programs are built inside Tests/build, so running the suite never overwrites the ./Tests/run.sh hello 8bitFibonacci ``` +To rebuild both tools with the address and undefined behaviour sanitizers and run the suite under them: +``` +make sanitize +``` +This catches reads and writes past the end of an array, use after free, leaks, and undefined arithmetic. It also fills fresh allocations with a junk pattern, which turns a read of uninitialised memory from something that quietly works into something the tests notice. It takes about twice as long as make test, and puts the ordinary binaries back when it finishes. + ### Additional Info: For more information on the custom ISA and programming for SplitBit, see the Programming Manual and Assembler Manual. diff --git a/Source/Assembler/Assembler.c b/Source/Assembler/Assembler.c index 6b63f0b..8b71c7b 100644 --- a/Source/Assembler/Assembler.c +++ b/Source/Assembler/Assembler.c @@ -80,6 +80,9 @@ void assemblerCleanup(intermediateElement *intermediateArray, int arraySize, cha // Free the list of labels. freeLabelList(); + // Free the list of vectors. + freeVectorList(); + // Free the output file name free(outputFileName); } @@ -161,9 +164,11 @@ int main(int argc, char *argv[]) { return 1; } - // Allocate initial space for the intermediate array. + // Allocate initial space for the intermediate array. calloc rather than malloc, + // because not every element sets every one of its own fields, and a stray + // byteLength would quietly shift every address that follows it. size_t arraySize = 1024; - intermediateElement *intermediateArray = malloc(arraySize * sizeof(intermediateElement)); + intermediateElement *intermediateArray = calloc(arraySize, sizeof(intermediateElement)); if (!intermediateArray) { fprintf(stderr, RED "Error: Memory allocation failed.\n" RESET); exit(1); @@ -176,6 +181,10 @@ int main(int argc, char *argv[]) { loadFile(&intermediateArray, source, &index, &arraySize); populateLabelTable(intermediateArray, index); fillInLabelAddresses(intermediateArray, index); + // Vectors come after the labels, because a handler is named by its label, and before + // the buffers are filled, because SWI needs the number its vector was given. + populateVectorTable(intermediateArray, index); + fillInVectorReferences(intermediateArray, index); populateOutputBuffers(intermediateArray, index, Program, &programLength, Data, &dataLength); if (!outputFileName) { outputFileName = createOutputFileName(fileName); diff --git a/Source/Assembler/Assm-util.c b/Source/Assembler/Assm-util.c index 448afdf..311d3c3 100644 --- a/Source/Assembler/Assm-util.c +++ b/Source/Assembler/Assm-util.c @@ -32,6 +32,19 @@ int checkIfKeyword(intermediateElement *currentElement) { } else if (strcmp(currentElement->token, "#Data") == 0) { // Same as for #Program, but mark for inclusion in the Data Segment. return KEYWORD_DATA; + } else if (strcmp(currentElement->token, "#Align") == 0) { + // Puts down as many zero bytes as it takes to reach the next multiple of + // the number that follows. The file that needs the boundary is then the + // file that asks for it, rather than relying on whatever came before. + return KEYWORD_ALIGN; + } else if (strcmp(currentElement->token, "#Reserve") == 0) { + // Puts down the number of zero bytes that follows, so that a label can + // stand for a region rather than just its first byte. + return KEYWORD_RESERVE; + } else if (strcmp(currentElement->token, "#Vectors") == 0) { + // Names which handler belongs to which vector. Nothing here is assembled + // into either segment; it is worked out and written into the vector table. + return KEYWORD_VECTORS; } else { // It's a malformed keyword. fprintf(stderr, RED "Error: Invalid Keyword \"%s\" in file \"%s\" at line number %d.\n" RESET, currentElement->token, currentElement->fileName, currentElement->lineNumber); @@ -159,6 +172,44 @@ int checkIfLiteralValue(intermediateElement *currentElement) { return 1; } +uint16_t readCount(intermediateElement *currentElement, const char *what) { + const char *token = currentElement->token; + int base; + const char *baseName; + if (token[0] != '0' || (token[1] != 'x' && token[1] != 'd')) { + fprintf(stderr, RED "Error: %s needs a number, prefaced with 0x or 0d. Found \"%s\".\n" RESET, what, token); + printf(" File: %s at line %d.\n", currentElement->fileName, currentElement->lineNumber); + exit(1); + } + if (token[1] == 'x') { + base = 16; + baseName = "hexadecimal"; + } else { + base = 10; + baseName = "decimal"; + } + const char *digits = token + 2; + if (*digits == '\0') { + fprintf(stderr, RED "Error: %s was given \"%s\", which has no digits after its prefix.\n" RESET, what, token); + printf(" File: %s at line %d.\n", currentElement->fileName, currentElement->lineNumber); + exit(1); + } + for (const char *c = digits; *c; c++) { + if (!(base == 16 ? isxdigit((unsigned char)*c) : isdigit((unsigned char)*c))) { + fprintf(stderr, RED "Error: \"%c\" is not a %s digit, in \"%s\".\n" RESET, *c, baseName, token); + printf(" File: %s at line %d.\n", currentElement->fileName, currentElement->lineNumber); + exit(1); + } + } + long value = strtol(digits, NULL, base); + if (value < 1 || value > 0xFFFF) { + fprintf(stderr, RED "Error: %s was given \"%s\". It has to be at least 1 and no more than 0xFFFF.\n" RESET, what, token); + printf(" File: %s at line %d.\n", currentElement->fileName, currentElement->lineNumber); + exit(1); + } + return (uint16_t)value; +} + int checkIfLabel(intermediateElement *currentElement) { char *token = currentElement->token; int length = strlen(token); @@ -207,7 +258,7 @@ int readToken(intermediateElement *currentElement, FILE *file, int *lineNumber) // Step 3: Handle string literals if (c == '"') { while ((c = fgetc(file)) != EOF && c != '"') { - if (i < sizeof(buffer) - 1) { + if (i < (int)(sizeof(buffer) - 1)) { buffer[i++] = c; } else { fprintf(stderr, "Error: String literal too long.\n"); @@ -228,7 +279,7 @@ int readToken(intermediateElement *currentElement, FILE *file, int *lineNumber) // Step 4: Handle non-string tokens ungetc(c, file); // Put the first character back while ((c = fgetc(file)) != EOF && !isspace(c) && c != ';') { - if (i < sizeof(buffer) - 1) { + if (i < (int)(sizeof(buffer) - 1)) { buffer[i++] = c; } else { fprintf(stderr, "Error: Token too long.\n"); diff --git a/Source/Assembler/Assm-util.h b/Source/Assembler/Assm-util.h index 28d3d17..08817d0 100644 --- a/Source/Assembler/Assm-util.h +++ b/Source/Assembler/Assm-util.h @@ -23,16 +23,31 @@ #define LABEL_DEFINITION 4 #define VALUE 5 #define STRING 6 +// A name from the Vector Segment, used as the operand of SWI. It stands for a vector +// number rather than an address, so it emits one byte where a label emits two. +#define VECTOR_REFERENCE 7 +// Zero bytes put down to move the cursor along, from #Reserve. How many is known as +// soon as it is read. +#define PADDING 8 +// The same, from #Align, where how many depends on where the cursor has got to. The +// count is worked out in the second pass and the alignment itself is kept in address. +#define ALIGNMENT 9 // Keyword values. #define KEYWORD_INCLUDE 1 #define KEYWORD_PROGRAM 2 #define KEYWORD_DATA 3 +#define KEYWORD_VECTORS 4 +#define KEYWORD_ALIGN 5 +#define KEYWORD_RESERVE 6 // Destination values. #define NOWHERE 0 #define PROGRAM 1 #define DATA 2 +// The Vector Segment does not become bytes at an address the way the other two do. It +// says which handler belongs to which vector, and the assembler works out the rest. +#define VECTORS 3 // For colorful text. #define RESET "\x1B[0m" @@ -66,4 +81,9 @@ int checkIfLabel(intermediateElement *currentElement); int readToken(intermediateElement *currentElement, FILE *file, int *lineNumber); +// Reads a count written the way a literal is, but allowing the full range of an address +// rather than a single byte. #Align and #Reserve both take one, and neither number is +// ever emitted as a byte, so there is no reason to hold them to a byte's range. +uint16_t readCount(intermediateElement *currentElement, const char *what); + #endif diff --git a/Source/Assembler/assembly.c b/Source/Assembler/assembly.c index dc3a29e..251759a 100644 --- a/Source/Assembler/assembly.c +++ b/Source/Assembler/assembly.c @@ -28,7 +28,10 @@ Instruction instruction_set[] = { {0x12, "BRA"}, {0x13, "BRB"}, {0x14, "BRC"}, + {0x15, "BRD"}, {0x17, "CALL"}, + {0x18, "SWI"}, + {0x19, "RETI"}, {0x1F, "RET"}, // Register Operations: {0x20, "RSTA"}, @@ -40,6 +43,10 @@ Instruction instruction_set[] = { {0x26, "INIA"}, {0x27, "INIB"}, {0x28, "CCF"}, + {0x29, "MVQA"}, + {0x2A, "MVQB"}, + {0x2B, "SIF"}, + {0x2C, "CIF"}, // Stack Operations: {0x30, "PSHQ"}, {0x31, "PSHA"}, @@ -61,6 +68,7 @@ Instruction instruction_set[] = { {0x49, "DPDN"}, {0x4A, "LDD"}, {0x4B, "STD"}, + {0x4C, "MVSD"}, // Output Operations: {0xD0, "OUTQ"}, {0xD1, "OUTA"}, @@ -92,6 +100,7 @@ int dataPointerOperands(uint8_t opcode) { case 0x4A: // LDD case 0x4B: // STD return 2; + case 0x15: // BRD case 0x33: // PSHD case 0x36: // POPD case 0x40: // INCD @@ -104,6 +113,7 @@ int dataPointerOperands(uint8_t opcode) { case 0x47: // SETD case 0x48: // DPUP case 0x49: // DPDN + case 0x4C: // MVSD return 1; default: return 0; diff --git a/Source/Assembler/assembly.h b/Source/Assembler/assembly.h index 7f31478..a223d8b 100644 --- a/Source/Assembler/assembly.h +++ b/Source/Assembler/assembly.h @@ -23,18 +23,62 @@ // .. 3 "DAT" // .. 2 Data Segment length // .. M Data Segment +// .. 3 "VEC", optional +// .. 2 Vector Segment length, in bytes +// .. K Vector Segment, four bytes per entry +// +// The Vector Segment is optional and comes last, so a binary written before it existed +// simply ends after its Data Segment and still loads. Each entry is two bytes saying +// where in Program Memory the vector sits, then two bytes saying where its handler is, +// most significant byte first. It is a list rather than an image of the table, so a +// program with three handlers costs twelve bytes instead of a padded kilobyte. // // The feature flags are how a binary says it needs something the base machine does // not provide, so that an emulator which cannot provide it refuses to run the binary // rather than quietly doing the wrong thing. No features are defined yet; the field // is here so that adding one later does not need another format version. +// ---- The vector table ---- +// +// The top kilobyte of Program Memory is reserved for vectors. Both tools have to +// agree on where it begins: the CPU starts execution through it, and the assembler +// has to refuse program text that would run into it. +// +// Entries are two bytes each, most significant byte first, the same order the branch +// instructions and this file format already use. +// +// 0xFC00 Software vectors 0 to 255 +// 0xFE00 Hardware vectors 0 to 255, one for each I/O port +// +// Software vectors 0 and 1 are start addresses rather than handlers. Vector 0 is +// where the machine begins at power on and vector 1 is a warm restart, so a zero in +// either of them is not "nothing installed" but the address 0x0000, which is where a +// program carrying no vector table of its own begins. A zero in any other entry does +// mean no handler is installed, and dispatching through one is a fault. + +#define SOFTWARE_VECTOR_BASE 0xFC00 +#define HARDWARE_VECTOR_BASE 0xFE00 +#define VECTOR_ENTRY_BYTES 2 +#define VECTOR_BOOT 0 +#define VECTOR_SOFT_RESET 1 +#define VECTOR_INVALID_OPCODE 2 +// Vectors 3 to 15 are held back for faults that do not exist yet, so that each cause +// can have an entry of its own rather than sharing one and needing a cause register to +// tell them apart. Everything from 16 up belongs to programs. +#define VECTOR_FIRST_FREE 16 + +// The first address the vector table occupies, and so the first address that program +// text may not use. +#define PROGRAM_TEXT_LIMIT SOFTWARE_VECTOR_BASE + #define SPLITBIT_MAGIC "SPBT" #define SPLITBIT_MAGIC_LENGTH 4 #define SPLITBIT_FORMAT_VERSION 1 #define SPLITBIT_FLAGS_LENGTH 4 #define SEGMENT_MARKER_LENGTH 3 #define SEGMENT_LENGTH_BYTES 2 +// Where a vector sits, and where its handler is. +#define VECTOR_ENTRY_FILE_BYTES 4 // Everything the format costs a file, on top of the two segments themselves. #define SPLITBIT_HEADER_BYTES (SPLITBIT_MAGIC_LENGTH + 1 + SPLITBIT_FLAGS_LENGTH \ diff --git a/Source/Assembler/firstPass.c b/Source/Assembler/firstPass.c index 733bc54..fb5b69f 100644 --- a/Source/Assembler/firstPass.c +++ b/Source/Assembler/firstPass.c @@ -164,13 +164,22 @@ int loadFile(intermediateElement **intermediateArray, char *fileName, int *inter } // Read off tokens. while (readToken(&(*intermediateArray)[*intermediateIndex], file, &lineNumber)) { - if (*intermediateIndex >= *arraySize - 1) { - *arraySize *= 2; // Double the size of the array - *intermediateArray = realloc(*intermediateArray, *arraySize * sizeof(intermediateElement)); - if (!intermediateArray) { + if ((size_t)*intermediateIndex >= *arraySize - 1) { + size_t grownSize = *arraySize * 2; // Double the size of the array. + // Into a temporary, so that the old allocation is still ours to free if + // this fails, rather than being lost the moment realloc returns NULL. + intermediateElement *grown = realloc(*intermediateArray, grownSize * sizeof(intermediateElement)); + if (!grown) { fprintf(stderr, RED "Error: Memory reallocation failed.\n" RESET); exit(1); } + // New elements have to start blank. realloc leaves the new space holding + // whatever the heap had in it before, and an element that never sets its + // own byteLength, such as a keyword or a label definition, would then add + // rubbish to the running address and move everything after it. + memset(grown + *arraySize, 0, (grownSize - *arraySize) * sizeof(intermediateElement)); + *intermediateArray = grown; + *arraySize = grownSize; } //printf("Token number %d\n", intermediateIndex); // Go ahead and mark what we already know about this token. @@ -185,13 +194,24 @@ int loadFile(intermediateElement **intermediateArray, char *fileName, int *inter status = NOWHERE; // Get the filename and work out where it actually is. (*intermediateIndex)++; - readToken(&(*intermediateArray)[*intermediateIndex], file, &lineNumber); + if (!readToken(&(*intermediateArray)[*intermediateIndex], file, &lineNumber)) { + // The file ended straight after the keyword, so there is no + // name to read and nothing sensible to go looking for. + fprintf(stderr, RED "Error: #Include without a file name.\n" RESET); + printf(" File: %s at line %d.\n", fileName, lineNumber); + exit(1); + } char *requested = (*intermediateArray)[*intermediateIndex].token; char *resolved = resolveInclude(fileName, requested); if (!resolved) { reportMissingInclude(fileName, requested, lineNumber); exit(1); } + // The included file's first token is about to be read into this + // same slot, so let the file name go now. Leaving it would strand + // the only pointer to it the moment it is overwritten. + free((*intermediateArray)[*intermediateIndex].token); + (*intermediateArray)[*intermediateIndex].token = NULL; // recordSourceFile takes the path, and hands back NULL if this file // has already been assembled. Including it twice is harmless, which // is what lets two libraries depend on a third. @@ -209,6 +229,56 @@ int loadFile(intermediateElement **intermediateArray, char *fileName, int *inter // Set the state to DATA so we mark additional tokens for inclusion into Data Memory. status = DATA; break; + case KEYWORD_ALIGN: + case KEYWORD_RESERVE: { + // Both take a count, and both only make sense somewhere that has a + // cursor to move along. + const char *what = (testValue == KEYWORD_ALIGN) ? "#Align" : "#Reserve"; + if (status != PROGRAM && status != DATA) { + fprintf(stderr, RED "Error: %s outside the Program or Data Segment.\n There is nothing there for it to move along.\n" RESET, what); + printf(" File: %s at line %d.\n", fileName, lineNumber); + exit(1); + } + // The count is read here rather than being left to the literal check, + // because it is an instruction to the assembler and never becomes a + // byte, so a byte's range would be the wrong limit for it. A page + // alignment needs 256, and a reservation is often far larger. + intermediateElement *directive = &(*intermediateArray)[*intermediateIndex]; + (*intermediateIndex)++; + if (!readToken(&(*intermediateArray)[*intermediateIndex], file, &lineNumber)) { + fprintf(stderr, RED "Error: %s without a number.\n" RESET, what); + printf(" File: %s at line %d.\n", fileName, lineNumber); + exit(1); + } + (*intermediateArray)[*intermediateIndex].fileName = fileName; + (*intermediateArray)[*intermediateIndex].lineNumber = lineNumber; + uint16_t count = readCount(&(*intermediateArray)[*intermediateIndex], what); + + // The count token itself contributes nothing; the directive carries + // everything, so that one element stands for one run of zeroes. + (*intermediateArray)[*intermediateIndex].type = KEYWORD; + (*intermediateArray)[*intermediateIndex].byteLength = 0; + (*intermediateArray)[*intermediateIndex].destination = NOWHERE; + + directive->destination = status; + if (testValue == KEYWORD_ALIGN) { + // How many zeroes this comes to depends on where the cursor has + // reached, which is not known until the second pass walks it. + directive->type = ALIGNMENT; + directive->address = count; + directive->byteLength = 0; + } else { + directive->type = PADDING; + directive->byteLength = count; + } + (*intermediateIndex)++; + continue; + } + case KEYWORD_VECTORS: + // Set the state to VECTORS. Tokens from here on name handlers rather + // than becoming bytes, and the second pass reads them. + status = VECTORS; + break; } // Next, check to see if it's an instruction. } else if (checkIfInstruction(&(*intermediateArray)[*intermediateIndex])) { @@ -235,6 +305,18 @@ int loadFile(intermediateElement **intermediateArray, char *fileName, int *inter printf(" File: %s at line %d.\n", fileName, lineNumber); exit(1); } + // A name written after SWI is a vector rather than an address, so it + // stands for one byte instead of two. This is settled by what the name + // follows, so that it does not depend on the Vector Segment having been + // read first, which it may not have been: it can live in another file. + if (status == PROGRAM + && (*intermediateArray)[*intermediateIndex].type == LABEL + && *intermediateIndex > 0 + && (*intermediateArray)[*intermediateIndex - 1].type == INSTRUCTION + && (*intermediateArray)[*intermediateIndex - 1].byteValue == 0x18) { + (*intermediateArray)[*intermediateIndex].type = VECTOR_REFERENCE; + (*intermediateArray)[*intermediateIndex].byteLength = 1; + } } } (*intermediateArray)[*intermediateIndex].destination = status; diff --git a/Source/Assembler/secondPass.c b/Source/Assembler/secondPass.c index ead7429..cfe7835 100644 --- a/Source/Assembler/secondPass.c +++ b/Source/Assembler/secondPass.c @@ -29,7 +29,7 @@ void freeLabelList() { labelCount = 0; } -void addLabel(char *labelName, uint16_t address, int type) { +void addLabel(char *labelName, uint16_t address, int type, const char *fileName, int lineNumber) { if (labelCount < MAX_LABELS) { // Duplicate labelName and remove the trailing colon, if present char *cleanedLabel = strdup(labelName); @@ -38,6 +38,18 @@ void addLabel(char *labelName, uint16_t address, int type) { cleanedLabel[len - 1] = '\0'; // Remove the colon } + // A name may only be defined once. Without this check a reference quietly + // resolves to whichever definition came first, so a typo or a name that two + // libraries both happen to use is very hard to track down. + for (int i = 0; i < labelCount; i++) { + if (strcmp(labelArray[i].label, cleanedLabel) == 0) { + fprintf(stderr, RED "Error: Label \"%s\" is defined more than once.\n" RESET, cleanedLabel); + printf("File: %s at line %d.\n", fileName, lineNumber); + free(cleanedLabel); + exit(1); + } + } + labelArray[labelCount].label = cleanedLabel; labelArray[labelCount].address = address; labelArray[labelCount].type = type; @@ -54,11 +66,22 @@ void populateLabelTable(intermediateElement *intermediateArray, int arraySize) { int dataCount = 0; // Loop through the array, if there's a label definition, add it to the label list. for (int i = 0; i < arraySize ; i++) { - if (intermediateArray[i].type == LABEL_DEFINITION) { + // How many zeroes an #Align comes to depends on where the cursor has reached, + // so it can only be worked out here, walking the tokens in order. It has to be + // settled before the running count moves past it, or every label after it lands + // in the wrong place. + if (intermediateArray[i].type == ALIGNMENT) { + int cursor = (intermediateArray[i].destination == PROGRAM) ? programCount : dataCount; + int alignment = intermediateArray[i].address; + intermediateArray[i].byteLength = (alignment - (cursor % alignment)) % alignment; + } + if (intermediateArray[i].type == LABEL_DEFINITION && intermediateArray[i].destination != VECTORS) { if (intermediateArray[i].destination == PROGRAM) { - addLabel(intermediateArray[i].token, (uint16_t)programCount, PROGRAM); + addLabel(intermediateArray[i].token, (uint16_t)programCount, PROGRAM, + intermediateArray[i].fileName, intermediateArray[i].lineNumber); } else { - addLabel(intermediateArray[i].token, (uint16_t)dataCount, DATA); + addLabel(intermediateArray[i].token, (uint16_t)dataCount, DATA, + intermediateArray[i].fileName, intermediateArray[i].lineNumber); } } if (intermediateArray[i].destination == PROGRAM) { @@ -69,8 +92,10 @@ void populateLabelTable(intermediateElement *intermediateArray, int arraySize) { if (debugSecondPass) printf("Token: %s with byte length %d to destination %d of type %d\n", intermediateArray[i].token ,intermediateArray[i].byteLength, intermediateArray[i].destination, intermediateArray[i].type); } - if (programCount > 0xFFFF ) { - fprintf(stderr, RED "Error: Program is too long to fit in Program Memory.\n" RESET); + if (programCount > PROGRAM_TEXT_LIMIT ) { + fprintf(stderr, RED "Error: Program is too long to fit in Program Memory.\n" + " Program text may not run past 0x%04X, where the vector table begins.\n" RESET, + PROGRAM_TEXT_LIMIT - 1); exit(1); } if (dataCount > 0xFFFF ) { @@ -79,6 +104,182 @@ void populateLabelTable(intermediateElement *intermediateArray, int arraySize) { } } +// ---- The Vector Segment ---- + +int findLabelAddress(const char *labelName); + +VectorEntry vectorArray[MAX_VECTORS]; +int vectorArrayCount = 0; + +int vectorCount() { + return vectorArrayCount; +} + +void freeVectorList() { + for (int i = 0; i < vectorArrayCount; i++) { + if (vectorArray[i].name) { + free(vectorArray[i].name); + } + } + vectorArrayCount = 0; +} + +// The words the Vector Segment understands. These are spelled without regard to case, +// the way mnemonics are, because they are part of the language rather than names the +// programmer chose. +static int sameWord(const char *a, const char *b) { + while (*a && *b) { + if (tolower((unsigned char)*a) != tolower((unsigned char)*b)) { + return 0; + } + a++; + b++; + } + return *a == *b; +} + +// The vectors that already mean something. Everything else a program names is numbered +// for it, starting above the range held back for faults. +static const struct { + const char *name; + uint8_t index; +} reservedVectors[] = { + { "Boot", VECTOR_BOOT }, + { "SoftReset", VECTOR_SOFT_RESET }, + { "BadOpcode", VECTOR_INVALID_OPCODE }, +}; +static const int reservedVectorCount = (int)(sizeof(reservedVectors) / sizeof(reservedVectors[0])); + +static void vectorError(const char *message, intermediateElement *element) { + fprintf(stderr, RED "Error: %s\n" RESET, message); + printf("File: %s at line %d.\n", element->fileName, element->lineNumber); + printf("Token: %s\n", element->token); + exit(1); +} + +// The next token belonging to the Vector Segment, or -1 if the segment has run out. +static int nextVectorToken(intermediateElement *intermediateArray, int arraySize, int from) { + for (int i = from; i < arraySize; i++) { + if (intermediateArray[i].destination == VECTORS && intermediateArray[i].type != KEYWORD) { + return i; + } + } + return -1; +} + +static void addVector(char *name, uint8_t index, uint16_t base, uint16_t handler, intermediateElement *element) { + if (vectorArrayCount >= MAX_VECTORS) { + vectorError("Too many vectors defined.", element); + } + for (int i = 0; i < vectorArrayCount; i++) { + if (vectorArray[i].index == index && vectorArray[i].base == base) { + fprintf(stderr, RED "Error: That vector already has a handler.\n" RESET); + printf("File: %s at line %d.\n", element->fileName, element->lineNumber); + exit(1); + } + if (name && vectorArray[i].name && strcmp(vectorArray[i].name, name) == 0) { + fprintf(stderr, RED "Error: Vector \"%s\" is named more than once.\n" RESET, name); + printf("File: %s at line %d.\n", element->fileName, element->lineNumber); + exit(1); + } + } + vectorArray[vectorArrayCount].name = name ? strdup(name) : NULL; + vectorArray[vectorArrayCount].index = index; + vectorArray[vectorArrayCount].base = base; + vectorArray[vectorArrayCount].handler = handler; + vectorArrayCount++; +} + +// Resolves the handler named by the token at the given index. +static uint16_t resolveHandler(intermediateElement *intermediateArray, int at, const char *what) { + if (at < 0) { + fprintf(stderr, RED "Error: %s is not followed by a handler to go to.\n" RESET, what); + exit(1); + } + if (intermediateArray[at].type != LABEL) { + vectorError("A vector's handler has to be named by a label.", &intermediateArray[at]); + } + int address = findLabelAddress(intermediateArray[at].token); + if (address == -1) { + vectorError("That handler does not exist.", &intermediateArray[at]); + } + return (uint16_t)address; +} + +void populateVectorTable(intermediateElement *intermediateArray, int arraySize) { + // Software vectors a program names for itself are numbered in the order they are + // written, starting above the block held back for faults. A programmer never types + // one, so there is no way to land on a reserved vector by accident. + int nextFreeVector = VECTOR_FIRST_FREE; + + int i = nextVectorToken(intermediateArray, arraySize, 0); + while (i >= 0) { + char *token = intermediateArray[i].token; + + if (sameWord(token, "Device")) { + // A device is named by the port it is plugged into, because that is what + // decides which vector it arrives through. There is nothing to allocate. + int portToken = nextVectorToken(intermediateArray, arraySize, i + 1); + if (portToken < 0 || intermediateArray[portToken].type != VALUE) { + vectorError("Device has to say which port, as a number.", &intermediateArray[i]); + } + int handlerToken = nextVectorToken(intermediateArray, arraySize, portToken + 1); + uint16_t handler = resolveHandler(intermediateArray, handlerToken, "Device"); + addVector(NULL, intermediateArray[portToken].byteValue, HARDWARE_VECTOR_BASE, + handler, &intermediateArray[i]); + i = nextVectorToken(intermediateArray, arraySize, handlerToken + 1); + continue; + } + + uint8_t index; + int reserved = 0; + for (int r = 0; r < reservedVectorCount; r++) { + if (sameWord(token, reservedVectors[r].name)) { + index = reservedVectors[r].index; + reserved = 1; + break; + } + } + if (!reserved) { + if (nextFreeVector > 255) { + vectorError("There are no software vectors left to give this one.", &intermediateArray[i]); + } + index = (uint8_t)nextFreeVector; + nextFreeVector++; + } + + int handlerToken = nextVectorToken(intermediateArray, arraySize, i + 1); + uint16_t handler = resolveHandler(intermediateArray, handlerToken, token); + addVector(token, index, SOFTWARE_VECTOR_BASE, handler, &intermediateArray[i]); + i = nextVectorToken(intermediateArray, arraySize, handlerToken + 1); + } +} + +void fillInVectorReferences(intermediateElement *intermediateArray, int arraySize) { + for (int i = 0; i < arraySize; i++) { + if (intermediateArray[i].type != VECTOR_REFERENCE) { + continue; + } + int found = 0; + for (int v = 0; v < vectorArrayCount; v++) { + if (vectorArray[v].name && strcmp(vectorArray[v].name, intermediateArray[i].token) == 0) { + if (vectorArray[v].base != SOFTWARE_VECTOR_BASE) { + vectorError("SWI can only reach a software vector.", &intermediateArray[i]); + } + intermediateArray[i].byteValue = vectorArray[v].index; + found = 1; + break; + } + } + if (!found) { + fprintf(stderr, RED "Error: \"%s\" is not a vector.\n Names used with SWI have to be given a handler in a #Vectors section.\n" RESET, + intermediateArray[i].token); + printf("File: %s at line %d.\n", intermediateArray[i].fileName, intermediateArray[i].lineNumber); + exit(1); + } + } +} + int findLabelAddress(const char *labelName) { for (int i = 0; i < labelCount; i++) { if (strcmp(labelArray[i].label, labelName) == 0) { @@ -90,6 +291,12 @@ int findLabelAddress(const char *labelName) { void fillInLabelAddresses(intermediateElement *intermediateArray, int arraySize) { for (int i = 0; i < arraySize; i++) { + // The Vector Segment is resolved separately. Most of what it holds is not a + // label at all: the words that name a vector are the segment's own, and looking + // them up here would report them as undefined. + if (intermediateArray[i].destination == VECTORS) { + continue; + } if (intermediateArray[i].type == LABEL) { // Look up the label in the label table int address = findLabelAddress(intermediateArray[i].token); @@ -122,12 +329,21 @@ static void checkOperands(intermediateElement *intermediateArray, int arraySize, int nextType = nextTokenType(intermediateArray, arraySize, i); const char *problem = NULL; - if (((opcode & 0xF0) == 0x10) && (opcode != 0x1F)) { + // Listed rather than matched on the high nibble, because not every instruction in + // the branch block takes an address: RET has none, and BRD gets its destination + // from a Data Pointer instead of from the program. + if (opcode == 0x10 || opcode == 0x11 || opcode == 0x12 || + opcode == 0x13 || opcode == 0x14 || opcode == 0x17) { // Branches and CALL take a two byte address, which only a label can supply. if (nextType != LABEL) problem = "Branch without label."; } else if ((opcode & 0xF0) == 0xD0 || (opcode & 0xF0) == 0xE0) { // The instruction is either an input or output and must be followed by a value. if (nextType != VALUE) problem = "I/O without destination port."; + } else if (opcode == 0x18) { + // SWI names a vector, either by the name it was given in the Vector Segment or, + // rarely, as a literal number. Without one it swallows whatever follows it and + // every address after that shifts. + if (nextType != VECTOR_REFERENCE && nextType != VALUE) problem = "SWI without a vector to go to."; } else if (opcode == 0x26 || opcode == 0x27) { // INIA and INIB must be followed by the literal value to load. if (nextType != VALUE) problem = "Immediate load without a value to load."; @@ -172,6 +388,17 @@ void populateOutputBuffers(intermediateElement *intermediateArray, int arraySize // Add literal value to Program buffer. Program[(*programCount)++] = intermediateArray[i].byteValue; break; + case VECTOR_REFERENCE: + // A vector is a number rather than a place, so this is one byte + // where a label would be two. + Program[(*programCount)++] = intermediateArray[i].byteValue; + break; + case PADDING: + case ALIGNMENT: + for (int z = 0; z < intermediateArray[i].byteLength; z++) { + Program[(*programCount)++] = 0x00; + } + break; case LABEL: // Split 16-bit label address into high and low bytes. Program[(*programCount)++] = (intermediateArray[i].address >> 8) & 0xFF; // High byte @@ -199,6 +426,12 @@ void populateOutputBuffers(intermediateElement *intermediateArray, int arraySize Data[(*dataCount)++] = (intermediateArray[i].address >> 8) & 0xFF; // High byte Data[(*dataCount)++] = intermediateArray[i].address & 0xFF; // Low byte break; + case PADDING: + case ALIGNMENT: + for (int z = 0; z < intermediateArray[i].byteLength; z++) { + Data[(*dataCount)++] = 0x00; + } + break; } } } @@ -230,7 +463,7 @@ void writeOutputFile(const char *outputFileName, uint8_t *Program, int programCo fputc(programSize & 0xFF, outputFile); // Low byte // Write the Program buffer to the file - if (fwrite(Program, sizeof(uint8_t), programCount, outputFile) != programCount) { + if (fwrite(Program, sizeof(uint8_t), programCount, outputFile) != (size_t)programCount) { fprintf(stderr, RED "Error: Failed to write Program data to file \"%s\".\n" RESET, outputFileName); fclose(outputFile); exit(1); @@ -245,13 +478,37 @@ void writeOutputFile(const char *outputFileName, uint8_t *Program, int programCo fputc(dataSize & 0xFF, outputFile); // Low byte // Write the Data buffer to the file - if (fwrite(Data, sizeof(uint8_t), dataCount, outputFile) != dataCount) { + if (fwrite(Data, sizeof(uint8_t), dataCount, outputFile) != (size_t)dataCount) { fprintf(stderr, RED "Error: Failed to write Data data to file \"%s\".\n" RESET, outputFileName); fclose(outputFile); exit(1); } + // The Vector Segment, only if the program named any. Leaving it out entirely is + // what lets a binary written before vectors existed still load: the reader treats + // the end of the file as an empty table rather than a missing one. + int vectorBytes = 0; + if (vectorArrayCount > 0) { + fwrite("VEC", sizeof(char), SEGMENT_MARKER_LENGTH, outputFile); + vectorBytes = vectorArrayCount * VECTOR_ENTRY_FILE_BYTES; + fputc((vectorBytes >> 8) & 0xFF, outputFile); + fputc(vectorBytes & 0xFF, outputFile); + for (int i = 0; i < vectorArrayCount; i++) { + uint16_t slot = vectorArray[i].base + (uint16_t)vectorArray[i].index * VECTOR_ENTRY_BYTES; + fputc((slot >> 8) & 0xFF, outputFile); + fputc(slot & 0xFF, outputFile); + fputc((vectorArray[i].handler >> 8) & 0xFF, outputFile); + fputc(vectorArray[i].handler & 0xFF, outputFile); + } + } + fclose(outputFile); printf("Successfully wrote SplitBit binary to \"%s\".\n", outputFileName); - printf(GREEN " Program Segment size: %d bytes.\n Data Segment size: %d bytes.\n Total size: %d bytes.\n" RESET, programCount, dataCount, (programCount + dataCount + SPLITBIT_HEADER_BYTES)); + printf(GREEN " Program Segment size: %d bytes.\n Data Segment size: %d bytes.\n" RESET, programCount, dataCount); + if (vectorArrayCount > 0) { + printf(GREEN " Vectors: %d.\n" RESET, vectorArrayCount); + } + printf(GREEN " Total size: %d bytes.\n" RESET, + (programCount + dataCount + SPLITBIT_HEADER_BYTES + + (vectorArrayCount > 0 ? SEGMENT_MARKER_LENGTH + SEGMENT_LENGTH_BYTES + vectorBytes : 0))); } diff --git a/Source/Assembler/secondPass.h b/Source/Assembler/secondPass.h index c250106..21d1b59 100644 --- a/Source/Assembler/secondPass.h +++ b/Source/Assembler/secondPass.h @@ -12,6 +12,7 @@ #include "Assm-util.h" #define MAX_LABELS 256 +#define MAX_VECTORS 256 typedef struct { char* label; @@ -19,8 +20,28 @@ typedef struct { int type; } Label; +// One line of the Vector Segment, once it has been worked out. +typedef struct { + char* name; // What it was called, or NULL for a device, which is named by its port. + uint8_t index; // Which vector in its table. + uint16_t base; // Which table: software or hardware. + uint16_t handler; // Where the handler ended up. +} VectorEntry; + void freeLabelList(); +void freeVectorList(); + +// Reads the Vector Segment: allocates a number to every named vector, works out which +// vector each device line means, and resolves the handlers. Runs after the labels are +// known, because a handler is named by its label. +void populateVectorTable(intermediateElement *intermediateArray, int arraySize); + +// Turns each vector name used as an operand of SWI into the number it was given. +void fillInVectorReferences(intermediateElement *intermediateArray, int arraySize); + +int vectorCount(); + void populateLabelTable(intermediateElement *intermediateArray, int arraySize); void fillInLabelAddresses(intermediateElement *intermediateArray, int arraySize); diff --git a/Source/Emulator/bootstrap.c b/Source/Emulator/bootstrap.c index dd615a6..80c927a 100644 --- a/Source/Emulator/bootstrap.c +++ b/Source/Emulator/bootstrap.c @@ -101,6 +101,49 @@ static uint8_t readSegment(FILE *file, const char *marker, uint8_t *Memory) { return loadSegment(file, Memory, length); } +// Reads the Vector Segment, which is optional and last. A file that simply ends here +// was written before vectors existed, and an empty table is exactly right for it: every +// entry reads as zero, which means no handler, and the boot vector reading zero means +// the program starts at 0x0000 the way it always did. +// +// Each entry says where in Program Memory the vector sits and where its handler is, so +// installing one is a write straight into the vector table. +static uint8_t readVectorSegment(FILE *file, uint8_t *Program) { + int first = fgetc(file); + if (first == EOF) { + return 0; + } + ungetc(first, file); + + char found[SEGMENT_MARKER_LENGTH + 1]; + if (readMarker(file, "VEC", SEGMENT_MARKER_LENGTH, found)) { + fprintf(stderr, "Error: Expected a \"VEC\" segment here, found \"%s\".\n", found); + return 1; + } + uint32_t length; + if (readNumber(file, SEGMENT_LENGTH_BYTES, "the vector segment length", &length)) { + return 1; + } + if (length % VECTOR_ENTRY_FILE_BYTES != 0) { + fprintf(stderr, "Error: The vector segment is %u bytes, which is not a whole number of vectors.\n", length); + return 1; + } + for (uint32_t i = 0; i < length / VECTOR_ENTRY_FILE_BYTES; i++) { + uint32_t slot, handler; + if (readNumber(file, 2, "a vector address", &slot) + || readNumber(file, 2, "a handler address", &handler)) { + return 1; + } + if (slot < SOFTWARE_VECTOR_BASE) { + fprintf(stderr, "Error: This binary puts a vector at 0x%04X, which is below the vector table.\n", slot); + return 1; + } + Program[slot] = (handler >> 8) & 0xFF; + Program[(uint16_t)(slot + 1)] = handler & 0xFF; + } + return 0; +} + uint8_t loadFile(char *path, uint8_t *Program, uint8_t *Data) { FILE *file = fopen(path, "rb"); if (file == NULL) { @@ -111,7 +154,8 @@ uint8_t loadFile(char *path, uint8_t *Program, uint8_t *Data) { // here means there is one exit, and so only one place that has to close the file. uint8_t failed = readFileHeader(file) || readSegment(file, "PRG", Program) - || readSegment(file, "DAT", Data); + || readSegment(file, "DAT", Data) + || readVectorSegment(file, Program); fclose(file); return failed; } diff --git a/Source/Emulator/cpu.c b/Source/Emulator/cpu.c index 792cc18..c5fc180 100644 --- a/Source/Emulator/cpu.c +++ b/Source/Emulator/cpu.c @@ -5,15 +5,78 @@ #include "cpu.h" #include "io.h" +#include "../Assembler/assembly.h" // For the vector table layout, which both tools share. uint16_t shiftRegister; +// Reads one entry out of a vector table. Most significant byte first, matching the +// branch instructions and the binary format. +static uint16_t readVector(const uint8_t *programMemory, uint16_t base, uint8_t index) { + uint16_t address = base + (uint16_t)index * VECTOR_ENTRY_BYTES; + return ((uint16_t)programMemory[address] << 8) | (uint16_t)programMemory[address + 1]; +} + +// Builds an interrupt frame and dispatches through a vector. The resume address is the +// address execution should carry on from once the handler returns, and it goes into the +// frame as a real address so that a handler can read it and make sense of it. +// +// Returns 0 if it dispatched. If the vector is empty there is nothing to dispatch to, so +// it raises a fault and returns 1 rather than jumping to the bottom of Program Memory +// and running whatever happens to be there. +// +// Note that a zero entry means "no handler" to everything that dispatches, including the +// two entries the CPU treats as start addresses when it reads them at reset. The +// exemption belongs to that one read, not to the entries themselves. +static uint8_t enterInterrupt(CPURegisters *cpu, uint16_t base, uint8_t index, uint16_t resumeAddress) { + uint16_t handler = readVector(cpu->Program, base, index); + if (handler == 0x0000) { + cpu->Fault = FAULT_NO_HANDLER; + cpu->FaultVector = index; + cpu->Status |= STATUS_FAULT; + cpu->Status |= STATUS_HALT; + return 1; + } + // Order mirrors genericCall exactly: low byte then high byte, lowest numbered Data + // Pointer first, so that anything walking the Stack sees a familiar shape. + cpu->Data[cpu->StackPointer] = resumeAddress & 0xFF; + cpu->StackPointer--; + cpu->Data[cpu->StackPointer] = (resumeAddress >> 8) & 0xFF; + cpu->StackPointer--; + for (int i = 0; i < DATA_POINTERS; i++) { + cpu->Data[cpu->StackPointer] = cpu->DataPointer[i] & 0xFF; + cpu->StackPointer--; + cpu->Data[cpu->StackPointer] = (cpu->DataPointer[i] >> 8) & 0xFF; + cpu->StackPointer--; + } + cpu->Data[cpu->StackPointer] = cpu->B; + cpu->StackPointer--; + cpu->Data[cpu->StackPointer] = cpu->A; + cpu->StackPointer--; + cpu->Data[cpu->StackPointer] = cpu->Q; + cpu->StackPointer--; + cpu->Data[cpu->StackPointer] = cpu->Status; + cpu->StackPointer--; + // A handler runs with hardware interrupts held off unless it says otherwise, so an + // interrupt cannot arrive inside the handler for another one and grow the Stack + // without bound. The old setting rode into the frame inside the Status register, so + // RETI puts it back without anything having to remember it separately. + cpu->Status &= ~STATUS_INTERRUPT; + // The Program Counter is stepped after every instruction, so land one short of the + // handler and let that step land on its first byte. genericBranch does the same. + cpu->ProgramCounter = handler - 1; + return 0; +} + void initializeCPU(CPURegisters *cpu, uint8_t *programMemory, uint8_t *dataMemory) { cpu->A = 0; cpu->B = 0; cpu->Q = 0; cpu->Status = 0; - cpu->ProgramCounter = 0x0000; + // Execution begins wherever the boot vector points. It is a start address rather + // than a handler, so a zero there is not "nothing installed" but the address + // 0x0000, which is where a program carrying no vector table of its own begins. + // That is what lets everything written before the table existed still run. + cpu->ProgramCounter = readVector(programMemory, SOFTWARE_VECTOR_BASE, VECTOR_BOOT); // Every Data Pointer starts at the bottom of Data Memory. for (int i = 0; i < DATA_POINTERS; i++) { cpu->DataPointer[i] = 0x0000; @@ -21,6 +84,8 @@ void initializeCPU(CPURegisters *cpu, uint8_t *programMemory, uint8_t *dataMemor cpu->StackPointer = 0xFFFF; cpu->Program = programMemory; cpu->Data = dataMemory; + cpu->Fault = FAULT_NONE; + cpu->FaultVector = 0; } void genericBranch(CPURegisters *cpu){ @@ -70,25 +135,29 @@ uint16_t *selectDataPointer(CPURegisters *cpu) { } uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { + // ADD and SUB share this. It is declared here rather than after a case label + // because a label may only be followed by a statement in ISO C, and a + // declaration is not one. + uint16_t result; switch(Instruction) { // 0x - Arithmetic and Logic Operations. case 0x00: // ADD - A + B + Carry -> Q - uint16_t result = (uint16_t)cpu->A + (uint16_t)cpu->B + (cpu->Status & 0x01); + result = (uint16_t)cpu->A + (uint16_t)cpu->B + (cpu->Status & STATUS_CARRY); if (result > 255) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->Q = result & 0xFF; break; case 0x01: // SUB - A - B - Carry -> Q - result = (uint16_t)cpu->A - (uint16_t)cpu->B - (cpu->Status & 0x01); + result = (uint16_t)cpu->A - (uint16_t)cpu->B - (cpu->Status & STATUS_CARRY); if (result > 255) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->Q = result & 0xFF; break; @@ -162,16 +231,68 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { break; case 0x14: // BRC - Do an immediate branch if the Carry Flag is set. - if (cpu->Status & 0x01) { + if (cpu->Status & STATUS_CARRY) { genericBranch(cpu); } else { cpu->ProgramCounter+=2; } break; + case 0x15: { + // BRD - Branch to the address held in a Data Pointer. + // This is the only branch whose destination is not written into the + // program, which is what makes a table of addresses something a program + // can dispatch through rather than only read. + uint16_t destination = *selectDataPointer(cpu); + // stepCPU adds one after every instruction, so aim one short. + cpu->ProgramCounter = destination - 1; + } + break; case 0x17: // CALL - Push the Program Counter to the Stack, and perform an immediate branch. genericCall(cpu); break; + case 0x18: { + // SWI - Software Interrupt. The byte after the opcode names the vector. + // Never masked: this is an instruction the program deliberately ran, not + // something a device asked for. + uint16_t site = cpu->ProgramCounter; + cpu->ProgramCounter++; + uint8_t vector = cpu->Program[cpu->ProgramCounter]; + // Execution resumes after the operand, which the Program Counter is sitting + // on, so the resume address is one further on than that. + if (enterInterrupt(cpu, SOFTWARE_VECTOR_BASE, vector, cpu->ProgramCounter + 1)) { + // No handler. Leave the Program Counter on the SWI itself rather than + // its operand, so the report names the instruction that failed. + cpu->ProgramCounter = site - 1; + } + } break; + case 0x19: { + // RETI - Return from an interrupt. Pops the frame in the exact reverse of + // the order enterInterrupt pushed it. + cpu->StackPointer++; + cpu->Status = cpu->Data[cpu->StackPointer]; + cpu->StackPointer++; + cpu->Q = cpu->Data[cpu->StackPointer]; + cpu->StackPointer++; + cpu->A = cpu->Data[cpu->StackPointer]; + cpu->StackPointer++; + cpu->B = cpu->Data[cpu->StackPointer]; + for (int i = DATA_POINTERS - 1; i >= 0; i--) { + cpu->StackPointer++; + cpu->DataPointer[i] = (uint16_t)cpu->Data[cpu->StackPointer] << 8; + cpu->StackPointer++; + cpu->DataPointer[i] |= (uint16_t)cpu->Data[cpu->StackPointer]; + } + uint16_t resumeAddress; + cpu->StackPointer++; + resumeAddress = (uint16_t)cpu->Data[cpu->StackPointer] << 8; + cpu->StackPointer++; + resumeAddress = resumeAddress | (uint16_t)cpu->Data[cpu->StackPointer]; + // The frame holds the address to carry on from. The Program Counter is + // stepped after every instruction, so land one short of it. RET does the + // same job with its +2, for the same reason. + cpu->ProgramCounter = resumeAddress - 1; + } break; case 0x1F: // RET - Return from subroutine, restore the registers and set the Program Counter to the Return Address. // Pop A from the Stack. @@ -213,9 +334,9 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { // INCA - Add 1 to A. // Set the Carry Flag if the register overflows. if (cpu->A == 0xFF) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->A++; break; @@ -223,9 +344,9 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { // INCB - Add 1 to B. // Set the Carry Flag if the register overflows. if (cpu->B == 0xFF) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->B++; break; @@ -233,9 +354,9 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { // DECA - Subtract 1 from A. // Set the Carry Flag if the register underflows. if (cpu->A == 0x00) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->A--; break; @@ -243,9 +364,9 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { // DECB - Subtract 1 from B. // Set the Carry Flag if the register underflows. if (cpu->B == 0x00) { - cpu->Status |= 0x01; + cpu->Status |= STATUS_CARRY; } else { - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; } cpu->B--; break; @@ -261,7 +382,25 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { break; case 0x28: // CCF - Clear the Carry Flag. - cpu->Status &= ~0x01; + cpu->Status &= ~STATUS_CARRY; + break; + case 0x29: + // MVQA - Copy Q into A. + cpu->A = cpu->Q; + break; + case 0x2A: + // MVQB - Copy Q into B. + cpu->B = cpu->Q; + break; + case 0x2B: + // SIF - Set the Interrupt Flag, enabling hardware interrupts. + cpu->Status |= STATUS_INTERRUPT; + break; + case 0x2C: + // CIF - Clear the Interrupt Flag, disabling hardware interrupts. + // Software interrupts and faults are delivered either way, so this + // only ever holds off a device. + cpu->Status &= ~STATUS_INTERRUPT; break; // // 3x - Stack Operations: @@ -390,6 +529,18 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { cpu->Data[(uint16_t)(address + 1)] = value & 0xFF; } break; + case 0x4C: { + // MVSD - Copy the Stack Pointer into the selected Data Pointer. + // + // The Stack Pointer still cannot be written, so this does not let a program + // move the Stack. It lets a program find it, which is what reading anything + // already on the Stack requires. An interrupt handler needs this to reach + // its own frame, and so does anything that wants to walk back through the + // calls that led to where it is. + uint16_t *target = selectDataPointer(cpu); + *target = cpu->StackPointer; + } + break; // // Dx - Output Operations: // @@ -429,7 +580,7 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { break; case 0xFF: // HALT - Set the Halt Bit of the Status Register. - cpu->Status |= 0x80; + cpu->Status |= STATUS_HALT; break; default: // Unknown Instruction. @@ -439,9 +590,51 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { } void stepCPU(CPURegisters *cpu) { - if (!(cpu->Status & 0x80)) { + if (!(cpu->Status & STATUS_HALT)) { + // A device asking for attention is answered between instructions and never + // inside one, so the address that goes into the frame is always the start of an + // instruction and RETI always lands somewhere meaningful. + // + // A line that is up while the Interrupt Flag is clear stays up. Masking holds a + // device off; it does not lose what the device was asking for. + if (cpu->Status & STATUS_INTERRUPT) { + int port = nextPendingInterrupt(); + if (port >= 0) { + clearInterrupt((uint8_t)port); + if (enterInterrupt(cpu, HARDWARE_VECTOR_BASE, (uint8_t)port, cpu->ProgramCounter)) { + // The device asked and nobody was listening. enterInterrupt has + // already stopped the machine; correct the cause, because the empty + // entry is in the hardware table rather than the software one. + cpu->Fault = FAULT_NO_DEVICE_HANDLER; + return; + } + // Entering the handler is what this cycle did, so no instruction runs. + // The step puts the Program Counter on the handler's first byte, the + // same way it does everywhere else. + cpu->ProgramCounter++; + return; + } + } // The CPU is not halted, so do a cycle. - executeOperation(cpu->Program[cpu->ProgramCounter], cpu); + if (executeOperation(cpu->Program[cpu->ProgramCounter], cpu)) { + // Nothing decodes that byte. Hand it to the fault vector, which gets the + // address of the offending byte itself rather than the one after it, so + // that a handler can read the byte that failed and say what it was. + // + // A handler returning with a bare RETI will therefore meet the same byte + // again. That is the documented behaviour: resuming past a fault means + // deciding where to resume, which is the handler's business and not the + // CPU's guess. + uint16_t faultingAddress = cpu->ProgramCounter; + if (enterInterrupt(cpu, SOFTWARE_VECTOR_BASE, VECTOR_INVALID_OPCODE, faultingAddress)) { + // Nothing is installed, so stop where we are. The Program Counter is + // still on the offending byte, which is what the report wants. The + // cause is the byte, not the empty vector, so say so. + cpu->Fault = FAULT_BAD_OPCODE; + return; + } + // Dispatched. Fall through, so the step below lands on the handler. + } cpu->ProgramCounter++; } } diff --git a/Source/Emulator/cpu.h b/Source/Emulator/cpu.h index 15ed2fd..630a0b3 100644 --- a/Source/Emulator/cpu.h +++ b/Source/Emulator/cpu.h @@ -26,6 +26,30 @@ #error "Cannot preserve more Data Pointers than the CPU has." #endif +// The bits of the Status register that mean something. +#define STATUS_CARRY 0x01 // An arithmetic result carried out of, or borrowed into, a byte. +#define STATUS_FAULT 0x02 // The CPU met a byte it could not decode, and stopped. +#define STATUS_INTERRUPT 0x04 // Hardware interrupts are enabled. Nothing reads this yet. +#define STATUS_HALT 0x80 // Execution has stopped, either from HALT or from a fault. + +// What an interrupt puts on the Stack: the resume address, every Data Pointer, and +// every register the CPU has. The CALL frame leaves Q and DP3 alone, but that is a +// convention between a caller and the subroutine it called. An interrupt arrives in +// code that never agreed to give anything up, so it saves the lot. +#define INTERRUPT_FRAME_BYTES (2 + DATA_POINTERS * 2 + 4) + +// Why the CPU stopped, when the Fault Flag is set. This is not something a program can +// read, and it is deliberately not a register: when a handler is installed, the vector +// it arrived through already says what happened, which is why the ISA has no fault +// cause. This exists for the case where nothing is installed and the machine is dead, +// so that whatever examines the wreckage can say something better than "it stopped". +typedef enum { + FAULT_NONE = 0, + FAULT_BAD_OPCODE, // A byte that does not decode to an instruction. + FAULT_NO_HANDLER, // Dispatched through a software vector with nothing in it. + FAULT_NO_DEVICE_HANDLER // A device interrupted, and its vector was empty. +} FaultCause; + // The struct containing the CPU registers. typedef struct { uint8_t A; @@ -37,6 +61,9 @@ typedef struct { uint16_t StackPointer; uint8_t *Program; uint8_t *Data; + // Set alongside the Fault Flag, and read only by whatever reports the stop. + uint8_t Fault; // A FaultCause. + uint8_t FaultVector; // Which vector was empty, when Fault is FAULT_NO_HANDLER. } CPURegisters; uint8_t executeOperation(uint8_t instruction, CPURegisters *cpu); diff --git a/Source/Emulator/emulator.c b/Source/Emulator/emulator.c index cd5c616..d400f86 100644 --- a/Source/Emulator/emulator.c +++ b/Source/Emulator/emulator.c @@ -99,7 +99,12 @@ int main (int argc, char *argv[]) { cycle_timer_init(&timer, CYCLE_RATE); uint8_t limitReached = 0; - while (!(cpu.Status & 0x80) && !limitReached) { + while (!(cpu.Status & STATUS_HALT) && !limitReached) { + if (options.debug) { + // Wait before advancing, not after, so that a keypress is what moves the + // machine on rather than something that happens once it already has. + getchar(); + } int cycles; if (options.debug) { // Debug mode advances one instruction per keypress, so the wall clock @@ -113,7 +118,7 @@ int main (int argc, char *argv[]) { for (int i = 0; i < cycles; i++) { stepCPU(&cpu); cycleCount++; - if (cpu.Status & 0x80) { + if (cpu.Status & STATUS_HALT) { // We've halted. break; } @@ -123,13 +128,26 @@ int main (int argc, char *argv[]) { } } if (options.debug) { - getchar(); printRegisters(&cpu, Program, Data); printf("Cycle: %lu\n", cycleCount); } } if (limitReached) { printf("Execution stopped after %lu cycles. (cycle limit reached)\n", cycleCount); + } else if (cpu.Status & STATUS_FAULT) { + // The Program Counter is still pointing at whatever the CPU could not get past. + printf("Execution halted after %lu cycles.\n", cycleCount); + if (cpu.Fault == FAULT_NO_HANDLER) { + fprintf(stderr, "Fault: Software vector %u, dispatched from Program Address 0x%04X, has no handler installed.\n", + cpu.FaultVector, cpu.ProgramCounter); + } else if (cpu.Fault == FAULT_NO_DEVICE_HANDLER) { + fprintf(stderr, "Fault: The device on port %u interrupted at Program Address 0x%04X, and hardware vector %u has no handler installed.\n", + cpu.FaultVector, cpu.ProgramCounter, cpu.FaultVector); + } else { + fprintf(stderr, "Fault: 0x%02X at Program Address 0x%04X is not an instruction.\n", + Program[cpu.ProgramCounter], cpu.ProgramCounter); + } + return 1; } else { printf("Execution halted after %lu cycles.\n", cycleCount); } diff --git a/Source/Emulator/io.c b/Source/Emulator/io.c index 5fcaa47..7164ce0 100644 --- a/Source/Emulator/io.c +++ b/Source/Emulator/io.c @@ -6,6 +6,37 @@ #include "io.h" #include +// One bit per port, so a device can ask for attention without anything having to poll +// it. Eight ports to the byte, low bit first. +#define INTERRUPT_LINE_BYTES 32 + +static uint8_t pendingInterrupts[INTERRUPT_LINE_BYTES]; + +void raiseInterrupt(uint8_t port) { + pendingInterrupts[port >> 3] |= (uint8_t)(1u << (port & 7)); +} + +void clearInterrupt(uint8_t port) { + pendingInterrupts[port >> 3] &= (uint8_t)~(1u << (port & 7)); +} + +int nextPendingInterrupt(void) { + // Lowest numbered port wins. This is a scan rather than a priority encoder, which + // means there is no arbitration to explain and a programmer can work out what + // happens next by reading the port numbers. + for (int group = 0; group < INTERRUPT_LINE_BYTES; group++) { + if (pendingInterrupts[group] == 0) { + continue; + } + for (int bit = 0; bit < 8; bit++) { + if (pendingInterrupts[group] & (1u << bit)) { + return group * 8 + bit; + } + } + } + return -1; +} + uint8_t OutputHandler(uint8_t DataByte, uint8_t Address) { // This function sends the DataByte to the appropriate place based on the Port Address. switch(Address) { @@ -15,6 +46,14 @@ uint8_t OutputHandler(uint8_t DataByte, uint8_t Address) { // Later, I'll want to use a buffer for this for performance, probably. putchar(DataByte); break; + case 0x10: + // A test device, and about the simplest one that can exist: writing to it + // puts its own line up. It stands in for the shape a real device has, where + // the CPU asks for something and is interrupted once the answer is ready, + // with the waiting taken out so that a test runs the same way every time. + // The byte written is ignored; only the asking matters. + raiseInterrupt(0x10); + break; default: // Writes to unused Output Ports are ignored. return 1; diff --git a/Source/Emulator/io.h b/Source/Emulator/io.h index ca40cb1..04e2f50 100644 --- a/Source/Emulator/io.h +++ b/Source/Emulator/io.h @@ -13,4 +13,20 @@ uint8_t OutputHandler(uint8_t DataByte, uint8_t Address); uint8_t InputHandler(uint8_t Address); +// ---- Interrupt lines ---- +// +// One line per port. A device puts its line up to ask for attention, and the CPU takes +// it down when it answers. Which line a device uses is not a choice: a device on port N +// interrupts on N, which is what saves the machine from needing any arbitration. +// +// These belong to the bus rather than to the CPU. Nothing here is saved in a frame, and +// a program cannot read them except by being interrupted. + +void raiseInterrupt(uint8_t port); + +void clearInterrupt(uint8_t port); + +// The lowest numbered port with its line up, or -1 if none of them are. +int nextPendingInterrupt(void); + #endif // IO_H diff --git a/Source/Emulator/utility.c b/Source/Emulator/utility.c index e55c9c1..3560f3c 100644 --- a/Source/Emulator/utility.c +++ b/Source/Emulator/utility.c @@ -68,11 +68,31 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) { return OPTIONS_OK; } +// Writes a byte out as eight binary digits, most significant first. printf's %b is +// a recent addition to C and not available everywhere, so this does it by hand. +// The buffer must have room for nine characters. +static void formatBinary(uint8_t value, char *out) { + for (int i = 0; i < 8; i++) { + out[i] = (value & (0x80 >> i)) ? '1' : '0'; + } + out[8] = '\0'; +} + void printRegisters(CPURegisters *cpu, uint8_t *Program, uint8_t *Data) { + char status[9]; + formatBinary(cpu->Status, status); printf("***** CPU Registers *****\n"); - printf("A: 0x%02X\tB: 0x%02X\tQ: 0x%02X\tStatus: 0b%08b\n", cpu->A, cpu->B, cpu->Q, cpu->Status); + printf("A: 0x%02X\tB: 0x%02X\tQ: 0x%02X\tStatus: 0b%s\n", cpu->A, cpu->B, cpu->Q, status); printf("Program Counter: 0x%04X Current Instruction: 0x%02X (%s)\n", cpu->ProgramCounter, Program[cpu->ProgramCounter],getMnemonic(Program[cpu->ProgramCounter])); - printf(" Data Pointer: 0x%04X Current Data Value: 0x%02X\n", cpu->DataPointer[0], Data[cpu->DataPointer[0]]); - printf(" Stack Pointer: 0x%04X Current Value: (0x%02X) (0x%02X)\n", cpu->StackPointer, Data[cpu->StackPointer+1], Data[cpu->StackPointer+2]); + for (int i = 0; i < DATA_POINTERS; i++) { + printf(" Data Pointer %d: 0x%04X Current Data Value: 0x%02X%s\n", + i, cpu->DataPointer[i], Data[cpu->DataPointer[i]], + i >= PRESERVED_DATA_POINTERS ? " (volatile)" : ""); + } + // The two casts keep these inside Data Memory. The Stack Pointer starts at the + // very top, so without them the display would read off the end of the array + // before a single byte has been pushed. + printf(" Stack Pointer: 0x%04X Current Value: (0x%02X) (0x%02X)\n", cpu->StackPointer, + Data[(uint16_t)(cpu->StackPointer + 1)], Data[(uint16_t)(cpu->StackPointer + 2)]); } diff --git a/SplitBit Assembler Manual.md b/SplitBit Assembler Manual.md index f309321..99d6cc2 100644 --- a/SplitBit Assembler Manual.md +++ b/SplitBit Assembler Manual.md @@ -1,13 +1,16 @@ # SplitBit Assembler Manual: -SplitBit assembly syntax is similar to many other assembler syntaxes. Whitepsace at the start or end of a line is disregarded by the assembler and may be used to make programs more readable to the programmer. The Instruction Mnemonics are listed in the SplitBit Programming Manual, and the assembler is not case sensitve in regard to the mnemonics. +SplitBit assembly syntax is similar to many other assembler syntaxes. Whitespace at the start or end of a line is disregarded by the assembler and may be used to make programs more readable to the programmer. The Instruction Mnemonics are listed in the SplitBit Programming Manual, and the assembler is not case sensitive in regard to the mnemonics. A semicolon, ';', denotes the start of a comment, anything beyond it on a line is disregarded by the assembler. -Special Keywords are denoted with hash marks, '#'. The Keywords are #Include, #Program, and #Data. +Special Keywords are denoted with hash marks, '#'. The Keywords are #Include, #Program, #Data, #Vectors, #Align, and #Reserve. + +The first four say what kind of thing follows them. #Align and #Reserve are instructions to the assembler in the middle of a segment, and are described under Moving The Cursor Along. SplitBit programs must have a Program Segment. You define the start of a program with the #Program Keyword. SplitBit programs may have a Data Segment. You may define the start of the data with the #Data Keyword. +SplitBit programs may have a Vector Segment. You define it with the #Vectors Keyword. See The Vector Segment below. ## Literal Values: @@ -15,7 +18,7 @@ Literal values may be defined in a few ways. Numerical values must be within the The assembler will accept: - Hexadecimal values prefaced with 0x, eg. 0x00, 0x7F. - Decimal values prefaced with 0d, eg. 0d0, 0d120, 0d255. -- Strings enclosed in double qoutes, eg. "a", "Hello, World!", "It is dark, you are likely to be eaten by a grue." +- Strings enclosed in double quotes, eg. "a", "Hello, World!", "It is dark, you are likely to be eaten by a grue." Any token beginning with a '0' is read as a numerical literal, so a malformed one is an error rather than something the assembler tries to interpret as a label. This also means a label cannot begin with a '0'. @@ -31,6 +34,8 @@ loopStart: errorHandler01: ``` +A name may only be defined once across a program and everything it includes. Defining it twice is an error, because otherwise a reference resolves to whichever definition came first, and a typo or a name that two libraries both happen to use is very hard to track down. + A label may be referenced by name, without the colon, to place its two byte address wherever the reference appears. In the Program Segment that is how the branch instructions and SETD are given somewhere to go. In the Data Segment it writes the address down as data, which is how a table of addresses is built for LDD to walk. @@ -78,10 +83,82 @@ Writing a selector on an instruction that does not work through a Data Pointer i ## Instruction Operands: -Instructions that read operand bytes out of Program Memory must be followed by those operands. The branch instructions and CALL take a label; SETD takes a label or a pair of literal bytes; INIA, INIB, DPUP, DPDN, and the input and output instructions each take a single literal byte. +Instructions that read operand bytes out of Program Memory must be followed by those operands. The branch instructions and CALL take a label; SETD takes a label or a pair of literal bytes; INIA, INIB, DPUP, DPDN, and the input and output instructions each take a single literal byte; SWI takes the name of a vector, or a literal number. + +Leaving an operand off is an error rather than something the assembler works around, because the instruction would otherwise take whatever followed it as the operand and every address after that would shift. Data Pointer selectors do not count as operands here, because they are written on the mnemonic rather than after it. +## Moving The Cursor Along: + +Both segments are written from the beginning, and every label stands for wherever the cursor had reached when the assembler met it. Two directives move that cursor without you having to write zeroes by hand. + +`#Align` puts down as many zero bytes as it takes to reach the next multiple of the number that follows it. + +``` +#Data + + #Align 0x100 +Segment: ; Guaranteed to begin at a page boundary. +``` + +This matters for code that does address arithmetic on a pointer's low byte and treats the carry out as reaching the end of something. Both prime sieves work that way, and both now ask for the boundary themselves. Before this existed they relied on print.asm padding its data out to a whole page, which worked but put the requirement in a different file from the code that needed it, and quietly charged every other program 253 bytes for it. + +`#Reserve` puts down the number of zero bytes that follows it, so that a label can stand for a whole region rather than just its first byte. + +``` +#Data + +Buffer: + #Reserve 0d256 ; Anything after this begins 256 bytes further on. +Next: +``` + +Without it a label like Buffer is one byte as far as the assembler knows, so a later label lands inside the region and the two quietly overlap. + +Both take a number written the way literals are, prefaced with 0x or 0d, but the number may go up to 0xFFFF rather than being held to a single byte. Neither number is ever emitted, so a byte's range would be the wrong limit: a page alignment needs 256, and a reservation is often much larger. + +Both work in the Program Segment as well as the Data Segment, and both are an error anywhere else, because outside a segment there is no cursor to move. + +## The Vector Segment: + +A vector says where to go when something happens: the machine starting up, a program asking for a service, a device wanting attention, or the CPU meeting a byte it cannot decode. The Vector Segment says which of your routines belongs to which vector, and the assembler works out the rest. + +A program does not need one. Without a Vector Segment a program starts at the beginning and behaves exactly as it always has. + +Every line names a vector and then the label of the routine that handles it. + +``` +#Vectors + + Boot realStart + BadOpcode reportFault + openFile openFileHandler + Device 0x10 diskReady +``` + +Three names already mean something: + +| Name | Vector | +| --- | --- | +| Boot | Where the machine begins at power on. Without this a program starts at the beginning of its Program Segment. | +| SoftReset | A warm restart. SWI SoftReset is how a program asks for one. | +| BadOpcode | The CPU met a byte that is not an instruction. | + +Anything else you name is a software interrupt of your own. You do not choose its number and you never write one: the assembler allocates them in the order they appear, starting above the range held back for faults that do not exist yet. That is the same bargain as labels everywhere else in SplitBit assembly, where you name a thing and let the assembler work out where it went. + +You then use the name as the operand of SWI: + +``` + SWI openFile +``` + +A device is different, because its number is not a choice. A device interrupts on the port it is plugged into, so the Device line says which port rather than giving it a name of its own. The port is a literal value, and the routine after it handles that device. + +The assembler will refuse two handlers for the same vector, a name used with SWI that no Vector Segment gives a handler to, and a handler that is not a label. + +Vectors 3 through 15 are held back for faults that have not been defined yet. They have no names, so there is currently no way to write a handler for one, and none is needed: each will be given a name of its own as the fault it stands for is defined. Because you never write a vector number, there is no way to land on one of them by accident either. + ## Including Other Files: The #Include Keyword tells the assembler to load another file to be assembled along with the current file. It is more or less equivalent to copying the contents of the included file into the current file being processed. You simply put the name of the file to include after the keyword. @@ -141,7 +218,7 @@ Programs/makefile in this repository builds every program that way, if you would #Program -start: ; By uninforced convention, Program Labels start with a lowercase letter. +start: ; By unenforced convention, Program Labels start with a lowercase letter. SETD HelloString ; Set the Data Pointer to the address of the string. CALL printString ; Call the string printing subroutine. HALT ; End the program. @@ -158,7 +235,7 @@ printString: ; Expects Data Pointer to be set to the beginning of the str #Data -HelloString: ; By uninforced convention, Data Labels start with a capital letter. +HelloString: ; By unenforced convention, Data Labels start with a capital letter. "Hello, World!" ``` @@ -197,3 +274,78 @@ Dest: ``` Remember that DP0, DP1 and DP2 survive a CALL, so a loop like this one can call a subroutine in the middle without losing either pointer. DP3 does not survive, which is what makes it the pointer a subroutine uses to hand an address back. + +## An Example Using Interrupts: + +This program installs three handlers and never writes a vector number. The Boot Vector sends the machine somewhere other than the first byte of the program, a trap the program names for itself is reached with SWI, and the test device on port 0x10 is caught when it asks for attention. + +``` +; Interrupt handling from all three directions. + +#Program + +start: + CIF ; Hold devices off while we set up. + SETD.0 Greeting + CALL printString + + SWI announce ; A trap of our own, reached by name. + + INIA 0d1 + OUTA 0x10 ; Ask the test device for attention. Its line goes up. + SIF ; Let it through. It is answered before the next instruction. + + HALT + +; A trap. It is entered with a full frame, so it may use any register it likes +; without agreeing anything with the code it interrupted. +announce: + SETD.0 Trapped + CALL printString + RETI + +; The device handler. Reached because the device sits on port 0x10. +deviceReady: + SETD.0 Device + CALL printString + RETI + +; The fault handler. It reports and stops, rather than trying to carry on. +reportFault: + SETD.0 Broken + CALL printString + HALT + +printString: ; Expects DP0 to be set to the beginning of the string. + LDA.0 + BRA printDone + OUTA 0x00 + INCD.0 + BRI printString + printDone: + INIA 0x0A + OUTA 0x00 + RET + +#Data + +Greeting: +"ready" +Trapped: +"trap" +Device: +"device" +Broken: +"bad opcode" + +#Vectors + + Boot start ; Begin here rather than at the first byte. + BadOpcode reportFault + announce announce ; A name of our own. The assembler numbers it. + Device 0x10 deviceReady ; Named by the port, because that is what decides it. +``` + +The output is `ready`, `trap`, then `device`. + +Note that a vector name and a routine name are kept apart, so naming both `announce` is allowed. If that reads as confusing, name them differently: nothing requires them to match. diff --git a/SplitBit Programming Manual.md b/SplitBit Programming Manual.md index 1b6b98a..ca47c69 100644 --- a/SplitBit Programming Manual.md +++ b/SplitBit Programming Manual.md @@ -16,8 +16,8 @@ It has ten registers: - Q is not preserved through subroutine calls. It can be used to pass a one byte result back to the calling routine. - The Program Counter is a 16 bit pointer into the Program Memory. - - The PC points to the current operation the CPU is executing, it initializes at Program Address 0x0000. - - The PC is only modified by the branch instructions and the CALL and RET instructions. It cannot be directly set by the programmer. + - The PC points to the current operation the CPU is executing. It starts at whatever address the Boot Vector holds. See The Vector Table below. + - The PC is only modified by the branch instructions, by CALL and RET, by SWI and RETI, and by an interrupt arriving. It cannot be directly set by the programmer. - The Data Pointers (0-3) are 16 bit pointers into the Data Memory. - A DP points to a byte of data that the CPU can read or write, and each one initializes at Data Address 0x0000. @@ -27,17 +27,121 @@ It has ten registers: - Because DP3 is not preserved, a subroutine can use it to pass an address back to the calling routine, in the same way Q passes back a byte. Unlike Q, an address can refer to as much data as you like. - The Stack Pointer is a 16 bit pointer into the Data Memory. - - The SP points to the current element of the stack, it initializes at location 0xFFFF. - - The SP value is only modified by the push and pop instructions and cannot be set by the programmer. - - The Stack lives in Data Memory, so a Data Pointer can be aimed at it and used to read what is on it. + - The SP points to the next free slot, not to the last thing pushed. It initializes at location 0xFFFF, so the first push writes there and the byte pushed last always sits one above the SP. + - The SP value is only modified by the push and pop instructions, by CALL and RET, and by an interrupt arriving or returning. It cannot be set by the programmer. MVSD copies it out without moving it. + - The Stack lives in Data Memory, so a Data Pointer can be aimed at it and used to read what is on it. MVSD is how a program finds out where to aim. - - The Status register is an 8 bit register whose various bits are used as flags. Only two of these flags are used in the current implementation. + - The Status register is an 8 bit register whose various bits are used as flags. Only four of these flags are used in the current implementation. - Bit 0 is the Carry/Borrow Flag. Any arithmetic operation either sets or clears it depending on whether or not the result causes Q to overflow/underflow. It is a 1 if a carry/underflow occurred, and a 0 otherwise. If A or B overflows or underflows from the use of an increment or decrement instruction, this flag will also be set. Non-overflowing increments or decrements will also reset it. - - Bit 7 is the Halt Flag. It is set by the HALT instruction. + - Bit 1 is the Fault Flag. It is set when the CPU cannot get past something and no handler was installed to deal with it: a byte that is not an instruction, or a dispatch through an empty vector. See Faults below. + - Bit 2 is the Interrupt Flag. It is set by SIF and cleared by CIF. While it is set the CPU answers devices asking for attention; while it is clear they wait. Arriving at a handler clears it, and RETI restores it along with the rest of the Status register. See Hardware Interrupts below. + - Bit 7 is the Halt Flag. It is set by the HALT instruction, and by a fault. + +## The Vector Table: + +The top kilobyte of Program Memory is reserved for vectors. Each entry is two bytes, most significant byte first, and holds a Program Memory address. + +| Address | Contents | +| --- | --- | +| 0xFC00 | Software vectors 0 to 255 | +| 0xFE00 | Hardware vectors 0 to 255, one for each I/O port | + +Program text may not run past 0xFBFF. The assembler refuses to assemble a program that would. + +The software vectors are given out like this: + +| Vector | Meaning | +| --- | --- | +| 0 | The Boot Vector. Where the machine begins at power on. | +| 1 | The Soft Reset Vector. A warm restart. | +| 2 | A byte that is not an instruction. | +| 3 to 15 | Held back for faults not yet defined. | +| 16 and up | A program's own, given out by the assembler in the order they are named. | + +A programmer does not write vector numbers. Handlers are named in the Vector Segment of an assembly file and used by name, the same way every other address in SplitBit is worked out by the assembler rather than typed. See the SplitBit Assembler Manual. + +The table holds two kinds of entry, and they behave differently when they are zero. + +Software vectors 0 and 1 are start addresses rather than handlers. Vector 0 is the Boot Vector: the CPU reads it at power on and begins executing there. Vector 1 is the Soft Reset Vector, for a warm restart. Nothing dispatches through either of them, and 0x0000 is an ordinary address to begin at, so a zero in one of these two means exactly what it says: start at 0x0000. + +That is deliberate, and it is what lets a program that carries no vector table of its own still run. Program Memory reads as zero where nothing was loaded into it, so such a program's Boot Vector reads 0x0000, which is where its first instruction sits. + +The cost of that rule is worth knowing: a machine with neither a Boot Vector nor anything at 0x0000 will start executing zeroes, and 0x00 decodes as ADD, so it will wander instead of stopping. There is no way for the CPU to tell that case apart from a program that genuinely begins at 0x0000. + +Every other entry is a handler. A zero in one of those means no handler is installed, and dispatching through it is a fault rather than a jump to the bottom of memory. + +The exemption for vectors 0 and 1 belongs to that one read the CPU makes at reset, not to the entries themselves. Anything that dispatches treats a zero as no handler, whichever entry it is, so SWI SoftReset through an empty Soft Reset Vector faults like any other. That is what makes SWI SoftReset the way to ask for a warm restart once one has been installed. + +## Interrupts: + +An interrupt is an involuntary transfer of control. A subroutine call is agreed to by the code that makes it, so CALL can leave Q and Data Pointer 3 alone and let a subroutine pass results back through them. An interrupt arrives in code that has never heard of it, where Q and DP3 are ordinary working registers, so it saves everything: + +| Pushed | Bytes | +| --- | --- | +| The address to resume at | 2 | +| Data Pointers 0 through 3 | 8 | +| B, then A, then Q, then Status | 4 | + +That is fourteen bytes of Stack per interrupt, and the order matches CALL: least significant byte first, lowest numbered Data Pointer first. + +Entry clears the Interrupt Flag, so a handler runs without being interrupted again unless it sets the flag itself. The old value of the flag rides into the frame inside the Status register, so RETI restores it along with everything else and nothing has to remember it separately. + +RETI pops the frame and carries on from the address in it. The frame holds a real address rather than an adjusted one, so a handler can read it and make sense of where it came from. + +A handler reaches its own frame with MVSD. The Stack Pointer points at the next free slot, so everything in the frame sits above it: + +| Offset from the Stack Pointer | Holds | +| --- | --- | +| 1 | Status | +| 2 | Q | +| 3 | A | +| 4 | B | +| 5 and 6 | Data Pointer 3, high byte then low | +| 7 and 8 | Data Pointer 2, high byte then low | +| 9 and 10 | Data Pointer 1, high byte then low | +| 11 and 12 | Data Pointer 0, high byte then low | +| 13 and 14 | The address to resume at, high byte then low | + +Writing to those bytes changes what RETI restores. Adding one to the address at offsets 13 and 14 is how a fault handler steps over the byte that failed and carries on, and rewriting the saved registers is how a handler hands something back to the code it interrupted. + +SWI is never masked, because it is an instruction the program deliberately ran rather than something a device asked for. + +## Hardware Interrupts: + +A device asks for attention by putting its line up. Which line it uses is not a choice: a device on port N interrupts on N, and arrives through hardware vector N. That is what spares the machine any arbitration, and it means a program can work out what a device will do by knowing where it is plugged in. + +A line is answered between instructions and never inside one, so the address in the frame is always the start of an instruction. + +The Interrupt Flag decides whether lines are answered at all. While it is clear, a line that goes up stays up: masking holds a device off, it does not lose what the device was asking for. The moment the flag is set, the line is answered on the very next step. Since entry clears the flag again, a handler is not interrupted while it works unless it sets the flag itself. + +When several lines are up at once, the lowest numbered port is answered first. This is a scan rather than a priority scheme, so there is nothing to configure and nothing to explain: a programmer works out what happens next by reading the port numbers. + +Answering a line takes it down, so a device that wants attention again has to ask again. A handler returning with RETI restores the Status register, and with it the Interrupt Flag as it was before, so anything still waiting is answered next. + +If a device interrupts and its vector is empty, that is a fault: the machine stops and the emulator says which port asked and where it was. + +## Devices: + +| Port | Device | +| --- | --- | +| 0x00 | The console. Writing sends a byte to standard output, reading takes one from standard input. | +| 0x10 | A test device. Writing anything to it puts its own line up, so that interrupt handling can be exercised without waiting on anything. The byte written is ignored. | + +## Faults: + +If the CPU reads a byte from Program Memory that does not decode to an instruction, it dispatches through Software Vector 2. + +Faults get a vector each rather than sharing one. Vector 2 is the only cause defined so far, and vectors 3 through 15 are held back for the ones that come later, so that a handler always knows what happened from the entry it arrived through. That is why the machine has no fault cause register to read. + +The address in the frame is the address of the offending byte itself, not the one after it. A handler can therefore read the byte that failed and say what it was. It also means a handler that returns with a bare RETI will meet the same byte again, because resuming past a fault means deciding where to resume, and only the handler knows that. + +If nothing is installed at Vector 2, the CPU sets the Fault Flag and the Halt Flag and stops, leaving the Program Counter on the offending byte. The emulator then reports the byte and its address, and exits with a non zero status. + +Stopping matters because the alternative is worse. A byte that means nothing is almost always a sign that execution has wandered into data, or that a program was built for a machine with instructions this one does not have. Stepping over it and carrying on turns a clear failure into a program that appears to run and quietly does the wrong thing. ## Naming a Data Pointer: -Twelve instructions work through a Data Pointer. Each of them carries a selector byte immediately after its opcode, naming which Data Pointer it means. LDD and STD move a pointer through a pointer, so they carry two selectors, the first naming the pointer being moved and the second naming the pointer that addresses it. +Sixteen instructions work through a Data Pointer. Each of them carries a selector byte immediately after its opcode, naming which Data Pointer it means. LDD and STD move a pointer through a pointer, so they carry two selectors, the first naming the pointer being moved and the second naming the pointer that addresses it. The selector is a full byte, but only enough of it is read to choose among the Data Pointers the machine has. A selector larger than the highest numbered pointer wraps around rather than being rejected, so it is the assembler's job to refuse to write one. @@ -60,7 +164,7 @@ The Bytes column is the total length of the instruction, counting its opcode, an | 07 | SHL | 1 | A and B form a circular shift register. Rotate this register left. | | 08 | SHR | 1 | A and B form a circular shift register. Rotate this register right. | -### Branch and Subroutine Operations: 7 Instructions +### Branch and Subroutine Operations: 8 Instructions | Hex Code | Mnemonic | Bytes | Description | | -- | ---- | -- | -- | | 10 | BRI | 3 | Branch Immediately. Loads the immediate next two bytes of Program Memory into the Program Counter, first the most significant byte, then the least. | @@ -68,10 +172,13 @@ The Bytes column is the total length of the instruction, counting its opcode, an | 12 | BRA | 3 | Branch on A. If A is zero, loads the immediate next two bytes of Program Memory into the Program Counter. | | 13 | BRB | 3 | Branch on B. If B is zero, loads the immediate next two bytes of Program Memory into the Program Counter. | | 14 | BRC | 3 | Branch if Carry is set. | +| 15 | BRD | 2 | Branch to the address held in the named Data Pointer. | | 17 | CALL | 3 | Call subroutine. Pushes the Program Counter, Data Pointers 0 through 2, B and A to the Stack, then performs an immediate branch. This costs ten bytes of Stack. | +| 18 | SWI | 2 | Software Interrupt. The next byte names a software vector. Pushes an interrupt frame and dispatches through it. Never masked. | +| 19 | RETI | 1 | Return from an interrupt. Restores everything the frame holds and carries on from where the interrupt arrived. | | 1F | RET | 1 | Return from subroutine. Restores A, B, and Data Pointers 0 through 2 from the Stack, then sets the Program Counter to the instruction after the CALL. Data Pointer 3 and Q are left as the subroutine leaves them. | -### Register Operations: 9 Instructions +### Register Operations: 11 Instructions | Hex Code | Mnemonic | Bytes | Description | | -- | ---- | -- | -- | | 20 | RSTA | 1 | Resets A to 0. | @@ -83,6 +190,12 @@ The Bytes column is the total length of the instruction, counting its opcode, an | 26 | INIA | 2 | Loads the next byte of Program Memory to A. | | 27 | INIB | 2 | Loads the next byte of Program Memory to B. | | 28 | CCF | 1 | Clears the Carry Flag. | +| 29 | MVQA | 1 | Copies Q into A. No flags are changed. | +| 2A | MVQB | 1 | Copies Q into B. No flags are changed. | +| 2B | SIF | 1 | Sets the Interrupt Flag. No other flags are changed. | +| 2C | CIF | 1 | Clears the Interrupt Flag. No other flags are changed. | + +Q is where every ALU result lands, and Q is not itself an ALU operand, so MVQA and MVQB are how a result becomes the input to the next sum. Without them the only route is to store Q into Data Memory and load it back, which costs two instructions and needs a Data Pointer aimed somewhere useful. With them a running total can be kept in the registers and never touch memory at all. ### Stack Operations: 7 Instructions | Hex Code | Mnemonic | Bytes | Description | @@ -110,6 +223,9 @@ The Bytes column is the total length of the instruction, counting its opcode, an | 49 | DPDN | 3 | Offsets the named Data Pointer down by the value of the byte following the selector. | | 4A | LDD | 3 | Loads the first named Data Pointer from the two bytes of Data Memory addressed by the second, most significant byte first. | | 4B | STD | 3 | Stores the first named Data Pointer into the two bytes of Data Memory addressed by the second, most significant byte first. | +| 4C | MVSD | 2 | Copies the Stack Pointer into the named Data Pointer. The Stack Pointer itself is unchanged and still cannot be written. | + +BRD is the only branch whose destination is not written into the program. Every other branch carries the address it goes to, fixed when the program was assembled; BRD takes it from a Data Pointer, which is what makes a table of addresses something a program can dispatch through rather than only read. Together with LDD it turns the Data Segment into somewhere a program can keep a list of places to go. LDD and STD are how a program follows an address it has stored, rather than one the assembler wrote into the instruction. Together with more than one Data Pointer, they are what makes a table of addresses usable: one pointer walks the table while another follows whatever entry it is on. Naming the same pointer twice, as in `LDD.0.0`, makes that pointer follow the address it is currently holding. diff --git a/Tests/expected/16bitFibonacci.out b/Tests/expected/16bitFibonacci.out index 7f68e1e..ea23c1b 100644 --- a/Tests/expected/16bitFibonacci.out +++ b/Tests/expected/16bitFibonacci.out @@ -1,2 +1,3 @@ 0000 0001 0001 0002 0003 0005 0008 000D 0015 0022 0037 0059 0090 00E9 0179 0262 03DB 063D 0A18 1055 1A6D 2AC2 452F 6FF1 Execution halted after 2534 cycles. +[exit 0] diff --git a/Tests/expected/16bitSegmentedSieve.out b/Tests/expected/16bitSegmentedSieve.out index 253ee1d..30a0e58 100644 --- a/Tests/expected/16bitSegmentedSieve.out +++ b/Tests/expected/16bitSegmentedSieve.out @@ -1,2 +1,3 @@ 0002 0003 0005 0007 000B 000D 0011 0013 0017 001D 001F 0025 0029 002B 002F 0035 003B 003D 0043 0047 0049 004F 0053 0059 0061 0065 0067 006B 006D 0071 007F 0083 0089 008B 0095 0097 009D 00A3 00A7 00AD 00B3 00B5 00BF 00C1 00C5 00C7 00D3 00DF 00E3 00E5 00E9 00EF 00F1 00FB 0101 0107 010D 010F 0115 0119 011B 0125 0133 0137 0139 013D 014B 0151 015B 015D 0161 0167 016F 0175 017B 017F 0185 018D 0191 0199 01A3 01A5 01AF 01B1 01B7 01BB 01C1 01C9 01CD 01CF 01D3 01DF 01E7 01EB 01F3 01F7 01FD 0209 020B 021D 0223 022D 0233 0239 023B 0241 024B 0251 0257 0259 025F 0265 0269 026B 0277 0281 0283 0287 028D 0293 0295 02A1 02A5 02AB 02B3 02BD 02C5 02CF 02D7 02DD 02E3 02E7 02EF 02F5 02F9 0301 0305 0313 031D 0329 032B 0335 0337 033B 033D 0347 0355 0359 035B 035F 036D 0371 0373 0377 038B 038F 0397 03A1 03A9 03AD 03B3 03B9 03C7 03CB 03D1 03D7 03DF 03E5 03F1 03F5 03FB 03FD 0407 0409 040F 0419 041B 0425 0427 042D 043F 0443 0445 0449 044F 0455 045D 0463 0469 047F 0481 048B 0493 049D 04A3 04A9 04B1 04BD 04C1 04C7 04CD 04CF 04D5 04E1 04EB 04FD 04FF 0503 0509 050B 0511 0515 0517 051B 0527 0529 052F 0551 0557 055D 0565 0577 0581 058F 0593 0595 0599 059F 05A7 05AB 05AD 05B3 05BF 05C9 05CB 05CF 05D1 05D5 05DB 05E7 05F3 05FB 0607 060D 0611 0617 061F 0623 062B 062F 063D 0641 0647 0649 064D 0653 0655 065B 0665 0679 067F 0683 0685 069D 06A1 06A3 06AD 06B9 06BB 06C5 06CD 06D3 06D9 06DF 06F1 06F7 06FB 06FD 0709 0713 071F 0727 0737 0745 074B 074F 0751 0755 0757 0761 076D 0773 0779 078B 078D 079D 079F 07B5 07BB 07C3 07C9 07CD 07CF 07D3 07DB 07E1 07EB 07ED 07F7 0805 080F 0815 0821 0823 0827 0829 0833 083F 0841 0851 0853 0859 085D 085F 0869 0871 0883 089B 089F 08A5 08AD 08BD 08BF 08C3 08CB 08DB 08DD 08E1 08E9 08EF 08F5 08F9 0905 0907 091D 0923 0925 092B 092F 0935 0943 0949 094D 094F 0955 0959 095F 096B 0971 0977 0985 0989 098F 099B 09A3 09A9 09AD 09C7 09D9 09E3 09EB 09EF 09F5 09F7 09FD 0A13 0A1F 0A21 0A31 0A39 0A3D 0A49 0A57 0A61 0A63 0A67 0A6F 0A75 0A7B 0A7F 0A81 0A85 0A8B 0A93 0A97 0A99 0A9F 0AA9 0AAB 0AB5 0ABD 0AC1 0ACF 0AD9 0AE5 0AE7 0AED 0AF1 0AF3 0B03 0B11 0B15 0B1B 0B23 0B29 0B2D 0B3F 0B47 0B51 0B57 0B5D 0B65 0B6F 0B7B 0B89 0B8D 0B93 0B99 0B9B 0BB7 0BB9 0BC3 0BCB 0BCF 0BDD 0BE1 0BE9 0BF5 0BFB 0C07 0C0B 0C11 0C25 0C2F 0C31 0C41 0C5B 0C5F 0C61 0C6D 0C73 0C77 0C83 0C89 0C91 0C95 0C9D 0CB3 0CB5 0CB9 0CBB 0CC7 0CE3 0CE5 0CEB 0CF1 0CF7 0CFB 0D01 0D03 0D0F 0D13 0D1F 0D21 0D2B 0D2D 0D3D 0D3F 0D4F 0D55 0D69 0D79 0D81 0D85 0D87 0D8B 0D8D 0DA3 0DAB 0DB7 0DBD 0DC7 0DC9 0DCD 0DD3 0DD5 0DDB 0DE5 0DE7 0DF3 0DFD 0DFF 0E09 0E17 0E1D 0E21 0E27 0E2F 0E35 0E3B 0E4B 0E57 0E59 0E5D 0E6B 0E71 0E75 0E7D 0E87 0E8F 0E95 0E9B 0EB1 0EB7 0EB9 0EC3 0ED1 0ED5 0EDB 0EED 0EEF 0EF9 0F07 0F0B 0F0D 0F17 0F25 0F29 0F31 0F43 0F47 0F4D 0F4F 0F53 0F59 0F5B 0F67 0F6B 0F7F 0F95 0FA1 0FA3 0FA7 0FAD 0FB3 0FB5 0FBB 0FD1 0FD3 0FD9 0FE9 0FEF 0FFB 0FFD 1003 100F 101F 1021 1025 102B 1039 103D 103F 1051 1069 1073 1079 107B 1085 1087 1091 1093 109D 10A3 10A5 10AF 10B1 10BB 10C1 10C9 10E7 10F1 10F3 10FD 1105 110B 1115 1127 112D 1139 1145 1147 1159 115F 1163 1169 116F 1181 1183 118D 119B 11A1 11A5 11A7 11AB 11C3 11C5 11D1 11D7 11E7 11EF 11F5 11FB 120D 121D 121F 1223 1229 122B 1231 1237 1241 1247 1253 125F 1271 1273 1279 127D 128F 1297 12AF 12B3 12B5 12B9 12BF 12C1 12CD 12D1 12DF 12FD 1307 130D 1319 1327 132D 1337 1343 1345 1349 134F 1357 135D 1367 1369 136D 137B 1381 1387 138B 1391 1393 139D 139F 13AF 13BB 13C3 13D5 13D9 13DF 13EB 13ED 13F3 13F9 13FF 141B 1421 142F 1433 143B 1445 144D 1459 146B 146F 1471 1475 148D 1499 149F 14A1 14B1 14B7 14BD 14CB 14D5 14E3 14E7 1505 150B 1511 1517 151F 1525 1529 152B 1537 153D 1541 1543 1549 155F 1565 1567 156B 157D 157F 1583 158F 1591 1597 159B 15B5 15BB 15C1 15C5 15CD 15D7 15F7 1607 1609 160F 1613 1615 1619 161B 1625 1633 1639 163D 1645 164F 1655 1669 166D 166F 1675 1693 1697 169F 16A9 16AF 16B5 16BD 16C3 16CF 16D3 16D9 16DB 16E1 16E5 16EB 16ED 16F7 16F9 1709 170F 1723 1727 1733 1741 175D 1763 1777 177B 178D 1795 179B 179F 17A5 17B3 17B9 17BF 17C9 17CB 17D5 17E1 17E9 17F3 17F5 17FF 1807 1813 181D 1835 1837 183B 1843 1849 184D 1855 1867 1871 1877 187D 187F 1885 188F 189B 189D 18A7 18AD 18B3 18B9 18C1 18C7 18D1 18D7 18D9 18DF 18E5 18EB 18F5 18FD 1915 191B 1931 1933 1945 1949 1951 195B 1979 1981 1993 1997 1999 19A3 19A9 19AB 19B1 19B5 19C7 19CF 19DB 19ED 19FD 1A03 1A05 1A11 1A17 1A21 1A23 1A2D 1A2F 1A35 1A3F 1A4D 1A51 1A69 1A6B 1A7B 1A7D 1A87 1A89 1A93 1AA7 1AAB 1AAD 1AB1 1AB9 1AC9 1ACF 1AD5 1AD7 1AE3 1AF3 1AFB 1AFF 1B05 1B23 1B25 1B2F 1B31 1B37 1B3B 1B41 1B47 1B4F 1B55 1B59 1B65 1B6B 1B73 1B7F 1B83 1B91 1B9D 1BA7 1BBF 1BC5 1BD1 1BD7 1BD9 1BEF 1BF7 1C09 1C13 1C19 1C27 1C2B 1C2D 1C33 1C3D 1C45 1C4B 1C4F 1C55 1C73 1C81 1C8B 1C8D 1C99 1CA3 1CA5 1CB5 1CB7 1CC9 1CE1 1CF3 1CF9 1D09 1D1B 1D21 1D23 1D35 1D39 1D3F 1D41 1D4B 1D53 1D5D 1D63 1D69 1D71 1D75 1D7B 1D7D 1D87 1D89 1D95 1D99 1D9F 1DA5 1DA7 1DB3 1DB7 1DC5 1DD7 1DDB 1DE1 1DF5 1DF9 1E01 1E07 1E0B 1E13 1E17 1E25 1E2B 1E2F 1E3D 1E49 1E4D 1E4F 1E6D 1E71 1E89 1E8F 1E95 1EA1 1EAD 1EBB 1EC1 1EC5 1EC7 1ECB 1EDD 1EE3 1EEF 1EF7 1EFD 1F01 1F0D 1F0F 1F1B 1F39 1F49 1F4B 1F51 1F67 1F75 1F7B 1F85 1F91 1F97 1F99 1F9D 1FA5 1FAF 1FB5 1FBB 1FD3 1FE1 1FE7 1FEB 1FF3 1FFF 2011 201B 201D 2027 2029 202D 2033 2047 204D 2051 205F 2063 2065 2069 2077 207D 2089 20A1 20AB 20B1 20B9 20C3 20C5 20E3 20E7 20ED 20EF 20FB 20FF 210D 2113 2135 2141 2149 214F 2159 215B 215F 2173 217D 2185 2195 2197 21A1 21AF 21B3 21B5 21C1 21C7 21D7 21DD 21E5 21E9 21F1 21F5 21FB 2203 2209 220F 221B 2221 2225 222B 2231 2239 224B 224F 2263 2267 2273 2275 227F 2285 2287 2291 229D 229F 22A3 22B7 22BD 22DB 22E1 22E5 22ED 22F7 2303 2309 230B 2327 2329 232F 2333 2335 2345 2351 2353 2359 2363 236B 2383 238F 2395 23A7 23AD 23B1 23BF 23C5 23C9 23D5 23DD 23E3 23EF 23F3 23F9 2405 240B 2417 2419 2429 243D 2441 2443 244D 245F 2467 246B 2479 247D 247F 2485 249B 24A1 24AF 24B5 24BB 24C5 24CB 24CD 24D7 24D9 24DD 24DF 24F5 24F7 24FB 2501 2507 2513 2519 2527 2531 253D 2543 254B 254F 2573 2581 258D 2593 2597 259D 259F 25AB 25B1 25BD 25CD 25CF 25D9 25E1 25F7 25F9 2605 260B 260F 2615 2627 2629 2635 263B 263F 264B 2653 2659 2665 2669 266F 267B 2681 2683 268F 269B 269F 26AD 26B3 26C3 26C9 26CB 26D5 26DD 26EF 26F5 2717 2719 2735 2737 274D 2753 2755 275F 276B 276D 2773 2777 277F 2795 279B 279D 27A7 27AF 27B3 27B9 27C1 27C5 27D1 27E3 27EF 2803 2807 280D 2813 281B 281F 2821 2831 283D 283F 2849 2851 285B 285D 2861 2867 2875 2881 2897 289F 28BB 28BD 28C1 28D5 28D9 28DB 28DF 28ED 28F7 2903 2905 2911 2921 2923 293F 2947 295D 2965 2969 296F 2975 2983 2987 298F 299B 29A1 29A7 29AB 29BF 29C3 29D5 29D7 29E3 29E9 29ED 29F3 2A01 2A13 2A1D 2A25 2A2F 2A4F 2A55 2A5F 2A65 2A6B 2A6D 2A73 2A83 2A89 2A8B 2A97 2A9D 2AB9 2ABB 2AC5 2ACD 2ADD 2AE3 2AEB 2AF1 2AFB 2B13 2B27 2B31 2B33 2B3D 2B3F 2B4B 2B4F 2B55 2B69 2B6D 2B6F 2B7B 2B8D 2B97 2B99 2BA3 2BA5 2BA9 2BBD 2BCD 2BE7 2BEB 2BF3 2BF9 2BFD 2C09 2C0F 2C17 2C23 2C2F 2C35 2C39 2C41 2C57 2C59 2C69 2C77 2C81 2C87 2C93 2C9F 2CAD 2CB3 2CB7 2CCB 2CCF 2CDB 2CE1 2CE3 2CE9 2CEF 2CFF 2D07 2D1D 2D1F 2D3B 2D43 2D49 2D4D 2D61 2D65 2D71 2D89 2D9D 2DA1 2DA9 2DB3 2DB5 2DC5 2DC7 2DD3 2DDF 2E01 2E03 2E07 2E0D 2E19 2E1F 2E25 2E2D 2E33 2E37 2E39 2E3F 2E57 2E5B 2E6F 2E79 2E7F 2E85 2E93 2E97 2E9D 2EA3 2EA5 2EB1 2EB7 2EC1 2EC3 2ECD 2ED3 2EE7 2EEB 2F05 2F09 2F0B 2F11 2F27 2F29 2F41 2F45 2F4B 2F4D 2F51 2F57 2F6F 2F75 2F7D 2F81 2F83 2FA5 2FAB 2FB3 2FC3 2FCF 2FD1 2FDB 2FDD 2FE7 2FED 2FF5 2FF9 3001 300D 3023 3029 3037 303B 3055 3059 305B 3067 3071 3079 307D 3085 3091 3095 30A3 30A9 30B9 30BF 30C7 30CB 30D1 30D7 30DF 30E5 30EF 30FB 30FD 3103 3109 3119 3121 3127 312D 3139 3143 3145 314B 315D 3161 3167 316D 3173 317F 3191 3199 319F 31A9 31B1 31C3 31C7 31D5 31DB 31ED 31F7 31FF 3209 3215 3217 321D 3229 3235 3259 325D 3263 326B 326F 3275 3277 327B 328D 3299 329F 32A7 32AD 32B3 32B7 32C9 32CB 32CF 32D1 32E9 32ED 32F3 32F9 3307 3325 332B 332F 3335 3341 3347 335B 335F 3367 336B 3373 3379 337F 3383 33A1 33A3 33AD 33B9 33C1 33CB 33D3 33EB 33F1 33FD 3401 340F 3413 3419 341B 3437 3445 3455 3457 3463 3469 346D 3481 348B 3491 3497 349D 34A5 34AF 34BB 34C9 34D3 34E1 34F1 34FF 3509 3517 351D 352D 3533 353B 3541 3551 3565 356F 3571 3577 357B 357D 3581 358D 358F 3599 359B 35A1 35B7 35BD 35BF 35C3 35D5 35DD 35E7 35EF 3605 3607 3611 3623 3631 3635 3637 363B 364D 364F 3653 3659 3661 366B 366D 368B 368F 36AD 36AF 36B9 36BB 36CD 36D1 36E3 36E9 36F7 3701 3703 3707 371B 373F 3745 3749 374F 375D 3761 3775 377F 378D 37A3 37A9 37AB 37C9 37D5 37DF 37F1 37F3 37F7 3805 380B 3821 3833 3835 3841 3847 384B 3853 3857 385F 3865 386F 3871 387D 388F 3899 38A7 38B7 38C5 38C9 38CF 38D5 38D7 38DD 38E1 38E3 38FF 3901 391D 3923 3925 3929 392F 393D 3941 394D 395B 396B 3979 397D 3983 398B 3991 3995 399B 39A1 39A7 39AF 39B3 39BB 39BF 39CD 39DD 39E5 39EB 39EF 39FB 3A03 3A13 3A15 3A1F 3A27 3A2B 3A31 3A4B 3A51 3A5B 3A63 3A67 3A6D 3A79 3A87 3AA5 3AA9 3AB7 3ACD 3AD5 3AE1 3AE5 3AEB 3AF3 3AFD 3B03 3B11 3B1B 3B21 3B23 3B2D 3B39 3B45 3B53 3B59 3B5F 3B71 3B7B 3B81 3B89 3B9B 3B9F 3BA5 3BA7 3BAD 3BB7 3BB9 3BC3 3BCB 3BD1 3BD7 3BE1 3BE3 3BF5 3BFF 3C01 3C0D 3C11 3C17 3C1F 3C29 3C35 3C43 3C4F 3C53 3C5B 3C65 3C6B 3C71 3C85 3C89 3C97 3CA7 3CB5 3CBF 3CC7 3CD1 3CDD 3CDF 3CF1 3CF7 3D03 3D0D 3D19 3D1B 3D1F 3D21 3D2D 3D33 3D37 3D3F 3D43 3D6F 3D73 3D75 3D79 3D7B 3D85 3D91 3D97 3D9D 3DAB 3DAF 3DB5 3DBB 3DC1 3DC9 3DCF 3DF3 3E05 3E09 3E0F 3E11 3E1D 3E23 3E29 3E2F 3E33 3E41 3E57 3E63 3E65 3E77 3E81 3E87 3EA1 3EB9 3EBD 3EBF 3EC3 3EC5 3EC9 3ED7 3EDB 3EE1 3EE7 3EEF 3EFF 3F0B 3F0D 3F37 3F3B 3F3D 3F41 3F59 3F5F 3F65 3F67 3F79 3F7D 3F8B 3F91 3FAD 3FBF 3FCD 3FD3 3FDD 3FE9 3FEB 3FF1 3FFD 401B 4021 4025 402B 4031 403F 4043 4045 405D 4061 4067 406D 4087 4091 40A3 40A9 40B1 40B7 40BD 40DB 40DF 40EB 40F7 40F9 4109 410B 4111 4115 4121 4133 4135 413B 413F 4159 4165 416B 4177 417B 4193 41AB 41B7 41BD 41BF 41CB 41E7 41EF 41F3 41F9 4205 4207 4219 421F 4223 4229 422F 4243 4253 4255 425B 4261 4273 427D 4283 4285 4289 4291 4297 429D 42B5 42C5 42CB 42D3 42DD 42E3 42F1 4307 430F 431F 4325 4327 4333 4337 4339 434F 4357 4369 438B 438D 4393 43A5 43A9 43AF 43B5 43BD 43C7 43CF 43E1 43E7 43EB 43ED 43F1 43F9 4409 440B 4417 4423 4429 443B 443F 4445 444B 4451 4453 4459 4465 446F 4483 448F 44A1 44A5 44AB 44AD 44BD 44BF 44C9 44D7 44DB 44F9 44FB 4505 4511 4513 452B 4531 4541 4549 4553 4555 4561 4577 457D 457F 458F 45A3 45AD 45AF 45BB 45C7 45D9 45E3 45EF 45F5 45F7 4601 4603 4609 4613 4625 4627 4633 4639 463D 4643 4645 465D 4679 467B 467F 4681 468B 468D 469D 46A9 46B1 46C7 46C9 46CF 46D3 46D5 46DF 46E5 46F9 4705 470F 4717 4723 4729 472F 4735 4739 474B 474D 4751 475D 476F 4771 477D 4783 4787 4789 4799 47A5 47B1 47BF 47C3 47CB 47DD 47E1 47ED 47FB 4801 4807 480B 4813 4819 481D 4831 483D 4847 4855 4859 485B 486B 486D 4879 4897 489B 48A1 48B9 48CD 48E5 48EF 48F7 4903 490D 4919 491F 492B 4937 493D 4945 4955 4963 4969 496D 4973 4997 49AB 49B5 49D3 49DF 49E1 49E5 49E7 4A03 4A0F 4A1D 4A23 4A39 4A41 4A45 4A57 4A5D 4A6B 4A7D 4A81 4A87 4A89 4A8F 4AB1 4AC3 4AC5 4AD5 4ADB 4AED 4AEF 4B07 4B0B 4B0D 4B13 4B1F 4B25 4B31 4B3B 4B43 4B49 4B59 4B65 4B6D 4B77 4B85 4BAD 4BB3 4BB5 4BBB 4BBF 4BCB 4BD9 4BDD 4BDF 4BE3 4BE5 4BE9 4BF1 4BF7 4C01 4C07 4C0D 4C0F 4C15 4C1B 4C21 4C2D 4C33 4C4B 4C55 4C57 4C61 4C67 4C73 4C79 4C7F 4C8D 4C93 4C99 4CCD 4CE1 4CE7 4CF1 4CF3 4CFD 4D05 4D0F 4D1B 4D27 4D29 4D2F 4D33 4D41 4D51 4D59 4D65 4D6B 4D81 4D83 4D8D 4D95 4D9B 4DB1 4DB3 4DC9 4DCF 4DD7 4DE1 4DED 4DF9 4DFB 4E05 4E0B 4E17 4E19 4E1D 4E2B 4E35 4E37 4E3D 4E4F 4E53 4E5F 4E67 4E79 4E85 4E8B 4E91 4E95 4E9B 4EA1 4EAF 4EB3 4EB5 4EC1 4ECD 4ED1 4ED7 4EE9 4EFB 4F07 4F09 4F19 4F25 4F2D 4F3F 4F49 4F63 4F67 4F6D 4F75 4F7B 4F81 4F85 4F87 4F91 4FA5 4FA9 4FAF 4FB7 4FBB 4FCF 4FD9 4FDB 4FFD 4FFF 5003 501B 501D 5029 5035 503F 5045 5047 5053 5071 5077 5083 5093 509F 50A1 50B7 50C9 50D5 50E3 50ED 50EF 50FB 5107 510B 510D 5111 5117 5123 5125 5135 5147 5149 5171 5179 5189 518F 5197 51A1 51A3 51A7 51B9 51C1 51CB 51D3 51DF 51E3 51F5 51F7 5209 5213 5215 5219 521B 521F 5227 5243 5245 524B 5261 526D 5273 5281 5293 5297 529D 52A5 52AB 52B1 52BB 52C3 52C7 52C9 52DB 52E5 52EB 52FF 5315 531D 5323 5341 5345 5347 534B 535D 5363 5381 5383 5387 538F 5395 5399 539F 53AB 53B9 53DB 53E9 53EF 53F3 53F5 53FB 53FF 540D 5411 5413 5419 5435 5437 543B 5441 5449 5453 5455 545F 5461 546B 546D 5471 548F 5491 549D 54A9 54B3 54C5 54D1 54DF 54E9 54EB 54F7 54FD 5507 550D 551B 5527 552B 5539 553D 554F 5551 555B 5563 5567 556F 5579 5585 5597 55A9 55B1 55B7 55C9 55D9 55E7 55ED 55F3 55FD 560B 560F 5615 5617 5623 562F 5633 5639 563F 564B 564D 565D 565F 566B 5671 5675 5683 5689 568D 568F 569B 56AD 56B1 56D5 56E7 56F3 56FF 5701 5705 5707 570B 5713 571F 5723 5747 574D 575F 5761 576D 5777 577D 5789 57A1 57A9 57AF 57B5 57C5 57D1 57D3 57E5 57EF 5803 580D 580F 5815 5827 582B 582D 5855 585B 585D 586D 586F 5873 587B 588D 5897 58A3 58A9 58AB 58B5 58BD 58C1 58C7 58D3 58D5 58DF 58F1 58F9 58FF 5903 5917 591B 5921 5945 594B 594D 5957 595D 5975 597B 5989 5999 599F 59B1 59B3 59BD 59D1 59DB 59E3 59E9 59ED 59F3 59F5 59FF 5A01 5A0D 5A11 5A13 5A17 5A1F 5A29 5A2F 5A3B 5A4D 5A5B 5A67 5A77 5A7F 5A85 5A95 5A9D 5AA1 5AA3 5AA9 5ABB 5AD3 5AE5 5AEF 5AFB 5AFD 5B01 5B0F 5B19 5B1F 5B25 5B2B 5B3D 5B49 5B4B 5B67 5B79 5B87 5B97 5BA3 5BB1 5BC9 5BD5 5BEB 5BF1 5BF3 5BFD 5C05 5C09 5C0B 5C0F 5C1D 5C29 5C2F 5C33 5C39 5C47 5C4B 5C4D 5C51 5C6F 5C75 5C77 5C7D 5C87 5C89 5CA7 5CBD 5CBF 5CC3 5CC9 5CD1 5CD7 5CDD 5CED 5CF9 5D05 5D0B 5D13 5D17 5D19 5D31 5D3D 5D41 5D47 5D4F 5D55 5D5B 5D65 5D67 5D6D 5D79 5D95 5DA3 5DA9 5DAD 5DB9 5DC1 5DC7 5DD3 5DD7 5DDD 5DEB 5DF1 5DFD 5E07 5E0D 5E13 5E1B 5E21 5E27 5E2B 5E2D 5E31 5E39 5E45 5E49 5E57 5E69 5E73 5E75 5E85 5E8B 5E9F 5EA5 5EAF 5EB7 5EBB 5ED9 5EFD 5F09 5F11 5F27 5F33 5F35 5F3B 5F47 5F57 5F5D 5F63 5F65 5F77 5F7B 5F95 5F99 5FA1 5FB3 5FBD 5FC5 5FCF 5FD5 5FE3 5FE7 5FFB 6011 6023 602F 6037 6053 605F 6065 606B 6073 6079 6085 609D 60AD 60BB 60BF 60CD 60D9 60DF 60E9 60F5 6109 610F 6113 611B 612D 6139 614B 6155 6157 615B 616F 6179 6187 618B 6191 6193 619D 61B5 61C7 61C9 61CD 61E1 61F1 61FF 6209 6217 621D 6221 6227 623B 6241 624B 6251 6253 625F 6265 6283 628D 6295 629B 629F 62A5 62AD 62D5 62D7 62DB 62DD 62E9 62FB 62FF 6305 630D 6317 631D 632F 6341 6343 634F 635F 6367 636D 6371 6377 637D 637F 63B3 63C1 63C5 63D9 63E9 63EB 63EF 63F5 6401 6403 6409 6415 6421 6427 642B 6439 6443 6449 644F 645D 6467 6475 6485 648D 6493 649F 64A3 64AB 64C1 64C7 64C9 64DB 64F1 64F7 64F9 650B 6511 6521 652F 6539 653F 654B 654D 6553 6557 655F 6571 657D 658D 658F 6593 65A1 65A5 65AD 65B9 65C5 65E3 65F3 65FB 65FF 6601 6607 661D 6629 6631 663B 6641 6647 664D 665B 6661 6673 667D 6689 668B 6695 6697 669B 66B5 66B9 66C5 66CD 66D1 66E3 66EB 66F5 6703 6713 6719 671F 6727 6731 6737 673F 6745 6751 675B 676F 6779 6781 6785 6791 67AB 67BD 67C1 67CD 67DF 67E5 6803 6809 6811 6817 682D 6839 683B 683F 6845 684B 684D 6857 6859 685D 6863 6869 686B 6871 6887 6899 689F 68B1 68BD 68C5 68D1 68D7 68E1 68ED 68EF 68FF 6901 690B 690D 6917 6929 692F 6943 6947 6949 694F 6965 696B 6971 6983 6989 6997 69A3 69B3 69B5 69BB 69C1 69C5 69D3 69DF 69E3 69E5 69F7 6A07 6A2B 6A37 6A3D 6A4B 6A67 6A69 6A75 6A7B 6A87 6A8D 6A91 6A93 6AA3 6AC1 6AC9 6AE1 6AE7 6B05 6B0F 6B11 6B23 6B27 6B2D 6B39 6B41 6B57 6B59 6B5F 6B75 6B87 6B89 6B93 6B95 6B9F 6BBD 6BBF 6BDB 6BE1 6BEF 6BFF 6C05 6C19 6C29 6C2B 6C31 6C35 6C55 6C59 6C5B 6C5F 6C65 6C67 6C73 6C77 6C7D 6C83 6C8F 6C91 6C97 6C9B 6CA1 6CA9 6CAF 6CB3 6CC7 6CCB 6CEB 6CF5 6CFD 6D0D 6D0F 6D25 6D27 6D2B 6D31 6D39 6D3F 6D4F 6D5D 6D61 6D73 6D7B 6D7F 6D93 6D99 6DA5 6DB1 6DB7 6DC1 6DC3 6DCD 6DCF 6DDB 6DF7 6E03 6E15 6E17 6E29 6E33 6E3B 6E45 6E75 6E77 6E7B 6E81 6E89 6E93 6E95 6E9F 6EBD 6EBF 6EE3 6EE9 6EF3 6EF9 6EFB 6F0D 6F11 6F17 6F1F 6F2F 6F3D 6F4D 6F53 6F61 6F65 6F79 6F7D 6F83 6F85 6F8F 6F9B 6F9D 6FA3 6FAF 6FB5 6FBB 6FBF 6FCB 6FCD 6FD3 6FD7 6FE3 6FE9 6FF1 6FF5 6FF7 6FFD 700F 7019 701F 7027 7033 7039 704F 7051 7057 7063 7075 7079 7087 708D 7091 70A5 70AB 70BB 70C3 70C7 70CF 70E5 70ED 70F9 70FF 7105 7115 7121 7133 7151 7159 715D 715F 7163 7169 7183 7187 7195 71AD 71C3 71C9 71CB 71D1 71DB 71E1 71EF 71F5 71FB 7207 7211 7217 7219 7225 722F 723B 7243 7255 7267 7271 7277 727F 728F 7295 729B 72A3 72B3 72C7 72CB 72CD 72D7 72D9 72E3 72EF 72F5 72FD 7303 730D 7321 732B 733D 7357 735B 7361 737F 7381 7385 738D 7393 739F 73AB 73BD 73C1 73C9 73DF 73E5 73E7 73F3 7415 741B 742D 7439 743F 7441 745D 746B 747B 7489 748D 749B 74A7 74AB 74B1 74B7 74B9 74DD 74E1 74E7 74FB 7507 751F 7525 753B 753D 754D 755F 756B 7577 7589 758B 7591 7597 759D 75A1 75A7 75B5 75B9 75BB 75D1 75D9 75E5 75EB 75F5 75FB 7603 760F 7621 762D 7633 763D 763F 7655 7663 7669 766F 7673 7685 768B 769F 76B5 76B7 76C3 76DB 76DF 76F1 7703 7705 771B 771D 7721 772D 7735 7741 774B 7759 775D 775F 7771 7781 77A7 77AD 77B3 77B9 77C5 77CF 77D5 77E1 77E9 77EF 77F3 77F9 7807 7825 782B 7835 783D 7853 7859 7861 786D 7877 7879 7883 7885 788B 7895 7897 78A1 78AD 78BF 78D3 78D9 78DD 78E5 78FB 7901 7907 7925 792B 7939 793F 794B 7957 795D 7967 7969 7973 7991 7993 79A3 79AB 79AF 79B1 79B7 79C9 79CD 79CF 79D5 79D9 79F3 79F7 79FF 7A05 7A0F 7A11 7A15 7A1B 7A23 7A27 7A2D 7A4B 7A57 7A59 7A5F 7A65 7A69 7A7D 7A93 7A9B 7A9F 7AA1 7AA5 7AED 7AF5 7AF9 7B01 7B17 7B19 7B1D 7B2B 7B35 7B37 7B3B 7B4F 7B55 7B5F 7B71 7B77 7B8B 7B9B 7BA1 7BA9 7BAF 7BB3 7BC7 7BD3 7BE9 7BEB 7BEF 7BF1 7BFD 7C07 7C19 7C1B 7C31 7C37 7C49 7C67 7C69 7C73 7C81 7C8B 7C93 7CA3 7CD5 7CDB 7CE5 7CED 7CF7 7D03 7D09 7D1B 7D1D 7D33 7D39 7D3B 7D3F 7D45 7D4D 7D53 7D59 7D63 7D75 7D77 7D8D 7D8F 7D9F 7DAD 7DB7 7DBD 7DBF 7DCB 7DD5 7DE9 7DED 7DFB 7E01 7E05 7E29 7E2B 7E2F 7E35 7E41 7E43 7E47 7E55 7E61 7E67 7E6B 7E71 7E73 7E79 7E7D 7E91 7E9B 7E9D 7EA7 7EAD 7EB9 7EBB 7ED3 7EDF 7EEB 7EF1 7EF7 7EFB 7F13 7F15 7F19 7F31 7F33 7F39 7F3D 7F43 7F4B 7F5B 7F61 7F63 7F6D 7F79 7F87 7F8D 7FAF 7FB5 7FC3 7FC9 7FCD 7FCF 7FED 8003 800B 800F 8015 801D 8021 8023 803F 8041 8047 804B 8065 8077 808D 808F 8095 80A5 80AB 80AD 80BD 80C9 80CB 80D7 80DB 80E1 80E7 80F5 80FF 8105 810D 8119 811D 812F 8131 813B 8143 8153 8159 815F 817D 817F 8189 819B 819D 81A7 81AF 81B3 81BB 81C7 81DF 8207 8209 8215 821F 8225 8231 8233 823F 8243 8245 8249 824F 8261 826F 827B 8281 8285 8293 82B1 82B5 82BD 82C7 82CF 82D5 82DF 82F1 82F9 82FD 830B 831B 8321 8329 832D 8333 8335 833F 8341 834D 8351 8353 8357 835D 8365 8369 836F 838F 83A7 83B1 83B9 83CB 83D5 83D7 83DD 83E7 83E9 83ED 83FF 8405 8411 8413 8423 8425 843B 8441 8447 844F 8461 8465 8477 8483 848B 8491 8495 84A9 84AF 84CD 84E3 84EF 84F1 84F7 8509 850D 854B 854F 8551 855D 8563 856D 856F 857B 8587 85A3 85A5 85A9 85B7 85CD 85D3 85D5 85DB 85E1 85EB 85F9 85FD 85FF 8609 860F 8617 8621 862F 8639 863F 8641 864D 8663 8675 867D 8687 8699 86A5 86A7 86B3 86B7 86C3 86C5 86CF 86D1 86D7 86E9 86EF 86F5 8717 871D 871F 872B 872F 8735 8747 8759 875B 876B 8771 8777 877F 8785 878F 87A1 87A9 87B3 87BB 87C5 87C7 87CB 87DD 87F7 8803 8819 881B 881F 8821 8837 883D 8843 8851 8861 8867 887B 8885 8891 8893 88A5 88CF 88D3 88EB 88ED 88F3 88FD 8909 890B 8911 891B 8923 8927 892D 8939 8945 894D 8951 8957 8963 8981 8995 899B 89B3 89B9 89C3 89CF 89D1 89DB 89EF 89F5 89FB 89FF 8A0B 8A19 8A23 8A35 8A41 8A49 8A4F 8A5B 8A5F 8A6D 8A77 8A79 8A85 8AA3 8AB3 8AB5 8AC1 8AC7 8ACB 8ACD 8AD1 8AD7 8AF1 8AF5 8B07 8B09 8B0D 8B13 8B21 8B57 8B5D 8B91 8B93 8BA3 8BA9 8BAF 8BBB 8BD5 8BD9 8BDB 8BE1 8BF7 8BFD 8BFF 8C0B 8C17 8C1D 8C27 8C39 8C3B 8C47 8C53 8C5D 8C6F 8C7B 8C81 8C89 8C8F 8C99 8C9F 8CA7 8CAB 8CAD 8CB1 8CC5 8CDD 8CE3 8CE9 8CF3 8D01 8D0B 8D0D 8D23 8D29 8D37 8D41 8D5B 8D5F 8D71 8D79 8D85 8D91 8D9B 8DA7 8DAD 8DB5 8DC5 8DCB 8DD3 8DD9 8DDF 8DF5 8DF7 8E01 8E15 8E1F 8E25 8E51 8E63 8E69 8E73 8E75 8E79 8E7F 8E8D 8E91 8EAB 8EAF 8EB1 8EBD 8EC7 8ECF 8ED3 8EDB 8EE7 8EEB 8EF7 8EFF 8F15 8F1D 8F23 8F2D 8F3F 8F45 8F4B 8F53 8F59 8F65 8F69 8F71 8F83 8F8D 8F99 8F9F 8FAB 8FAD 8FB3 8FB7 8FB9 8FC9 8FD5 8FE1 8FEF 8FF9 9007 900D 9017 9023 9025 9031 9037 903B 9041 9043 904F 9053 906D 9073 9085 908B 9095 909B 909D 90AF 90B9 90C1 90C5 90DF 90E9 90FD 9103 9113 9127 9133 913D 9145 914F 9151 9161 9167 917B 9185 9199 919D 91BB 91BD 91C1 91C9 91D9 91DB 91ED 91F1 91F3 91F9 9203 9215 9221 922F 9241 9247 9257 926B 9271 9275 927D 9283 9287 928D 9299 92A1 92AB 92AD 92B9 92BF 92C3 92C5 92CB 92D5 92D7 92E7 92F3 9301 930B 9311 9319 931F 933B 933D 9343 9355 9373 9395 9397 93A7 93B3 93B5 93C7 93D7 93DD 93E5 93EF 93F7 9401 9409 9413 943F 9445 944B 944F 9463 9467 9469 946D 947B 9497 949F 94A5 94B5 94C3 94E1 94E7 9505 9509 9517 9521 9527 952D 9535 9539 954B 9557 955D 955F 9575 9581 9589 958F 959B 959F 95AD 95B1 95B7 95B9 95BD 95CF 95E3 95E9 95F9 961F 962F 9631 9635 963B 963D 9665 968F 969D 96A1 96A7 96A9 96C1 96CB 96D1 96D3 96E5 96EF 96FB 96FD 970D 970F 9715 9725 972B 9733 9737 9739 9743 9749 9751 975B 975D 976F 977F 9787 9793 97A5 97B1 97B7 97C3 97CD 97D3 97D9 97EB 97F7 9805 9809 980B 9815 9829 982F 983B 9841 9851 986B 986F 9881 9883 9887 98A7 98B1 98B9 98BF 98C3 98C9 98CF 98DD 98E3 98F5 98F9 98FB 990D 9917 991F 9929 9931 993B 993D 9941 9947 9949 9953 997D 9985 9991 9995 999B 99AD 99AF 99BF 99C7 99CB 99CD 99D7 99E5 99F1 99FB 9A0F 9A13 9A1B 9A25 9A4B 9A4F 9A55 9A57 9A61 9A75 9A7F 9A8B 9A91 9A9D 9AB7 9AC3 9AC7 9ACF 9AEB 9AF3 9AF7 9AFF 9B17 9B1D 9B27 9B2F 9B35 9B45 9B51 9B59 9B63 9B6F 9B77 9B8D 9B93 9B95 9B9F 9BA1 9BA7 9BB1 9BB7 9BBD 9BC5 9BCB 9BCF 9BDD 9BF9 9C01 9C11 9C23 9C2B 9C2F 9C35 9C49 9C4D 9C5F 9C65 9C67 9C7F 9C97 9C9D 9CA3 9CAF 9CBB 9CBF 9CC1 9CD7 9CD9 9CE3 9CE9 9CF1 9CFD 9D01 9D15 9D27 9D2D 9D31 9D3D 9D55 9D5B 9D61 9D97 9D9F 9DA5 9DA9 9DC3 9DE7 9DEB 9DED 9DF1 9E0B 9E17 9E23 9E27 9E2D 9E33 9E3B 9E47 9E51 9E53 9E5F 9E6F 9E81 9E87 9E8F 9E95 9EA1 9EB3 9EBD 9EBF 9EF5 9EF9 9EFB 9F05 9F23 9F2F 9F37 9F3B 9F43 9F53 9F61 9F6D 9F73 9F77 9F7D 9F89 9F8F 9F91 9F95 9FA3 9FAF 9FB3 9FC1 9FC7 9FDF 9FE5 9FEB 9FF5 A001 A00D A021 A033 A039 A03F A04F A057 A05B A061 A075 A079 A099 A09D A0AB A0B5 A0B7 A0BD A0C9 A0D9 A0DB A0DF A0E5 A0F1 A0F3 A0FD A105 A10B A10F A111 A11B A129 A12F A135 A141 A153 A175 A17D A187 A18D A1A5 A1AB A1AD A1B7 A1C3 A1C5 A1E3 A1ED A1FB A207 A213 A223 A229 A22F A231 A243 A247 A24D A26B A279 A27D A283 A289 A28B A291 A295 A29B A2A9 A2AF A2B3 A2BB A2C5 A2D1 A2D7 A2F7 A301 A309 A31F A321 A32B A331 A349 A351 A355 A373 A379 A37B A387 A397 A39F A3A5 A3A9 A3AF A3B7 A3C7 A3D5 A3DB A3E1 A3E5 A3E7 A3F1 A3FD A3FF A40F A41D A421 A423 A427 A43B A44D A457 A459 A463 A469 A475 A493 A49B A4AD A4B9 A4C3 A4C5 A4CB A4D1 A4D5 A4E1 A4ED A4EF A4F3 A4FF A511 A529 A52B A535 A53B A543 A553 A55B A561 A56D A577 A585 A58B A597 A59D A5A3 A5A7 A5A9 A5C1 A5C5 A5CB A5D3 A5D9 A5DD A5DF A5E3 A5E9 A5F7 A5FB A603 A60D A625 A63D A649 A64B A651 A65D A673 A691 A693 A699 A6AB A6B5 A6BB A6C1 A6C9 A6CD A6CF A6D5 A6DF A6E7 A6F1 A6F7 A6FF A70F A715 A723 A729 A72D A745 A74D A757 A759 A765 A76B A76F A793 A795 A7AB A7B1 A7B9 A7BF A7C9 A7D1 A7D7 A7E3 A7ED A7FB A805 A80B A81D A829 A82B A837 A83B A855 A85F A86D A87D A88F A897 A8A9 A8B5 A8C1 A8C7 A8D7 A8E5 A8FD A907 A913 A91B A931 A937 A939 A943 A97F A985 A987 A98B A993 A9A3 A9B1 A9BB A9C1 A9D9 A9DF A9EB A9FD AA15 AA17 AA35 AA39 AA3B AA47 AA4D AA57 AA59 AA5D AA6B AA71 AA81 AA83 AA8D AA95 AAAB AABF AAC5 AAC9 AAE9 AAEF AB01 AB05 AB07 AB0B AB0D AB11 AB19 AB4D AB5B AB71 AB73 AB89 AB9D ABA7 ABAF ABB9 ABBB ABC1 ABC5 ABD3 ABD7 ABDD ABF1 ABF5 ABFB ABFD AC09 AC15 AC1B AC27 AC37 AC39 AC45 AC4F AC57 AC5B AC61 AC63 AC7F AC8B AC93 AC9D ACA9 ACAB ACAF ACBD ACD9 ACE1 ACE7 ACEB ACED ACF1 ACF7 ACF9 AD05 AD3F AD45 AD53 AD5D AD5F AD65 AD81 ADA1 ADA5 ADC3 ADCB ADD1 ADD5 ADDB ADE7 ADF3 ADF5 ADF9 ADFF AE05 AE13 AE23 AE2B AE49 AE4D AE4F AE59 AE61 AE67 AE6B AE71 AE8B AE8F AE9B AE9D AEA7 AEB9 AEC5 AED1 AEE3 AEE5 AEE9 AEF5 AEFD AF09 AF13 AF27 AF2B AF33 AF43 AF4F AF57 AF5D AF6D AF75 AF7F AF8B AF99 AF9F AFA3 AFAB AFB7 AFBB AFCF AFD5 AFFD B005 B015 B01B B03F B041 B047 B04B B051 B053 B069 B07B B07D B087 B08D B0B1 B0BF B0CB B0CF B0E1 B0E9 B0ED B0FB B105 B107 B111 B119 B11D B11F B131 B141 B14D B15B B165 B173 B179 B17F B1A9 B1B3 B1B9 B1BF B1D3 B1DD B1E5 B1F1 B1F5 B201 B213 B215 B21F B22D B23F B249 B25B B263 B269 B26D B27B B281 B28B B2A9 B2B7 B2BD B2C3 B2C7 B2D3 B2F9 B2FD B2FF B303 B309 B311 B31D B327 B32D B33F B345 B377 B37D B381 B387 B393 B39B B3A5 B3C5 B3CB B3E1 B3E3 B3ED B3F9 B40B B40D B413 B417 B435 B43D B443 B449 B45B B465 B467 B46B B477 B48B B495 B49D B4B5 B4BF B4C1 B4C7 B4DD B4E3 B4E5 B4F7 B501 B50D B50F B52D B53F B54B B567 B569 B56F B573 B579 B587 B58D B599 B5A3 B5AB B5AF B5BB B5D5 B5DF B5E7 B5ED B5FD B5FF B609 B61B B629 B62F B633 B639 B647 B657 B659 B65F B663 B66F B683 B687 B69B B69F B6A5 B6B1 B6B3 B6D7 B6DB B6E1 B6E3 B6ED B6EF B705 B70D B713 B71D B729 B735 B747 B755 B76D B791 B795 B7A9 B7C1 B7CB B7D1 B7D3 B7EF B7F5 B807 B80F B813 B819 B821 B827 B82B B82D B839 B855 B867 B875 B885 B893 B8A5 B8AF B8B7 B8BD B8C1 B8C7 B8CD B8D5 B8EB B8F7 B8F9 B903 B915 B91B B91D B92F B939 B93B B947 B951 B963 B983 B989 B98D B993 B999 B9A1 B9A7 B9AD B9B7 B9CB B9D1 B9DD B9E7 B9EF B9F9 BA07 BA0D BA17 BA25 BA29 BA2B BA41 BA53 BA55 BA5F BA61 BA65 BA79 BA7D BA7F BAA1 BAA3 BAAF BAB5 BABF BAC1 BACB BADD BAE3 BAF1 BAFD BB09 BB1F BB27 BB2D BB3D BB43 BB4B BB4F BB5B BB61 BB69 BB6D BB91 BB97 BB9D BBB1 BBC9 BBCF BBDB BBED BBF7 BBF9 BC03 BC1D BC23 BC33 BC3B BC41 BC45 BC5D BC6F BC77 BC83 BC8F BC99 BCAB BCB7 BCB9 BCD1 BCD5 BCE1 BCF3 BCFF BD0D BD17 BD19 BD1D BD35 BD41 BD4F BD59 BD5F BD61 BD67 BD6B BD71 BD8B BD8F BD95 BD9B BD9D BDB3 BDBB BDCD BDD1 BDE3 BDEB BDEF BE07 BE09 BE15 BE21 BE25 BE27 BE5B BE5D BE6F BE75 BE79 BE7F BE8B BE8D BE93 BE9F BEA9 BEB1 BEB5 BEB7 BECF BED9 BEDB BEE5 BEE7 BEF3 BEF9 BF0B BF33 BF39 BF4D BF5D BF5F BF6B BF71 BF7B BF87 BF89 BF8D BF93 BFA1 BFAD BFB9 BFCF BFD5 BFDD BFE1 BFE3 BFF3 C005 C011 C013 C019 C029 C02F C031 C037 C03B C047 C065 C06D C07D C07F C091 C09B C0B3 C0B5 C0BB C0D3 C0D7 C0D9 C0EF C0F1 C101 C103 C109 C115 C119 C12B C133 C137 C145 C149 C15B C173 C179 C17B C181 C18B C18D C197 C1BD C1C3 C1CD C1DB C1E1 C1E7 C1FF C203 C205 C211 C221 C22F C23F C24B C24D C253 C25D C277 C27B C27D C289 C28F C293 C29F C2A7 C2B3 C2BD C2CF C2D5 C2E3 C2FF C301 C307 C311 C313 C317 C325 C347 C349 C34F C365 C367 C371 C37F C383 C385 C395 C39D C3A7 C3AD C3B5 C3BF C3C7 C3CB C3D1 C3D3 C3E3 C3E9 C3EF C401 C41F C42D C433 C437 C455 C457 C461 C46F C473 C487 C491 C499 C49D C4A5 C4B7 C4BB C4C9 C4CF C4D3 C4EB C4F1 C4F7 C509 C51B C51D C541 C547 C551 C55F C56B C56F C575 C577 C595 C59B C59F C5A1 C5A7 C5C3 C5D7 C5DB C5EF C5FB C613 C623 C635 C641 C64F C655 C659 C665 C685 C691 C697 C6A1 C6A9 C6B3 C6B9 C6CB C6CD C6DD C6EB C6F1 C707 C70D C719 C71B C72D C731 C739 C757 C763 C767 C773 C775 C77F C7A5 C7BB C7BD C7C1 C7CF C7D5 C7E1 C7F9 C7FD C7FF C803 C811 C81D C827 C829 C839 C83F C853 C857 C86B C881 C88D C88F C893 C895 C8A1 C8B7 C8CF C8D5 C8DB C8DD C8E3 C8E7 C8ED C8EF C8F9 C905 C911 C917 C919 C91F C92F C937 C93D C941 C953 C95F C96B C979 C97D C989 C98F C997 C99D C9AF C9B5 C9BF C9CB C9D9 C9DF C9E3 C9EB CA01 CA07 CA09 CA25 CA37 CA39 CA4B CA55 CA5B CA69 CA73 CA75 CA7F CA8D CA93 CA9D CA9F CAB5 CABB CAC3 CAC9 CAD9 CAE5 CAED CB03 CB05 CB09 CB17 CB29 CB35 CB3B CB53 CB59 CB63 CB65 CB71 CB87 CB99 CB9F CBB3 CBB9 CBC3 CBD1 CBD5 CBD7 CBDD CBE9 CBFF CC0D CC19 CC1D CC23 CC2B CC41 CC43 CC4D CC59 CC61 CC89 CC8B CC91 CC9B CCA3 CCA7 CCD1 CCE5 CCE9 CD09 CD15 CD1F CD25 CD31 CD3D CD3F CD49 CD51 CD57 CD5B CD63 CD67 CD81 CD93 CD97 CD9F CDBB CDC1 CDD3 CDD9 CDE5 CDE7 CDF1 CDF7 CDFD CE0B CE15 CE21 CE2F CE47 CE4D CE51 CE65 CE7B CE7D CE8F CE93 CE99 CEA5 CEA7 CEB7 CEC9 CED7 CEDD CEE3 CEE7 CEED CEF5 CF07 CF0B CF19 CF37 CF3B CF4D CF55 CF5F CF61 CF65 CF6D CF79 CF7D CF89 CF9B CF9D CFA9 CFB3 CFB5 CFC5 CFCD CFD1 CFEF CFF1 CFF7 D013 D015 D01F D021 D033 D03D D04B D04F D069 D06F D081 D085 D099 D09F D0A3 D0AB D0BD D0C1 D0CD D0E7 D0FF D103 D117 D12D D12F D141 D157 D159 D15D D169 D16B D171 D177 D17D D181 D187 D195 D199 D1B1 D1BD D1C3 D1D5 D1D7 D1E3 D1FF D20D D211 D217 D21F D235 D23B D247 D259 D261 D265 D279 D27F D283 D289 D28B D29D D2A3 D2A7 D2B3 D2BF D2C7 D2E3 D2E9 D2F1 D2FB D2FD D315 D321 D32B D343 D34B D355 D369 D375 D37B D387 D393 D397 D3A5 D3B1 D3C9 D3EB D3FD D405 D40F D415 D427 D42F D433 D43B D44B D459 D45F D463 D469 D481 D483 D489 D48D D493 D495 D4A5 D4AB D4B1 D4C5 D4DD D4E1 D4E3 D4E7 D4F5 D4F9 D50B D50D D513 D51F D523 D531 D535 D537 D549 D559 D55F D565 D567 D577 D58B D591 D597 D5B5 D5B9 D5C1 D5C7 D5DF D5EF D5F5 D5FB D603 D60F D62D D631 D643 D655 D65D D661 D67B D685 D687 D69D D6A5 D6AF D6BD D6C3 D6C7 D6D9 D6E1 D6ED D709 D70B D711 D715 D721 D727 D73F D745 D74D D757 D76B D77B D783 D7A1 D7A7 D7AD D7B1 D7B3 D7BD D7CB D7D1 D7DB D7FB D811 D823 D825 D829 D82B D82F D837 D84D D855 D867 D873 D88F D891 D8A1 D8AD D8BF D8CD D8D7 D8E9 D8F5 D8FB D91B D925 D933 D939 D943 D945 D94F D951 D957 D96D D96F D973 D979 D981 D98B D991 D99F D9A5 D9A9 D9B5 D9D3 D9EB D9F1 D9F7 D9FF DA05 DA09 DA0B DA0F DA15 DA1D DA23 DA29 DA3F DA51 DA59 DA5D DA5F DA71 DA77 DA7B DA7D DA8D DA9F DAB3 DABD DAC3 DAC9 DAE7 DAE9 DAF5 DB11 DB17 DB1D DB23 DB25 DB31 DB3B DB43 DB55 DB67 DB6B DB73 DB85 DB8F DB91 DBAD DBAF DBB9 DBC7 DBCB DBCD DBEB DBF7 DC0D DC27 DC31 DC39 DC3F DC49 DC51 DC61 DC6F DC75 DC7B DC85 DC93 DC99 DC9D DC9F DCA9 DCB5 DCB7 DCBD DCC7 DCCF DCD3 DCD5 DCDF DCF9 DD0F DD15 DD17 DD23 DD35 DD39 DD53 DD57 DD5F DD69 DD6F DD7D DD87 DD89 DD9B DDA1 DDAB DDBF DDC5 DDCB DDCF DDE7 DDE9 DDED DDF5 DDFB DE0B DE19 DE29 DE3B DE3D DE41 DE4D DE4F DE59 DE5B DE61 DE6D DE77 DE7D DE83 DE97 DE9D DEA1 DEA7 DECD DED1 DED7 DEE3 DEF1 DEF5 DF01 DF09 DF13 DF1F DF2B DF33 DF37 DF3D DF4B DF55 DF5B DF67 DF69 DF73 DF85 DF87 DF99 DFA3 DFAB DFB5 DFB7 DFC3 DFC7 DFD5 DFF1 DFF3 E003 E005 E017 E01D E027 E02D E035 E045 E053 E071 E07B E08F E095 E09F E0B7 E0B9 E0D5 E0D7 E0E3 E0F3 E0F9 E101 E125 E129 E131 E135 E143 E14F E159 E161 E16D E171 E177 E17F E183 E189 E197 E1AD E1B5 E1BB E1BF E1C1 E1CB E1D1 E1E5 E1EF E1F7 E1FD E203 E219 E22B E22D E23D E243 E257 E25B E275 E279 E287 E29D E2AB E2AF E2BB E2C1 E2C9 E2CD E2D3 E2D9 E2F3 E2FD E2FF E311 E323 E327 E329 E339 E33B E34D E351 E357 E35F E363 E369 E375 E377 E37D E383 E39F E3C5 E3C9 E3D1 E3E1 E3FB E3FF E401 E40B E417 E419 E423 E42B E431 E43B E447 E449 E453 E455 E46D E471 E48F E4A9 E4AF E4B5 E4C7 E4CD E4D3 E4E9 E4EB E4F5 E507 E521 E525 E537 E53F E545 E54B E557 E567 E56D E575 E585 E58B E593 E5A3 E5A5 E5CF E609 E611 E615 E61B E61D E621 E629 E639 E63F E653 E657 E663 E66F E675 E681 E683 E68D E68F E695 E6AB E6AD E6B7 E6BD E6C5 E6CB E6D5 E6E3 E6E9 E6EF E6F3 E705 E70D E717 E71F E72F E73D E747 E749 E753 E755 E761 E767 E76B E77F E789 E791 E7C5 E7CD E7D7 E7DD E7DF E7E9 E7F1 E7FB E801 E807 E80F E819 E81B E831 E833 E837 E83D E84B E84F E851 E869 E875 E879 E893 E8A5 E8A9 E8AF E8BD E8DB E8E1 E8E5 E8EB E8ED E903 E90B E90F E915 E917 E92D E933 E93B E94B E951 E95F E963 E969 E97B E983 E98F E995 E9A1 E9B9 E9D7 E9E7 E9EF EA11 EA19 EA2F EA35 EA43 EA4D EA5F EA6D EA71 EA7D EA85 EA89 EAAD EAB3 EAB9 EABB EAC5 EAC7 EACB EADF EAE5 EAEB EAF5 EB01 EB07 EB09 EB31 EB39 EB3F EB5B EB61 EB63 EB6F EB81 EB85 EB9D EBAB EBB1 EBB7 EBC1 EBD5 EBDF EBED EBFD EC0B EC1B EC21 EC29 EC4D EC51 EC5D EC69 EC6F EC7B ECAD ECB9 ECBF ECC3 ECC9 ECCF ECD7 ECDD ECE7 ECE9 ECF3 ECF5 ED07 ED11 ED1F ED2F ED37 ED3D ED41 ED55 ED59 ED5B ED65 ED6B ED79 ED8B ED95 EDBB EDC5 EDD7 EDD9 EDE3 EDE5 EDF1 EDF5 EDF7 EDFB EE09 EE0F EE19 EE21 EE49 EE4F EE63 EE67 EE73 EE7B EE81 EEA3 EEAB EEC1 EEC9 EED5 EEDF EEE1 EEF1 EF1B EF27 EF2F EF45 EF4D EF63 EF6B EF71 EF93 EF95 EF9B EF9F EFAD EFB3 EFC3 EFC5 EFDB EFE1 EFE9 F001 F017 F01D F01F F02B F02F F035 F043 F047 F04F F067 F06B F071 F077 F079 F08F F0A3 F0A9 F0AD F0BB F0BF F0C5 F0CB F0D3 F0D9 F0E3 F0E9 F0F1 F0F7 F107 F115 F11B F121 F137 F13D F155 F175 F17B F18D F193 F1A5 F1AF F1B7 F1D5 F1E7 F1ED F1FD F209 F20F F21B F21D F223 F227 F233 F23B F241 F257 F25F F265 F269 F277 F281 F293 F2A7 F2B1 F2B3 F2B9 F2BD F2BF F2DB F2ED F2EF F2F9 F2FF F305 F30B F319 F341 F359 F35B F35F F367 F373 F377 F38B F38F F3AF F3C1 F3D1 F3D7 F3FB F403 F409 F40D F413 F421 F425 F42B F445 F44B F455 F463 F475 F47F F485 F48B F499 F4A3 F4A9 F4AF F4BD F4C3 F4DB F4DF F4ED F503 F50B F517 F521 F529 F535 F547 F551 F563 F56B F583 F58D F595 F599 F5B1 F5B7 F5C9 F5CF F5D1 F5DB F5F9 F5FB F605 F607 F60B F60D F635 F637 F653 F65B F661 F667 F679 F67F F689 F697 F69B F6AD F6CB F6DD F6DF F6EB F709 F70F F72D F731 F743 F74F F751 F755 F763 F769 F773 F779 F781 F787 F791 F79D F79F F7A5 F7B1 F7BB F7BD F7CF F7D3 F7E7 F7EB F7F1 F7FF F805 F80B F821 F827 F82D F835 F847 F859 F863 F865 F86F F871 F877 F87B F881 F88D F89F F8A1 F8AB F8B3 F8B7 F8C9 F8CB F8D1 F8D7 F8DD F8E7 F8EF F8F9 F8FF F911 F91D F925 F931 F937 F93B F941 F94F F95F F961 F96D F971 F977 F99D F9A3 F9A9 F9B9 F9CD F9E9 F9FD FA07 FA0D FA13 FA21 FA25 FA3F FA43 FA51 FA5B FA6D FA7B FA97 FA99 FA9D FAAB FABB FABD FAD9 FADF FAE7 FAED FB0F FB17 FB1B FB2D FB2F FB3F FB47 FB4D FB75 FB7D FB8F FB93 FBB1 FBB7 FBC3 FBC5 FBE3 FBE9 FBF3 FC01 FC29 FC37 FC41 FC43 FC4F FC59 FC61 FC65 FC6D FC73 FC79 FC95 FC97 FC9B FCA7 FCB5 FCC5 FCCD FCEB FCFB FD0D FD0F FD19 FD2B FD31 FD51 FD55 FD67 FD6D FD6F FD7B FD85 FD97 FD99 FD9F FDA9 FDB7 FDC9 FDE5 FDEB FDF3 FE03 FE05 FE09 FE1D FE27 FE2F FE41 FE4B FE4D FE57 FE5F FE63 FE69 FE75 FE7B FE8F FE93 FE95 FE9B FE9F FEB3 FEBD FED7 FEE9 FEF3 FEF5 FF07 FF0D FF1D FF2B FF2F FF49 FF4D FF5B FF65 FF71 FF7F FF85 FF8B FF8F FF9D FFA7 FFA9 FFC7 FFD9 FFEF FFF1 Execution halted after 2821638 cycles. +[exit 0] diff --git a/Tests/expected/16bitSegmentedSieveModern.out b/Tests/expected/16bitSegmentedSieveModern.out new file mode 100644 index 0000000..6fabc45 --- /dev/null +++ b/Tests/expected/16bitSegmentedSieveModern.out @@ -0,0 +1,3 @@ +0002 0003 0005 0007 000B 000D 0011 0013 0017 001D 001F 0025 0029 002B 002F 0035 003B 003D 0043 0047 0049 004F 0053 0059 0061 0065 0067 006B 006D 0071 007F 0083 0089 008B 0095 0097 009D 00A3 00A7 00AD 00B3 00B5 00BF 00C1 00C5 00C7 00D3 00DF 00E3 00E5 00E9 00EF 00F1 00FB 0101 0107 010D 010F 0115 0119 011B 0125 0133 0137 0139 013D 014B 0151 015B 015D 0161 0167 016F 0175 017B 017F 0185 018D 0191 0199 01A3 01A5 01AF 01B1 01B7 01BB 01C1 01C9 01CD 01CF 01D3 01DF 01E7 01EB 01F3 01F7 01FD 0209 020B 021D 0223 022D 0233 0239 023B 0241 024B 0251 0257 0259 025F 0265 0269 026B 0277 0281 0283 0287 028D 0293 0295 02A1 02A5 02AB 02B3 02BD 02C5 02CF 02D7 02DD 02E3 02E7 02EF 02F5 02F9 0301 0305 0313 031D 0329 032B 0335 0337 033B 033D 0347 0355 0359 035B 035F 036D 0371 0373 0377 038B 038F 0397 03A1 03A9 03AD 03B3 03B9 03C7 03CB 03D1 03D7 03DF 03E5 03F1 03F5 03FB 03FD 0407 0409 040F 0419 041B 0425 0427 042D 043F 0443 0445 0449 044F 0455 045D 0463 0469 047F 0481 048B 0493 049D 04A3 04A9 04B1 04BD 04C1 04C7 04CD 04CF 04D5 04E1 04EB 04FD 04FF 0503 0509 050B 0511 0515 0517 051B 0527 0529 052F 0551 0557 055D 0565 0577 0581 058F 0593 0595 0599 059F 05A7 05AB 05AD 05B3 05BF 05C9 05CB 05CF 05D1 05D5 05DB 05E7 05F3 05FB 0607 060D 0611 0617 061F 0623 062B 062F 063D 0641 0647 0649 064D 0653 0655 065B 0665 0679 067F 0683 0685 069D 06A1 06A3 06AD 06B9 06BB 06C5 06CD 06D3 06D9 06DF 06F1 06F7 06FB 06FD 0709 0713 071F 0727 0737 0745 074B 074F 0751 0755 0757 0761 076D 0773 0779 078B 078D 079D 079F 07B5 07BB 07C3 07C9 07CD 07CF 07D3 07DB 07E1 07EB 07ED 07F7 0805 080F 0815 0821 0823 0827 0829 0833 083F 0841 0851 0853 0859 085D 085F 0869 0871 0883 089B 089F 08A5 08AD 08BD 08BF 08C3 08CB 08DB 08DD 08E1 08E9 08EF 08F5 08F9 0905 0907 091D 0923 0925 092B 092F 0935 0943 0949 094D 094F 0955 0959 095F 096B 0971 0977 0985 0989 098F 099B 09A3 09A9 09AD 09C7 09D9 09E3 09EB 09EF 09F5 09F7 09FD 0A13 0A1F 0A21 0A31 0A39 0A3D 0A49 0A57 0A61 0A63 0A67 0A6F 0A75 0A7B 0A7F 0A81 0A85 0A8B 0A93 0A97 0A99 0A9F 0AA9 0AAB 0AB5 0ABD 0AC1 0ACF 0AD9 0AE5 0AE7 0AED 0AF1 0AF3 0B03 0B11 0B15 0B1B 0B23 0B29 0B2D 0B3F 0B47 0B51 0B57 0B5D 0B65 0B6F 0B7B 0B89 0B8D 0B93 0B99 0B9B 0BB7 0BB9 0BC3 0BCB 0BCF 0BDD 0BE1 0BE9 0BF5 0BFB 0C07 0C0B 0C11 0C25 0C2F 0C31 0C41 0C5B 0C5F 0C61 0C6D 0C73 0C77 0C83 0C89 0C91 0C95 0C9D 0CB3 0CB5 0CB9 0CBB 0CC7 0CE3 0CE5 0CEB 0CF1 0CF7 0CFB 0D01 0D03 0D0F 0D13 0D1F 0D21 0D2B 0D2D 0D3D 0D3F 0D4F 0D55 0D69 0D79 0D81 0D85 0D87 0D8B 0D8D 0DA3 0DAB 0DB7 0DBD 0DC7 0DC9 0DCD 0DD3 0DD5 0DDB 0DE5 0DE7 0DF3 0DFD 0DFF 0E09 0E17 0E1D 0E21 0E27 0E2F 0E35 0E3B 0E4B 0E57 0E59 0E5D 0E6B 0E71 0E75 0E7D 0E87 0E8F 0E95 0E9B 0EB1 0EB7 0EB9 0EC3 0ED1 0ED5 0EDB 0EED 0EEF 0EF9 0F07 0F0B 0F0D 0F17 0F25 0F29 0F31 0F43 0F47 0F4D 0F4F 0F53 0F59 0F5B 0F67 0F6B 0F7F 0F95 0FA1 0FA3 0FA7 0FAD 0FB3 0FB5 0FBB 0FD1 0FD3 0FD9 0FE9 0FEF 0FFB 0FFD 1003 100F 101F 1021 1025 102B 1039 103D 103F 1051 1069 1073 1079 107B 1085 1087 1091 1093 109D 10A3 10A5 10AF 10B1 10BB 10C1 10C9 10E7 10F1 10F3 10FD 1105 110B 1115 1127 112D 1139 1145 1147 1159 115F 1163 1169 116F 1181 1183 118D 119B 11A1 11A5 11A7 11AB 11C3 11C5 11D1 11D7 11E7 11EF 11F5 11FB 120D 121D 121F 1223 1229 122B 1231 1237 1241 1247 1253 125F 1271 1273 1279 127D 128F 1297 12AF 12B3 12B5 12B9 12BF 12C1 12CD 12D1 12DF 12FD 1307 130D 1319 1327 132D 1337 1343 1345 1349 134F 1357 135D 1367 1369 136D 137B 1381 1387 138B 1391 1393 139D 139F 13AF 13BB 13C3 13D5 13D9 13DF 13EB 13ED 13F3 13F9 13FF 141B 1421 142F 1433 143B 1445 144D 1459 146B 146F 1471 1475 148D 1499 149F 14A1 14B1 14B7 14BD 14CB 14D5 14E3 14E7 1505 150B 1511 1517 151F 1525 1529 152B 1537 153D 1541 1543 1549 155F 1565 1567 156B 157D 157F 1583 158F 1591 1597 159B 15B5 15BB 15C1 15C5 15CD 15D7 15F7 1607 1609 160F 1613 1615 1619 161B 1625 1633 1639 163D 1645 164F 1655 1669 166D 166F 1675 1693 1697 169F 16A9 16AF 16B5 16BD 16C3 16CF 16D3 16D9 16DB 16E1 16E5 16EB 16ED 16F7 16F9 1709 170F 1723 1727 1733 1741 175D 1763 1777 177B 178D 1795 179B 179F 17A5 17B3 17B9 17BF 17C9 17CB 17D5 17E1 17E9 17F3 17F5 17FF 1807 1813 181D 1835 1837 183B 1843 1849 184D 1855 1867 1871 1877 187D 187F 1885 188F 189B 189D 18A7 18AD 18B3 18B9 18C1 18C7 18D1 18D7 18D9 18DF 18E5 18EB 18F5 18FD 1915 191B 1931 1933 1945 1949 1951 195B 1979 1981 1993 1997 1999 19A3 19A9 19AB 19B1 19B5 19C7 19CF 19DB 19ED 19FD 1A03 1A05 1A11 1A17 1A21 1A23 1A2D 1A2F 1A35 1A3F 1A4D 1A51 1A69 1A6B 1A7B 1A7D 1A87 1A89 1A93 1AA7 1AAB 1AAD 1AB1 1AB9 1AC9 1ACF 1AD5 1AD7 1AE3 1AF3 1AFB 1AFF 1B05 1B23 1B25 1B2F 1B31 1B37 1B3B 1B41 1B47 1B4F 1B55 1B59 1B65 1B6B 1B73 1B7F 1B83 1B91 1B9D 1BA7 1BBF 1BC5 1BD1 1BD7 1BD9 1BEF 1BF7 1C09 1C13 1C19 1C27 1C2B 1C2D 1C33 1C3D 1C45 1C4B 1C4F 1C55 1C73 1C81 1C8B 1C8D 1C99 1CA3 1CA5 1CB5 1CB7 1CC9 1CE1 1CF3 1CF9 1D09 1D1B 1D21 1D23 1D35 1D39 1D3F 1D41 1D4B 1D53 1D5D 1D63 1D69 1D71 1D75 1D7B 1D7D 1D87 1D89 1D95 1D99 1D9F 1DA5 1DA7 1DB3 1DB7 1DC5 1DD7 1DDB 1DE1 1DF5 1DF9 1E01 1E07 1E0B 1E13 1E17 1E25 1E2B 1E2F 1E3D 1E49 1E4D 1E4F 1E6D 1E71 1E89 1E8F 1E95 1EA1 1EAD 1EBB 1EC1 1EC5 1EC7 1ECB 1EDD 1EE3 1EEF 1EF7 1EFD 1F01 1F0D 1F0F 1F1B 1F39 1F49 1F4B 1F51 1F67 1F75 1F7B 1F85 1F91 1F97 1F99 1F9D 1FA5 1FAF 1FB5 1FBB 1FD3 1FE1 1FE7 1FEB 1FF3 1FFF 2011 201B 201D 2027 2029 202D 2033 2047 204D 2051 205F 2063 2065 2069 2077 207D 2089 20A1 20AB 20B1 20B9 20C3 20C5 20E3 20E7 20ED 20EF 20FB 20FF 210D 2113 2135 2141 2149 214F 2159 215B 215F 2173 217D 2185 2195 2197 21A1 21AF 21B3 21B5 21C1 21C7 21D7 21DD 21E5 21E9 21F1 21F5 21FB 2203 2209 220F 221B 2221 2225 222B 2231 2239 224B 224F 2263 2267 2273 2275 227F 2285 2287 2291 229D 229F 22A3 22B7 22BD 22DB 22E1 22E5 22ED 22F7 2303 2309 230B 2327 2329 232F 2333 2335 2345 2351 2353 2359 2363 236B 2383 238F 2395 23A7 23AD 23B1 23BF 23C5 23C9 23D5 23DD 23E3 23EF 23F3 23F9 2405 240B 2417 2419 2429 243D 2441 2443 244D 245F 2467 246B 2479 247D 247F 2485 249B 24A1 24AF 24B5 24BB 24C5 24CB 24CD 24D7 24D9 24DD 24DF 24F5 24F7 24FB 2501 2507 2513 2519 2527 2531 253D 2543 254B 254F 2573 2581 258D 2593 2597 259D 259F 25AB 25B1 25BD 25CD 25CF 25D9 25E1 25F7 25F9 2605 260B 260F 2615 2627 2629 2635 263B 263F 264B 2653 2659 2665 2669 266F 267B 2681 2683 268F 269B 269F 26AD 26B3 26C3 26C9 26CB 26D5 26DD 26EF 26F5 2717 2719 2735 2737 274D 2753 2755 275F 276B 276D 2773 2777 277F 2795 279B 279D 27A7 27AF 27B3 27B9 27C1 27C5 27D1 27E3 27EF 2803 2807 280D 2813 281B 281F 2821 2831 283D 283F 2849 2851 285B 285D 2861 2867 2875 2881 2897 289F 28BB 28BD 28C1 28D5 28D9 28DB 28DF 28ED 28F7 2903 2905 2911 2921 2923 293F 2947 295D 2965 2969 296F 2975 2983 2987 298F 299B 29A1 29A7 29AB 29BF 29C3 29D5 29D7 29E3 29E9 29ED 29F3 2A01 2A13 2A1D 2A25 2A2F 2A4F 2A55 2A5F 2A65 2A6B 2A6D 2A73 2A83 2A89 2A8B 2A97 2A9D 2AB9 2ABB 2AC5 2ACD 2ADD 2AE3 2AEB 2AF1 2AFB 2B13 2B27 2B31 2B33 2B3D 2B3F 2B4B 2B4F 2B55 2B69 2B6D 2B6F 2B7B 2B8D 2B97 2B99 2BA3 2BA5 2BA9 2BBD 2BCD 2BE7 2BEB 2BF3 2BF9 2BFD 2C09 2C0F 2C17 2C23 2C2F 2C35 2C39 2C41 2C57 2C59 2C69 2C77 2C81 2C87 2C93 2C9F 2CAD 2CB3 2CB7 2CCB 2CCF 2CDB 2CE1 2CE3 2CE9 2CEF 2CFF 2D07 2D1D 2D1F 2D3B 2D43 2D49 2D4D 2D61 2D65 2D71 2D89 2D9D 2DA1 2DA9 2DB3 2DB5 2DC5 2DC7 2DD3 2DDF 2E01 2E03 2E07 2E0D 2E19 2E1F 2E25 2E2D 2E33 2E37 2E39 2E3F 2E57 2E5B 2E6F 2E79 2E7F 2E85 2E93 2E97 2E9D 2EA3 2EA5 2EB1 2EB7 2EC1 2EC3 2ECD 2ED3 2EE7 2EEB 2F05 2F09 2F0B 2F11 2F27 2F29 2F41 2F45 2F4B 2F4D 2F51 2F57 2F6F 2F75 2F7D 2F81 2F83 2FA5 2FAB 2FB3 2FC3 2FCF 2FD1 2FDB 2FDD 2FE7 2FED 2FF5 2FF9 3001 300D 3023 3029 3037 303B 3055 3059 305B 3067 3071 3079 307D 3085 3091 3095 30A3 30A9 30B9 30BF 30C7 30CB 30D1 30D7 30DF 30E5 30EF 30FB 30FD 3103 3109 3119 3121 3127 312D 3139 3143 3145 314B 315D 3161 3167 316D 3173 317F 3191 3199 319F 31A9 31B1 31C3 31C7 31D5 31DB 31ED 31F7 31FF 3209 3215 3217 321D 3229 3235 3259 325D 3263 326B 326F 3275 3277 327B 328D 3299 329F 32A7 32AD 32B3 32B7 32C9 32CB 32CF 32D1 32E9 32ED 32F3 32F9 3307 3325 332B 332F 3335 3341 3347 335B 335F 3367 336B 3373 3379 337F 3383 33A1 33A3 33AD 33B9 33C1 33CB 33D3 33EB 33F1 33FD 3401 340F 3413 3419 341B 3437 3445 3455 3457 3463 3469 346D 3481 348B 3491 3497 349D 34A5 34AF 34BB 34C9 34D3 34E1 34F1 34FF 3509 3517 351D 352D 3533 353B 3541 3551 3565 356F 3571 3577 357B 357D 3581 358D 358F 3599 359B 35A1 35B7 35BD 35BF 35C3 35D5 35DD 35E7 35EF 3605 3607 3611 3623 3631 3635 3637 363B 364D 364F 3653 3659 3661 366B 366D 368B 368F 36AD 36AF 36B9 36BB 36CD 36D1 36E3 36E9 36F7 3701 3703 3707 371B 373F 3745 3749 374F 375D 3761 3775 377F 378D 37A3 37A9 37AB 37C9 37D5 37DF 37F1 37F3 37F7 3805 380B 3821 3833 3835 3841 3847 384B 3853 3857 385F 3865 386F 3871 387D 388F 3899 38A7 38B7 38C5 38C9 38CF 38D5 38D7 38DD 38E1 38E3 38FF 3901 391D 3923 3925 3929 392F 393D 3941 394D 395B 396B 3979 397D 3983 398B 3991 3995 399B 39A1 39A7 39AF 39B3 39BB 39BF 39CD 39DD 39E5 39EB 39EF 39FB 3A03 3A13 3A15 3A1F 3A27 3A2B 3A31 3A4B 3A51 3A5B 3A63 3A67 3A6D 3A79 3A87 3AA5 3AA9 3AB7 3ACD 3AD5 3AE1 3AE5 3AEB 3AF3 3AFD 3B03 3B11 3B1B 3B21 3B23 3B2D 3B39 3B45 3B53 3B59 3B5F 3B71 3B7B 3B81 3B89 3B9B 3B9F 3BA5 3BA7 3BAD 3BB7 3BB9 3BC3 3BCB 3BD1 3BD7 3BE1 3BE3 3BF5 3BFF 3C01 3C0D 3C11 3C17 3C1F 3C29 3C35 3C43 3C4F 3C53 3C5B 3C65 3C6B 3C71 3C85 3C89 3C97 3CA7 3CB5 3CBF 3CC7 3CD1 3CDD 3CDF 3CF1 3CF7 3D03 3D0D 3D19 3D1B 3D1F 3D21 3D2D 3D33 3D37 3D3F 3D43 3D6F 3D73 3D75 3D79 3D7B 3D85 3D91 3D97 3D9D 3DAB 3DAF 3DB5 3DBB 3DC1 3DC9 3DCF 3DF3 3E05 3E09 3E0F 3E11 3E1D 3E23 3E29 3E2F 3E33 3E41 3E57 3E63 3E65 3E77 3E81 3E87 3EA1 3EB9 3EBD 3EBF 3EC3 3EC5 3EC9 3ED7 3EDB 3EE1 3EE7 3EEF 3EFF 3F0B 3F0D 3F37 3F3B 3F3D 3F41 3F59 3F5F 3F65 3F67 3F79 3F7D 3F8B 3F91 3FAD 3FBF 3FCD 3FD3 3FDD 3FE9 3FEB 3FF1 3FFD 401B 4021 4025 402B 4031 403F 4043 4045 405D 4061 4067 406D 4087 4091 40A3 40A9 40B1 40B7 40BD 40DB 40DF 40EB 40F7 40F9 4109 410B 4111 4115 4121 4133 4135 413B 413F 4159 4165 416B 4177 417B 4193 41AB 41B7 41BD 41BF 41CB 41E7 41EF 41F3 41F9 4205 4207 4219 421F 4223 4229 422F 4243 4253 4255 425B 4261 4273 427D 4283 4285 4289 4291 4297 429D 42B5 42C5 42CB 42D3 42DD 42E3 42F1 4307 430F 431F 4325 4327 4333 4337 4339 434F 4357 4369 438B 438D 4393 43A5 43A9 43AF 43B5 43BD 43C7 43CF 43E1 43E7 43EB 43ED 43F1 43F9 4409 440B 4417 4423 4429 443B 443F 4445 444B 4451 4453 4459 4465 446F 4483 448F 44A1 44A5 44AB 44AD 44BD 44BF 44C9 44D7 44DB 44F9 44FB 4505 4511 4513 452B 4531 4541 4549 4553 4555 4561 4577 457D 457F 458F 45A3 45AD 45AF 45BB 45C7 45D9 45E3 45EF 45F5 45F7 4601 4603 4609 4613 4625 4627 4633 4639 463D 4643 4645 465D 4679 467B 467F 4681 468B 468D 469D 46A9 46B1 46C7 46C9 46CF 46D3 46D5 46DF 46E5 46F9 4705 470F 4717 4723 4729 472F 4735 4739 474B 474D 4751 475D 476F 4771 477D 4783 4787 4789 4799 47A5 47B1 47BF 47C3 47CB 47DD 47E1 47ED 47FB 4801 4807 480B 4813 4819 481D 4831 483D 4847 4855 4859 485B 486B 486D 4879 4897 489B 48A1 48B9 48CD 48E5 48EF 48F7 4903 490D 4919 491F 492B 4937 493D 4945 4955 4963 4969 496D 4973 4997 49AB 49B5 49D3 49DF 49E1 49E5 49E7 4A03 4A0F 4A1D 4A23 4A39 4A41 4A45 4A57 4A5D 4A6B 4A7D 4A81 4A87 4A89 4A8F 4AB1 4AC3 4AC5 4AD5 4ADB 4AED 4AEF 4B07 4B0B 4B0D 4B13 4B1F 4B25 4B31 4B3B 4B43 4B49 4B59 4B65 4B6D 4B77 4B85 4BAD 4BB3 4BB5 4BBB 4BBF 4BCB 4BD9 4BDD 4BDF 4BE3 4BE5 4BE9 4BF1 4BF7 4C01 4C07 4C0D 4C0F 4C15 4C1B 4C21 4C2D 4C33 4C4B 4C55 4C57 4C61 4C67 4C73 4C79 4C7F 4C8D 4C93 4C99 4CCD 4CE1 4CE7 4CF1 4CF3 4CFD 4D05 4D0F 4D1B 4D27 4D29 4D2F 4D33 4D41 4D51 4D59 4D65 4D6B 4D81 4D83 4D8D 4D95 4D9B 4DB1 4DB3 4DC9 4DCF 4DD7 4DE1 4DED 4DF9 4DFB 4E05 4E0B 4E17 4E19 4E1D 4E2B 4E35 4E37 4E3D 4E4F 4E53 4E5F 4E67 4E79 4E85 4E8B 4E91 4E95 4E9B 4EA1 4EAF 4EB3 4EB5 4EC1 4ECD 4ED1 4ED7 4EE9 4EFB 4F07 4F09 4F19 4F25 4F2D 4F3F 4F49 4F63 4F67 4F6D 4F75 4F7B 4F81 4F85 4F87 4F91 4FA5 4FA9 4FAF 4FB7 4FBB 4FCF 4FD9 4FDB 4FFD 4FFF 5003 501B 501D 5029 5035 503F 5045 5047 5053 5071 5077 5083 5093 509F 50A1 50B7 50C9 50D5 50E3 50ED 50EF 50FB 5107 510B 510D 5111 5117 5123 5125 5135 5147 5149 5171 5179 5189 518F 5197 51A1 51A3 51A7 51B9 51C1 51CB 51D3 51DF 51E3 51F5 51F7 5209 5213 5215 5219 521B 521F 5227 5243 5245 524B 5261 526D 5273 5281 5293 5297 529D 52A5 52AB 52B1 52BB 52C3 52C7 52C9 52DB 52E5 52EB 52FF 5315 531D 5323 5341 5345 5347 534B 535D 5363 5381 5383 5387 538F 5395 5399 539F 53AB 53B9 53DB 53E9 53EF 53F3 53F5 53FB 53FF 540D 5411 5413 5419 5435 5437 543B 5441 5449 5453 5455 545F 5461 546B 546D 5471 548F 5491 549D 54A9 54B3 54C5 54D1 54DF 54E9 54EB 54F7 54FD 5507 550D 551B 5527 552B 5539 553D 554F 5551 555B 5563 5567 556F 5579 5585 5597 55A9 55B1 55B7 55C9 55D9 55E7 55ED 55F3 55FD 560B 560F 5615 5617 5623 562F 5633 5639 563F 564B 564D 565D 565F 566B 5671 5675 5683 5689 568D 568F 569B 56AD 56B1 56D5 56E7 56F3 56FF 5701 5705 5707 570B 5713 571F 5723 5747 574D 575F 5761 576D 5777 577D 5789 57A1 57A9 57AF 57B5 57C5 57D1 57D3 57E5 57EF 5803 580D 580F 5815 5827 582B 582D 5855 585B 585D 586D 586F 5873 587B 588D 5897 58A3 58A9 58AB 58B5 58BD 58C1 58C7 58D3 58D5 58DF 58F1 58F9 58FF 5903 5917 591B 5921 5945 594B 594D 5957 595D 5975 597B 5989 5999 599F 59B1 59B3 59BD 59D1 59DB 59E3 59E9 59ED 59F3 59F5 59FF 5A01 5A0D 5A11 5A13 5A17 5A1F 5A29 5A2F 5A3B 5A4D 5A5B 5A67 5A77 5A7F 5A85 5A95 5A9D 5AA1 5AA3 5AA9 5ABB 5AD3 5AE5 5AEF 5AFB 5AFD 5B01 5B0F 5B19 5B1F 5B25 5B2B 5B3D 5B49 5B4B 5B67 5B79 5B87 5B97 5BA3 5BB1 5BC9 5BD5 5BEB 5BF1 5BF3 5BFD 5C05 5C09 5C0B 5C0F 5C1D 5C29 5C2F 5C33 5C39 5C47 5C4B 5C4D 5C51 5C6F 5C75 5C77 5C7D 5C87 5C89 5CA7 5CBD 5CBF 5CC3 5CC9 5CD1 5CD7 5CDD 5CED 5CF9 5D05 5D0B 5D13 5D17 5D19 5D31 5D3D 5D41 5D47 5D4F 5D55 5D5B 5D65 5D67 5D6D 5D79 5D95 5DA3 5DA9 5DAD 5DB9 5DC1 5DC7 5DD3 5DD7 5DDD 5DEB 5DF1 5DFD 5E07 5E0D 5E13 5E1B 5E21 5E27 5E2B 5E2D 5E31 5E39 5E45 5E49 5E57 5E69 5E73 5E75 5E85 5E8B 5E9F 5EA5 5EAF 5EB7 5EBB 5ED9 5EFD 5F09 5F11 5F27 5F33 5F35 5F3B 5F47 5F57 5F5D 5F63 5F65 5F77 5F7B 5F95 5F99 5FA1 5FB3 5FBD 5FC5 5FCF 5FD5 5FE3 5FE7 5FFB 6011 6023 602F 6037 6053 605F 6065 606B 6073 6079 6085 609D 60AD 60BB 60BF 60CD 60D9 60DF 60E9 60F5 6109 610F 6113 611B 612D 6139 614B 6155 6157 615B 616F 6179 6187 618B 6191 6193 619D 61B5 61C7 61C9 61CD 61E1 61F1 61FF 6209 6217 621D 6221 6227 623B 6241 624B 6251 6253 625F 6265 6283 628D 6295 629B 629F 62A5 62AD 62D5 62D7 62DB 62DD 62E9 62FB 62FF 6305 630D 6317 631D 632F 6341 6343 634F 635F 6367 636D 6371 6377 637D 637F 63B3 63C1 63C5 63D9 63E9 63EB 63EF 63F5 6401 6403 6409 6415 6421 6427 642B 6439 6443 6449 644F 645D 6467 6475 6485 648D 6493 649F 64A3 64AB 64C1 64C7 64C9 64DB 64F1 64F7 64F9 650B 6511 6521 652F 6539 653F 654B 654D 6553 6557 655F 6571 657D 658D 658F 6593 65A1 65A5 65AD 65B9 65C5 65E3 65F3 65FB 65FF 6601 6607 661D 6629 6631 663B 6641 6647 664D 665B 6661 6673 667D 6689 668B 6695 6697 669B 66B5 66B9 66C5 66CD 66D1 66E3 66EB 66F5 6703 6713 6719 671F 6727 6731 6737 673F 6745 6751 675B 676F 6779 6781 6785 6791 67AB 67BD 67C1 67CD 67DF 67E5 6803 6809 6811 6817 682D 6839 683B 683F 6845 684B 684D 6857 6859 685D 6863 6869 686B 6871 6887 6899 689F 68B1 68BD 68C5 68D1 68D7 68E1 68ED 68EF 68FF 6901 690B 690D 6917 6929 692F 6943 6947 6949 694F 6965 696B 6971 6983 6989 6997 69A3 69B3 69B5 69BB 69C1 69C5 69D3 69DF 69E3 69E5 69F7 6A07 6A2B 6A37 6A3D 6A4B 6A67 6A69 6A75 6A7B 6A87 6A8D 6A91 6A93 6AA3 6AC1 6AC9 6AE1 6AE7 6B05 6B0F 6B11 6B23 6B27 6B2D 6B39 6B41 6B57 6B59 6B5F 6B75 6B87 6B89 6B93 6B95 6B9F 6BBD 6BBF 6BDB 6BE1 6BEF 6BFF 6C05 6C19 6C29 6C2B 6C31 6C35 6C55 6C59 6C5B 6C5F 6C65 6C67 6C73 6C77 6C7D 6C83 6C8F 6C91 6C97 6C9B 6CA1 6CA9 6CAF 6CB3 6CC7 6CCB 6CEB 6CF5 6CFD 6D0D 6D0F 6D25 6D27 6D2B 6D31 6D39 6D3F 6D4F 6D5D 6D61 6D73 6D7B 6D7F 6D93 6D99 6DA5 6DB1 6DB7 6DC1 6DC3 6DCD 6DCF 6DDB 6DF7 6E03 6E15 6E17 6E29 6E33 6E3B 6E45 6E75 6E77 6E7B 6E81 6E89 6E93 6E95 6E9F 6EBD 6EBF 6EE3 6EE9 6EF3 6EF9 6EFB 6F0D 6F11 6F17 6F1F 6F2F 6F3D 6F4D 6F53 6F61 6F65 6F79 6F7D 6F83 6F85 6F8F 6F9B 6F9D 6FA3 6FAF 6FB5 6FBB 6FBF 6FCB 6FCD 6FD3 6FD7 6FE3 6FE9 6FF1 6FF5 6FF7 6FFD 700F 7019 701F 7027 7033 7039 704F 7051 7057 7063 7075 7079 7087 708D 7091 70A5 70AB 70BB 70C3 70C7 70CF 70E5 70ED 70F9 70FF 7105 7115 7121 7133 7151 7159 715D 715F 7163 7169 7183 7187 7195 71AD 71C3 71C9 71CB 71D1 71DB 71E1 71EF 71F5 71FB 7207 7211 7217 7219 7225 722F 723B 7243 7255 7267 7271 7277 727F 728F 7295 729B 72A3 72B3 72C7 72CB 72CD 72D7 72D9 72E3 72EF 72F5 72FD 7303 730D 7321 732B 733D 7357 735B 7361 737F 7381 7385 738D 7393 739F 73AB 73BD 73C1 73C9 73DF 73E5 73E7 73F3 7415 741B 742D 7439 743F 7441 745D 746B 747B 7489 748D 749B 74A7 74AB 74B1 74B7 74B9 74DD 74E1 74E7 74FB 7507 751F 7525 753B 753D 754D 755F 756B 7577 7589 758B 7591 7597 759D 75A1 75A7 75B5 75B9 75BB 75D1 75D9 75E5 75EB 75F5 75FB 7603 760F 7621 762D 7633 763D 763F 7655 7663 7669 766F 7673 7685 768B 769F 76B5 76B7 76C3 76DB 76DF 76F1 7703 7705 771B 771D 7721 772D 7735 7741 774B 7759 775D 775F 7771 7781 77A7 77AD 77B3 77B9 77C5 77CF 77D5 77E1 77E9 77EF 77F3 77F9 7807 7825 782B 7835 783D 7853 7859 7861 786D 7877 7879 7883 7885 788B 7895 7897 78A1 78AD 78BF 78D3 78D9 78DD 78E5 78FB 7901 7907 7925 792B 7939 793F 794B 7957 795D 7967 7969 7973 7991 7993 79A3 79AB 79AF 79B1 79B7 79C9 79CD 79CF 79D5 79D9 79F3 79F7 79FF 7A05 7A0F 7A11 7A15 7A1B 7A23 7A27 7A2D 7A4B 7A57 7A59 7A5F 7A65 7A69 7A7D 7A93 7A9B 7A9F 7AA1 7AA5 7AED 7AF5 7AF9 7B01 7B17 7B19 7B1D 7B2B 7B35 7B37 7B3B 7B4F 7B55 7B5F 7B71 7B77 7B8B 7B9B 7BA1 7BA9 7BAF 7BB3 7BC7 7BD3 7BE9 7BEB 7BEF 7BF1 7BFD 7C07 7C19 7C1B 7C31 7C37 7C49 7C67 7C69 7C73 7C81 7C8B 7C93 7CA3 7CD5 7CDB 7CE5 7CED 7CF7 7D03 7D09 7D1B 7D1D 7D33 7D39 7D3B 7D3F 7D45 7D4D 7D53 7D59 7D63 7D75 7D77 7D8D 7D8F 7D9F 7DAD 7DB7 7DBD 7DBF 7DCB 7DD5 7DE9 7DED 7DFB 7E01 7E05 7E29 7E2B 7E2F 7E35 7E41 7E43 7E47 7E55 7E61 7E67 7E6B 7E71 7E73 7E79 7E7D 7E91 7E9B 7E9D 7EA7 7EAD 7EB9 7EBB 7ED3 7EDF 7EEB 7EF1 7EF7 7EFB 7F13 7F15 7F19 7F31 7F33 7F39 7F3D 7F43 7F4B 7F5B 7F61 7F63 7F6D 7F79 7F87 7F8D 7FAF 7FB5 7FC3 7FC9 7FCD 7FCF 7FED 8003 800B 800F 8015 801D 8021 8023 803F 8041 8047 804B 8065 8077 808D 808F 8095 80A5 80AB 80AD 80BD 80C9 80CB 80D7 80DB 80E1 80E7 80F5 80FF 8105 810D 8119 811D 812F 8131 813B 8143 8153 8159 815F 817D 817F 8189 819B 819D 81A7 81AF 81B3 81BB 81C7 81DF 8207 8209 8215 821F 8225 8231 8233 823F 8243 8245 8249 824F 8261 826F 827B 8281 8285 8293 82B1 82B5 82BD 82C7 82CF 82D5 82DF 82F1 82F9 82FD 830B 831B 8321 8329 832D 8333 8335 833F 8341 834D 8351 8353 8357 835D 8365 8369 836F 838F 83A7 83B1 83B9 83CB 83D5 83D7 83DD 83E7 83E9 83ED 83FF 8405 8411 8413 8423 8425 843B 8441 8447 844F 8461 8465 8477 8483 848B 8491 8495 84A9 84AF 84CD 84E3 84EF 84F1 84F7 8509 850D 854B 854F 8551 855D 8563 856D 856F 857B 8587 85A3 85A5 85A9 85B7 85CD 85D3 85D5 85DB 85E1 85EB 85F9 85FD 85FF 8609 860F 8617 8621 862F 8639 863F 8641 864D 8663 8675 867D 8687 8699 86A5 86A7 86B3 86B7 86C3 86C5 86CF 86D1 86D7 86E9 86EF 86F5 8717 871D 871F 872B 872F 8735 8747 8759 875B 876B 8771 8777 877F 8785 878F 87A1 87A9 87B3 87BB 87C5 87C7 87CB 87DD 87F7 8803 8819 881B 881F 8821 8837 883D 8843 8851 8861 8867 887B 8885 8891 8893 88A5 88CF 88D3 88EB 88ED 88F3 88FD 8909 890B 8911 891B 8923 8927 892D 8939 8945 894D 8951 8957 8963 8981 8995 899B 89B3 89B9 89C3 89CF 89D1 89DB 89EF 89F5 89FB 89FF 8A0B 8A19 8A23 8A35 8A41 8A49 8A4F 8A5B 8A5F 8A6D 8A77 8A79 8A85 8AA3 8AB3 8AB5 8AC1 8AC7 8ACB 8ACD 8AD1 8AD7 8AF1 8AF5 8B07 8B09 8B0D 8B13 8B21 8B57 8B5D 8B91 8B93 8BA3 8BA9 8BAF 8BBB 8BD5 8BD9 8BDB 8BE1 8BF7 8BFD 8BFF 8C0B 8C17 8C1D 8C27 8C39 8C3B 8C47 8C53 8C5D 8C6F 8C7B 8C81 8C89 8C8F 8C99 8C9F 8CA7 8CAB 8CAD 8CB1 8CC5 8CDD 8CE3 8CE9 8CF3 8D01 8D0B 8D0D 8D23 8D29 8D37 8D41 8D5B 8D5F 8D71 8D79 8D85 8D91 8D9B 8DA7 8DAD 8DB5 8DC5 8DCB 8DD3 8DD9 8DDF 8DF5 8DF7 8E01 8E15 8E1F 8E25 8E51 8E63 8E69 8E73 8E75 8E79 8E7F 8E8D 8E91 8EAB 8EAF 8EB1 8EBD 8EC7 8ECF 8ED3 8EDB 8EE7 8EEB 8EF7 8EFF 8F15 8F1D 8F23 8F2D 8F3F 8F45 8F4B 8F53 8F59 8F65 8F69 8F71 8F83 8F8D 8F99 8F9F 8FAB 8FAD 8FB3 8FB7 8FB9 8FC9 8FD5 8FE1 8FEF 8FF9 9007 900D 9017 9023 9025 9031 9037 903B 9041 9043 904F 9053 906D 9073 9085 908B 9095 909B 909D 90AF 90B9 90C1 90C5 90DF 90E9 90FD 9103 9113 9127 9133 913D 9145 914F 9151 9161 9167 917B 9185 9199 919D 91BB 91BD 91C1 91C9 91D9 91DB 91ED 91F1 91F3 91F9 9203 9215 9221 922F 9241 9247 9257 926B 9271 9275 927D 9283 9287 928D 9299 92A1 92AB 92AD 92B9 92BF 92C3 92C5 92CB 92D5 92D7 92E7 92F3 9301 930B 9311 9319 931F 933B 933D 9343 9355 9373 9395 9397 93A7 93B3 93B5 93C7 93D7 93DD 93E5 93EF 93F7 9401 9409 9413 943F 9445 944B 944F 9463 9467 9469 946D 947B 9497 949F 94A5 94B5 94C3 94E1 94E7 9505 9509 9517 9521 9527 952D 9535 9539 954B 9557 955D 955F 9575 9581 9589 958F 959B 959F 95AD 95B1 95B7 95B9 95BD 95CF 95E3 95E9 95F9 961F 962F 9631 9635 963B 963D 9665 968F 969D 96A1 96A7 96A9 96C1 96CB 96D1 96D3 96E5 96EF 96FB 96FD 970D 970F 9715 9725 972B 9733 9737 9739 9743 9749 9751 975B 975D 976F 977F 9787 9793 97A5 97B1 97B7 97C3 97CD 97D3 97D9 97EB 97F7 9805 9809 980B 9815 9829 982F 983B 9841 9851 986B 986F 9881 9883 9887 98A7 98B1 98B9 98BF 98C3 98C9 98CF 98DD 98E3 98F5 98F9 98FB 990D 9917 991F 9929 9931 993B 993D 9941 9947 9949 9953 997D 9985 9991 9995 999B 99AD 99AF 99BF 99C7 99CB 99CD 99D7 99E5 99F1 99FB 9A0F 9A13 9A1B 9A25 9A4B 9A4F 9A55 9A57 9A61 9A75 9A7F 9A8B 9A91 9A9D 9AB7 9AC3 9AC7 9ACF 9AEB 9AF3 9AF7 9AFF 9B17 9B1D 9B27 9B2F 9B35 9B45 9B51 9B59 9B63 9B6F 9B77 9B8D 9B93 9B95 9B9F 9BA1 9BA7 9BB1 9BB7 9BBD 9BC5 9BCB 9BCF 9BDD 9BF9 9C01 9C11 9C23 9C2B 9C2F 9C35 9C49 9C4D 9C5F 9C65 9C67 9C7F 9C97 9C9D 9CA3 9CAF 9CBB 9CBF 9CC1 9CD7 9CD9 9CE3 9CE9 9CF1 9CFD 9D01 9D15 9D27 9D2D 9D31 9D3D 9D55 9D5B 9D61 9D97 9D9F 9DA5 9DA9 9DC3 9DE7 9DEB 9DED 9DF1 9E0B 9E17 9E23 9E27 9E2D 9E33 9E3B 9E47 9E51 9E53 9E5F 9E6F 9E81 9E87 9E8F 9E95 9EA1 9EB3 9EBD 9EBF 9EF5 9EF9 9EFB 9F05 9F23 9F2F 9F37 9F3B 9F43 9F53 9F61 9F6D 9F73 9F77 9F7D 9F89 9F8F 9F91 9F95 9FA3 9FAF 9FB3 9FC1 9FC7 9FDF 9FE5 9FEB 9FF5 A001 A00D A021 A033 A039 A03F A04F A057 A05B A061 A075 A079 A099 A09D A0AB A0B5 A0B7 A0BD A0C9 A0D9 A0DB A0DF A0E5 A0F1 A0F3 A0FD A105 A10B A10F A111 A11B A129 A12F A135 A141 A153 A175 A17D A187 A18D A1A5 A1AB A1AD A1B7 A1C3 A1C5 A1E3 A1ED A1FB A207 A213 A223 A229 A22F A231 A243 A247 A24D A26B A279 A27D A283 A289 A28B A291 A295 A29B A2A9 A2AF A2B3 A2BB A2C5 A2D1 A2D7 A2F7 A301 A309 A31F A321 A32B A331 A349 A351 A355 A373 A379 A37B A387 A397 A39F A3A5 A3A9 A3AF A3B7 A3C7 A3D5 A3DB A3E1 A3E5 A3E7 A3F1 A3FD A3FF A40F A41D A421 A423 A427 A43B A44D A457 A459 A463 A469 A475 A493 A49B A4AD A4B9 A4C3 A4C5 A4CB A4D1 A4D5 A4E1 A4ED A4EF A4F3 A4FF A511 A529 A52B A535 A53B A543 A553 A55B A561 A56D A577 A585 A58B A597 A59D A5A3 A5A7 A5A9 A5C1 A5C5 A5CB A5D3 A5D9 A5DD A5DF A5E3 A5E9 A5F7 A5FB A603 A60D A625 A63D A649 A64B A651 A65D A673 A691 A693 A699 A6AB A6B5 A6BB A6C1 A6C9 A6CD A6CF A6D5 A6DF A6E7 A6F1 A6F7 A6FF A70F A715 A723 A729 A72D A745 A74D A757 A759 A765 A76B A76F A793 A795 A7AB A7B1 A7B9 A7BF A7C9 A7D1 A7D7 A7E3 A7ED A7FB A805 A80B A81D A829 A82B A837 A83B A855 A85F A86D A87D A88F A897 A8A9 A8B5 A8C1 A8C7 A8D7 A8E5 A8FD A907 A913 A91B A931 A937 A939 A943 A97F A985 A987 A98B A993 A9A3 A9B1 A9BB A9C1 A9D9 A9DF A9EB A9FD AA15 AA17 AA35 AA39 AA3B AA47 AA4D AA57 AA59 AA5D AA6B AA71 AA81 AA83 AA8D AA95 AAAB AABF AAC5 AAC9 AAE9 AAEF AB01 AB05 AB07 AB0B AB0D AB11 AB19 AB4D AB5B AB71 AB73 AB89 AB9D ABA7 ABAF ABB9 ABBB ABC1 ABC5 ABD3 ABD7 ABDD ABF1 ABF5 ABFB ABFD AC09 AC15 AC1B AC27 AC37 AC39 AC45 AC4F AC57 AC5B AC61 AC63 AC7F AC8B AC93 AC9D ACA9 ACAB ACAF ACBD ACD9 ACE1 ACE7 ACEB ACED ACF1 ACF7 ACF9 AD05 AD3F AD45 AD53 AD5D AD5F AD65 AD81 ADA1 ADA5 ADC3 ADCB ADD1 ADD5 ADDB ADE7 ADF3 ADF5 ADF9 ADFF AE05 AE13 AE23 AE2B AE49 AE4D AE4F AE59 AE61 AE67 AE6B AE71 AE8B AE8F AE9B AE9D AEA7 AEB9 AEC5 AED1 AEE3 AEE5 AEE9 AEF5 AEFD AF09 AF13 AF27 AF2B AF33 AF43 AF4F AF57 AF5D AF6D AF75 AF7F AF8B AF99 AF9F AFA3 AFAB AFB7 AFBB AFCF AFD5 AFFD B005 B015 B01B B03F B041 B047 B04B B051 B053 B069 B07B B07D B087 B08D B0B1 B0BF B0CB B0CF B0E1 B0E9 B0ED B0FB B105 B107 B111 B119 B11D B11F B131 B141 B14D B15B B165 B173 B179 B17F B1A9 B1B3 B1B9 B1BF B1D3 B1DD B1E5 B1F1 B1F5 B201 B213 B215 B21F B22D B23F B249 B25B B263 B269 B26D B27B B281 B28B B2A9 B2B7 B2BD B2C3 B2C7 B2D3 B2F9 B2FD B2FF B303 B309 B311 B31D B327 B32D B33F B345 B377 B37D B381 B387 B393 B39B B3A5 B3C5 B3CB B3E1 B3E3 B3ED B3F9 B40B B40D B413 B417 B435 B43D B443 B449 B45B B465 B467 B46B B477 B48B B495 B49D B4B5 B4BF B4C1 B4C7 B4DD B4E3 B4E5 B4F7 B501 B50D B50F B52D B53F B54B B567 B569 B56F B573 B579 B587 B58D B599 B5A3 B5AB B5AF B5BB B5D5 B5DF B5E7 B5ED B5FD B5FF B609 B61B B629 B62F B633 B639 B647 B657 B659 B65F B663 B66F B683 B687 B69B B69F B6A5 B6B1 B6B3 B6D7 B6DB B6E1 B6E3 B6ED B6EF B705 B70D B713 B71D B729 B735 B747 B755 B76D B791 B795 B7A9 B7C1 B7CB B7D1 B7D3 B7EF B7F5 B807 B80F B813 B819 B821 B827 B82B B82D B839 B855 B867 B875 B885 B893 B8A5 B8AF B8B7 B8BD B8C1 B8C7 B8CD B8D5 B8EB B8F7 B8F9 B903 B915 B91B B91D B92F B939 B93B B947 B951 B963 B983 B989 B98D B993 B999 B9A1 B9A7 B9AD B9B7 B9CB B9D1 B9DD B9E7 B9EF B9F9 BA07 BA0D BA17 BA25 BA29 BA2B BA41 BA53 BA55 BA5F BA61 BA65 BA79 BA7D BA7F BAA1 BAA3 BAAF BAB5 BABF BAC1 BACB BADD BAE3 BAF1 BAFD BB09 BB1F BB27 BB2D BB3D BB43 BB4B BB4F BB5B BB61 BB69 BB6D BB91 BB97 BB9D BBB1 BBC9 BBCF BBDB BBED BBF7 BBF9 BC03 BC1D BC23 BC33 BC3B BC41 BC45 BC5D BC6F BC77 BC83 BC8F BC99 BCAB BCB7 BCB9 BCD1 BCD5 BCE1 BCF3 BCFF BD0D BD17 BD19 BD1D BD35 BD41 BD4F BD59 BD5F BD61 BD67 BD6B BD71 BD8B BD8F BD95 BD9B BD9D BDB3 BDBB BDCD BDD1 BDE3 BDEB BDEF BE07 BE09 BE15 BE21 BE25 BE27 BE5B BE5D BE6F BE75 BE79 BE7F BE8B BE8D BE93 BE9F BEA9 BEB1 BEB5 BEB7 BECF BED9 BEDB BEE5 BEE7 BEF3 BEF9 BF0B BF33 BF39 BF4D BF5D BF5F BF6B BF71 BF7B BF87 BF89 BF8D BF93 BFA1 BFAD BFB9 BFCF BFD5 BFDD BFE1 BFE3 BFF3 C005 C011 C013 C019 C029 C02F C031 C037 C03B C047 C065 C06D C07D C07F C091 C09B C0B3 C0B5 C0BB C0D3 C0D7 C0D9 C0EF C0F1 C101 C103 C109 C115 C119 C12B C133 C137 C145 C149 C15B C173 C179 C17B C181 C18B C18D C197 C1BD C1C3 C1CD C1DB C1E1 C1E7 C1FF C203 C205 C211 C221 C22F C23F C24B C24D C253 C25D C277 C27B C27D C289 C28F C293 C29F C2A7 C2B3 C2BD C2CF C2D5 C2E3 C2FF C301 C307 C311 C313 C317 C325 C347 C349 C34F C365 C367 C371 C37F C383 C385 C395 C39D C3A7 C3AD C3B5 C3BF C3C7 C3CB C3D1 C3D3 C3E3 C3E9 C3EF C401 C41F C42D C433 C437 C455 C457 C461 C46F C473 C487 C491 C499 C49D C4A5 C4B7 C4BB C4C9 C4CF C4D3 C4EB C4F1 C4F7 C509 C51B C51D C541 C547 C551 C55F C56B C56F C575 C577 C595 C59B C59F C5A1 C5A7 C5C3 C5D7 C5DB C5EF C5FB C613 C623 C635 C641 C64F C655 C659 C665 C685 C691 C697 C6A1 C6A9 C6B3 C6B9 C6CB C6CD C6DD C6EB C6F1 C707 C70D C719 C71B C72D C731 C739 C757 C763 C767 C773 C775 C77F C7A5 C7BB C7BD C7C1 C7CF C7D5 C7E1 C7F9 C7FD C7FF C803 C811 C81D C827 C829 C839 C83F C853 C857 C86B C881 C88D C88F C893 C895 C8A1 C8B7 C8CF C8D5 C8DB C8DD C8E3 C8E7 C8ED C8EF C8F9 C905 C911 C917 C919 C91F C92F C937 C93D C941 C953 C95F C96B C979 C97D C989 C98F C997 C99D C9AF C9B5 C9BF C9CB C9D9 C9DF C9E3 C9EB CA01 CA07 CA09 CA25 CA37 CA39 CA4B CA55 CA5B CA69 CA73 CA75 CA7F CA8D CA93 CA9D CA9F CAB5 CABB CAC3 CAC9 CAD9 CAE5 CAED CB03 CB05 CB09 CB17 CB29 CB35 CB3B CB53 CB59 CB63 CB65 CB71 CB87 CB99 CB9F CBB3 CBB9 CBC3 CBD1 CBD5 CBD7 CBDD CBE9 CBFF CC0D CC19 CC1D CC23 CC2B CC41 CC43 CC4D CC59 CC61 CC89 CC8B CC91 CC9B CCA3 CCA7 CCD1 CCE5 CCE9 CD09 CD15 CD1F CD25 CD31 CD3D CD3F CD49 CD51 CD57 CD5B CD63 CD67 CD81 CD93 CD97 CD9F CDBB CDC1 CDD3 CDD9 CDE5 CDE7 CDF1 CDF7 CDFD CE0B CE15 CE21 CE2F CE47 CE4D CE51 CE65 CE7B CE7D CE8F CE93 CE99 CEA5 CEA7 CEB7 CEC9 CED7 CEDD CEE3 CEE7 CEED CEF5 CF07 CF0B CF19 CF37 CF3B CF4D CF55 CF5F CF61 CF65 CF6D CF79 CF7D CF89 CF9B CF9D CFA9 CFB3 CFB5 CFC5 CFCD CFD1 CFEF CFF1 CFF7 D013 D015 D01F D021 D033 D03D D04B D04F D069 D06F D081 D085 D099 D09F D0A3 D0AB D0BD D0C1 D0CD D0E7 D0FF D103 D117 D12D D12F D141 D157 D159 D15D D169 D16B D171 D177 D17D D181 D187 D195 D199 D1B1 D1BD D1C3 D1D5 D1D7 D1E3 D1FF D20D D211 D217 D21F D235 D23B D247 D259 D261 D265 D279 D27F D283 D289 D28B D29D D2A3 D2A7 D2B3 D2BF D2C7 D2E3 D2E9 D2F1 D2FB D2FD D315 D321 D32B D343 D34B D355 D369 D375 D37B D387 D393 D397 D3A5 D3B1 D3C9 D3EB D3FD D405 D40F D415 D427 D42F D433 D43B D44B D459 D45F D463 D469 D481 D483 D489 D48D D493 D495 D4A5 D4AB D4B1 D4C5 D4DD D4E1 D4E3 D4E7 D4F5 D4F9 D50B D50D D513 D51F D523 D531 D535 D537 D549 D559 D55F D565 D567 D577 D58B D591 D597 D5B5 D5B9 D5C1 D5C7 D5DF D5EF D5F5 D5FB D603 D60F D62D D631 D643 D655 D65D D661 D67B D685 D687 D69D D6A5 D6AF D6BD D6C3 D6C7 D6D9 D6E1 D6ED D709 D70B D711 D715 D721 D727 D73F D745 D74D D757 D76B D77B D783 D7A1 D7A7 D7AD D7B1 D7B3 D7BD D7CB D7D1 D7DB D7FB D811 D823 D825 D829 D82B D82F D837 D84D D855 D867 D873 D88F D891 D8A1 D8AD D8BF D8CD D8D7 D8E9 D8F5 D8FB D91B D925 D933 D939 D943 D945 D94F D951 D957 D96D D96F D973 D979 D981 D98B D991 D99F D9A5 D9A9 D9B5 D9D3 D9EB D9F1 D9F7 D9FF DA05 DA09 DA0B DA0F DA15 DA1D DA23 DA29 DA3F DA51 DA59 DA5D DA5F DA71 DA77 DA7B DA7D DA8D DA9F DAB3 DABD DAC3 DAC9 DAE7 DAE9 DAF5 DB11 DB17 DB1D DB23 DB25 DB31 DB3B DB43 DB55 DB67 DB6B DB73 DB85 DB8F DB91 DBAD DBAF DBB9 DBC7 DBCB DBCD DBEB DBF7 DC0D DC27 DC31 DC39 DC3F DC49 DC51 DC61 DC6F DC75 DC7B DC85 DC93 DC99 DC9D DC9F DCA9 DCB5 DCB7 DCBD DCC7 DCCF DCD3 DCD5 DCDF DCF9 DD0F DD15 DD17 DD23 DD35 DD39 DD53 DD57 DD5F DD69 DD6F DD7D DD87 DD89 DD9B DDA1 DDAB DDBF DDC5 DDCB DDCF DDE7 DDE9 DDED DDF5 DDFB DE0B DE19 DE29 DE3B DE3D DE41 DE4D DE4F DE59 DE5B DE61 DE6D DE77 DE7D DE83 DE97 DE9D DEA1 DEA7 DECD DED1 DED7 DEE3 DEF1 DEF5 DF01 DF09 DF13 DF1F DF2B DF33 DF37 DF3D DF4B DF55 DF5B DF67 DF69 DF73 DF85 DF87 DF99 DFA3 DFAB DFB5 DFB7 DFC3 DFC7 DFD5 DFF1 DFF3 E003 E005 E017 E01D E027 E02D E035 E045 E053 E071 E07B E08F E095 E09F E0B7 E0B9 E0D5 E0D7 E0E3 E0F3 E0F9 E101 E125 E129 E131 E135 E143 E14F E159 E161 E16D E171 E177 E17F E183 E189 E197 E1AD E1B5 E1BB E1BF E1C1 E1CB E1D1 E1E5 E1EF E1F7 E1FD E203 E219 E22B E22D E23D E243 E257 E25B E275 E279 E287 E29D E2AB E2AF E2BB E2C1 E2C9 E2CD E2D3 E2D9 E2F3 E2FD E2FF E311 E323 E327 E329 E339 E33B E34D E351 E357 E35F E363 E369 E375 E377 E37D E383 E39F E3C5 E3C9 E3D1 E3E1 E3FB E3FF E401 E40B E417 E419 E423 E42B E431 E43B E447 E449 E453 E455 E46D E471 E48F E4A9 E4AF E4B5 E4C7 E4CD E4D3 E4E9 E4EB E4F5 E507 E521 E525 E537 E53F E545 E54B E557 E567 E56D E575 E585 E58B E593 E5A3 E5A5 E5CF E609 E611 E615 E61B E61D E621 E629 E639 E63F E653 E657 E663 E66F E675 E681 E683 E68D E68F E695 E6AB E6AD E6B7 E6BD E6C5 E6CB E6D5 E6E3 E6E9 E6EF E6F3 E705 E70D E717 E71F E72F E73D E747 E749 E753 E755 E761 E767 E76B E77F E789 E791 E7C5 E7CD E7D7 E7DD E7DF E7E9 E7F1 E7FB E801 E807 E80F E819 E81B E831 E833 E837 E83D E84B E84F E851 E869 E875 E879 E893 E8A5 E8A9 E8AF E8BD E8DB E8E1 E8E5 E8EB E8ED E903 E90B E90F E915 E917 E92D E933 E93B E94B E951 E95F E963 E969 E97B E983 E98F E995 E9A1 E9B9 E9D7 E9E7 E9EF EA11 EA19 EA2F EA35 EA43 EA4D EA5F EA6D EA71 EA7D EA85 EA89 EAAD EAB3 EAB9 EABB EAC5 EAC7 EACB EADF EAE5 EAEB EAF5 EB01 EB07 EB09 EB31 EB39 EB3F EB5B EB61 EB63 EB6F EB81 EB85 EB9D EBAB EBB1 EBB7 EBC1 EBD5 EBDF EBED EBFD EC0B EC1B EC21 EC29 EC4D EC51 EC5D EC69 EC6F EC7B ECAD ECB9 ECBF ECC3 ECC9 ECCF ECD7 ECDD ECE7 ECE9 ECF3 ECF5 ED07 ED11 ED1F ED2F ED37 ED3D ED41 ED55 ED59 ED5B ED65 ED6B ED79 ED8B ED95 EDBB EDC5 EDD7 EDD9 EDE3 EDE5 EDF1 EDF5 EDF7 EDFB EE09 EE0F EE19 EE21 EE49 EE4F EE63 EE67 EE73 EE7B EE81 EEA3 EEAB EEC1 EEC9 EED5 EEDF EEE1 EEF1 EF1B EF27 EF2F EF45 EF4D EF63 EF6B EF71 EF93 EF95 EF9B EF9F EFAD EFB3 EFC3 EFC5 EFDB EFE1 EFE9 F001 F017 F01D F01F F02B F02F F035 F043 F047 F04F F067 F06B F071 F077 F079 F08F F0A3 F0A9 F0AD F0BB F0BF F0C5 F0CB F0D3 F0D9 F0E3 F0E9 F0F1 F0F7 F107 F115 F11B F121 F137 F13D F155 F175 F17B F18D F193 F1A5 F1AF F1B7 F1D5 F1E7 F1ED F1FD F209 F20F F21B F21D F223 F227 F233 F23B F241 F257 F25F F265 F269 F277 F281 F293 F2A7 F2B1 F2B3 F2B9 F2BD F2BF F2DB F2ED F2EF F2F9 F2FF F305 F30B F319 F341 F359 F35B F35F F367 F373 F377 F38B F38F F3AF F3C1 F3D1 F3D7 F3FB F403 F409 F40D F413 F421 F425 F42B F445 F44B F455 F463 F475 F47F F485 F48B F499 F4A3 F4A9 F4AF F4BD F4C3 F4DB F4DF F4ED F503 F50B F517 F521 F529 F535 F547 F551 F563 F56B F583 F58D F595 F599 F5B1 F5B7 F5C9 F5CF F5D1 F5DB F5F9 F5FB F605 F607 F60B F60D F635 F637 F653 F65B F661 F667 F679 F67F F689 F697 F69B F6AD F6CB F6DD F6DF F6EB F709 F70F F72D F731 F743 F74F F751 F755 F763 F769 F773 F779 F781 F787 F791 F79D F79F F7A5 F7B1 F7BB F7BD F7CF F7D3 F7E7 F7EB F7F1 F7FF F805 F80B F821 F827 F82D F835 F847 F859 F863 F865 F86F F871 F877 F87B F881 F88D F89F F8A1 F8AB F8B3 F8B7 F8C9 F8CB F8D1 F8D7 F8DD F8E7 F8EF F8F9 F8FF F911 F91D F925 F931 F937 F93B F941 F94F F95F F961 F96D F971 F977 F99D F9A3 F9A9 F9B9 F9CD F9E9 F9FD FA07 FA0D FA13 FA21 FA25 FA3F FA43 FA51 FA5B FA6D FA7B FA97 FA99 FA9D FAAB FABB FABD FAD9 FADF FAE7 FAED FB0F FB17 FB1B FB2D FB2F FB3F FB47 FB4D FB75 FB7D FB8F FB93 FBB1 FBB7 FBC3 FBC5 FBE3 FBE9 FBF3 FC01 FC29 FC37 FC41 FC43 FC4F FC59 FC61 FC65 FC6D FC73 FC79 FC95 FC97 FC9B FCA7 FCB5 FCC5 FCCD FCEB FCFB FD0D FD0F FD19 FD2B FD31 FD51 FD55 FD67 FD6D FD6F FD7B FD85 FD97 FD99 FD9F FDA9 FDB7 FDC9 FDE5 FDEB FDF3 FE03 FE05 FE09 FE1D FE27 FE2F FE41 FE4B FE4D FE57 FE5F FE63 FE69 FE75 FE7B FE8F FE93 FE95 FE9B FE9F FEB3 FEBD FED7 FEE9 FEF3 FEF5 FF07 FF0D FF1D FF2B FF2F FF49 FF4D FF5B FF65 FF71 FF7F FF85 FF8B FF8F FF9D FFA7 FFA9 FFC7 FFD9 FFEF FFF1 +Execution halted after 2743229 cycles. +[exit 0] diff --git a/Tests/expected/16x16Life.out b/Tests/expected/16x16Life.out index 9d9c224..724d752 100644 --- a/Tests/expected/16x16Life.out +++ b/Tests/expected/16x16Life.out @@ -223,3 +223,4 @@ Execution stopped after 3000000 cycles. (cycle limit reached) +[exit 0] diff --git a/Tests/expected/16x16LifeModern.out b/Tests/expected/16x16LifeModern.out new file mode 100644 index 0000000..724d752 --- /dev/null +++ b/Tests/expected/16x16LifeModern.out @@ -0,0 +1,226 @@ + # + # + ### + + + + + + + + + + + + + + + # # + ## + # + + + + + + + + + + + + + + # + # # + ## + + + + + + + + + + + + + + # + ## + ## + + + + + + + + + + + + + + # + # + ### + + + + + + + + + + + + + + + # # + ## + # + + + + + + + + + + + + + + # + # # + ## + + + + + + + + + + + + + + # + ## + ## + + + + + + + + + + + + + + # + # + ### + + + + + + + + + + + + + + + # # + ## + # + + + + + + + + + + + + + + # + # # + ## + + + + + + + + + + + + + + # + ## + ## + + + + + + + + + + + + + + # + # + ### + + + + + + + + + + + + + + + # # + ## + # + + + + + + + + + +Execution stopped after 3000000 cycles. (cycle limit reached) +[exit 0] diff --git a/Tests/expected/32bitFibonacci.out b/Tests/expected/32bitFibonacci.out index 1bad25d..6665a29 100644 --- a/Tests/expected/32bitFibonacci.out +++ b/Tests/expected/32bitFibonacci.out @@ -1,2 +1,3 @@ 00000000 00000001 00000001 00000002 00000003 00000005 00000008 0000000D 00000015 00000022 00000037 00000059 00000090 000000E9 00000179 00000262 000003DB 0000063D 00000A18 00001055 00001A6D 00002AC2 0000452F 00006FF1 0000B520 00012511 0001DA31 0002FF42 0004D973 0007D8B5 000CB228 00148ADD 00213D05 0035C7E2 005704E7 008CCCC9 00E3D1B0 01709E79 02547029 03C50EA2 06197ECB 09DE8D6D 0FF80C38 19D699A5 29CEA5DD 43A53F82 6D73E55F Execution halted after 10610 cycles. +[exit 0] diff --git a/Tests/expected/8bitFibonacci.out b/Tests/expected/8bitFibonacci.out index 6901f93..84d38e4 100644 --- a/Tests/expected/8bitFibonacci.out +++ b/Tests/expected/8bitFibonacci.out @@ -1,2 +1,3 @@ 0 1 1 2 3 5 8 13 21 34 55 89 144 233 Execution halted after 1506 cycles. +[exit 0] diff --git a/Tests/expected/8bitSieve.out b/Tests/expected/8bitSieve.out index bc87b96..b513462 100644 --- a/Tests/expected/8bitSieve.out +++ b/Tests/expected/8bitSieve.out @@ -1,2 +1,3 @@ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 Execution halted after 54061 cycles. +[exit 0] diff --git a/Tests/expected/dataPointerTest.out b/Tests/expected/dataPointerTest.out index a8dc798..43daeb6 100644 --- a/Tests/expected/dataPointerTest.out +++ b/Tests/expected/dataPointerTest.out @@ -1,2 +1,3 @@ ABCZ Execution halted after 21 cycles. +[exit 0] diff --git a/Tests/expected/deviceTest.out b/Tests/expected/deviceTest.out new file mode 100644 index 0000000..22a0cd1 --- /dev/null +++ b/Tests/expected/deviceTest.out @@ -0,0 +1,5 @@ +O +K +! +Execution halted after 19 cycles. +[exit 0] diff --git a/Tests/expected/dispatchTest.out b/Tests/expected/dispatchTest.out new file mode 100644 index 0000000..07f62ec --- /dev/null +++ b/Tests/expected/dispatchTest.out @@ -0,0 +1,6 @@ +one +two +three +done +Execution halted after 126 cycles. +[exit 0] diff --git a/Tests/expected/faultResumeTest.out b/Tests/expected/faultResumeTest.out new file mode 100644 index 0000000..6f47687 --- /dev/null +++ b/Tests/expected/faultResumeTest.out @@ -0,0 +1,4 @@ +O +K +Execution halted after 17 cycles. +[exit 0] diff --git a/Tests/expected/faultTest.out b/Tests/expected/faultTest.out new file mode 100644 index 0000000..4290ce5 --- /dev/null +++ b/Tests/expected/faultTest.out @@ -0,0 +1,3 @@ +Fault: 0xFE at Program Address 0x0002 is not an instruction. +Execution halted after 2 cycles. +[exit 1] diff --git a/Tests/expected/hello.out b/Tests/expected/hello.out index db7a106..cb4c900 100644 --- a/Tests/expected/hello.out +++ b/Tests/expected/hello.out @@ -1,2 +1,3 @@ Hello, World! Execution halted after 70 cycles. +[exit 0] diff --git a/Tests/expected/inputTest.out b/Tests/expected/inputTest.out index a373732..dfe6cfd 100644 --- a/Tests/expected/inputTest.out +++ b/Tests/expected/inputTest.out @@ -1,3 +1,4 @@ Input Test: Will echo anything you put in. Hello SplitBit Execution halted after 406 cycles. +[exit 0] diff --git a/Tests/expected/inputTestOld.out b/Tests/expected/inputTestOld.out index a373732..dfe6cfd 100644 --- a/Tests/expected/inputTestOld.out +++ b/Tests/expected/inputTestOld.out @@ -1,3 +1,4 @@ Input Test: Will echo anything you put in. Hello SplitBit Execution halted after 406 cycles. +[exit 0] diff --git a/Tests/expected/int16print.out b/Tests/expected/int16print.out index 7c83316..f3fbc4a 100644 --- a/Tests/expected/int16print.out +++ b/Tests/expected/int16print.out @@ -1,3 +1,4 @@ 00 00 00 00 01 1 Execution halted after 4707 cycles. +[exit 0] diff --git a/Tests/expected/interruptExample.out b/Tests/expected/interruptExample.out new file mode 100644 index 0000000..de2fd9e --- /dev/null +++ b/Tests/expected/interruptExample.out @@ -0,0 +1,5 @@ +ready +trap +device +Execution halted after 105 cycles. +[exit 0] diff --git a/Tests/expected/interruptFlagTest.out b/Tests/expected/interruptFlagTest.out new file mode 100644 index 0000000..c83d9fd --- /dev/null +++ b/Tests/expected/interruptFlagTest.out @@ -0,0 +1,3 @@ +OKC +Execution halted after 19 cycles. +[exit 0] diff --git a/Tests/expected/maskTest.out b/Tests/expected/maskTest.out new file mode 100644 index 0000000..33bee68 --- /dev/null +++ b/Tests/expected/maskTest.out @@ -0,0 +1,5 @@ +Fault: The device on port 16 interrupted at Program Address 0x0019, and hardware vector 16 has no handler installed. +M +S +Execution halted after 16 cycles. +[exit 1] diff --git a/Tests/expected/mathTest.out b/Tests/expected/mathTest.out index 85803a1..0a3e7bb 100644 --- a/Tests/expected/mathTest.out +++ b/Tests/expected/mathTest.out @@ -1,2 +1,3 @@ 0000 0032 Execution halted after 1134 cycles. +[exit 0] diff --git a/Tests/expected/moveQTest.out b/Tests/expected/moveQTest.out new file mode 100644 index 0000000..944b1a5 --- /dev/null +++ b/Tests/expected/moveQTest.out @@ -0,0 +1,3 @@ +AAA +Execution halted after 24 cycles. +[exit 0] diff --git a/Tests/expected/paddingTest.out b/Tests/expected/paddingTest.out new file mode 100644 index 0000000..80bb92d --- /dev/null +++ b/Tests/expected/paddingTest.out @@ -0,0 +1,3 @@ +00 31 +Execution halted after 78 cycles. +[exit 0] diff --git a/Tests/expected/pointerTableTest.out b/Tests/expected/pointerTableTest.out index fca296e..aa0fe31 100644 --- a/Tests/expected/pointerTableTest.out +++ b/Tests/expected/pointerTableTest.out @@ -2,3 +2,4 @@ Hello World H Execution halted after 79 cycles. +[exit 0] diff --git a/Tests/expected/printHello.out b/Tests/expected/printHello.out index 9dd3378..0781814 100644 --- a/Tests/expected/printHello.out +++ b/Tests/expected/printHello.out @@ -1,3 +1,4 @@ Hello, World! 42 is the great answer. Execution halted after 295 cycles. +[exit 0] diff --git a/Tests/expected/printTest.out b/Tests/expected/printTest.out index b96d922..b6c53f5 100644 --- a/Tests/expected/printTest.out +++ b/Tests/expected/printTest.out @@ -10,3 +10,4 @@ Testing printByteHex... Testing complete! Execution halted after 71185 cycles. +[exit 0] diff --git a/Tests/expected/replCalculator.out b/Tests/expected/replCalculator.out index 78bcde3..2f61824 100644 --- a/Tests/expected/replCalculator.out +++ b/Tests/expected/replCalculator.out @@ -14,3 +14,4 @@ SplitBit calculator (+ - * & | ^), Q quits. > 18 > Goodbye!Execution halted after 2960 cycles. +[exit 0] diff --git a/Tests/expected/stackPointerTest.out b/Tests/expected/stackPointerTest.out new file mode 100644 index 0000000..71b2916 --- /dev/null +++ b/Tests/expected/stackPointerTest.out @@ -0,0 +1,3 @@ +OK +Execution halted after 14 cycles. +[exit 0] diff --git a/Tests/expected/staticTableTest.out b/Tests/expected/staticTableTest.out index db8c57f..f436217 100644 --- a/Tests/expected/staticTableTest.out +++ b/Tests/expected/staticTableTest.out @@ -3,3 +3,4 @@ two three AFTER Execution halted after 122 cycles. +[exit 0] diff --git a/Tests/expected/swiFaultTest.out b/Tests/expected/swiFaultTest.out new file mode 100644 index 0000000..79f7f77 --- /dev/null +++ b/Tests/expected/swiFaultTest.out @@ -0,0 +1,4 @@ +Fault: Software vector 20, dispatched from Program Address 0x0008, has no handler installed. +O +Execution halted after 5 cycles. +[exit 1] diff --git a/Tests/expected/twoPointerCopy.out b/Tests/expected/twoPointerCopy.out index 93d0bd6..fae471e 100644 --- a/Tests/expected/twoPointerCopy.out +++ b/Tests/expected/twoPointerCopy.out @@ -1,2 +1,3 @@ Two pointers, no stack shenanigans. Execution halted after 395 cycles. +[exit 0] diff --git a/Tests/expected/vectorTest.out b/Tests/expected/vectorTest.out new file mode 100644 index 0000000..427b2f3 --- /dev/null +++ b/Tests/expected/vectorTest.out @@ -0,0 +1,5 @@ +OK! +good +AFTER +Execution halted after 77 cycles. +[exit 0] diff --git a/Tests/manifest b/Tests/manifest index e644829..a06edbd 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -29,6 +29,9 @@ printHello | printHello.asm | run | - 32bitFibonacci | Fibonacci/32bitFibonacci.asm | run | - | - 8bitSieve | primeSieve/8bitSieve.asm | run | - | - 16bitSegmentedSieve | primeSieve/16bitSegmentedSieve.asm | run | - | - +# The four pointer rewrite. It emits exactly the same primes as the line above, which +# is the whole point of keeping both: the pair is a direct before and after. +16bitSegmentedSieveModern | primeSieve/16bitSegmentedSieveModern.asm | run | - | - mathTest | testPrograms/mathTest.asm | run | - | - printTest | testPrograms/printTest.asm | run | - | - int16print | Libraries/int16print.asm | run | - | - @@ -38,6 +41,47 @@ dataPointerTest | testPrograms/dataPointerTest.asm | run | - twoPointerCopy | testPrograms/twoPointerCopy.asm | run | - | - pointerTableTest | testPrograms/pointerTableTest.asm | run | - | - staticTableTest | testPrograms/staticTableTest.asm | run | - | - +dispatchTest | testPrograms/dispatchTest.asm | run | - | - + +# ---- Moving an ALU result back into an operand register ---- +moveQTest | testPrograms/moveQTest.asm | run | - | - + +# ---- Moving the cursor along ---- +paddingTest | testPrograms/paddingTest.asm | run | - | - + +# ---- Finding the Stack ---- +stackPointerTest | testPrograms/stackPointerTest.asm | run | - | - + +# ---- The Interrupt Flag ---- +# Nothing reads the flag yet. This checks that setting and clearing it leaves +# the registers and the Carry Flag it shares a byte with untouched. +interruptFlagTest | testPrograms/interruptFlagTest.asm | run | - | - + +# ---- Vectors laid down by the assembler ---- +# These are the interrupt path end to end. Until #Vectors existed, none of them could +# be written as a source file at all, because nothing could install a handler. +vectorTest | testPrograms/vectorTest.asm | run | - | - +deviceTest | testPrograms/deviceTest.asm | run | - | - +faultResumeTest | testPrograms/faultResumeTest.asm | run | - | - +# The worked example out of the Assembler Manual, so the manual cannot go stale. +interruptExample | testPrograms/interruptExample.asm | run | - | - + +# ---- Holding a device off, and then letting it through ---- +# Faults on purpose. The fault is the proof that the line was answered, and where it +# lands in the output is the proof of when. +maskTest | testPrograms/maskTest.asm | run | - | - + +# ---- Dispatching through a vector with nothing in it ---- +# Also meant to fault. Until the assembler can lay a vector table down, every entry +# reads as zero, so this is the only half of the interrupt path a source file can +# reach on its own. The round trip through a handler is covered by hand built +# binaries until #Vectors arrives. +swiFaultTest | testPrograms/swiFaultTest.asm | run | - | - + +# ---- Meeting a byte that is not an instruction ---- +# This one is meant to fault. It checks the CPU stops, says what it found and +# where, and exits non zero, rather than stepping over it and carrying on. +faultTest | testPrograms/faultTest.asm | run | - | - # ---- Programs driven by console input ---- inputTest | inputTest.asm | run | inputTest.in | - @@ -48,6 +92,12 @@ replCalculator | replCalculator.asm | run | replCalcu # 3,000,000 cycles is about fourteen generations of the glider, which puts # evolveBoard and its pointer juggling through its paces many times over. 16x16Life | gameOfLife/16x16Life.asm | run | - | 3000000 +# The four pointer rewrite, on the same budget so the two can be compared directly. +# Note that this cannot show a speed difference: frameDelay is 255 by 255 and swamps +# the simulation, so both versions render the same fourteen generations and produce +# identical bytes. What it checks is that the rewrite still evolves the board the same +# way, which is what a regression test is for. +16x16LifeModern | gameOfLife/16x16LifeModern.asm | run | - | 3000000 # ---- Libraries: no entry point, so only check that they assemble ---- lib-int8 | Libraries/int8.asm | assemble | - | - @@ -55,6 +105,18 @@ lib-int16 | Libraries/int16.asm | assemble | - lib-int32 | Libraries/int32.asm | assemble | - | - lib-math | Libraries/math.asm | assemble | - | - +# ---- Deliberately broken, to check the assembler still diagnoses them ---- +# These are not programs anyone meant to run. Each one contains a single mistake +# that the assembler used to accept quietly, and is here so that it cannot start +# being accepted quietly again. +diagDuplicateLabel | testPrograms/diagnostics/duplicateLabel.asm | xfail | - | - +diagBareInclude | testPrograms/diagnostics/bareInclude.asm | xfail | - | - +diagUnknownVector | testPrograms/diagnostics/unknownVector.asm | xfail | - | - +diagDuplicateVector | testPrograms/diagnostics/duplicateVector.asm | xfail | - | - +diagBareSWI | testPrograms/diagnostics/bareSWI.asm | xfail | - | - +diagAlignOutside | testPrograms/diagnostics/alignOutside.asm | xfail | - | - +diagBareAlign | testPrograms/diagnostics/bareAlign.asm | xfail | - | - + # ---- Known breakages, recorded rather than ignored ---- # print.asm branches to 'start', which only the including program defines. lib-print | Libraries/print.asm | xfail | - | - diff --git a/Tests/run.sh b/Tests/run.sh index 4f8f37f..d5c2b7f 100755 --- a/Tests/run.sh +++ b/Tests/run.sh @@ -166,11 +166,18 @@ while IFS='|' read -r name src mode stdin limit; do # bounds them by cycle count rather than by wall clock. EMUARGS=(--fast) [ "$limit" != "-" ] && EMUARGS+=(--cycles "$limit") - if ! timeout "$RUN_TIMEOUT" "$EMULATOR" "${EMUARGS[@]}" "$BIN" <"$IN" >"$OUT" 2>&1; then + timeout "$RUN_TIMEOUT" "$EMULATOR" "${EMUARGS[@]}" "$BIN" <"$IN" >"$OUT" 2>&1 + STATUS=$? + if [ "$STATUS" -eq 124 ]; then FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name") report "FAIL" "$name" "did not finish within ${RUN_TIMEOUT}s" continue fi + # What a program exits with is part of what it does, so it is recorded + # with the output rather than thrown away. A program that faults is + # supposed to exit non zero, and that should be just as pinned down as + # what it printed. + printf '[exit %d]\n' "$STATUS" >> "$OUT" check "$name" "$OUT" ;; *) diff --git a/makefile b/makefile index d6b2ed7..a565e66 100644 --- a/makefile +++ b/makefile @@ -11,6 +11,12 @@ PREFIX ?= /usr/local # editing a header rebuilds everything that includes it. DEPFLAGS = -MMD -MP +# Both tools use POSIX interfaces that ISO C does not have: realpath, clock_gettime, +# strdup, dirname and getopt. Asking for POSIX.1-2008 by name means the build does +# not rely on the compiler happening to default to a mode where those are visible, +# and it survives someone overriding CFLAGS, which is why it is kept separate. +POSIXFLAGS = -D_POSIX_C_SOURCE=200809L + # Directories SRC_DIR_EMU = Source/Emulator SRC_DIR_ASM = Source/Assembler @@ -41,12 +47,12 @@ $(ASM_TARGET): $(ASM_OBJS) # Compile emulator source files to object files $(OBJ_DIR)/%.o: $(SRC_DIR_EMU)/%.c mkdir -p $(OBJ_DIR) - $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(POSIXFLAGS) $(DEPFLAGS) -c $< -o $@ # Compile assembler source files to object files $(OBJ_DIR)/%.o: $(SRC_DIR_ASM)/%.c mkdir -p $(OBJ_DIR) - $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(POSIXFLAGS) $(DEPFLAGS) -c $< -o $@ # Pull in the header dependencies written out by the compiler above. -include $(EMU_OBJS:.o=.d) $(ASM_OBJS:.o=.d) @@ -55,6 +61,28 @@ $(OBJ_DIR)/%.o: $(SRC_DIR_ASM)/%.c test: $(EMU_TARGET) $(ASM_TARGET) @./Tests/run.sh +# Rebuild both tools with the address and undefined behaviour sanitizers and run +# the test suite under them. Slower than 'make test', and worth running before a +# release or after anything that touches memory handling. +# +# The sanitizers catch reads and writes off the end of an array, use after free, +# leaks, and undefined arithmetic. They also fill fresh allocations with a junk +# pattern, which is what turns a read of uninitialised memory from something that +# quietly works into something the tests notice. +# +# If the suite fails, the sanitizer binaries are deliberately left in place so +# that the failing case can be run again by hand. 'make' puts the normal ones back. +SANITIZE_FLAGS = -Wall -Wextra -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer + +sanitize: + @$(MAKE) --no-print-directory clean + @$(MAKE) --no-print-directory CFLAGS="$(SANITIZE_FLAGS)" + @echo "Running the test suite under AddressSanitizer and UndefinedBehaviorSanitizer." + @./Tests/run.sh + @$(MAKE) --no-print-directory clean + @$(MAKE) --no-print-directory + @echo "Sanitizer run finished cleanly. Normal binaries rebuilt." + # Record the current output of every test as the expected result. # Only do this when the current output is known to be correct. bless: $(EMU_TARGET) $(ASM_TARGET) @@ -72,4 +100,4 @@ install: $(EMU_TARGET) $(ASM_TARGET) install -m 755 $^ "$(PREFIX)/bin/" # Phony targets -.PHONY: all clean install test bless +.PHONY: all clean install test bless sanitize