A list of files in a makefile goes stale the moment somebody adds a program and forgets to name it, and what they forgot is invisible until they go looking for it on the machine. So SplitDisk gained a mirror command and the disk rule is one line: putting a file where the others live is now the whole of putting it on the disk. EVERY FILE GOES THROUGH put AND EVERY DIRECTORY THROUGH mkdir. That is the point of it - mirror adds a walk and no filesystem code at all, so anything the format refuses here it refuses everywhere, in the same words. What is new is the walk, and the walk is what the six checks in Tests/disk.sh are about: that it goes all the way down, that it leaves dotfiles and named directories behind, and that a name too long stops it. REFUSED RATHER THAN SKIPPED, because a disk quietly missing a file is the exact failure a mirror exists to prevent. Which meant four sources had to be renamed - a directory entry holds 22 characters and they were 23, 23, 24 and 29: 16bitSegmentedSieve.asm -> 16bitSieve.asm 16bitSegmentedSieveModern.asm -> 16bitSieveModern.asm consoleInterruptTest.asm -> consoleInterrupt.asm controllerWriteTest.asm -> controllerWrite.asm The test names in the manifest are unchanged, since those are identifiers and every recorded result is filed under them. Only where the source lives has moved. The entries are sorted before anything is written. readdir hands them back in whatever order the host filesystem feels like, and a disk image that comes out different from one run to the next is an image no test could compare against another. The disk grew from one megabyte to four and from 192 directory entries to 1,024. The sources are 2,850 blocks and the mirror filled the old directory on its first run, which is a thing that should not need thinking about again. The Tests fixture disk is deliberately NOT mirrored. It is a controlled fixture with known contents, and the shipped disk is the one meant to be useful; they want different things. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
242 lines
5.0 KiB
NASM
242 lines
5.0 KiB
NASM
; A segmented Sieve of Eratosthenes for the complete 16-bit address range.
|
|
;
|
|
; The sieve uses a 256-byte sliding window. Each entry in PrimeStates contains:
|
|
; prime, high byte of next multiple, low byte of next multiple
|
|
;
|
|
; Once a prime becomes active at p*p, adding an 8-bit prime to offsets in a
|
|
; 256-byte window must wrap exactly once before the next window. The wrapped
|
|
; low byte becomes that prime's starting offset in the following window.
|
|
;
|
|
; Output is hexadecimal (0002 through FFFD), separated by spaces.
|
|
|
|
#Include print.asm
|
|
|
|
#Program
|
|
|
|
start:
|
|
RSTA
|
|
SETD Page
|
|
STA
|
|
|
|
nextPage:
|
|
; Clear all 256 flags. A wrapping to zero terminates the loop.
|
|
SETD Segment
|
|
RSTA
|
|
RSTB
|
|
clearSegment:
|
|
STB
|
|
INCD
|
|
INCA
|
|
BRA segmentCleared
|
|
BRI clearSegment
|
|
|
|
segmentCleared:
|
|
; Zero and one are not prime.
|
|
SETD Page
|
|
LDA
|
|
BRA excludeZeroAndOne
|
|
BRI markSegment
|
|
excludeZeroAndOne:
|
|
SETD Segment
|
|
INIA 0x01
|
|
STA
|
|
INCD
|
|
STA
|
|
|
|
markSegment:
|
|
; Process the 54 primes not greater than sqrt(0xFFFF).
|
|
SETD PrimeStates
|
|
INIA 0d54
|
|
primeLoop:
|
|
CALL processPrime
|
|
DPUP 0d03
|
|
DECA
|
|
BRA scanSegment
|
|
BRI primeLoop
|
|
|
|
scanSegment:
|
|
; A is the low byte of the candidate and wraps after 0xFF.
|
|
SETD Segment
|
|
RSTA
|
|
scanLoop:
|
|
LDB
|
|
BRB emitPrime
|
|
scanNext:
|
|
INCD
|
|
INCA
|
|
BRA advancePage
|
|
BRI scanLoop
|
|
|
|
emitPrime:
|
|
CALL printCandidateHex
|
|
BRI scanNext
|
|
|
|
advancePage:
|
|
SETD Page
|
|
LDA
|
|
INCA
|
|
STA
|
|
BRA finished
|
|
BRI nextPage
|
|
|
|
finished:
|
|
CALL lineFeed
|
|
HALT
|
|
|
|
; DP points at a PrimeStates entry on entry and is preserved by CALL.
|
|
processPrime:
|
|
PSHD
|
|
INCD
|
|
LDA
|
|
SETD Page
|
|
LDB
|
|
XOR
|
|
BRQ primeIsActive
|
|
POPD
|
|
RET
|
|
|
|
primeIsActive:
|
|
; Recover and retain the state-entry pointer for the final update.
|
|
POPD
|
|
PSHD
|
|
|
|
; Load the prime into B and its current offset into A.
|
|
LDA
|
|
PSHA
|
|
DPUP 0d02
|
|
LDA
|
|
POPB
|
|
|
|
; Form Segment + offset. Segment is page-aligned in Data Memory.
|
|
SETD Segment
|
|
PSHB
|
|
PSHD
|
|
POPB
|
|
CCF
|
|
ADD
|
|
PSHQ
|
|
POPD
|
|
POPB
|
|
|
|
markPrimeLoop:
|
|
INIA 0x01
|
|
STA
|
|
|
|
; Add the prime to the low byte of DP using the stack as a 16-bit
|
|
; address adapter. Carry means that the next multiple is in the next page.
|
|
PSHD
|
|
POPA
|
|
CCF
|
|
ADD
|
|
PSHQ
|
|
POPD
|
|
BRC primeFinished
|
|
BRI markPrimeLoop
|
|
|
|
primeFinished:
|
|
; Q is the wrapped offset for the next page.
|
|
POPD
|
|
INCD
|
|
LDA
|
|
INCA
|
|
STA
|
|
INCD
|
|
STQ
|
|
RET
|
|
|
|
; A contains the candidate's low byte. Page contains its high byte.
|
|
printCandidateHex:
|
|
PSHA
|
|
SETD Page
|
|
LDA
|
|
CALL printByteHex
|
|
POPA
|
|
CALL printByteHex
|
|
CALL blankSpace
|
|
RET
|
|
|
|
#Data
|
|
|
|
; 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
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 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
|