vcpu/core/
decode.rs

1use crate::{
2  core::{
3    cpu::Cpu,
4    instruction::{AddressingMode, Instruction, OpCode},
5  },
6  error::CpuError,
7};
8
9impl Cpu {
10  pub(crate) fn decode(&mut self, opcode: u8) -> Result<Instruction, CpuError> {
11    let (opcode, mode, cycles) = match opcode {
12      // ADC
13      0x69 => (OpCode::ADC, AddressingMode::immediate(self), 2),
14      0x65 => (OpCode::ADC, AddressingMode::zero_page(self), 3),
15      0x75 => (OpCode::ADC, AddressingMode::zero_page_x(self), 4),
16      0x6D => (OpCode::ADC, AddressingMode::absolute(self), 4),
17      0x7D => (OpCode::ADC, AddressingMode::absolute_x(self), 4),
18      0x79 => (OpCode::ADC, AddressingMode::absolute_y(self), 4),
19      0x61 => (OpCode::ADC, AddressingMode::indirect_x(self), 6),
20      0x71 => (OpCode::ADC, AddressingMode::indirect_y(self), 5),
21      // AND
22      0x29 => (OpCode::AND, AddressingMode::immediate(self), 2),
23      0x25 => (OpCode::AND, AddressingMode::zero_page(self), 3),
24      0x35 => (OpCode::AND, AddressingMode::zero_page_x(self), 4),
25      0x2D => (OpCode::AND, AddressingMode::absolute(self), 4),
26      0x3D => (OpCode::AND, AddressingMode::absolute_x(self), 4),
27      0x39 => (OpCode::AND, AddressingMode::absolute_y(self), 4),
28      0x21 => (OpCode::AND, AddressingMode::indirect_x(self), 6),
29      0x31 => (OpCode::AND, AddressingMode::indirect_y(self), 5),
30      // ASL
31      0x0A => (OpCode::ASL, AddressingMode::accumulator(self), 2),
32      0x06 => (OpCode::ASL, AddressingMode::zero_page(self), 5),
33      0x16 => (OpCode::ASL, AddressingMode::zero_page_x(self), 6),
34      0x0E => (OpCode::ASL, AddressingMode::absolute(self), 6),
35      0x1E => (OpCode::ASL, AddressingMode::absolute_x(self), 7),
36      // BIT
37      0x24 => (OpCode::BIT, AddressingMode::zero_page(self), 3),
38      0x2C => (OpCode::BIT, AddressingMode::absolute(self), 4),
39      // BRANCH
40      0x10 => (OpCode::BPL, AddressingMode::relative(self), 2),
41      0x30 => (OpCode::BMI, AddressingMode::relative(self), 2),
42      0x50 => (OpCode::BVC, AddressingMode::relative(self), 2),
43      0x70 => (OpCode::BVS, AddressingMode::relative(self), 2),
44      0x90 => (OpCode::BCC, AddressingMode::relative(self), 2),
45      0xB0 => (OpCode::BCS, AddressingMode::relative(self), 2),
46      0xD0 => (OpCode::BNE, AddressingMode::relative(self), 2),
47      0xF0 => (OpCode::BEQ, AddressingMode::relative(self), 2),
48      // BREAK
49      0x00 => (OpCode::BRK, AddressingMode::implied(self), 7),
50      // CMP
51      0xC9 => (OpCode::CMP, AddressingMode::immediate(self), 2),
52      0xC5 => (OpCode::CMP, AddressingMode::zero_page(self), 3),
53      0xD5 => (OpCode::CMP, AddressingMode::zero_page_x(self), 4),
54      0xCD => (OpCode::CMP, AddressingMode::absolute(self), 4),
55      0xDD => (OpCode::CMP, AddressingMode::absolute_x(self), 4),
56      0xD9 => (OpCode::CMP, AddressingMode::absolute_y(self), 4),
57      0xC1 => (OpCode::CMP, AddressingMode::indirect_x(self), 6),
58      0xD1 => (OpCode::CMP, AddressingMode::indirect_y(self), 5),
59      // CPX
60      0xE0 => (OpCode::CPX, AddressingMode::immediate(self), 2),
61      0xE4 => (OpCode::CPX, AddressingMode::zero_page(self), 3),
62      0xEC => (OpCode::CPX, AddressingMode::absolute(self), 4),
63      // CPY
64      0xC0 => (OpCode::CPY, AddressingMode::immediate(self), 2),
65      0xC4 => (OpCode::CPY, AddressingMode::zero_page(self), 3),
66      0xCC => (OpCode::CPY, AddressingMode::absolute(self), 4),
67      // DEC
68      0xC6 => (OpCode::DEC, AddressingMode::zero_page(self), 5),
69      0xD6 => (OpCode::DEC, AddressingMode::zero_page_x(self), 6),
70      0xCE => (OpCode::DEC, AddressingMode::absolute(self), 6),
71      0xDE => (OpCode::DEC, AddressingMode::absolute_x(self), 7),
72      // EOR
73      0x49 => (OpCode::EOR, AddressingMode::immediate(self), 2),
74      0x45 => (OpCode::EOR, AddressingMode::zero_page(self), 3),
75      0x55 => (OpCode::EOR, AddressingMode::zero_page_x(self), 4),
76      0x4D => (OpCode::EOR, AddressingMode::absolute(self), 4),
77      0x5D => (OpCode::EOR, AddressingMode::absolute_x(self), 4),
78      0x59 => (OpCode::EOR, AddressingMode::absolute_y(self), 4),
79      0x41 => (OpCode::EOR, AddressingMode::indirect_x(self), 6),
80      0x51 => (OpCode::EOR, AddressingMode::indirect_y(self), 5),
81      // FLAGS
82      0x18 => (OpCode::CLC, AddressingMode::implied(self), 2),
83      0x38 => (OpCode::SEC, AddressingMode::implied(self), 2),
84      0x58 => (OpCode::CLI, AddressingMode::implied(self), 2),
85      0x78 => (OpCode::SEI, AddressingMode::implied(self), 2),
86      0xB8 => (OpCode::CLV, AddressingMode::implied(self), 2),
87      0xD8 => (OpCode::CLD, AddressingMode::implied(self), 2),
88      0xF8 => (OpCode::SED, AddressingMode::implied(self), 2),
89      // INC
90      0xE6 => (OpCode::INC, AddressingMode::zero_page(self), 5),
91      0xF6 => (OpCode::INC, AddressingMode::zero_page_x(self), 6),
92      0xEE => (OpCode::INC, AddressingMode::absolute(self), 6),
93      0xFE => (OpCode::INC, AddressingMode::absolute_x(self), 7),
94      // JMP
95      0x4C => (OpCode::JMP, AddressingMode::absolute(self), 3),
96      0x6C => (OpCode::JMP, AddressingMode::indirect(self), 5),
97      // JSR
98      0x20 => (OpCode::JSR, AddressingMode::absolute(self), 6),
99      // LDA
100      0xA9 => (OpCode::LDA, AddressingMode::immediate(self), 2),
101      0xA5 => (OpCode::LDA, AddressingMode::zero_page(self), 3),
102      0xB5 => (OpCode::LDA, AddressingMode::zero_page_x(self), 4),
103      0xAD => (OpCode::LDA, AddressingMode::absolute(self), 4),
104      0xBD => (OpCode::LDA, AddressingMode::absolute_x(self), 4),
105      0xB9 => (OpCode::LDA, AddressingMode::absolute_y(self), 4),
106      0xA1 => (OpCode::LDA, AddressingMode::indirect_x(self), 6),
107      0xB1 => (OpCode::LDA, AddressingMode::indirect_y(self), 5),
108      // LDX
109      0xA2 => (OpCode::LDX, AddressingMode::immediate(self), 2),
110      0xA6 => (OpCode::LDX, AddressingMode::zero_page(self), 3),
111      0xB6 => (OpCode::LDX, AddressingMode::zero_page_y(self), 4),
112      0xAE => (OpCode::LDX, AddressingMode::absolute(self), 4),
113      0xBE => (OpCode::LDX, AddressingMode::absolute_y(self), 4),
114      // LDY
115      0xA0 => (OpCode::LDY, AddressingMode::immediate(self), 2),
116      0xA4 => (OpCode::LDY, AddressingMode::zero_page(self), 3),
117      0xB4 => (OpCode::LDY, AddressingMode::zero_page_x(self), 4),
118      0xAC => (OpCode::LDY, AddressingMode::absolute(self), 4),
119      0xBC => (OpCode::LDY, AddressingMode::absolute_x(self), 4),
120      // LSR
121      0x4A => (OpCode::LSR, AddressingMode::accumulator(self), 2),
122      0x46 => (OpCode::LSR, AddressingMode::zero_page(self), 5),
123      0x56 => (OpCode::LSR, AddressingMode::zero_page_x(self), 6),
124      0x4E => (OpCode::LSR, AddressingMode::absolute(self), 6),
125      0x5E => (OpCode::LSR, AddressingMode::absolute_x(self), 7),
126      // NOP
127      0xEA => (OpCode::NOP, AddressingMode::implied(self), 2),
128      // ORA
129      0x09 => (OpCode::ORA, AddressingMode::immediate(self), 2),
130      0x05 => (OpCode::ORA, AddressingMode::zero_page(self), 3),
131      0x15 => (OpCode::ORA, AddressingMode::zero_page_x(self), 4),
132      0x0D => (OpCode::ORA, AddressingMode::absolute(self), 4),
133      0x1D => (OpCode::ORA, AddressingMode::absolute_x(self), 4),
134      0x19 => (OpCode::ORA, AddressingMode::absolute_y(self), 4),
135      0x01 => (OpCode::ORA, AddressingMode::indirect_x(self), 6),
136      0x11 => (OpCode::ORA, AddressingMode::indirect_y(self), 5),
137      // REGISTER
138      0xAA => (OpCode::TAX, AddressingMode::implied(self), 2),
139      0x8A => (OpCode::TXA, AddressingMode::implied(self), 2),
140      0xCA => (OpCode::DEX, AddressingMode::implied(self), 2),
141      0xE8 => (OpCode::INX, AddressingMode::implied(self), 2),
142      0xA8 => (OpCode::TAY, AddressingMode::implied(self), 2),
143      0x98 => (OpCode::TYA, AddressingMode::implied(self), 2),
144      0x88 => (OpCode::DEY, AddressingMode::implied(self), 2),
145      0xC8 => (OpCode::INY, AddressingMode::implied(self), 2),
146      // ROL
147      0x2A => (OpCode::ROL, AddressingMode::accumulator(self), 2),
148      0x26 => (OpCode::ROL, AddressingMode::zero_page(self), 5),
149      0x36 => (OpCode::ROL, AddressingMode::zero_page_x(self), 6),
150      0x2E => (OpCode::ROL, AddressingMode::absolute(self), 6),
151      0x3E => (OpCode::ROL, AddressingMode::absolute_x(self), 7),
152      // ROR
153      0x6A => (OpCode::ROR, AddressingMode::accumulator(self), 2),
154      0x66 => (OpCode::ROR, AddressingMode::zero_page(self), 5),
155      0x76 => (OpCode::ROR, AddressingMode::zero_page_x(self), 6),
156      0x6E => (OpCode::ROR, AddressingMode::absolute(self), 6),
157      0x7E => (OpCode::ROR, AddressingMode::absolute_x(self), 7),
158      // RTI
159      0x40 => (OpCode::RTI, AddressingMode::implied(self), 6),
160      // RTS
161      0x60 => (OpCode::RTS, AddressingMode::implied(self), 6),
162      // SBC
163      0xE9 => (OpCode::SBC, AddressingMode::immediate(self), 2),
164      0xE5 => (OpCode::SBC, AddressingMode::zero_page(self), 3),
165      0xF5 => (OpCode::SBC, AddressingMode::zero_page_x(self), 4),
166      0xED => (OpCode::SBC, AddressingMode::absolute(self), 4),
167      0xFD => (OpCode::SBC, AddressingMode::absolute_x(self), 4),
168      0xF9 => (OpCode::SBC, AddressingMode::absolute_y(self), 4),
169      0xE1 => (OpCode::SBC, AddressingMode::indirect_x(self), 6),
170      0xF1 => (OpCode::SBC, AddressingMode::indirect_y(self), 5),
171      // STA
172      0x85 => (OpCode::STA, AddressingMode::zero_page(self), 3),
173      0x95 => (OpCode::STA, AddressingMode::zero_page_x(self), 4),
174      0x8D => (OpCode::STA, AddressingMode::absolute(self), 4),
175      0x9D => (OpCode::STA, AddressingMode::absolute_x(self), 5),
176      0x99 => (OpCode::STA, AddressingMode::absolute_y(self), 5),
177      0x81 => (OpCode::STA, AddressingMode::indirect_x(self), 6),
178      0x91 => (OpCode::STA, AddressingMode::indirect_y(self), 6),
179      // STACK
180      0x9A => (OpCode::TXS, AddressingMode::implied(self), 2),
181      0xBA => (OpCode::TSX, AddressingMode::implied(self), 2),
182      0x48 => (OpCode::PHA, AddressingMode::implied(self), 3),
183      0x68 => (OpCode::PLA, AddressingMode::implied(self), 4),
184      0x08 => (OpCode::PHP, AddressingMode::implied(self), 3),
185      0x28 => (OpCode::PLP, AddressingMode::implied(self), 4),
186      // STX
187      0x86 => (OpCode::STX, AddressingMode::zero_page(self), 3),
188      0x96 => (OpCode::STX, AddressingMode::zero_page_y(self), 4),
189      0x8E => (OpCode::STX, AddressingMode::absolute(self), 4),
190      // STY
191      0x84 => (OpCode::STY, AddressingMode::zero_page(self), 3),
192      0x94 => (OpCode::STY, AddressingMode::zero_page_x(self), 4),
193      0x8C => (OpCode::STY, AddressingMode::absolute(self), 4),
194      _ => Err(CpuError::InvalidOpCode(opcode))?,
195    };
196
197    let mode = mode?;
198
199    Ok(Instruction { opcode, mode, cycles })
200  }
201}