r6502 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/LICENSE +20 -0
- data/README.md +27 -0
- data/bin/r6502 +41 -0
- data/lib/r6502.rb +6 -0
- data/lib/r6502/assembler.rb +204 -0
- data/lib/r6502/cpu_execution.rb +95 -0
- data/lib/r6502/cpu_instructions.rb +517 -0
- data/lib/r6502/instr_table.rb +213 -0
- data/lib/r6502/memory.rb +21 -0
- data/lib/r6502/opcode_table.rb +64 -0
- data/r6502.gemspec +13 -0
- data/spec/r6502/assembler_spec.rb +226 -0
- data/spec/r6502/cpu_execution_spec.rb +119 -0
- data/spec/r6502/cpu_instructions_spec.rb +1284 -0
- data/spec/r6502/memory_spec.rb +37 -0
- data/spec/spec_helper.rb +1 -0
- metadata +60 -0
@@ -0,0 +1,213 @@
|
|
1
|
+
module R6502
|
2
|
+
class Cpu
|
3
|
+
def instr_mode(opcode)
|
4
|
+
#adc
|
5
|
+
{ 0x69 => [:adc, :imm],
|
6
|
+
0x65 => [:adc, :zp],
|
7
|
+
0x75 => [:adc, :zpx],
|
8
|
+
0x6d => [:adc, :abs],
|
9
|
+
0x7d => [:adc, :absx],
|
10
|
+
0x79 => [:adc, :absy],
|
11
|
+
0x61 => [:adc, :indx],
|
12
|
+
0x71 => [:adc, :indy],
|
13
|
+
#and
|
14
|
+
0x29 => [:and, :imm],
|
15
|
+
0x25 => [:and, :zp],
|
16
|
+
0x35 => [:and, :zpx],
|
17
|
+
0x2d => [:and, :abs],
|
18
|
+
0x3d => [:and, :absx],
|
19
|
+
0x39 => [:and, :absy],
|
20
|
+
0x21 => [:and, :indx],
|
21
|
+
0x31 => [:and, :indy],
|
22
|
+
#asl
|
23
|
+
0x0a => [:asl, :acc],
|
24
|
+
0x06 => [:asl, :zp],
|
25
|
+
0x16 => [:asl, :zpx],
|
26
|
+
0x0e => [:asl, :abs],
|
27
|
+
0x1e => [:asl, :absx],
|
28
|
+
#bit
|
29
|
+
0x24 => [:bit, :zp],
|
30
|
+
0x2c => [:bit, :abs],
|
31
|
+
#bpl
|
32
|
+
0x10 => [:bpl, :rel],
|
33
|
+
#bmi
|
34
|
+
0x30 => [:bmi, :rel],
|
35
|
+
#bvc
|
36
|
+
0x50 => [:bvc, :rel],
|
37
|
+
#bvs
|
38
|
+
0x70 => [:bvs, :rel],
|
39
|
+
#bcc
|
40
|
+
0x90 => [:bcc, :rel],
|
41
|
+
#bcs
|
42
|
+
0xb0 => [:bcs, :rel],
|
43
|
+
#bne
|
44
|
+
0xd0 => [:bne, :rel],
|
45
|
+
#beq
|
46
|
+
0xf0 => [:beq, :rel],
|
47
|
+
#brk
|
48
|
+
0x00 => [:brk, :imp],
|
49
|
+
#cmp
|
50
|
+
0xc9 => [:cmp, :imm],
|
51
|
+
0xc5 => [:cmp, :zp],
|
52
|
+
0xd5 => [:cmp, :zpx],
|
53
|
+
0xcd => [:cmp, :abs],
|
54
|
+
0xdd => [:cmp, :absx],
|
55
|
+
0xd9 => [:cmp, :absy],
|
56
|
+
0xc1 => [:cmp, :indx],
|
57
|
+
0xd1 => [:cmp, :indy],
|
58
|
+
#cpx
|
59
|
+
0xe0 => [:cpx, :imm],
|
60
|
+
0xe4 => [:cpx, :zp],
|
61
|
+
0xec => [:cpx, :abs],
|
62
|
+
#cpy
|
63
|
+
0xc0 => [:cpy, :imm],
|
64
|
+
0xc4 => [:cpy, :zp],
|
65
|
+
0xcc => [:cpy, :abs],
|
66
|
+
#dec
|
67
|
+
0xc6 => [:dec, :zp],
|
68
|
+
0xd6 => [:dec, :zpx],
|
69
|
+
0xce => [:dec, :abs],
|
70
|
+
0xde => [:dec, :absx],
|
71
|
+
#eor
|
72
|
+
0x49 => [:eor, :imm],
|
73
|
+
0x45 => [:eor, :zp],
|
74
|
+
0x55 => [:eor, :zpx],
|
75
|
+
0x4d => [:eor, :abs],
|
76
|
+
0x5d => [:eor, :absx],
|
77
|
+
0x59 => [:eor, :absy],
|
78
|
+
0x41 => [:eor, :indx],
|
79
|
+
0x51 => [:eor, :indy],
|
80
|
+
#clc
|
81
|
+
0x18 => [:clc, :imp],
|
82
|
+
#sec
|
83
|
+
0x38 => [:sec, :imp],
|
84
|
+
#cli
|
85
|
+
0x58 => [:cli, :imp],
|
86
|
+
#sei
|
87
|
+
0x78 => [:sei, :imp],
|
88
|
+
#clv
|
89
|
+
0xb8 => [:clv, :imp],
|
90
|
+
#cld
|
91
|
+
0xd8 => [:cld, :imp],
|
92
|
+
#sed
|
93
|
+
0xf8 => [:sed, :imp],
|
94
|
+
#inc
|
95
|
+
0xe6 => [:inc, :zp],
|
96
|
+
0xf6 => [:inc, :zpx],
|
97
|
+
0xee => [:inc, :abs],
|
98
|
+
0xfe => [:inc, :absx],
|
99
|
+
#jmp,
|
100
|
+
0x4c => [:jmp, :abs],
|
101
|
+
0x6c => [:jmp, :ind],
|
102
|
+
#jsr,
|
103
|
+
0x20 => [:jsr, :abs],
|
104
|
+
#lda,
|
105
|
+
0xa9 => [:lda, :imm],
|
106
|
+
0xa5 => [:lda, :zp],
|
107
|
+
0xb5 => [:lda, :zpx],
|
108
|
+
0xad => [:lda, :abs],
|
109
|
+
0xbd => [:lda, :absx],
|
110
|
+
0xb9 => [:lda, :absy],
|
111
|
+
0xa1 => [:lda, :indx],
|
112
|
+
0xb1 => [:lda, :indy],
|
113
|
+
#ldx,
|
114
|
+
0xa2 => [:ldx, :imm],
|
115
|
+
0xa6 => [:ldx, :zp],
|
116
|
+
0xb6 => [:ldx, :zpy],
|
117
|
+
0xae => [:ldx, :abs],
|
118
|
+
0xbe => [:ldx, :absy],
|
119
|
+
#ldy,
|
120
|
+
0xa0 => [:ldy, :imm],
|
121
|
+
0xa4 => [:ldy, :zp],
|
122
|
+
0xb4 => [:ldy, :zpx],
|
123
|
+
0xac => [:ldy, :abs],
|
124
|
+
0xbc => [:ldy, :absx],
|
125
|
+
#lsr,
|
126
|
+
0x4a => [:lsr, :imp],
|
127
|
+
0x46 => [:lsr, :zp],
|
128
|
+
0x56 => [:lsr, :zpx],
|
129
|
+
0x4e => [:lsr, :abs],
|
130
|
+
0x5e => [:lsr, :absx],
|
131
|
+
#nop,
|
132
|
+
0xea => [:nop, :imp],
|
133
|
+
#ora,
|
134
|
+
0x09 => [:ora, :imm],
|
135
|
+
0x05 => [:ora, :zp],
|
136
|
+
0x15 => [:ora, :zpx],
|
137
|
+
0x0d => [:ora, :abs],
|
138
|
+
0x1d => [:ora, :absx],
|
139
|
+
0x19 => [:ora, :absy],
|
140
|
+
0x01 => [:ora, :indx],
|
141
|
+
0x11 => [:ora, :indy],
|
142
|
+
#tax,
|
143
|
+
0xaa => [:tax, :imp],
|
144
|
+
#txa,
|
145
|
+
0x8a => [:txa, :imp],
|
146
|
+
#dex,
|
147
|
+
0xca => [:dex, :imp],
|
148
|
+
#inx,
|
149
|
+
0xe8 => [:inx, :imp],
|
150
|
+
#tay,
|
151
|
+
0xa8 => [:tay, :imp],
|
152
|
+
#tya,
|
153
|
+
0x98 => [:tya, :imp],
|
154
|
+
#dey,
|
155
|
+
0x88 => [:dey, :imp],
|
156
|
+
#iny,
|
157
|
+
0xc8 => [:iny, :imp],
|
158
|
+
#rol,
|
159
|
+
0x2a => [:rol, :imp],
|
160
|
+
0x26 => [:rol, :zp],
|
161
|
+
0x36 => [:rol, :zpx],
|
162
|
+
0x2e => [:rol, :abs],
|
163
|
+
0x3e => [:rol, :absx],
|
164
|
+
#ror,
|
165
|
+
0x6a => [:ror, :imp],
|
166
|
+
0x66 => [:ror, :zp],
|
167
|
+
0x76 => [:ror, :zpx],
|
168
|
+
0x6e => [:ror, :abs],
|
169
|
+
0x7e => [:ror, :absx],
|
170
|
+
#rti,
|
171
|
+
0x40 => [:rti, :imp],
|
172
|
+
#rts,
|
173
|
+
0x60 => [:rts, :imp],
|
174
|
+
#sbc,
|
175
|
+
0xe9 => [:sbc, :imm],
|
176
|
+
0xe5 => [:sbc, :zp],
|
177
|
+
0xf5 => [:sbc, :zpx],
|
178
|
+
0xed => [:sbc, :abs],
|
179
|
+
0xfd => [:sbc, :absx],
|
180
|
+
0xf9 => [:sbc, :absy],
|
181
|
+
0xe1 => [:sbc, :indx],
|
182
|
+
0xf1 => [:sbc, :indy],
|
183
|
+
#sta,
|
184
|
+
0x85 => [:sta, :zp],
|
185
|
+
0x95 => [:sta, :zpx],
|
186
|
+
0x8d => [:sta, :abs],
|
187
|
+
0x9d => [:sta, :absx],
|
188
|
+
0x99 => [:sta, :absy],
|
189
|
+
0x81 => [:sta, :indx],
|
190
|
+
0x91 => [:sta, :indy],
|
191
|
+
#txs,
|
192
|
+
0x9a => [:txs, :imp],
|
193
|
+
#tsx,
|
194
|
+
0xba => [:tsx, :imp],
|
195
|
+
#pha,
|
196
|
+
0x48 => [:pha, :imp],
|
197
|
+
#pla,
|
198
|
+
0x68 => [:pla, :imp],
|
199
|
+
#php,
|
200
|
+
0x08 => [:php, :imp],
|
201
|
+
#plp,
|
202
|
+
0x28 => [:plp, :imp],
|
203
|
+
#stx,
|
204
|
+
0x86 => [:stx, :zp],
|
205
|
+
0x96 => [:stx, :zpy],
|
206
|
+
0x8e => [:stx, :abs],
|
207
|
+
#sty,
|
208
|
+
0x84 => [:sty, :zp],
|
209
|
+
0x94 => [:sty, :zpx],
|
210
|
+
0x8c => [:sty, :abs] }[opcode]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
data/lib/r6502/memory.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module R6502
|
2
|
+
class Memory
|
3
|
+
def initialize
|
4
|
+
@mem_array = []
|
5
|
+
end
|
6
|
+
def set( addr, val )
|
7
|
+
@mem_array[addr] = val & 0xff
|
8
|
+
end
|
9
|
+
def get( addr )
|
10
|
+
@mem_array[addr] || 0
|
11
|
+
end
|
12
|
+
def get_word( addr )
|
13
|
+
get(addr) + ( get(addr + 1) << 8 )
|
14
|
+
end
|
15
|
+
def get_range( top, bot )
|
16
|
+
bytes = []
|
17
|
+
(top..bot).each { |i| bytes << get(i) }
|
18
|
+
bytes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module R6502
|
2
|
+
class Assembler
|
3
|
+
def opcode(instr, mode)
|
4
|
+
{ :adc => {:imm => 0x69, :zp => 0x65, :zpx => 0x75, :zpy => nil, :abs => 0x6d, :absx => 0x7d, :absy => 0x79, :ind => nil, :indx => 0x61, :indy => 0x71, :imp => nil, :rel => nil },
|
5
|
+
:and => {:imm => 0x29, :zp => 0x25, :zpx => 0x35, :zpy => nil, :abs => 0x2d, :absx => 0x3d, :absy => 0x39, :ind => nil, :indx => 0x21, :indy => 0x31, :imp => nil, :rel => nil },
|
6
|
+
:asl => {:imm => nil, :zp => 0x06, :zpx => 0x16, :zpy => nil, :abs => 0x0e, :absx => 0x1e, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x0a, :rel => nil },
|
7
|
+
:bit => {:imm => nil, :zp => 0x24, :zpx => nil, :zpy => nil, :abs => 0x2c, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
8
|
+
:bpl => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0x10},
|
9
|
+
:bmi => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0x30},
|
10
|
+
:bvc => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0x50},
|
11
|
+
:bvs => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0x70},
|
12
|
+
:bcc => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0x90},
|
13
|
+
:bcs => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0xb0},
|
14
|
+
:bne => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0xd0},
|
15
|
+
:beq => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => 0xf0},
|
16
|
+
:brk => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x00, :rel => nil },
|
17
|
+
:cmp => {:imm => 0xc9, :zp => 0xc5, :zpx => 0xd5, :zpy => nil, :abs => 0xcd, :absx => 0xdd, :absy => 0xd9, :ind => nil, :indx => 0xc1, :indy => 0xd1, :imp => nil, :rel => nil },
|
18
|
+
:cpx => {:imm => 0xe0, :zp => 0xe4, :zpx => nil, :zpy => nil, :abs => 0xec, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
19
|
+
:cpy => {:imm => 0xc0, :zp => 0xc4, :zpx => nil, :zpy => nil, :abs => 0xcc, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
20
|
+
:dec => {:imm => nil, :zp => 0xc6, :zpx => 0xd6, :zpy => nil, :abs => 0xce, :absx => 0xde, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
21
|
+
:eor => {:imm => 0x49, :zp => 0x45, :zpx => 0x55, :zpy => nil, :abs => 0x4d, :absx => 0x5d, :absy => 0x59, :ind => nil, :indx => 0x41, :indy => 0x51, :imp => nil, :rel => nil },
|
22
|
+
:clc => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x18, :rel => nil },
|
23
|
+
:sec => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x38, :rel => nil },
|
24
|
+
:cli => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x58, :rel => nil },
|
25
|
+
:sei => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x78, :rel => nil },
|
26
|
+
:clv => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xb8, :rel => nil },
|
27
|
+
:cld => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xd8, :rel => nil },
|
28
|
+
:sed => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xf8, :rel => nil },
|
29
|
+
:inc => {:imm => nil, :zp => 0xe6, :zpx => 0xf6, :zpy => nil, :abs => 0xee, :absx => 0xfe, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
30
|
+
:jmp => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => 0x4c, :absx => nil, :absy => nil, :ind => 0x6c, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
31
|
+
:jsr => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => 0x20, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
32
|
+
:lda => {:imm => 0xa9, :zp => 0xa5, :zpx => 0xb5, :zpy => nil, :abs => 0xad, :absx => 0xbd, :absy => 0xb9, :ind => nil, :indx => 0xa1, :indy => 0xb1, :imp => nil, :rel => nil },
|
33
|
+
:ldx => {:imm => 0xa2, :zp => 0xa6, :zpx => nil, :zpy => 0xb6, :abs => 0xae, :absx => nil, :absy => 0xbe, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
34
|
+
:ldy => {:imm => 0xa0, :zp => 0xa4, :zpx => 0xb4, :zpy => nil, :abs => 0xac, :absx => 0xbc, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
35
|
+
:lsr => {:imm => nil, :zp => 0x46, :zpx => 0x56, :zpy => nil, :abs => 0x4e, :absx => 0x5e, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x4a, :rel => nil },
|
36
|
+
:nop => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xea, :rel => nil },
|
37
|
+
:ora => {:imm => 0x09, :zp => 0x05, :zpx => 0x15, :zpy => nil, :abs => 0x0d, :absx => 0x1d, :absy => 0x19, :ind => nil, :indx => 0x01, :indy => 0x11, :imp => nil, :rel => nil },
|
38
|
+
:tax => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xaa, :rel => nil },
|
39
|
+
:txa => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x8a, :rel => nil },
|
40
|
+
:dex => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xca, :rel => nil },
|
41
|
+
:inx => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xe8, :rel => nil },
|
42
|
+
:tay => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xa8, :rel => nil },
|
43
|
+
:tya => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x98, :rel => nil },
|
44
|
+
:dey => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x88, :rel => nil },
|
45
|
+
:iny => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xc8, :rel => nil },
|
46
|
+
:ror => {:imm => nil, :zp => 0x66, :zpx => 0x76, :zpy => nil, :abs => 0x6e, :absx => 0x7e, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x6a, :rel => nil },
|
47
|
+
:rol => {:imm => nil, :zp => 0x26, :zpx => 0x36, :zpy => nil, :abs => 0x2e, :absx => 0x3e, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x2a, :rel => nil },
|
48
|
+
:rti => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x40, :rel => nil },
|
49
|
+
:rts => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x60, :rel => nil },
|
50
|
+
:sbc => {:imm => 0xe9, :zp => 0xe5, :zpx => 0xf5, :zpy => nil, :abs => 0xed, :absx => 0xfd, :absy => 0xf9, :ind => nil, :indx => 0xe1, :indy => 0xf1, :imp => nil, :rel => nil },
|
51
|
+
:sta => {:imm => nil, :zp => 0x85, :zpx => 0x95, :zpy => nil, :abs => 0x8d, :absx => 0x9d, :absy => 0x99, :ind => nil, :indx => 0x81, :indy => 0x91, :imp => nil, :rel => nil },
|
52
|
+
:txs => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x9a, :rel => nil },
|
53
|
+
:tsx => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0xba, :rel => nil },
|
54
|
+
:pha => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x48, :rel => nil },
|
55
|
+
:pla => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x68, :rel => nil },
|
56
|
+
:php => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x08, :rel => nil },
|
57
|
+
:plp => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => 0x28, :rel => nil },
|
58
|
+
:stx => {:imm => nil, :zp => 0x86, :zpx => nil, :zpy => 0x96, :abs => 0x8e, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
59
|
+
:sty => {:imm => nil, :zp => 0x84, :zpx => 0x94, :zpy => nil, :abs => 0x8c, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil },
|
60
|
+
:nil => {:imm => nil, :zp => nil, :zpx => nil, :zpy => nil, :abs => nil, :absx => nil, :absy => nil, :ind => nil, :indx => nil, :indy => nil, :imp => nil, :rel => nil }
|
61
|
+
}[instr][mode]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/r6502.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'r6502'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2014-04-09'
|
5
|
+
s.summary = "6502 simulator and assembler"
|
6
|
+
s.description = "6502 simulator and assembler, work-in-progress, not cycle-accurate, etc."
|
7
|
+
s.author = "Joe Landers"
|
8
|
+
s.email = 'joe@joelanders.net'
|
9
|
+
s.files = Dir['**/*']
|
10
|
+
s.homepage =
|
11
|
+
'https://github.com/joelanders/r6502'
|
12
|
+
s.license = 'MIT'
|
13
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module R6502
|
4
|
+
describe Assembler do
|
5
|
+
before(:each) do
|
6
|
+
@mem = Memory.new
|
7
|
+
@asm = Assembler.new(@mem)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "Assembler" do
|
11
|
+
it "Assembles a file and places machine code in memory." do
|
12
|
+
@asm.process_file("lda $2000 ;cmt\nloop nop\njmp loop\n")
|
13
|
+
@mem.get_range(0x600, 0x602).should == [0xad, 0x00, 0x20]
|
14
|
+
@mem.get_range(0x603, 0x606).should == [0xea, 0x4c, 0x03, 0x06]
|
15
|
+
end
|
16
|
+
it "handles relative addressing correctly (negative)" do
|
17
|
+
@asm.process_file("ldx \#$04\nloop dex\nbne loop")
|
18
|
+
@mem.get_range(0x600, 0x604).should == [0xa2, 0x04, 0xca, 0xd0, 0xfd]
|
19
|
+
end
|
20
|
+
it "handles relative addressing correctly (positive)" do
|
21
|
+
@asm.process_file("ldx \#$04\nbne finish\nnop\nnop\nfinish")
|
22
|
+
@mem.get_range(0x600, 0x605).should == [0xa2, 0x04, 0xd0, 0x02, 0xea, 0xea]
|
23
|
+
end
|
24
|
+
describe "assembles a line of assembly" do
|
25
|
+
describe "reads a line of assembly" do
|
26
|
+
describe "parses the pieces of a line of assembly" do
|
27
|
+
it "removes label from an assembly instr" do
|
28
|
+
@asm.delabel('loop: brk').should == 'brk'
|
29
|
+
@asm.delabel('scoop:').should == ''
|
30
|
+
@asm.delabel('').should == ''
|
31
|
+
@asm.delabel(' ').should == ''
|
32
|
+
@asm.delabel(' lda $2000').should == 'lda $2000'
|
33
|
+
@asm.delabel('doop lda $2000').should == 'lda $2000'
|
34
|
+
end
|
35
|
+
it "removes comment and trailing whitespace" do
|
36
|
+
@asm.uncomment('nop ; comment here').should == 'nop'
|
37
|
+
@asm.uncomment('lda #$ff; com').should == 'lda #$ff'
|
38
|
+
end
|
39
|
+
it "extracts command part of line" do
|
40
|
+
@asm.extract_command('nop').should == :nop
|
41
|
+
@asm.extract_command(' nop').should == :nop
|
42
|
+
@asm.extract_command('adc \($44\),y').should == :adc
|
43
|
+
@asm.extract_command('asl $0100').should == :asl
|
44
|
+
end
|
45
|
+
it "extracts parameter part of line" do
|
46
|
+
@asm.extract_param('and $abcd,x').should == '$abcd,x'
|
47
|
+
@asm.extract_param('cmd \($bb,x\)').should == '\($bb,x\)'
|
48
|
+
@asm.extract_param('nop').should == ''
|
49
|
+
end
|
50
|
+
end # end of "parses the pieces of a line of assembly"
|
51
|
+
|
52
|
+
# under "reads a line of assembly"
|
53
|
+
describe "determines addressing mode" do
|
54
|
+
it "immediate" do
|
55
|
+
@asm.addr_mode('#$10').should == :imm
|
56
|
+
@asm.addr_mode('#$4').should == :imm
|
57
|
+
end
|
58
|
+
it "zero page" do
|
59
|
+
@asm.addr_mode('$20').should == :zp
|
60
|
+
@asm.addr_mode('$2').should == :zp
|
61
|
+
end
|
62
|
+
it "zero page, x" do
|
63
|
+
@asm.addr_mode('$30,x').should == :zpx
|
64
|
+
@asm.addr_mode('$3,x').should == :zpx
|
65
|
+
end
|
66
|
+
it "zero page, y" do
|
67
|
+
@asm.addr_mode('$40,y').should == :zpy
|
68
|
+
@asm.addr_mode('$4,y').should == :zpy
|
69
|
+
end
|
70
|
+
it "absolute" do
|
71
|
+
@asm.addr_mode('$ffff').should == :abs
|
72
|
+
@asm.addr_mode('$eee').should == :abs
|
73
|
+
@asm.addr_mode('loop').should == :abs
|
74
|
+
end
|
75
|
+
it "absolute, x" do
|
76
|
+
@asm.addr_mode('$1000,x').should == :absx
|
77
|
+
@asm.addr_mode('$800,x').should == :absx
|
78
|
+
end
|
79
|
+
it "absolute, y" do
|
80
|
+
@asm.addr_mode('$4000,y').should == :absy
|
81
|
+
@asm.addr_mode('$f00,y').should == :absy
|
82
|
+
end
|
83
|
+
it "indirect" do
|
84
|
+
@asm.addr_mode('($deca)').should == :ind
|
85
|
+
@asm.addr_mode('($dec)').should == :ind
|
86
|
+
end
|
87
|
+
it "indirect, x" do
|
88
|
+
@asm.addr_mode('($de,x)').should == :indx
|
89
|
+
@asm.addr_mode('($b,x)').should == :indx
|
90
|
+
end
|
91
|
+
it "indirect, y" do
|
92
|
+
@asm.addr_mode('($ed),y').should == :indy
|
93
|
+
@asm.addr_mode('($e),y').should == :indy
|
94
|
+
end
|
95
|
+
it "implied" do
|
96
|
+
@asm.addr_mode('').should == :imp
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# under "reads a line of assembly"
|
101
|
+
it "figures out the opcode" do
|
102
|
+
@asm.opcode(:lda, :imm).should == 0xa9
|
103
|
+
@asm.opcode(:lda, :zp).should == 0xa5
|
104
|
+
@asm.opcode(:nop, :imp).should == 0xea
|
105
|
+
end
|
106
|
+
# under "reads a line of assembly"
|
107
|
+
it "records the label and its address" do
|
108
|
+
@asm.delabel('loop: nop').should == 'nop'
|
109
|
+
@asm.labels.should == {'loop' => 0x600}
|
110
|
+
@asm.label_get('loop').should == 0x600
|
111
|
+
end
|
112
|
+
end # end of "reads a line of assembly"
|
113
|
+
|
114
|
+
# under "assembles a line of assembly"
|
115
|
+
it "records mem. bytes whose values we don't know yet" do
|
116
|
+
@asm.defer_value(0x601, 'main')
|
117
|
+
@asm.deferred.should == {0x601 => 'main'}
|
118
|
+
@asm.asm_instr('jmp main').should == [0x4c, 0xff, 0xff]
|
119
|
+
end
|
120
|
+
it "implied" do
|
121
|
+
@asm.asm_instr('nop').should == [0xea]
|
122
|
+
@asm.asm_instr('asl').should == [0x0a]
|
123
|
+
end
|
124
|
+
it "absolute" do
|
125
|
+
@asm.asm_instr('lda $dcba').should == [0xad, 0xba, 0xdc]
|
126
|
+
end
|
127
|
+
it "absolute, x" do
|
128
|
+
@asm.asm_instr('adc $cbad,x').should == [0x7d, 0xad, 0xcb]
|
129
|
+
end
|
130
|
+
it "absolute y" do
|
131
|
+
@asm.asm_instr('and $badc,y').should == [0x39, 0xdc, 0xba]
|
132
|
+
end
|
133
|
+
it "immediate" do
|
134
|
+
@asm.asm_instr('lda #$aa').should == [0xa9, 0xaa]
|
135
|
+
end
|
136
|
+
it "zero page" do
|
137
|
+
@asm.asm_instr('asl $10').should == [0x06, 0x10]
|
138
|
+
end
|
139
|
+
it "zero page, x" do
|
140
|
+
@asm.asm_instr('cmp $36,x').should == [0xd5, 0x36]
|
141
|
+
end
|
142
|
+
it "zero page, y" do
|
143
|
+
@asm.asm_instr('ldx $63,y').should == [0xb6, 0x63]
|
144
|
+
end
|
145
|
+
it "indirect" do
|
146
|
+
@asm.asm_instr('jmp ($fffe)').should == [0x6c, 0xfe, 0xff]
|
147
|
+
end
|
148
|
+
it "indirect, x" do
|
149
|
+
@asm.asm_instr('eor ($10,x)').should == [0x41, 0x10]
|
150
|
+
end
|
151
|
+
it "indirect, y" do
|
152
|
+
@asm.asm_instr('ora ($20),y').should == [0x11, 0x20]
|
153
|
+
end
|
154
|
+
it "relative" do
|
155
|
+
@asm.asm_instr('bne $12').should == [0xd0, 0x12]
|
156
|
+
end
|
157
|
+
end # end of "assembles a line of assembly"
|
158
|
+
|
159
|
+
# under "describe Assembler"
|
160
|
+
describe "puts machine code in memory" do
|
161
|
+
it "starts with pc = 0x600" do
|
162
|
+
@asm.pc.should == 0x600
|
163
|
+
end
|
164
|
+
it "places multiple bytes in memory, tracks pc" do
|
165
|
+
@asm.pc.should == 0x600
|
166
|
+
[0xa1, 0xb2, 0xc3, 0xd4].each {|b| @asm.write_byte(b) }
|
167
|
+
@mem.get_range(0x600, 0x603).should == [0xa1, 0xb2, 0xc3, 0xd4]
|
168
|
+
@asm.pc.should == 0x604
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# under "describe Assembler"
|
173
|
+
describe "assembles and places (multiple) lines" do
|
174
|
+
it "processes a 1-byte instruction" do
|
175
|
+
@asm.process_line('nop ; comment')
|
176
|
+
@asm.pc.should == 0x601
|
177
|
+
@mem.get(0x600).should == 0xea
|
178
|
+
end
|
179
|
+
it "processes a mixed-case 1-byte instruction" do
|
180
|
+
@asm.process_line('NOp ; comment')
|
181
|
+
@asm.pc.should == 0x601
|
182
|
+
@mem.get(0x600).should == 0xea
|
183
|
+
end
|
184
|
+
it "processes a 2-byte instruction" do
|
185
|
+
@asm.process_line('lda #$6c')
|
186
|
+
@asm.pc.should == 0x602
|
187
|
+
@mem.get_range(0x600, 0x601).should == [0xa9, 0x6c]
|
188
|
+
end
|
189
|
+
it "processes a 3-byte instruction" do
|
190
|
+
@asm.process_line('inc $2001')
|
191
|
+
@asm.pc.should == 0x603
|
192
|
+
@mem.get_range(0x600, 0x602).should == [0xee, 0x01, 0x20]
|
193
|
+
end
|
194
|
+
it "processes a few instructions" do
|
195
|
+
@asm.process_line('nop')
|
196
|
+
@asm.process_line('asl')
|
197
|
+
@asm.process_line('ldx $55')
|
198
|
+
@asm.pc.should == 0x604
|
199
|
+
@mem.get_range(0x600, 0x603).should == [0xea, 0x0a, 0xa6, 0x55]
|
200
|
+
end
|
201
|
+
it "processes instructions with leading labels" do
|
202
|
+
@asm.process_line('top: nop')
|
203
|
+
@asm.process_line('second: asl')
|
204
|
+
@asm.process_line('third ldx $55')
|
205
|
+
@asm.process_line('fourth')
|
206
|
+
@asm.pc.should == 0x604
|
207
|
+
@mem.get_range(0x600, 0x603).should == [0xea, 0x0a, 0xa6, 0x55]
|
208
|
+
@asm.label_get('top').should == 0x600
|
209
|
+
@asm.label_get('second').should == 0x601
|
210
|
+
@asm.label_get('third').should == 0x602
|
211
|
+
@asm.label_get('fourth').should == 0x604
|
212
|
+
end
|
213
|
+
it "processes instructions with referenced-to labels" do
|
214
|
+
@asm.process_line('jmp cleanup')
|
215
|
+
@mem.get_range(0x600, 0x602).should == [0x4c, 0xff, 0xff]
|
216
|
+
@asm.deferred.should == {0x601 => 'cleanup'}
|
217
|
+
@asm.pc.should == 0x603
|
218
|
+
end
|
219
|
+
it "processes relative-addressing labels" do
|
220
|
+
@asm.process_line('beq loop')
|
221
|
+
@mem.get_range(0x600, 0x602).should == [0xf0, 0xff, 0x00]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|