
The defs.h header will take care of including the various config.h headers. For now, it's just config.h, but we'll add more when we integrate gnulib in. This header should be used instead of config.h, and should be the first include in every .c file. We won't rely on the old behavior where we expected files to include the port's sim-main.h which then includes the common sim-basics.h which then includes config.h. We have a ton of code that includes things before sim-main.h, and it sometimes needs to be that way. Creating a dedicated header avoids the ordering mess and implicit inclusion that shows up otherwise.
531 lines
17 KiB
C
531 lines
17 KiB
C
/* Example synacor simulator.
|
||
|
||
Copyright (C) 2005-2021 Free Software Foundation, Inc.
|
||
Contributed by Mike Frysinger.
|
||
|
||
This file is part of simulators.
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||
|
||
/* This file contains the main simulator decoding logic. i.e. everything that
|
||
is architecture specific. */
|
||
|
||
/* This must come before any other includes. */
|
||
#include "defs.h"
|
||
|
||
#include "sim-main.h"
|
||
|
||
/* Get the register number from the number. */
|
||
static unsigned16
|
||
register_num (SIM_CPU *cpu, unsigned16 num)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (cpu);
|
||
|
||
if (num < 0x8000 || num >= 0x8008)
|
||
sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
|
||
|
||
return num & 0xf;
|
||
}
|
||
|
||
/* Helper to process immediates according to the ISA. */
|
||
static unsigned16
|
||
interp_num (SIM_CPU *cpu, unsigned16 num)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (cpu);
|
||
|
||
if (num < 0x8000)
|
||
{
|
||
/* Numbers 0..32767 mean a literal value. */
|
||
TRACE_DECODE (cpu, "%#x is a literal", num);
|
||
return num;
|
||
}
|
||
else if (num < 0x8008)
|
||
{
|
||
/* Numbers 32768..32775 instead mean registers 0..7. */
|
||
TRACE_DECODE (cpu, "%#x is register R%i", num, num & 0xf);
|
||
return cpu->regs[num & 0xf];
|
||
}
|
||
else
|
||
{
|
||
/* Numbers 32776..65535 are invalid. */
|
||
TRACE_DECODE (cpu, "%#x is an invalid number", num);
|
||
sim_engine_halt (sd, cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
|
||
}
|
||
}
|
||
|
||
/* Decode & execute a single instruction. */
|
||
void step_once (SIM_CPU *cpu)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (cpu);
|
||
unsigned16 iw1, num1;
|
||
sim_cia pc = sim_pc_get (cpu);
|
||
|
||
iw1 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc);
|
||
TRACE_EXTRACT (cpu, "%04x: iw1: %#x", pc, iw1);
|
||
/* This never happens, but technically is possible in the ISA. */
|
||
num1 = interp_num (cpu, iw1);
|
||
|
||
if (num1 == 0)
|
||
{
|
||
/* halt: 0: Stop execution and terminate the program. */
|
||
TRACE_INSN (cpu, "HALT");
|
||
sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0);
|
||
}
|
||
else if (num1 == 1)
|
||
{
|
||
/* set: 1 a b: Set register <a> to the value of <b>. */
|
||
unsigned16 iw2, iw3, num2, num3;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
TRACE_EXTRACT (cpu, "SET %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "SET R%i %#x", num2, num3);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, num3);
|
||
cpu->regs[num2] = num3;
|
||
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 2)
|
||
{
|
||
/* push: 2 a: Push <a> onto the stack. */
|
||
unsigned16 iw2, num2;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
TRACE_EXTRACT (cpu, "PUSH %#x", iw2);
|
||
TRACE_INSN (cpu, "PUSH %#x", num2);
|
||
|
||
sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, num2);
|
||
cpu->sp -= 2;
|
||
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
|
||
|
||
pc += 4;
|
||
}
|
||
else if (num1 == 3)
|
||
{
|
||
/* pop: 3 a: Remove the top element from the stack and write it into <a>.
|
||
Empty stack = error. */
|
||
unsigned16 iw2, num2, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
TRACE_EXTRACT (cpu, "POP %#x", iw2);
|
||
TRACE_INSN (cpu, "POP R%i", num2);
|
||
cpu->sp += 2;
|
||
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
|
||
result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 4;
|
||
}
|
||
else if (num1 == 4)
|
||
{
|
||
/* eq: 4 a b c: Set <a> to 1 if <b> is equal to <c>; set it to 0
|
||
otherwise. */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 == num4);
|
||
TRACE_EXTRACT (cpu, "EQ %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "EQ R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = (%#x == %#x) = %i", num2, num3, num4, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 5)
|
||
{
|
||
/* gt: 5 a b c: Set <a> to 1 if <b> is greater than <c>; set it to 0
|
||
otherwise. */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 > num4);
|
||
TRACE_EXTRACT (cpu, "GT %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "GT R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = (%#x > %#x) = %i", num2, num3, num4, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 6)
|
||
{
|
||
/* jmp: 6 a: Jump to <a>. */
|
||
unsigned16 iw2, num2;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
/* Addresses are 16-bit aligned. */
|
||
num2 <<= 1;
|
||
TRACE_EXTRACT (cpu, "JMP %#x", iw2);
|
||
TRACE_INSN (cpu, "JMP %#x", num2);
|
||
|
||
pc = num2;
|
||
TRACE_BRANCH (cpu, "JMP %#x", pc);
|
||
}
|
||
else if (num1 == 7)
|
||
{
|
||
/* jt: 7 a b: If <a> is nonzero, jump to <b>. */
|
||
unsigned16 iw2, iw3, num2, num3;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
/* Addresses are 16-bit aligned. */
|
||
num3 <<= 1;
|
||
TRACE_EXTRACT (cpu, "JT %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "JT %#x %#x", num2, num3);
|
||
TRACE_DECODE (cpu, "JT %#x != 0 -> %s", num2, num2 ? "taken" : "nop");
|
||
|
||
if (num2)
|
||
{
|
||
pc = num3;
|
||
TRACE_BRANCH (cpu, "JT %#x", pc);
|
||
}
|
||
else
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 8)
|
||
{
|
||
/* jf: 8 a b: If <a> is zero, jump to <b>. */
|
||
unsigned16 iw2, iw3, num2, num3;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
/* Addresses are 16-bit aligned. */
|
||
num3 <<= 1;
|
||
TRACE_EXTRACT (cpu, "JF %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "JF %#x %#x", num2, num3);
|
||
TRACE_DECODE (cpu, "JF %#x == 0 -> %s", num2, num2 ? "nop" : "taken");
|
||
|
||
if (!num2)
|
||
{
|
||
pc = num3;
|
||
TRACE_BRANCH (cpu, "JF %#x", pc);
|
||
}
|
||
else
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 9)
|
||
{
|
||
/* add: 9 a b c: Assign <a> the sum of <b> and <c> (modulo 32768). */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 + num4) % 32768;
|
||
TRACE_EXTRACT (cpu, "ADD %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "ADD R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = (%#x + %#x) %% %i = %#x", num2, num3, num4,
|
||
32768, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 10)
|
||
{
|
||
/* mult: 10 a b c: Store into <a> the product of <b> and <c> (modulo
|
||
32768). */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 * num4) % 32768;
|
||
TRACE_EXTRACT (cpu, "MULT %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "MULT R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = (%#x * %#x) %% %i = %#x", num2, num3, num4,
|
||
32768, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 11)
|
||
{
|
||
/* mod: 11 a b c: Store into <a> the remainder of <b> divided by <c>. */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = num3 % num4;
|
||
TRACE_EXTRACT (cpu, "MOD %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "MOD R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = %#x %% %#x = %#x", num2, num3, num4, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 12)
|
||
{
|
||
/* and: 12 a b c: Stores into <a> the bitwise and of <b> and <c>. */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 & num4);
|
||
TRACE_EXTRACT (cpu, "AND %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "AND R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = %#x & %#x = %#x", num2, num3, num4, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 13)
|
||
{
|
||
/* or: 13 a b c: Stores into <a> the bitwise or of <b> and <c>. */
|
||
unsigned16 iw2, iw3, iw4, num2, num3, num4, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
iw4 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 6);
|
||
num4 = interp_num (cpu, iw4);
|
||
result = (num3 | num4);
|
||
TRACE_EXTRACT (cpu, "OR %#x %#x %#x", iw2, iw3, iw4);
|
||
TRACE_INSN (cpu, "OR R%i %#x %#x", num2, num3, num4);
|
||
TRACE_DECODE (cpu, "R%i = %#x | %#x = %#x", num2, num3, num4, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 8;
|
||
}
|
||
else if (num1 == 14)
|
||
{
|
||
/* not: 14 a b: Stores 15-bit bitwise inverse of <b> in <a>. */
|
||
unsigned16 iw2, iw3, num2, num3, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
result = (~num3) & 0x7fff;
|
||
TRACE_EXTRACT (cpu, "NOT %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "NOT R%i %#x", num2, num3);
|
||
TRACE_DECODE (cpu, "R%i = (~%#x) & 0x7fff = %#x", num2, num3, result);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 15)
|
||
{
|
||
/* rmem: 15 a b: Read memory at address <b> and write it to <a>. */
|
||
unsigned16 iw2, iw3, num2, num3, result;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
/* Addresses are 16-bit aligned. */
|
||
num3 <<= 1;
|
||
TRACE_EXTRACT (cpu, "RMEM %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "RMEM R%i %#x", num2, num3);
|
||
|
||
TRACE_MEMORY (cpu, "reading %#x", num3);
|
||
result = sim_core_read_aligned_2 (cpu, pc, read_map, num3);
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", num2, result);
|
||
cpu->regs[num2] = result;
|
||
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 16)
|
||
{
|
||
/* wmem: 16 a b: Write the value from <b> into memory at address <a>. */
|
||
unsigned16 iw2, iw3, num2, num3;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
iw3 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 4);
|
||
num3 = interp_num (cpu, iw3);
|
||
/* Addresses are 16-bit aligned. */
|
||
num2 <<= 1;
|
||
TRACE_EXTRACT (cpu, "WMEM %#x %#x", iw2, iw3);
|
||
TRACE_INSN (cpu, "WMEM %#x %#x", num2, num3);
|
||
|
||
TRACE_MEMORY (cpu, "writing %#x to %#x", num3, num2);
|
||
sim_core_write_aligned_2 (cpu, pc, write_map, num2, num3);
|
||
|
||
pc += 6;
|
||
}
|
||
else if (num1 == 17)
|
||
{
|
||
/* call: 17 a: Write the address of the next instruction to the stack and
|
||
jump to <a>. */
|
||
unsigned16 iw2, num2;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
/* Addresses are 16-bit aligned. */
|
||
num2 <<= 1;
|
||
TRACE_EXTRACT (cpu, "CALL %#x", iw2);
|
||
TRACE_INSN (cpu, "CALL %#x", num2);
|
||
|
||
TRACE_MEMORY (cpu, "pushing %#x onto stack", (pc + 4) >> 1);
|
||
sim_core_write_aligned_2 (cpu, pc, write_map, cpu->sp, (pc + 4) >> 1);
|
||
cpu->sp -= 2;
|
||
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
|
||
|
||
pc = num2;
|
||
TRACE_BRANCH (cpu, "CALL %#x", pc);
|
||
}
|
||
else if (num1 == 18)
|
||
{
|
||
/* ret: 18: Remove the top element from the stack and jump to it; empty
|
||
stack = halt. */
|
||
unsigned16 result;
|
||
|
||
TRACE_INSN (cpu, "RET");
|
||
cpu->sp += 2;
|
||
TRACE_REGISTER (cpu, "SP = %#x", cpu->sp);
|
||
result = sim_core_read_aligned_2 (cpu, pc, read_map, cpu->sp);
|
||
TRACE_MEMORY (cpu, "popping %#x off of stack", result << 1);
|
||
|
||
pc = result << 1;
|
||
TRACE_BRANCH (cpu, "RET -> %#x", pc);
|
||
}
|
||
else if (num1 == 19)
|
||
{
|
||
/* out: 19 a: Write the character <a> to the terminal. */
|
||
unsigned16 iw2, num2;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = interp_num (cpu, iw2);
|
||
TRACE_EXTRACT (cpu, "OUT %#x", iw2);
|
||
TRACE_INSN (cpu, "OUT %#x", num2);
|
||
TRACE_EVENTS (cpu, "write to stdout: %#x (%c)", num2, num2);
|
||
|
||
sim_io_printf (sd, "%c", num2);
|
||
|
||
pc += 4;
|
||
}
|
||
else if (num1 == 20)
|
||
{
|
||
/* in: 20 a: read a character from the terminal and write its ascii code
|
||
to <a>. It can be assumed that once input starts, it will continue
|
||
until a newline is encountered. This means that you can safely read
|
||
lines from the keyboard and trust that they will be fully read. */
|
||
unsigned16 iw2, num2;
|
||
char c;
|
||
|
||
iw2 = sim_core_read_aligned_2 (cpu, pc, exec_map, pc + 2);
|
||
num2 = register_num (cpu, iw2);
|
||
TRACE_EXTRACT (cpu, "IN %#x", iw2);
|
||
TRACE_INSN (cpu, "IN %#x", num2);
|
||
sim_io_read_stdin (sd, &c, 1);
|
||
TRACE_EVENTS (cpu, "read from stdin: %#x (%c)", c, c);
|
||
|
||
/* The challenge uses lowercase for all inputs, so insert some low level
|
||
helpers of our own to make it a bit nicer. */
|
||
switch (c)
|
||
{
|
||
case 'Q':
|
||
sim_engine_halt (sd, cpu, NULL, pc, sim_exited, 0);
|
||
break;
|
||
}
|
||
|
||
TRACE_REGISTER (cpu, "R%i = %#x", iw2 & 0xf, c);
|
||
cpu->regs[iw2 & 0xf] = c;
|
||
|
||
pc += 4;
|
||
}
|
||
else if (num1 == 21)
|
||
{
|
||
/* noop: 21: no operation */
|
||
TRACE_INSN (cpu, "NOOP");
|
||
|
||
pc += 2;
|
||
}
|
||
else
|
||
sim_engine_halt (sd, cpu, NULL, pc, sim_signalled, SIM_SIGILL);
|
||
|
||
TRACE_REGISTER (cpu, "PC = %#x", pc);
|
||
sim_pc_set (cpu, pc);
|
||
}
|
||
|
||
/* Return the program counter for this cpu. */
|
||
static sim_cia
|
||
pc_get (sim_cpu *cpu)
|
||
{
|
||
return cpu->pc;
|
||
}
|
||
|
||
/* Set the program counter for this cpu to the new pc value. */
|
||
static void
|
||
pc_set (sim_cpu *cpu, sim_cia pc)
|
||
{
|
||
cpu->pc = pc;
|
||
}
|
||
|
||
/* Initialize the state for a single cpu. Usuaully this involves clearing all
|
||
registers back to their reset state. Should also hook up the fetch/store
|
||
helper functions too. */
|
||
void initialize_cpu (SIM_DESC sd, SIM_CPU *cpu)
|
||
{
|
||
memset (cpu->regs, 0, sizeof (cpu->regs));
|
||
cpu->pc = 0;
|
||
/* Make sure it's initialized outside of the 16-bit address space. */
|
||
cpu->sp = 0x80000;
|
||
|
||
CPU_PC_FETCH (cpu) = pc_get;
|
||
CPU_PC_STORE (cpu) = pc_set;
|
||
}
|