Skip to content

Commit bfae795

Browse files
committed
Code reorganization.
cpu code moved into go6502/cpu package app code moved into go6502 root started work on go6502 app documentation
1 parent 0a3d439 commit bfae795

32 files changed

+527
-218
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
debug
22
debug.test
3+
go6502
34
todo.txt

README.md

+260-93
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,264 @@
11
go6502
22
======
33

4-
The go6502 package implements a 6502 CPU emulator, assembler, disassembler,
5-
and debugger.
6-
7-
See http://godoc.org/github.com/beevik/go6502 for the godoc-formatted API
8-
documentation.
9-
10-
This project is currently under construction and is changing frequently.
11-
12-
### Example
13-
14-
Initialize a 64KB memory space and load some machine code from a byte
15-
slice.
16-
```go
17-
mem := go6502.NewFlatMemory()
18-
19-
// Load a byte slice of machine code at address 0x600
20-
mem.StoreBytes(0x600, []byte{0xa2, 0x05, 0xa1, 0x02, 0xa9, 0x08, 0x8d,
21-
0x01, 0x02, 0x69, 0xfe, 0x8d, 0x00, 0x02, 0xa9, 0xff, 0xad, 0x00,
22-
0x02, 0xa2, 0xee, 0x4c, 0x00, 0x06})
23-
```
24-
25-
Create an emulated CMOS 65c02 CPU and initialize its program counter.
26-
```go
27-
cpu := go6502.NewCPU(go6502.CMOS, mem)
28-
cpu.SetPC(0x600)
29-
```
30-
31-
Use the `Step()` function to manually step the CPU one instruction at a time.
32-
```go
33-
for i := 0; i < 20; i++ {
34-
cpu.Step()
35-
}
36-
```
37-
38-
Use the `go6502/disasm` package to disassemble machine code while stepping
39-
the CPU.
40-
```go
41-
for i := 0; i < 20; i++ {
42-
pc := cpu.Reg.PC
43-
line, _, _ := disasm.Disassemble(cpu.Mem, pc)
44-
cpu.Step()
45-
fmt.Printf("%04X- %-12s A=%02X X=%02X Y=%02X PS=[%s] SP=%02X PC=%04X Cycles=%d\n",
46-
pc, line,
47-
cpu.Reg.A, cpu.Reg.X, cpu.Reg.Y, psString(&cpu.Reg),
48-
cpu.Reg.SP, cpu.Reg.PC,
49-
cpu.Cycles)
50-
}
51-
```
52-
53-
Output:
54-
```
55-
0600- LDX #$05 A=00 X=05 Y=00 PS=[------] SP=FF PC=0602 Cycles=2
56-
0602- LDA ($02,X) A=00 X=05 Y=00 PS=[-Z----] SP=FF PC=0604 Cycles=8
57-
0604- LDA #$08 A=08 X=05 Y=00 PS=[------] SP=FF PC=0606 Cycles=10
58-
0606- STA $0201 A=08 X=05 Y=00 PS=[------] SP=FF PC=0609 Cycles=14
59-
0609- ADC #$FE A=06 X=05 Y=00 PS=[C-----] SP=FF PC=060B Cycles=16
60-
060B- STA $0200 A=06 X=05 Y=00 PS=[C-----] SP=FF PC=060E Cycles=20
61-
060E- LDA #$FF A=FF X=05 Y=00 PS=[C----N] SP=FF PC=0610 Cycles=22
62-
0610- LDA $0200 A=06 X=05 Y=00 PS=[C-----] SP=FF PC=0613 Cycles=26
63-
0613- LDX #$EE A=06 X=EE Y=00 PS=[C----N] SP=FF PC=0615 Cycles=28
64-
0615- JMP $0600 A=06 X=EE Y=00 PS=[C----N] SP=FF PC=0600 Cycles=31
65-
0600- LDX #$05 A=06 X=05 Y=00 PS=[C-----] SP=FF PC=0602 Cycles=33
66-
0602- LDA ($02,X) A=00 X=05 Y=00 PS=[CZ----] SP=FF PC=0604 Cycles=39
67-
0604- LDA #$08 A=08 X=05 Y=00 PS=[C-----] SP=FF PC=0606 Cycles=41
68-
0606- STA $0201 A=08 X=05 Y=00 PS=[C-----] SP=FF PC=0609 Cycles=45
69-
0609- ADC #$FE A=07 X=05 Y=00 PS=[C-----] SP=FF PC=060B Cycles=47
70-
060B- STA $0200 A=07 X=05 Y=00 PS=[C-----] SP=FF PC=060E Cycles=51
71-
060E- LDA #$FF A=FF X=05 Y=00 PS=[C----N] SP=FF PC=0610 Cycles=53
72-
0610- LDA $0200 A=07 X=05 Y=00 PS=[C-----] SP=FF PC=0613 Cycles=57
73-
0613- LDX #$EE A=07 X=EE Y=00 PS=[C----N] SP=FF PC=0615 Cycles=59
74-
0615- JMP $0600 A=07 X=EE Y=00 PS=[C----N] SP=FF PC=0600 Cycles=62
75-
```
76-
77-
Here is the implementation of the helper function `psString` used in the
78-
example:
79-
```go
80-
func psString(r *go6502.Registers) string {
81-
v := func(bit bool, ch byte) byte {
82-
if bit {
83-
return ch
84-
}
85-
return '-'
86-
}
87-
b := []byte{
88-
v(r.Carry, 'C'),
89-
v(r.Zero, 'Z'),
90-
v(r.InterruptDisable, 'I'),
91-
v(r.Decimal, 'D'),
92-
v(r.Overflow, 'O'),
93-
v(r.Negative, 'N'),
94-
}
95-
return string(b)
96-
}
4+
_This project is currently under construction and is changing frequently._
5+
6+
go6502 is a collection of go packages used to emulate a 6502 or 65C02 CPU. It
7+
includes a CPU emulator, a cross-assembler, a disassembler, a debugger, and a
8+
host that wraps them all together.
9+
10+
The go6502 application in the root directory wraps the host and provides an
11+
interactive interface to the go6502 packages' features.
12+
13+
# Tutorial
14+
15+
Let's start by considering the go6502 `sample.cmd` script:
16+
17+
```
18+
load monitor $F800
19+
assemble sample
20+
load sample
21+
set PC START
22+
d .
23+
```
24+
25+
We'll describe these commands in further detail later, but for now just
26+
know that this script's commands do the following things:
27+
1. Load the `monitor.bin` binary file at memory address `F800`.
28+
2. Assemble the `sample.asm` file using the go6502 cross-assembler, generating
29+
a `sample.bin` binary file and a `sample.map` source map file.
30+
3. Load the `sample.bin` file at the origin address specified by the
31+
`sample.asm` file.
32+
4. Set the program counter to the `START` address, which was exported by
33+
`sample.asm`.
34+
5. Disassemble the first few lines of machine code starting from the program
35+
counter address.
36+
37+
To run this script, build the go6502 application and type the following on the
38+
command line:
39+
40+
```
41+
go6502 sample.cmd
42+
```
43+
44+
You should then see:
45+
46+
```
47+
Loaded 'monitor.bin' to $F800..$FFFF
48+
Assembled 'sample.asm' to 'sample.bin'.
49+
Loaded 'sample.bin' to $1000..$10FF
50+
Loaded 'sample.map' source map
51+
Register PC set to $1000.
52+
1000- A2 EE LDX #$EE
53+
1002- 48 PHA
54+
1003- 20 18 10 JSR $1018
55+
1006- 20 1B 10 JSR $101B
56+
1009- 20 35 10 JSR $1035
57+
100C- 20 45 10 JSR $1045
58+
100F- F0 06 BEQ $1017
59+
1011- A0 3B LDY #$3B
60+
1013- A9 10 LDA #$10
61+
1015- A2 55 LDX #$55
62+
63+
1000- A2 EE LDX #$EE A=00 X=00 Y=00 PS=[------] SP=FF PC=1000 C=0
64+
*
65+
```
66+
67+
The output shows the result of go6502 running each command in the sample
68+
script. Once the script is finished running, go6502 enters interactive mode
69+
and provides a `*` prompt for further input.
70+
71+
Just before the prompt is a line starting with `1000-`. This line shows the
72+
disassembly of the instruction at the current program counter address and the
73+
state of the CPU registers. The `C` value indicates the number of CPU cycles
74+
that have elapsed since the application started.
75+
76+
## Getting help
77+
78+
Let's enter our first interactive command. Type `help` to see a list of all
79+
commands.
80+
81+
```
82+
* help
83+
go6502 commands:
84+
annotate Annotate an address
85+
assemble Assemble a file and save the binary
86+
breakpoint Breakpoint commands
87+
databreakpoint Data breakpoint commands
88+
disassemble Disassemble code
89+
evaluate Evaluate an expression
90+
exports List exported addresses
91+
load Load a binary file
92+
memory Memory commands
93+
quit Quit the program
94+
registers Display register contents
95+
run Run the CPU
96+
set Set a host setting
97+
step Step the debugger
98+
```
99+
100+
To get further help about a command, type `help <cmd>`. In some cases, you
101+
will be shown a list of subcommands that must be used with the command. Let's
102+
try `help step`.
103+
104+
```
105+
* help step
106+
Step commands:
107+
in Step in to routine
108+
over Step over a routine
109+
```
110+
111+
This output tells you that the `step` command requires an `in` or `over`
112+
subcommand. To step the debugger into a routine, for instance, you would
113+
type `step in`.
114+
115+
## Stepping the debugger
116+
117+
Let's use one of the `step` subcommands to step the debugger by a single CPU
118+
instruction. Type `step in`.
119+
120+
```
121+
1000- A2 EE LDX #$EE A=00 X=00 Y=00 PS=[------] SP=FF PC=1000 C=0
122+
* step in
123+
1002- A9 05 LDA #$05 A=00 X=EE Y=00 PS=[N-----] SP=FF PC=1002 C=2
124+
*
125+
```
126+
127+
By stepping into one instruction, the emulated CPU has executed the `LDX #$EE`
128+
instruction at address `1000`. This has advanced the program counter to
129+
`1002`, loaded the value `EE` into the X register, and advanced the CPU
130+
cycle counter by 2 cycles.
131+
132+
Each time go6502 runs a command interactively, it disassembles the instruction
133+
to be executed next (i.e., the instruction at the current program counter
134+
address). It also displays the current contents of the CPU registers and the
135+
CPU cycle counter.
136+
137+
Many go6502 commands have aliases. The alias for the `step in` command is
138+
`si`. Now, type `si 4` to step into the next 4 instructions:
139+
140+
```
141+
1002- A9 05 LDA #$05 A=00 X=EE Y=00 PS=[N-----] SP=FF PC=1002 C=2
142+
* si 4
143+
1004- 20 19 10 JSR $1019 A=05 X=EE Y=00 PS=[------] SP=FF PC=1004 C=4
144+
1019- A9 FF LDA #$FF A=05 X=EE Y=00 PS=[------] SP=FD PC=1019 C=10
145+
101B- 60 RTS A=FF X=EE Y=00 PS=[N-----] SP=FD PC=101B C=12
146+
1007- 20 1C 10 JSR $101C A=FF X=EE Y=00 PS=[N-----] SP=FF PC=1007 C=18
147+
*
148+
```
149+
150+
This output shows that the CPU has stepped into the next 4 instructions
151+
starting at address `1002`. Each executed instruction is disassembled and
152+
displayed along with the CPU's register values at the start of each
153+
instruction. In total, 18 CPU cycles have elapsed, and the program counter
154+
ends at address `1007`. The instruction at `1007` has not yet been
155+
executed.
156+
157+
Note that the `step in` command stepped _into_ the `JSR $1019` subroutine call
158+
rather than stepping _over_ it. If you weren't interested in stepping through
159+
all the code inside the subroutine, you could have used the `step over`
160+
command instead. This would have caused the debugger to invisibly execute all
161+
instructions inside the subroutine, returning control to the application only
162+
after the `RTS` instruction was executed.
163+
164+
Since the CPU is about to execute another `JSR` instruction, let's try the
165+
`step over` command (or `s` for short).
166+
167+
```
168+
1007- 20 1C 10 JSR $101C A=FF X=EE Y=00 PS=[N-----] SP=FF PC=1007 C=18
169+
* s
170+
100A- 20 36 10 JSR $1036 A=00 X=EE Y=00 PS=[-Z----] SP=FF PC=100A C=70
171+
*
172+
```
173+
174+
After stepping over the `JSR` call at address `1007`, all of the instructions
175+
inside the subroutine at `101C` have been executed, and control has returned
176+
to go6502 at address `100A` after 52 CPU cycles have elapsed.
177+
178+
## Shortcut: Hit Enter!
179+
180+
A useful shortcut you will probably use frequently is hitting the Enter key at
181+
the prompt. This causes go6502 to repeat the previously entered command.
182+
183+
Let's try hitting Enter twice to repeat the `step over` command two more
184+
times.
185+
186+
```
187+
100A- 20 36 10 JSR $1036 A=00 X=EE Y=00 PS=[-Z----] SP=FF PC=100A C=70
188+
*
189+
100D- 20 46 10 JSR $1046 A=00 X=00 Y=00 PS=[-Z----] SP=FF PC=100D C=103
190+
*
191+
1010- F0 06 BEQ $1018 A=00 X=00 Y=00 PS=[-Z----] SP=FF PC=1010 C=136
192+
*
193+
```
194+
195+
As you can see, go6502 has stepped "over" two more `JSR` instructions,
196+
elapsing another 66 CPU cycles and leaving the program counter at `1010`.
197+
198+
## Disassembling code
199+
200+
Now let's disassemble code at the current program counter address to get a
201+
preview of the code about to be executed:
202+
203+
```
204+
* d .
205+
1010- F0 06 BEQ $1018
206+
1012- A0 3B LDY #$3B
207+
1014- A9 10 LDA #$10
208+
1016- A2 56 LDX #$56
209+
1018- 00 BRK
210+
1019- A9 FF LDA #$FF
211+
101B- 60 RTS
212+
101C- A9 20 LDA #$20
213+
101E- A5 20 LDA $20
214+
1020- B5 20 LDA $20,X
215+
*
216+
```
217+
218+
The `.` is shorthand for the current program counter address. You may also
219+
pass an address or mathematical expression to disassemble code starting at any
220+
address:
221+
222+
```
223+
* d START+2
224+
1002- A9 05 LDA #$05
225+
1004- 20 19 10 JSR $1019
226+
1007- 20 1C 10 JSR $101C
227+
100A- 20 36 10 JSR $1036
228+
100D- 20 46 10 JSR $1046
229+
1010- F0 06 BEQ $1018
230+
1012- A0 3B LDY #$3B
231+
1014- A9 10 LDA #$10
232+
1016- A2 56 LDX #$56
233+
1018- 00 BRK
234+
*
235+
```
236+
237+
By default, go6502 disassembles 10 instructions, but you can disassemble a
238+
different number of instructions by specifying a second argument:
239+
240+
```
241+
d . 3
242+
1010- F0 06 BEQ $1018
243+
1012- A0 3B LDY #$3B
244+
1014- A9 10 LDA #$10
245+
*
246+
```
247+
248+
If you hit Enter after using a disassemble command, go6502 will continue
249+
disassembly from where it left off.
250+
251+
```
252+
*
253+
1016- A2 56 LDX #$56
254+
1018- 00 BRK
255+
1019- A9 FF LDA #$FF
256+
*
257+
```
258+
259+
If you don't like the number of instructions that go6502 disassembles by
260+
default, you can change it with the `set` command:
261+
262+
```
263+
set DisasmLinesToDisplay 20
97264
```

app/.gitignore

-2
This file was deleted.

app/sample.bin

-264 Bytes
Binary file not shown.

app/sample.cmd

-6
This file was deleted.

app/sample.map

-140 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)