Checkpoint.
This commit is contained in:
parent
e805911e18
commit
77202fb7f7
4 changed files with 179 additions and 10 deletions
15
STATUS.md
15
STATUS.md
|
|
@ -105,6 +105,21 @@ push/pop over a static stack, snprintf "%ld", and strcmp to verify
|
|||
the end-to-end composition under a realistic-ish workload — adds,
|
||||
subs, muls, divs, and 3-deep operand stacks all work.
|
||||
|
||||
**setjmp / longjmp** (smoke #88) now work end-to-end: setjmp saves
|
||||
SP / 24-bit ret addr / DP, longjmp restores them and returns the
|
||||
val argument as setjmp's "second return". Required two fixes:
|
||||
(a) the assembler misencoded `sta (dp), y` as absolute,Y instead of
|
||||
DP-indirect-Y — switched to raw `.byte 0x91, 0xe0`; (b) added
|
||||
`__attribute__((returns_twice))` to the setjmp declaration so the
|
||||
optimizer doesn't constant-fold post-setjmp env reads to 0.
|
||||
|
||||
**CRC32** (smoke #89) verifies the standard "123456789" → 0xCBF43926
|
||||
end-to-end — exercises uint32_t shifts, XORs, char-by-char loops.
|
||||
|
||||
**Brainfuck interpreter** (smoke #90) executes a small bf program
|
||||
and verifies the output bytes — exercises loop bracket matching,
|
||||
pointer math (data pointer), branching on cell value.
|
||||
|
||||
The **DWARF sidecar** (`link816 --debug-out FILE`) now applies
|
||||
text/rodata/bss/init_array relocations to every `.debug_*` section
|
||||
before writing it. PC values in `.debug_addr` and `.debug_line` end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
typedef unsigned char jmp_buf[8];
|
||||
|
||||
int setjmp(jmp_buf env);
|
||||
// `returns_twice` tells clang that setjmp may "return" a second time
|
||||
// (via longjmp) — without this the optimizer may treat env as
|
||||
// uninitialized after the call and constant-fold reads to 0.
|
||||
int setjmp(jmp_buf env) __attribute__((returns_twice));
|
||||
void longjmp(jmp_buf env, int val) __attribute__((noreturn));
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1146,6 +1146,10 @@ __negdi_b:
|
|||
; setjmp returned 0 with all-callee-savable regs already preserved by
|
||||
; setjmp's caller.
|
||||
; --------------------------------------------------------------------
|
||||
; NOTE: llvm-mc misencodes `sta (dp), y` and `lda (dp), y` as the
|
||||
; absolute-,Y opcodes (0x99 / 0xb9) instead of the DP-indirect-Y
|
||||
; opcodes (0x91 / 0xb1). Use raw `.byte` for those. Y is supplied
|
||||
; via LDY before each indirect access.
|
||||
.globl setjmp
|
||||
setjmp:
|
||||
sta 0xe0 ; jmp_buf addr -> DP scratch
|
||||
|
|
@ -1153,18 +1157,18 @@ setjmp:
|
|||
clc
|
||||
adc #0x3 ; A = caller's SP (undo JSL push)
|
||||
ldy #0
|
||||
sta (0xe0), y ; env[0..1] = caller SP
|
||||
.byte 0x91, 0xe0 ; sta (0xe0), y : env[0..1] = caller SP (16-bit M)
|
||||
lda 0x1, s ; A = retaddr lo:hi
|
||||
ldy #2
|
||||
sta (0xe0), y ; env[2..3] = retaddr lo:hi
|
||||
.byte 0x91, 0xe0 ; sta (0xe0), y : env[2..3] = retaddr lo:hi
|
||||
sep #0x20
|
||||
lda 0x3, s ; A_lo = bank
|
||||
ldy #4
|
||||
sta (0xe0), y ; env[4] = bank
|
||||
.byte 0x91, 0xe0 ; sta (0xe0), y : env[4] = bank (8-bit M)
|
||||
rep #0x20
|
||||
tdc ; A = DP
|
||||
ldy #5
|
||||
sta (0xe0), y ; env[5..6] = DP
|
||||
.byte 0x91, 0xe0 ; sta (0xe0), y : env[5..6] = DP
|
||||
lda #0 ; setjmp returns 0
|
||||
rtl
|
||||
|
||||
|
|
@ -1175,22 +1179,22 @@ longjmp:
|
|||
sta 0xe2 ; save val
|
||||
; Restore SP: env[0..1] - 3 (so the upcoming PHAs land at the right slots).
|
||||
ldy #0
|
||||
lda (0xe0), y ; A = saved SP
|
||||
.byte 0xb1, 0xe0 ; lda (0xe0), y : A = saved SP (16-bit)
|
||||
sec
|
||||
sbc #0x3
|
||||
tcs ; SP = saved_SP - 3
|
||||
; Push retaddr: bank, then 16-bit lo:hi. RTL pulls lo, hi, bank.
|
||||
sep #0x20
|
||||
ldy #4
|
||||
lda (0xe0), y ; bank
|
||||
.byte 0xb1, 0xe0 ; lda (0xe0), y : bank (8-bit)
|
||||
pha
|
||||
rep #0x20
|
||||
ldy #2
|
||||
lda (0xe0), y ; lo:hi
|
||||
.byte 0xb1, 0xe0 ; lda (0xe0), y : lo:hi (16-bit)
|
||||
pha
|
||||
; Restore DP.
|
||||
ldy #5
|
||||
lda (0xe0), y
|
||||
.byte 0xb1, 0xe0 ; lda (0xe0), y : DP (16-bit)
|
||||
tcd
|
||||
; Compute return value: val if nonzero, else 1.
|
||||
lda 0xe2
|
||||
|
|
|
|||
|
|
@ -2531,6 +2531,153 @@ EOF
|
|||
fi
|
||||
rm -f "$cRpFile" "$oRpFile" "$binRpFile"
|
||||
|
||||
log "check: MAME runs setjmp/longjmp from nested recursion (#88)"
|
||||
cSjFile="$(mktemp --suffix=.c)"
|
||||
oSjFile="$(mktemp --suffix=.o)"
|
||||
binSjFile="$(mktemp --suffix=.bin)"
|
||||
cat > "$cSjFile" <<'EOF'
|
||||
typedef unsigned char jmp_buf[8];
|
||||
int setjmp(jmp_buf env) __attribute__((returns_twice));
|
||||
void longjmp(jmp_buf env, int val) __attribute__((noreturn));
|
||||
__attribute__((noinline)) void switchToBank2(void) {
|
||||
__asm__ volatile ("sep #0x20\n.byte 0xa9,0x02\npha\nplb\nrep #0x20\n");
|
||||
}
|
||||
__attribute__((noinline))
|
||||
static void deep(jmp_buf env, int level) {
|
||||
if (level >= 3) longjmp(env, 99);
|
||||
deep(env, level + 1);
|
||||
}
|
||||
int main(void) {
|
||||
jmp_buf env;
|
||||
int v = setjmp(env);
|
||||
unsigned short ok = 0;
|
||||
if (v == 0) {
|
||||
deep(env, 0);
|
||||
ok = 0xDEAD;
|
||||
} else if (v == 99) {
|
||||
ok = 0x1234;
|
||||
}
|
||||
switchToBank2();
|
||||
*(volatile unsigned short *)0x5000 = ok;
|
||||
while (1) {}
|
||||
}
|
||||
EOF
|
||||
"$CLANG" --target=w65816 -O2 -ffunction-sections -c \
|
||||
"$cSjFile" -o "$oSjFile"
|
||||
"$PROJECT_ROOT/tools/link816" -o "$binSjFile" --text-base 0x1000 \
|
||||
"$oCrt0F" "$oLibcF" "$oStrtolF" "$oSnprintfF" "$oQsortF" \
|
||||
"$oExtrasF" "$oStrtokF" "$oMathF" "$oSfF" "$oSdF" \
|
||||
"$oLibgccFile" "$oSjFile" >/dev/null 2>&1
|
||||
if ! bash "$PROJECT_ROOT/scripts/runInMame.sh" "$binSjFile" --check \
|
||||
0x025000=1234 >/dev/null 2>&1; then
|
||||
die "MAME: setjmp/longjmp end-to-end != 0x1234 (#88)"
|
||||
fi
|
||||
rm -f "$cSjFile" "$oSjFile" "$binSjFile"
|
||||
|
||||
log "check: MAME runs CRC32('123456789') == 0xCBF43926 (#89)"
|
||||
cCrFile="$(mktemp --suffix=.c)"
|
||||
oCrFile="$(mktemp --suffix=.o)"
|
||||
binCrFile="$(mktemp --suffix=.bin)"
|
||||
cat > "$cCrFile" <<'EOF'
|
||||
typedef unsigned long uint32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
__attribute__((noinline)) void switchToBank2(void) {
|
||||
__asm__ volatile ("sep #0x20\n.byte 0xa9,0x02\npha\nplb\nrep #0x20\n");
|
||||
}
|
||||
static uint32_t crc32(const uint8_t *buf, unsigned int len) {
|
||||
uint32_t crc = 0xFFFFFFFFul;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
crc = crc ^ (uint32_t)buf[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
uint32_t mask = -(crc & 1ul);
|
||||
crc = (crc >> 1) ^ (0xEDB88320ul & mask);
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
int main(void) {
|
||||
const char *s = "123456789";
|
||||
unsigned int n = 0;
|
||||
while (s[n]) n++;
|
||||
uint32_t c = crc32((const uint8_t *)s, n);
|
||||
switchToBank2();
|
||||
*(volatile uint32_t *)0x5000 = c;
|
||||
while (1) {}
|
||||
}
|
||||
EOF
|
||||
"$CLANG" --target=w65816 -O2 -ffunction-sections -c \
|
||||
"$cCrFile" -o "$oCrFile"
|
||||
"$PROJECT_ROOT/tools/link816" -o "$binCrFile" --text-base 0x1000 \
|
||||
"$oCrt0F" "$oLibcF" "$oStrtolF" "$oSnprintfF" "$oQsortF" \
|
||||
"$oExtrasF" "$oStrtokF" "$oMathF" "$oSfF" "$oSdF" \
|
||||
"$oLibgccFile" "$oCrFile" >/dev/null 2>&1
|
||||
if ! bash "$PROJECT_ROOT/scripts/runInMame.sh" "$binCrFile" --check \
|
||||
0x025000=3926 0x025002=cbf4 >/dev/null 2>&1; then
|
||||
die "MAME: CRC32 != 0xCBF43926 (#89)"
|
||||
fi
|
||||
rm -f "$cCrFile" "$oCrFile" "$binCrFile"
|
||||
|
||||
log "check: MAME runs brainfuck \"...AB...\" interpreter (#90)"
|
||||
cBfFile="$(mktemp --suffix=.c)"
|
||||
oBfFile="$(mktemp --suffix=.o)"
|
||||
binBfFile="$(mktemp --suffix=.bin)"
|
||||
cat > "$cBfFile" <<'EOF'
|
||||
typedef unsigned char u8;
|
||||
__attribute__((noinline)) void switchToBank2(void) {
|
||||
__asm__ volatile ("sep #0x20\n.byte 0xa9,0x02\npha\nplb\nrep #0x20\n");
|
||||
}
|
||||
#define TAPE_SIZE 32
|
||||
static u8 g_tape[TAPE_SIZE];
|
||||
static u8 g_out[8];
|
||||
static int g_outIdx;
|
||||
__attribute__((noinline,optnone))
|
||||
static void runBf(const char *prog) {
|
||||
g_outIdx = 0;
|
||||
for (int i = 0; i < TAPE_SIZE; i++) g_tape[i] = 0;
|
||||
int dp = 0; int pc = 0;
|
||||
while (prog[pc]) {
|
||||
char c = prog[pc];
|
||||
if (c == '+') g_tape[dp]++;
|
||||
else if (c == '-') g_tape[dp]--;
|
||||
else if (c == '>') dp++;
|
||||
else if (c == '<') dp--;
|
||||
else if (c == '.') { if (g_outIdx < 8) g_out[g_outIdx++] = g_tape[dp]; }
|
||||
else if (c == '[') {
|
||||
if (g_tape[dp] == 0) {
|
||||
int d = 1;
|
||||
while (d > 0) { pc++; if (prog[pc]=='[') d++; else if (prog[pc]==']') d--; }
|
||||
}
|
||||
} else if (c == ']') {
|
||||
if (g_tape[dp] != 0) {
|
||||
int d = 1;
|
||||
while (d > 0) { pc--; if (prog[pc]==']') d++; else if (prog[pc]=='[') d--; }
|
||||
}
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
int main(void) {
|
||||
runBf("++++++++[>++++++++<-]>+.+.");
|
||||
// Capture g_out values BEFORE bank switch — after the switch DBR=2
|
||||
// and bank-0 globals can't be read absolutely.
|
||||
unsigned short out01 = (unsigned short)g_out[0] | ((unsigned short)g_out[1] << 8);
|
||||
switchToBank2();
|
||||
*(volatile unsigned short *)0x5000 = out01;
|
||||
while (1) {}
|
||||
}
|
||||
EOF
|
||||
"$CLANG" --target=w65816 -O2 -ffunction-sections -c \
|
||||
"$cBfFile" -o "$oBfFile"
|
||||
"$PROJECT_ROOT/tools/link816" -o "$binBfFile" --text-base 0x1000 \
|
||||
"$oCrt0F" "$oLibcF" "$oStrtolF" "$oSnprintfF" "$oQsortF" \
|
||||
"$oExtrasF" "$oStrtokF" "$oMathF" "$oSfF" "$oSdF" \
|
||||
"$oLibgccFile" "$oBfFile" >/dev/null 2>&1
|
||||
if ! bash "$PROJECT_ROOT/scripts/runInMame.sh" "$binBfFile" --check \
|
||||
0x025000=4241 >/dev/null 2>&1; then
|
||||
die "MAME: brainfuck 'AB' output != 0x4241 (#90)"
|
||||
fi
|
||||
rm -f "$cBfFile" "$oBfFile" "$binBfFile"
|
||||
|
||||
log "check: MAME runs sqrt/pow + sin/cos/exp/log + strpbrk/spn/cspn (#81 + #82 + #83)"
|
||||
cTrFile="$(mktemp --suffix=.c)"
|
||||
oTrFile="$(mktemp --suffix=.o)"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue