]>
Commit | Line | Data |
---|---|---|
26da232c MF |
1 | /* Example synacor simulator. |
2 | ||
3 | Copyright (C) 2005-2021 Free Software Foundation, Inc. | |
4 | Contributed by Mike Frysinger. | |
5 | ||
6 | This file is part of simulators. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | /* This file contains the main simulator decoding logic. i.e. everything that | |
22 | is architecture specific. */ | |
23 | ||
6df01ab8 MF |
24 | /* This must come before any other includes. */ |
25 | #include "defs.h" | |
26da232c MF |
26 | |
27 | #include "sim-main.h" | |
1fef66b0 | 28 | #include "sim-signal.h" |
26da232c MF |
29 | \f |
30 | /* Get the register number from the number. */ | |
31 | static unsigned16 | |
32 | register_num (SIM_CPU *cpu, unsigned16 num) | |
33 | { | |
34 | SIM_DESC sd = CPU_STATE (cpu); | |
35 | ||
36 | if (num < 0x8000 || num >= 0x8008) | |
37 | sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); | |
38 | ||
39 | return num & 0xf; | |
40 | } | |
41 | ||
42 | /* Helper to process immediates according to the ISA. */ | |
43 | static unsigned16 | |
44 | interp_num (SIM_CPU *cpu, unsigned16 num) | |
45 | { | |
46 | SIM_DESC sd = CPU_STATE (cpu); | |
47 | ||
48 | if (num < 0x8000) | |
49 | { | |
50 | /* Numbers 0..32767 mean a literal value. */ | |
51 | TRACE_DECODE (cpu, "%#x is a literal", num); | |
52 | return num; | |
53 | } | |
54 | else if (num < 0x8008) | |
55 | { | |
56 | /* Numbers 32768..32775 instead mean registers 0..7. */ | |
57 | TRACE_DECODE (cpu, "%#x is register R%i", num, num & 0xf); | |
58 | return cpu->regs[num & 0xf]; | |
59 | } | |
60 | else | |
61 | { | |
62 | /* Numbers 32776..65535 are invalid. */ | |
63 | TRACE_DECODE (cpu, "%#x is an invalid number", num); | |
64 | sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL); | |
65 | } | |
66 | } | |
67 | \f | |
68 | /* Decode & execute a single instruction. */ | |
69 | void step_once (SIM_CPU *cpu) | |
70 | { | |
71 | SIM_DESC sd = CPU_STATE (cpu); | |
72 | unsigned16 iw1, num1; | |
73 | sim_cia pc = sim_pc_get (cpu); | |
74 | ||
75 | iw1 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc); | |
76 | TRACE_EXTRACT (cpu, "%04x: iw1: %#x", pc, iw1); | |
77 | /* This never happens, but technically is possible in the ISA. */ | |
78 | num1 = interp_num (cpu, iw1); | |
79 | ||
80 | if (num1 == 0) | |
81 | { | |
82 | /* halt: 0: Stop execution and terminate the program. */ | |
83 | TRACE_INSN (cpu, "HALT"); | |
84 | sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0); | |
85 | } | |
86 | else if (num1 == 1) | |
87 | { | |
88 | /* set: 1 a b: Set register <a> to the value of <b>. */ | |
89 | unsigned16 iw2, iw3, num2, num3; | |
90 | ||
91 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
92 | num2 = register_num (cpu, iw2); | |
93 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
94 | num3 = interp_num (cpu, iw3); | |
95 | TRACE_EXTRACT (cpu, "SET %#x %#x", iw2, iw3); | |
96 | TRACE_INSN (cpu, "SET R%i %#x", num2, num3); | |
97 | ||
98 | TRACE_REGISTER (cpu, "R%i = %#x", num2, num3); | |
99 | cpu->regs[num2] = num3; | |
100 | ||
101 | pc += 6; | |
102 | } | |
103 | else if (num1 == 2) | |
104 | { | |
105 | /* push: 2 a: Push <a> onto the stack. */ | |
106 | unsigned16 iw2, num2; | |
107 | ||
108 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
109 | num2 = interp_num (cpu, iw2); | |
110 | TRACE_EXTRACT (cpu, "PUSH %#x", iw2); | |
111 | TRACE_INSN (cpu, "PUSH %#x", num2); | |
112 | ||
113 | sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, num2); | |
114 | cpu->sp -= 2; | |
115 | TRACE_REGISTER (cpu, "SP = %#x", cpu->sp); | |
116 | ||
117 | pc += 4; | |
118 | } | |
119 | else if (num1 == 3) | |
120 | { | |
121 | /* pop: 3 a: Remove the top element from the stack and write it into <a>. | |
122 | Empty stack = error. */ | |
123 | unsigned16 iw2, num2, result; | |
124 | ||
125 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
126 | num2 = register_num (cpu, iw2); | |
127 | TRACE_EXTRACT (cpu, "POP %#x", iw2); | |
128 | TRACE_INSN (cpu, "POP R%i", num2); | |
129 | cpu->sp += 2; | |
130 | TRACE_REGISTER (cpu, "SP = %#x", cpu->sp); | |
131 | result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp); | |
132 | ||
133 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
134 | cpu->regs[num2] = result; | |
135 | ||
136 | pc += 4; | |
137 | } | |
138 | else if (num1 == 4) | |
139 | { | |
140 | /* eq: 4 a b c: Set <a> to 1 if <b> is equal to <c>; set it to 0 | |
141 | otherwise. */ | |
142 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
143 | ||
144 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
145 | num2 = register_num (cpu, iw2); | |
146 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
147 | num3 = interp_num (cpu, iw3); | |
148 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
149 | num4 = interp_num (cpu, iw4); | |
150 | result = (num3 == num4); | |
151 | TRACE_EXTRACT (cpu, "EQ %#x %#x %#x", iw2, iw3, iw4); | |
152 | TRACE_INSN (cpu, "EQ R%i %#x %#x", num2, num3, num4); | |
153 | TRACE_DECODE (cpu, "R%i = (%#x == %#x) = %i", num2, num3, num4, result); | |
154 | ||
155 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
156 | cpu->regs[num2] = result; | |
157 | ||
158 | pc += 8; | |
159 | } | |
160 | else if (num1 == 5) | |
161 | { | |
162 | /* gt: 5 a b c: Set <a> to 1 if <b> is greater than <c>; set it to 0 | |
163 | otherwise. */ | |
164 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
165 | ||
166 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
167 | num2 = register_num (cpu, iw2); | |
168 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
169 | num3 = interp_num (cpu, iw3); | |
170 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
171 | num4 = interp_num (cpu, iw4); | |
172 | result = (num3 > num4); | |
173 | TRACE_EXTRACT (cpu, "GT %#x %#x %#x", iw2, iw3, iw4); | |
174 | TRACE_INSN (cpu, "GT R%i %#x %#x", num2, num3, num4); | |
175 | TRACE_DECODE (cpu, "R%i = (%#x > %#x) = %i", num2, num3, num4, result); | |
176 | ||
177 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
178 | cpu->regs[num2] = result; | |
179 | ||
180 | pc += 8; | |
181 | } | |
182 | else if (num1 == 6) | |
183 | { | |
184 | /* jmp: 6 a: Jump to <a>. */ | |
185 | unsigned16 iw2, num2; | |
186 | ||
187 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
188 | num2 = interp_num (cpu, iw2); | |
189 | /* Addresses are 16-bit aligned. */ | |
190 | num2 <<= 1; | |
191 | TRACE_EXTRACT (cpu, "JMP %#x", iw2); | |
192 | TRACE_INSN (cpu, "JMP %#x", num2); | |
193 | ||
194 | pc = num2; | |
195 | TRACE_BRANCH (cpu, "JMP %#x", pc); | |
196 | } | |
197 | else if (num1 == 7) | |
198 | { | |
199 | /* jt: 7 a b: If <a> is nonzero, jump to <b>. */ | |
200 | unsigned16 iw2, iw3, num2, num3; | |
201 | ||
202 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
203 | num2 = interp_num (cpu, iw2); | |
204 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
205 | num3 = interp_num (cpu, iw3); | |
206 | /* Addresses are 16-bit aligned. */ | |
207 | num3 <<= 1; | |
208 | TRACE_EXTRACT (cpu, "JT %#x %#x", iw2, iw3); | |
209 | TRACE_INSN (cpu, "JT %#x %#x", num2, num3); | |
210 | TRACE_DECODE (cpu, "JT %#x != 0 -> %s", num2, num2 ? "taken" : "nop"); | |
211 | ||
212 | if (num2) | |
213 | { | |
214 | pc = num3; | |
215 | TRACE_BRANCH (cpu, "JT %#x", pc); | |
216 | } | |
217 | else | |
218 | pc += 6; | |
219 | } | |
220 | else if (num1 == 8) | |
221 | { | |
222 | /* jf: 8 a b: If <a> is zero, jump to <b>. */ | |
223 | unsigned16 iw2, iw3, num2, num3; | |
224 | ||
225 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
226 | num2 = interp_num (cpu, iw2); | |
227 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
228 | num3 = interp_num (cpu, iw3); | |
229 | /* Addresses are 16-bit aligned. */ | |
230 | num3 <<= 1; | |
231 | TRACE_EXTRACT (cpu, "JF %#x %#x", iw2, iw3); | |
232 | TRACE_INSN (cpu, "JF %#x %#x", num2, num3); | |
233 | TRACE_DECODE (cpu, "JF %#x == 0 -> %s", num2, num2 ? "nop" : "taken"); | |
234 | ||
235 | if (!num2) | |
236 | { | |
237 | pc = num3; | |
238 | TRACE_BRANCH (cpu, "JF %#x", pc); | |
239 | } | |
240 | else | |
241 | pc += 6; | |
242 | } | |
243 | else if (num1 == 9) | |
244 | { | |
245 | /* add: 9 a b c: Assign <a> the sum of <b> and <c> (modulo 32768). */ | |
246 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
247 | ||
248 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
249 | num2 = register_num (cpu, iw2); | |
250 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
251 | num3 = interp_num (cpu, iw3); | |
252 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
253 | num4 = interp_num (cpu, iw4); | |
254 | result = (num3 + num4) % 32768; | |
255 | TRACE_EXTRACT (cpu, "ADD %#x %#x %#x", iw2, iw3, iw4); | |
256 | TRACE_INSN (cpu, "ADD R%i %#x %#x", num2, num3, num4); | |
257 | TRACE_DECODE (cpu, "R%i = (%#x + %#x) %% %i = %#x", num2, num3, num4, | |
258 | 32768, result); | |
259 | ||
260 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
261 | cpu->regs[num2] = result; | |
262 | ||
263 | pc += 8; | |
264 | } | |
265 | else if (num1 == 10) | |
266 | { | |
267 | /* mult: 10 a b c: Store into <a> the product of <b> and <c> (modulo | |
268 | 32768). */ | |
269 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
270 | ||
271 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
272 | num2 = register_num (cpu, iw2); | |
273 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
274 | num3 = interp_num (cpu, iw3); | |
275 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
276 | num4 = interp_num (cpu, iw4); | |
277 | result = (num3 * num4) % 32768; | |
278 | TRACE_EXTRACT (cpu, "MULT %#x %#x %#x", iw2, iw3, iw4); | |
279 | TRACE_INSN (cpu, "MULT R%i %#x %#x", num2, num3, num4); | |
280 | TRACE_DECODE (cpu, "R%i = (%#x * %#x) %% %i = %#x", num2, num3, num4, | |
281 | 32768, result); | |
282 | ||
283 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
284 | cpu->regs[num2] = result; | |
285 | ||
286 | pc += 8; | |
287 | } | |
288 | else if (num1 == 11) | |
289 | { | |
290 | /* mod: 11 a b c: Store into <a> the remainder of <b> divided by <c>. */ | |
291 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
292 | ||
293 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
294 | num2 = register_num (cpu, iw2); | |
295 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
296 | num3 = interp_num (cpu, iw3); | |
297 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
298 | num4 = interp_num (cpu, iw4); | |
299 | result = num3 % num4; | |
300 | TRACE_EXTRACT (cpu, "MOD %#x %#x %#x", iw2, iw3, iw4); | |
301 | TRACE_INSN (cpu, "MOD R%i %#x %#x", num2, num3, num4); | |
302 | TRACE_DECODE (cpu, "R%i = %#x %% %#x = %#x", num2, num3, num4, result); | |
303 | ||
304 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
305 | cpu->regs[num2] = result; | |
306 | ||
307 | pc += 8; | |
308 | } | |
309 | else if (num1 == 12) | |
310 | { | |
311 | /* and: 12 a b c: Stores into <a> the bitwise and of <b> and <c>. */ | |
312 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
313 | ||
314 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
315 | num2 = register_num (cpu, iw2); | |
316 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
317 | num3 = interp_num (cpu, iw3); | |
318 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
319 | num4 = interp_num (cpu, iw4); | |
320 | result = (num3 & num4); | |
321 | TRACE_EXTRACT (cpu, "AND %#x %#x %#x", iw2, iw3, iw4); | |
322 | TRACE_INSN (cpu, "AND R%i %#x %#x", num2, num3, num4); | |
323 | TRACE_DECODE (cpu, "R%i = %#x & %#x = %#x", num2, num3, num4, result); | |
324 | ||
325 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
326 | cpu->regs[num2] = result; | |
327 | ||
328 | pc += 8; | |
329 | } | |
330 | else if (num1 == 13) | |
331 | { | |
332 | /* or: 13 a b c: Stores into <a> the bitwise or of <b> and <c>. */ | |
333 | unsigned16 iw2, iw3, iw4, num2, num3, num4, result; | |
334 | ||
335 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
336 | num2 = register_num (cpu, iw2); | |
337 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
338 | num3 = interp_num (cpu, iw3); | |
339 | iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6); | |
340 | num4 = interp_num (cpu, iw4); | |
341 | result = (num3 | num4); | |
342 | TRACE_EXTRACT (cpu, "OR %#x %#x %#x", iw2, iw3, iw4); | |
343 | TRACE_INSN (cpu, "OR R%i %#x %#x", num2, num3, num4); | |
344 | TRACE_DECODE (cpu, "R%i = %#x | %#x = %#x", num2, num3, num4, result); | |
345 | ||
346 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
347 | cpu->regs[num2] = result; | |
348 | ||
349 | pc += 8; | |
350 | } | |
351 | else if (num1 == 14) | |
352 | { | |
353 | /* not: 14 a b: Stores 15-bit bitwise inverse of <b> in <a>. */ | |
354 | unsigned16 iw2, iw3, num2, num3, result; | |
355 | ||
356 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
357 | num2 = register_num (cpu, iw2); | |
358 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
359 | num3 = interp_num (cpu, iw3); | |
360 | result = (~num3) & 0x7fff; | |
361 | TRACE_EXTRACT (cpu, "NOT %#x %#x", iw2, iw3); | |
362 | TRACE_INSN (cpu, "NOT R%i %#x", num2, num3); | |
363 | TRACE_DECODE (cpu, "R%i = (~%#x) & 0x7fff = %#x", num2, num3, result); | |
364 | ||
365 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
366 | cpu->regs[num2] = result; | |
367 | ||
368 | pc += 6; | |
369 | } | |
370 | else if (num1 == 15) | |
371 | { | |
372 | /* rmem: 15 a b: Read memory at address <b> and write it to <a>. */ | |
373 | unsigned16 iw2, iw3, num2, num3, result; | |
374 | ||
375 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
376 | num2 = register_num (cpu, iw2); | |
377 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
378 | num3 = interp_num (cpu, iw3); | |
379 | /* Addresses are 16-bit aligned. */ | |
380 | num3 <<= 1; | |
381 | TRACE_EXTRACT (cpu, "RMEM %#x %#x", iw2, iw3); | |
382 | TRACE_INSN (cpu, "RMEM R%i %#x", num2, num3); | |
383 | ||
384 | TRACE_MEMORY (cpu, "reading %#x", num3); | |
385 | result = sim_core_read_aligned_2 (cpu, pc, read_map, num3); | |
386 | ||
387 | TRACE_REGISTER (cpu, "R%i = %#x", num2, result); | |
388 | cpu->regs[num2] = result; | |
389 | ||
390 | pc += 6; | |
391 | } | |
392 | else if (num1 == 16) | |
393 | { | |
394 | /* wmem: 16 a b: Write the value from <b> into memory at address <a>. */ | |
395 | unsigned16 iw2, iw3, num2, num3; | |
396 | ||
397 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
398 | num2 = interp_num (cpu, iw2); | |
399 | iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4); | |
400 | num3 = interp_num (cpu, iw3); | |
401 | /* Addresses are 16-bit aligned. */ | |
402 | num2 <<= 1; | |
403 | TRACE_EXTRACT (cpu, "WMEM %#x %#x", iw2, iw3); | |
404 | TRACE_INSN (cpu, "WMEM %#x %#x", num2, num3); | |
405 | ||
406 | TRACE_MEMORY (cpu, "writing %#x to %#x", num3, num2); | |
407 | sim_core_write_aligned_2 (cpu, pc, write_map, num2, num3); | |
408 | ||
409 | pc += 6; | |
410 | } | |
411 | else if (num1 == 17) | |
412 | { | |
413 | /* call: 17 a: Write the address of the next instruction to the stack and | |
414 | jump to <a>. */ | |
415 | unsigned16 iw2, num2; | |
416 | ||
417 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
418 | num2 = interp_num (cpu, iw2); | |
419 | /* Addresses are 16-bit aligned. */ | |
420 | num2 <<= 1; | |
421 | TRACE_EXTRACT (cpu, "CALL %#x", iw2); | |
422 | TRACE_INSN (cpu, "CALL %#x", num2); | |
423 | ||
424 | TRACE_MEMORY (cpu, "pushing %#x onto stack", (pc + 4) >> 1); | |
425 | sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, (pc + 4) >> 1); | |
426 | cpu->sp -= 2; | |
427 | TRACE_REGISTER (cpu, "SP = %#x", cpu->sp); | |
428 | ||
429 | pc = num2; | |
430 | TRACE_BRANCH (cpu, "CALL %#x", pc); | |
431 | } | |
432 | else if (num1 == 18) | |
433 | { | |
434 | /* ret: 18: Remove the top element from the stack and jump to it; empty | |
435 | stack = halt. */ | |
436 | unsigned16 result; | |
437 | ||
438 | TRACE_INSN (cpu, "RET"); | |
439 | cpu->sp += 2; | |
440 | TRACE_REGISTER (cpu, "SP = %#x", cpu->sp); | |
441 | result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp); | |
442 | TRACE_MEMORY (cpu, "popping %#x off of stack", result << 1); | |
443 | ||
444 | pc = result << 1; | |
445 | TRACE_BRANCH (cpu, "RET -> %#x", pc); | |
446 | } | |
447 | else if (num1 == 19) | |
448 | { | |
449 | /* out: 19 a: Write the character <a> to the terminal. */ | |
450 | unsigned16 iw2, num2; | |
451 | ||
452 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
453 | num2 = interp_num (cpu, iw2); | |
454 | TRACE_EXTRACT (cpu, "OUT %#x", iw2); | |
455 | TRACE_INSN (cpu, "OUT %#x", num2); | |
456 | TRACE_EVENTS (cpu, "write to stdout: %#x (%c)", num2, num2); | |
457 | ||
458 | sim_io_printf (sd, "%c", num2); | |
459 | ||
460 | pc += 4; | |
461 | } | |
462 | else if (num1 == 20) | |
463 | { | |
464 | /* in: 20 a: read a character from the terminal and write its ascii code | |
465 | to <a>. It can be assumed that once input starts, it will continue | |
466 | until a newline is encountered. This means that you can safely read | |
467 | lines from the keyboard and trust that they will be fully read. */ | |
468 | unsigned16 iw2, num2; | |
469 | char c; | |
470 | ||
471 | iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2); | |
472 | num2 = register_num (cpu, iw2); | |
473 | TRACE_EXTRACT (cpu, "IN %#x", iw2); | |
474 | TRACE_INSN (cpu, "IN %#x", num2); | |
475 | sim_io_read_stdin (sd, &c, 1); | |
476 | TRACE_EVENTS (cpu, "read from stdin: %#x (%c)", c, c); | |
477 | ||
478 | /* The challenge uses lowercase for all inputs, so insert some low level | |
479 | helpers of our own to make it a bit nicer. */ | |
480 | switch (c) | |
481 | { | |
482 | case 'Q': | |
483 | sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0); | |
484 | break; | |
485 | } | |
486 | ||
487 | TRACE_REGISTER (cpu, "R%i = %#x", iw2 & 0xf, c); | |
488 | cpu->regs[iw2 & 0xf] = c; | |
489 | ||
490 | pc += 4; | |
491 | } | |
492 | else if (num1 == 21) | |
493 | { | |
494 | /* noop: 21: no operation */ | |
495 | TRACE_INSN (cpu, "NOOP"); | |
496 | ||
497 | pc += 2; | |
498 | } | |
499 | else | |
500 | sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL); | |
501 | ||
502 | TRACE_REGISTER (cpu, "PC = %#x", pc); | |
503 | sim_pc_set (cpu, pc); | |
504 | } | |
505 | \f | |
506 | /* Return the program counter for this cpu. */ | |
507 | static sim_cia | |
508 | pc_get (sim_cpu *cpu) | |
509 | { | |
510 | return cpu->pc; | |
511 | } | |
512 | ||
513 | /* Set the program counter for this cpu to the new pc value. */ | |
514 | static void | |
515 | pc_set (sim_cpu *cpu, sim_cia pc) | |
516 | { | |
517 | cpu->pc = pc; | |
518 | } | |
519 | ||
520 | /* Initialize the state for a single cpu. Usuaully this involves clearing all | |
521 | registers back to their reset state. Should also hook up the fetch/store | |
522 | helper functions too. */ | |
523 | void initialize_cpu (SIM_DESC sd, SIM_CPU *cpu) | |
524 | { | |
525 | memset (cpu->regs, 0, sizeof (cpu->regs)); | |
526 | cpu->pc = 0; | |
527 | /* Make sure it's initialized outside of the 16-bit address space. */ | |
528 | cpu->sp = 0x80000; | |
529 | ||
530 | CPU_PC_FETCH (cpu) = pc_get; | |
531 | CPU_PC_STORE (cpu) = pc_set; | |
532 | } |