I needed a period-63 LFSR implementation in 6502 assembly for some NES code I was writing. Normally, I like to unit test code, but it wasn't obvious how to do that with an NES. Thankfully, the cc65 project already has a great simulator with semi-hosted C stdio support that you can use for this sort of thing. This post explains how I tested my LFSR implementation.
I started with the LFSR code itself, in lfsr.asm:
.export _lfsr_state
.export _lfsr_update
.segment "DATA"
_lfsr_state: .res 1
.segment "CODE"
.proc _lfsr_update
; period 63 lfsr with polynomial x^6 + x^5 + 1, computed in top 6 bits
; Bottom 2 bits must always be 0.
lda _lfsr_state
asl
bpl :+
eor #4
: bcc :+
eor #4
: sta _lfsr_state
rts
.endproc
I'm still new to 6502 coding, so I'm sure this is suboptimal, but it seemed like a good start. The whole point of the exercise is to make it easier to optimize small routines, after all.
Then I made main.c:
#include <stdio.h>
#include <stdint.h>
extern void lfsr_update(void);
extern uint8_t lfsr_state;
int main(void)
{
uint8_t i = 0;
uint8_t first;
lfsr_state = 0x4;
first = lfsr_state;
do {
printf("%d: %02X\n", i++, lfsr_state);
lfsr_update();
} while (first != lfsr_state);
return 0;
}
This initializes the LFSR (in the top 6 bits of lfsr_state) to a non-zero value, then updates it until it sees the same value again, printing the intermediate values.
Assuming you installed cc65 already, you can compile this with the commands:
$ cl65 --target sim6502 -o test main.c lfsr.asm
Then you can simulate it with the command:
$ sim65 test
This should give the output:
0: 04
1: 08
2: 10
3: 20
4: 40
5: 84
6: 0C
7: 18
8: 30
9: 60
10: C4
11: 88
12: 14
13: 28
14: 50
15: A4
16: 4C
17: 9C
18: 3C
19: 78
20: F4
21: E8
22: D0
23: A0
24: 44
25: 8C
26: 1C
27: 38
28: 70
29: E4
30: C8
31: 90
32: 24
33: 48
34: 94
35: 2C
36: 58
37: B4
38: 6C
39: DC
40: B8
41: 74
42: EC
43: D8
44: B0
45: 64
46: CC
47: 98
48: 34
49: 68
50: D4
51: A8
52: 54
53: AC
54: 5C
55: BC
56: 7C
57: FC
58: F8
59: F0
60: E0
61: C0
62: 80
This shows that the LFSR cycles after 63 steps, as intended. It also always leaves bits 0-1 clear.
The major limitation of this approach for testing is that if your routines are not using cc65's normal calling convention, you may have to write a wrapper function to be able to call them from C.
The sim65 tool also allows cycle counts to help optimization, but I don't think it can produce any sort of instruction trace that would make it more useful for debugging.
No comments:
Post a Comment