Files
SplitBit-Emulator/Programs/testPrograms/controllerWrite.asm
T
AnachronautandClaude Opus 5 0852666e73 Mirror the source tree onto the system disk
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
2026-08-29 08:45:46 -04:00

128 lines
2.4 KiB
NASM

; Writes Program Memory through the controller, and gets turned away from what it may
; not touch.
;
; Writing code is the thing SplitBit's instruction set deliberately cannot do. The
; controller can, which is what makes a loader possible. The marker below is written and
; then read back through the controller, so the change is observed rather than assumed.
;
; The two refusals are the other half. Bank 2 is the bank table and is read only, so
; writing to it is a GuardViolation. Bank 200 has nothing registered in it, so naming it
; is a BankFault. Both handlers step the saved address past the instruction that was
; refused, the way any handler carrying on past a fault has to.
;
; Correct output is:
; AA BB the marker after being written through the controller
; readonly
; nobank
; done
#Include print.asm
#Program
start:
; Aim both ends of the controller at the marker.
SETD.0 Marker
PSHD.0
POPA
POPB
PSHA
PSHB
RSTA
OUTA 0xE0 ; SourceBank = 0
OUTA 0xE3 ; DestBank = 0
POPB
OUTB 0xE1 ; SourceHigh
OUTB 0xE4 ; DestHigh
POPA
OUTA 0xE2 ; SourceLow
OUTA 0xE5 ; DestLow
; Write two bytes over the marker. This is Program Memory being changed at run time.
INIA 0xAA
OUTA 0xE9
INIA 0xBB
OUTA 0xE9
; Read them back the same way, to prove they landed.
CALL readAndPrint
CALL readAndPrint
CALL lineFeed
; Bank 2 is the bank table, and it is read only.
INIA 0d2
OUTA 0xE3
RSTA
OUTA 0xE4
OUTA 0xE5
INIA 0d1
OUTA 0xE9 ; Refused: GuardViolation.
; Bank 200 has nothing in it.
INIA 0d200
OUTA 0xE3
INIA 0d1
OUTA 0xE9 ; Refused: BankFault.
SETD.0 Done
CALL printString
CALL lineFeed
HALT
readAndPrint:
INA 0xE9
CALL printByteHex
CALL blankSpace
RET
readOnlyHandler:
SETD.0 ReadOnly
CALL printString
CALL lineFeed
BRI stepPastRefusal
noBankHandler:
SETD.0 NoBank
CALL printString
CALL lineFeed
BRI stepPastRefusal
; Steps the saved address past the refused instruction. OUT is two bytes, an opcode and
; a port, so two is what it takes.
stepPastRefusal:
MVSD.0
DPUP.0 0d14
LDA.0
CCF
INIB 0d2
ADD
MVQA
STA.0
BRC carried
RETI
carried:
DECD.0
LDA.0
INCA
STA.0
RETI
; Never executed.
Marker:
0x00 0x00
#Data
ReadOnly:
"readonly"
NoBank:
"nobank"
Done:
"done"
#Vectors
GuardViolation readOnlyHandler
BankFault noBankHandler