Files
Anachronaut 2b079324ae Add SplitLint, and let it be told when something is deliberate
SplitLint reports valid assembly that has a shorter direct expression:
zero loads that could be RSTA or RSTB, Q moved through the stack where MVQA
would do, self-cancelling push and pop pairs, assignments overwritten
before use, unreachable fallthrough, one-byte pointer moves that could be
INCD or DECD, a branch to the label directly below it, a SETD reloading an
address the pointer already holds, and branches whose carry is known.

Its model is deliberately local and conservative: every label and every
directive forgets all known state, so a claim only ever lives inside a
straight-line region. It knows the calling convention - CALL forgets DP3
and keeps the rest, RCAL and SWI forget everything - and it shares
assembly.o with the assembler, so an added opcode cannot leave it holding a
private copy of the instruction table.

260 warnings across the corpus, of which three were wrong in the way that
matters: branchTest.asm and interruptFlagTest.asm exist to check that a
branch whose carry is known behaves correctly, so a diagnostic saying the
outcome is known is exactly right and exactly unwanted.

A line whose comment says "splitlint: <reason>" is now not reported on. THE
REASON IS REQUIRED and a bare marker is refused, because a suppression
nobody explained outlives whatever made it necessary. Suppressed warnings
are not counted, so --fatal-warnings does not fail on one, and the number
of them is printed at the end so the claim is visible rather than silent.

Tests/lint.sh checked a TOTAL: twenty three warnings expected, twenty three
found. That number stays right while the thing behind it goes wrong - a
rule that stopped firing while another fired twice would pass, and so would
a rule reporting at the wrong line. It now checks which warning came out
and at which line, that nothing else came out, and that the four lines
meant to stay quiet did. Confirmed by breaking one rule's message and
watching it name that rule: the old assertion passed the same sabotage,
because the warning still fired and the count never moved.

Written with the user while I was away; my part is the suppression
mechanism, the harness rewrite, and the three marks in the test programs.
2026-08-26 17:23:17 -04:00

118 lines
2.4 KiB
NASM

; The negative sense branches.
;
; A quarter of every conditional branch in the corpus used to be a branch over an
; unconditional one, because only "branch if zero" existed. Each of those needed a label
; invented purely to be jumped past, which is a cost in names as much as in bytes.
;
; These test the register directly, the way the positive ones do. A branch on this machine
; never depends on which instruction ran last, except for the two that read the Carry Flag
; and say so in their names.
;
; Each case is checked both ways round, so a branch that always went the same way would
; be caught rather than looking correct half the time.
;
; Correct output is:
; QAB C qab c
; 9876543210
#Include print.asm
#Program
start:
; ---- Each one taken when it should be. ----
RSTA
INIB 0d1
CCF
ADD ; Q is 1, so not zero.
BNQ qTaken
BRI wrong
qTaken:
INIA 0d81 ; 'Q'
OUTA 0x00
INIA 0d5
BNA aTaken
BRI wrong
aTaken:
INIA 0d65 ; 'A'
OUTA 0x00
INIB 0d5
BNB bTaken
BRI wrong
bTaken:
INIA 0d66 ; 'B'
OUTA 0x00
CCF
BNC cTaken ; splitlint: this test exists to check a branch whose carry is known
BRI wrong
cTaken:
CALL blankSpace
INIA 0d67 ; 'C'
OUTA 0x00
CALL blankSpace
; ---- And each one not taken when it should not be. ----
RSTA
RSTB
CCF
ADD ; Q is zero.
BNQ wrong
INIA 0d113 ; 'q'
OUTA 0x00
RSTA
BNA wrong
INIA 0d97 ; 'a'
OUTA 0x00
RSTB
BNB wrong
INIA 0d98 ; 'b'
OUTA 0x00
; Set the carry by overflowing, then check BNC does not take it.
INIA 0xFF
INIB 0x01
CCF
ADD
BNC wrong ; splitlint: the point is that a set carry does NOT take this
CALL blankSpace
INIA 0d99 ; 'c'
OUTA 0x00
CALL lineFeed
; ---- A countdown, which is what the missing sense was mostly wanted for. ----
; Before these existed this loop needed a label to jump over, and now it does not.
INIA 0d10
SETD.0 Count
STA.0
countLoop:
LDA.0
DECA ; Ten down to one becomes nine down to zero.
INIB 0d48 ; '0'
CCF
ADD
MVQA
OUTA 0x00
LDA.0
DECA
STA.0
BNA countLoop ; One instruction where it used to take two and a label.
CALL lineFeed
HALT
wrong:
SETD.0 Wrong
CALL printString
CALL lineFeed
HALT
#Data
Wrong:
"a branch went the wrong way"
Count:
0x00