1 #include "chip8.h"
2 #include "chip8_printer.h"
3
4 #define SET_DECODE_TO(opmask, cb) m_opcodes[opmask] = [this](u16 opcode, const InstructionPtr& instruction) -> bool { return cb(opcode, instruction); };
5
6 namespace REDasm {
7
CHIP8Assembler()8 CHIP8Assembler::CHIP8Assembler(): AssemblerPlugin()
9 {
10 SET_DECODE_TO(0x0000, decode0xxx);
11 SET_DECODE_TO(0x1000, decode1xxx);
12 SET_DECODE_TO(0x2000, decode2xxx);
13 SET_DECODE_TO(0x3000, decode3xxx);
14 SET_DECODE_TO(0x4000, decode4xxx);
15 SET_DECODE_TO(0x5000, decode5xxx);
16 SET_DECODE_TO(0x6000, decode6xxx);
17 SET_DECODE_TO(0x7000, decode7xxx);
18 SET_DECODE_TO(0x8000, decode8xxx);
19 SET_DECODE_TO(0x9000, decode9xxx);
20 SET_DECODE_TO(0xA000, decodeAxxx);
21 SET_DECODE_TO(0xB000, decodeBxxx);
22 SET_DECODE_TO(0xC000, decodeCxxx);
23 SET_DECODE_TO(0xD000, decodeDxxx);
24 SET_DECODE_TO(0xE000, decodeExxx);
25 SET_DECODE_TO(0xF000, decodeFxxx);
26 }
27
createPrinter(DisassemblerAPI * disassembler) const28 Printer *CHIP8Assembler::createPrinter(DisassemblerAPI *disassembler) const { return new CHIP8Printer(disassembler); }
29
decodeInstruction(const BufferView & view,const InstructionPtr & instruction)30 bool CHIP8Assembler::decodeInstruction(const BufferView& view, const InstructionPtr &instruction)
31 {
32 u16be opcode = static_cast<u16be>(view);
33 instruction->id = opcode;
34 instruction->size = sizeof(u16);
35
36 auto it = m_opcodes.find(opcode & 0xF000);
37
38 if((it == m_opcodes.end()) || !it->second(opcode, instruction))
39 return false;
40
41 return true;
42 }
43
onDecoded(const InstructionPtr & instruction)44 void CHIP8Assembler::onDecoded(const InstructionPtr &instruction)
45 {
46 if(instruction->mnemonic == "rts")
47 instruction->type = InstructionType::Stop;
48 else if(instruction->mnemonic == "jmp")
49 instruction->type = InstructionType::Jump;
50 else if((instruction->mnemonic == "ske") || (instruction->mnemonic == "skne") || (instruction->mnemonic == "skp") || (instruction->mnemonic == "sknp"))
51 instruction->type = InstructionType::ConditionalJump;
52 else if(instruction->mnemonic == "call")
53 instruction->type = InstructionType::Call;
54 else if(instruction->mnemonic == "add")
55 instruction->type = InstructionType::Add;
56 else if(instruction->mnemonic == "sub")
57 instruction->type = InstructionType::Sub;
58 else if(instruction->mnemonic == "and")
59 instruction->type = InstructionType::And;
60 else if(instruction->mnemonic == "or")
61 instruction->type = InstructionType::Or;
62 else if(instruction->mnemonic == "xor")
63 instruction->type = InstructionType::Xor;
64 else if((instruction->mnemonic == "mov") || (instruction->mnemonic == "ldra"))
65 instruction->type = InstructionType::Load;
66 else if(instruction->mnemonic == "stra")
67 instruction->type = InstructionType::Store;
68 else if(instruction->mnemonic == "sys")
69 instruction->type = InstructionType::Privileged;
70 }
71
decode0xxx(u16 opcode,const InstructionPtr & instruction) const72 bool CHIP8Assembler::decode0xxx(u16 opcode, const InstructionPtr &instruction) const
73 {
74 if(opcode == 0x00E0)
75 instruction->mnemonic = "cls";
76 else if(opcode == 0x00EE)
77 instruction->mnemonic = "rts";
78 else if(opcode == 0x00FB) // SuperChip only
79 instruction->mnemonic = "scright";
80 else if(opcode == 0x00FC) // SuperChip only
81 instruction->mnemonic = "scleft";
82 else if(opcode == 0x00FE) // SuperChip only
83 instruction->mnemonic = "low";
84 else if(opcode == 0x00FF) // SuperChip only
85 instruction->mnemonic = "high";
86 else if((opcode & 0x00F0) == 0x00C0) // SuperChip only
87 {
88 instruction->mnemonic = "scdown";
89 instruction->cnst(opcode & 0x000F);
90 }
91 else
92 {
93 instruction->mnemonic = "sys";
94 instruction->cnst(opcode & 0x0FFF);
95 }
96
97 return true;
98 }
99
decode1xxx(u16 opcode,const InstructionPtr & instruction) const100 bool CHIP8Assembler::decode1xxx(u16 opcode, const InstructionPtr &instruction) const
101 {
102 instruction->mnemonic = "jmp";
103 instruction->imm(opcode & 0x0FFF);
104 instruction->targetIdx(0);
105 return true;
106 }
107
decode2xxx(u16 opcode,const InstructionPtr & instruction) const108 bool CHIP8Assembler::decode2xxx(u16 opcode, const InstructionPtr &instruction) const
109 {
110 instruction->mnemonic = "call";
111 instruction->imm(opcode & 0x0FFF);
112 instruction->targetIdx(0);
113 return true;
114 }
115
decode3xxx(u16 opcode,const InstructionPtr & instruction) const116 bool CHIP8Assembler::decode3xxx(u16 opcode, const InstructionPtr &instruction) const
117 {
118 instruction->mnemonic = "ske";
119 instruction->reg((opcode & 0x0F00) >> 8);
120 instruction->imm(opcode & 0x00FF);
121 instruction->target(instruction->endAddress() + instruction->size);
122 return true;
123 }
124
decode4xxx(u16 opcode,const InstructionPtr & instruction) const125 bool CHIP8Assembler::decode4xxx(u16 opcode, const InstructionPtr &instruction) const
126 {
127 instruction->mnemonic = "skne";
128 instruction->reg((opcode & 0x0F00) >> 8);
129 instruction->imm(opcode & 0x00FF);
130 instruction->target(instruction->endAddress() + instruction->size);
131 return true;
132 }
133
decode5xxx(u16 opcode,const InstructionPtr & instruction) const134 bool CHIP8Assembler::decode5xxx(u16 opcode, const InstructionPtr &instruction) const
135 {
136 if((opcode & 0x000F) != 0)
137 return false;
138
139 instruction->mnemonic = "ske";
140 instruction->reg((opcode & 0x0F00) >> 8);
141 instruction->reg((opcode & 0x00F0) >> 4);
142 instruction->target(instruction->endAddress() + instruction->size);
143 return true;
144 }
145
decode6xxx(u16 opcode,const InstructionPtr & instruction) const146 bool CHIP8Assembler::decode6xxx(u16 opcode, const InstructionPtr &instruction) const
147 {
148 instruction->mnemonic = "mov";
149 instruction->reg((opcode & 0x0F00) >> 8);
150 instruction->cnst(opcode & 0x00FF);
151 return true;
152 }
153
decode7xxx(u16 opcode,const InstructionPtr & instruction) const154 bool CHIP8Assembler::decode7xxx(u16 opcode, const InstructionPtr &instruction) const
155 {
156 instruction->mnemonic = "add";
157 instruction->reg((opcode & 0x0F00) >> 8);
158 instruction->cnst(opcode & 0x00FF);
159 return true;
160 }
161
decode8xxx(u16 opcode,const InstructionPtr & instruction) const162 bool CHIP8Assembler::decode8xxx(u16 opcode, const InstructionPtr &instruction) const
163 {
164 u8 op = opcode & 0x000F;
165
166 if(op == 0x0)
167 instruction->mnemonic = "mov";
168 else if(op == 0x1)
169 instruction->mnemonic = "or";
170 else if(op == 0x2)
171 instruction->mnemonic = "and";
172 else if(op == 0x3)
173 instruction->mnemonic = "xor";
174 else if(op == 0x4)
175 instruction->mnemonic = "add";
176 else if(op == 0x5)
177 instruction->mnemonic = "sub";
178 else if(op == 0x6)
179 instruction->mnemonic = "shr";
180 else if(op == 0x7)
181 instruction->mnemonic = "sub";
182 else if(op == 0xE)
183 instruction->mnemonic = "shl";
184 else
185 return false;
186
187 instruction->reg((opcode & 0x0F00) >> 8);
188
189 if((op != 0x6) && (op != 0xE)) // Skip 2nd operand if op == shift_instructions
190 instruction->reg((opcode & 0x00F0) >> 4);
191
192 return true;
193 }
194
decode9xxx(u16 opcode,const InstructionPtr & instruction) const195 bool CHIP8Assembler::decode9xxx(u16 opcode, const InstructionPtr &instruction) const
196 {
197 if((opcode & 0x000F) != 0)
198 return false;
199
200 instruction->mnemonic = "skne";
201 instruction->reg((opcode & 0x0F00) >> 8);
202 instruction->reg((opcode & 0x00F0) >> 4);
203 instruction->target(instruction->endAddress() + instruction->size);
204 return true;
205 }
206
decodeAxxx(u16 opcode,const InstructionPtr & instruction) const207 bool CHIP8Assembler::decodeAxxx(u16 opcode, const InstructionPtr &instruction) const
208 {
209 instruction->mnemonic = "mov";
210 instruction->reg(CHIP8_REG_I_ID, CHIP8_REG_I);
211 instruction->cnst(opcode & 0x0FFF);
212 return true;
213 }
214
decodeBxxx(u16 opcode,const InstructionPtr & instruction) const215 bool CHIP8Assembler::decodeBxxx(u16 opcode, const InstructionPtr &instruction) const
216 {
217 instruction->mnemonic = "jmp";
218 instruction->disp(CHIP8_REG_V0_ID, opcode & 0x0FFF);
219 return true;
220 }
221
decodeCxxx(u16 opcode,const InstructionPtr & instruction) const222 bool CHIP8Assembler::decodeCxxx(u16 opcode, const InstructionPtr &instruction) const
223 {
224 instruction->mnemonic = "rand";
225 instruction->reg((opcode & 0x0F00) >> 8);
226 instruction->cnst(opcode & 0x00FF);
227 return true;
228 }
229
decodeDxxx(u16 opcode,const InstructionPtr & instruction) const230 bool CHIP8Assembler::decodeDxxx(u16 opcode, const InstructionPtr &instruction) const
231 {
232 instruction->mnemonic = "draw";
233 instruction->reg((opcode & 0x0F00) >> 8);
234 instruction->reg((opcode & 0x00F0) >> 4);
235 instruction->cnst(opcode & 0x000F);
236 return true;
237 }
238
decodeExxx(u16 opcode,const InstructionPtr & instruction) const239 bool CHIP8Assembler::decodeExxx(u16 opcode, const InstructionPtr &instruction) const
240 {
241 u16 op = opcode & 0xFF;
242
243 if(op == 0x9E)
244 instruction->mnemonic = "skp";
245 else if(op == 0xA1)
246 instruction->mnemonic = "sknp";
247
248 instruction->reg((opcode & 0x0F00) >> 8, CHIP8_REG_K);
249 instruction->target(instruction->endAddress() + instruction->size);
250 return true;
251 }
252
decodeFxxx(u16 opcode,const InstructionPtr & instruction) const253 bool CHIP8Assembler::decodeFxxx(u16 opcode, const InstructionPtr &instruction) const
254 {
255 u16 op = opcode & 0x00FF;
256
257 if(op == 0x07)
258 instruction->mnemonic = "gdelay";
259 else if(op == 0x0A)
260 instruction->mnemonic = "wkey";
261 else if(op == 0x15)
262 instruction->mnemonic = "sdelay";
263 else if(op == 0x18)
264 instruction->mnemonic = "ssound";
265 else if(op == 0x1E)
266 {
267 instruction->mnemonic = "add";
268 instruction->reg(CHIP8_REG_I_ID, CHIP8_REG_I);
269 }
270 else if(op == 0x29)
271 instruction->mnemonic = "font";
272 else if(op == 0x30) // SuperChip only
273 instruction->mnemonic = "xfont";
274 else if(op == 0x33)
275 instruction->mnemonic = "bcd";
276 else if(op == 0x55)
277 instruction->mnemonic = "stra";
278 else if(op == 0x65)
279 instruction->mnemonic = "ldra";
280 else
281 return false;
282
283 instruction->reg((opcode & 0x0F00) >> 8);
284 return true;
285 }
286
287 } // namespace REDasm
288