3b2: Allow handling of TRACE and BREAKPOINT traps
The 3B2 emulator did not have support for traps, rendering debugging under the simulator fairly useless. This change adds support for trap handling. The 'sdb' UNIX debugger under SVR3 should now work correctly.
This commit is contained in:
parent
8494112ee4
commit
651faa78ae
4 changed files with 138 additions and 133 deletions
245
3B2/3b2_cpu.c
245
3B2/3b2_cpu.c
|
@ -74,7 +74,7 @@ int8 cpu_etype = -1; /* Currently set expanded datatype */
|
||||||
|
|
||||||
t_bool cpu_nmi = FALSE; /* If set, there has been an NMI */
|
t_bool cpu_nmi = FALSE; /* If set, there has been an NMI */
|
||||||
|
|
||||||
uint8 cpu_ilen = 0; /* Length (in bytes) of instruction
|
int32 pc_incr = 0; /* Length (in bytes) of instruction
|
||||||
currently being executed */
|
currently being executed */
|
||||||
t_bool cpu_ex_halt = FALSE; /* Flag to halt on exceptions /
|
t_bool cpu_ex_halt = FALSE; /* Flag to halt on exceptions /
|
||||||
traps */
|
traps */
|
||||||
|
@ -133,6 +133,7 @@ static DEBTAB cpu_deb_tab[] = {
|
||||||
{ "IRQ", IRQ_MSG, "Interrupt Handling" },
|
{ "IRQ", IRQ_MSG, "Interrupt Handling" },
|
||||||
{ "IO", IO_D_MSG, "I/O Dispatch" },
|
{ "IO", IO_D_MSG, "I/O Dispatch" },
|
||||||
{ "TRACE", TRACE_MSG, "Call Trace" },
|
{ "TRACE", TRACE_MSG, "Call Trace" },
|
||||||
|
{ "ERROR", ERR_MSG, "Error" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,7 +203,7 @@ mnemonic hword_ops[HWORD_OP_COUNT] = {
|
||||||
|
|
||||||
/* Lookup table of operand types. */
|
/* Lookup table of operand types. */
|
||||||
mnemonic ops[256] = {
|
mnemonic ops[256] = {
|
||||||
{0x00, -1, OP_NONE, NA, "???", -1, -1, -1, -1},
|
{0x00, 0, OP_NONE, NA, "halt", -1, -1, -1, -1},
|
||||||
{0x01, -1, OP_NONE, NA, "???", -1, -1, -1, -1},
|
{0x01, -1, OP_NONE, NA, "???", -1, -1, -1, -1},
|
||||||
{0x02, 2, OP_COPR, WD, "SPOPRD", -1, -1, -1, -1},
|
{0x02, 2, OP_COPR, WD, "SPOPRD", -1, -1, -1, -1},
|
||||||
{0x03, 3, OP_COPR, WD, "SPOPD2", -1, -1, -1, -1},
|
{0x03, 3, OP_COPR, WD, "SPOPD2", -1, -1, -1, -1},
|
||||||
|
@ -1314,10 +1315,6 @@ t_bool cpu_on_interrupt(uint8 ipl)
|
||||||
uint32 new_pcbp;
|
uint32 new_pcbp;
|
||||||
uint16 id = ipl; /* TODO: Does this need to be uint16? */
|
uint16 id = ipl; /* TODO: Does this need to be uint16? */
|
||||||
|
|
||||||
sim_debug(IRQ_MSG, &cpu_dev,
|
|
||||||
"[%08x] [cpu_on_interrupt] ipl=%d\n",
|
|
||||||
R[NUM_PC], ipl);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "If a nonmaskable interrupt request is received, an auto-vector
|
* "If a nonmaskable interrupt request is received, an auto-vector
|
||||||
* interrupt acknowledge cycle is performed (as if an autovector
|
* interrupt acknowledge cycle is performed (as if an autovector
|
||||||
|
@ -1330,7 +1327,7 @@ t_bool cpu_on_interrupt(uint8 ipl)
|
||||||
|
|
||||||
cpu_km = TRUE;
|
cpu_km = TRUE;
|
||||||
|
|
||||||
if ((R[NUM_PSW] & PSW_QIE_MASK) >> PSW_QIE) {
|
if (R[NUM_PSW] & PSW_QIE_MASK) {
|
||||||
/* TODO: Maybe implement quick interrupts at some point, but
|
/* TODO: Maybe implement quick interrupts at some point, but
|
||||||
the 3B2 ROM and SVR3 don't appear to use them. */
|
the 3B2 ROM and SVR3 don't appear to use them. */
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -1363,7 +1360,7 @@ t_bool cpu_on_interrupt(uint8 ipl)
|
||||||
|
|
||||||
t_stat sim_instr(void)
|
t_stat sim_instr(void)
|
||||||
{
|
{
|
||||||
uint8 et, isc;
|
uint8 et, isc, trap;
|
||||||
|
|
||||||
/* Temporary register used for overflow detection */
|
/* Temporary register used for overflow detection */
|
||||||
t_uint64 result;
|
t_uint64 result;
|
||||||
|
@ -1396,10 +1393,10 @@ t_stat sim_instr(void)
|
||||||
return STOP_EX;
|
return STOP_EX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abort_reason == ABORT_EXC) {
|
|
||||||
et = R[NUM_PSW] & PSW_ET_MASK;
|
et = R[NUM_PSW] & PSW_ET_MASK;
|
||||||
isc = (R[NUM_PSW] & PSW_ISC_MASK) >> PSW_ISC;
|
isc = (R[NUM_PSW] & PSW_ISC_MASK) >> PSW_ISC;
|
||||||
|
|
||||||
|
if (abort_reason == ABORT_EXC) {
|
||||||
switch(abort_context) {
|
switch(abort_context) {
|
||||||
case C_NORMAL_GATE_VECTOR:
|
case C_NORMAL_GATE_VECTOR:
|
||||||
cpu_on_normal_exception(N_GATE_VECTOR);
|
cpu_on_normal_exception(N_GATE_VECTOR);
|
||||||
|
@ -1442,13 +1439,12 @@ t_stat sim_instr(void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* TODO: Handle traps */
|
|
||||||
stop_reason = STOP_EX;
|
|
||||||
}
|
}
|
||||||
|
/* Traps are handled at the end of instruction execution */
|
||||||
}
|
}
|
||||||
|
|
||||||
while (stop_reason == 0) {
|
while (stop_reason == 0) {
|
||||||
|
trap = 0;
|
||||||
abort_context = C_NONE;
|
abort_context = C_NONE;
|
||||||
|
|
||||||
if (sim_brk_summ && sim_brk_test(R[NUM_PC], SWMASK ('E'))) {
|
if (sim_brk_summ && sim_brk_test(R[NUM_PC], SWMASK ('E'))) {
|
||||||
|
@ -1469,7 +1465,6 @@ t_stat sim_instr(void)
|
||||||
/* Process DMA requests */
|
/* Process DMA requests */
|
||||||
dmac_service_drqs();
|
dmac_service_drqs();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Post-increment IU mode pointers (if needed).
|
* Post-increment IU mode pointers (if needed).
|
||||||
*
|
*
|
||||||
|
@ -1490,7 +1485,6 @@ t_stat sim_instr(void)
|
||||||
cpu_on_interrupt(cpu_ipl());
|
cpu_on_interrupt(cpu_ipl());
|
||||||
cpu_nmi = FALSE;
|
cpu_nmi = FALSE;
|
||||||
cpu_in_wait = FALSE;
|
cpu_in_wait = FALSE;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_in_wait) {
|
if (cpu_in_wait) {
|
||||||
|
@ -1501,7 +1495,6 @@ t_stat sim_instr(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the TM bits */
|
/* Reset the TM bits */
|
||||||
R[NUM_PSW] &= ~PSW_TM;
|
|
||||||
R[NUM_PSW] |= PSW_TM_MASK;
|
R[NUM_PSW] |= PSW_TM_MASK;
|
||||||
|
|
||||||
/* Record the instruction for history */
|
/* Record the instruction for history */
|
||||||
|
@ -1513,8 +1506,8 @@ t_stat sim_instr(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode the instruction */
|
/* Decode the instruction */
|
||||||
memset(cpu_instr, 0, sizeof(instr));
|
clear_instruction(cpu_instr);
|
||||||
cpu_ilen = decode_instruction(cpu_instr);
|
pc_incr = decode_instruction(cpu_instr);
|
||||||
|
|
||||||
/* Make sure to update the valid bit for history keeping (if
|
/* Make sure to update the valid bit for history keeping (if
|
||||||
* enabled) */
|
* enabled) */
|
||||||
|
@ -1590,63 +1583,53 @@ t_stat sim_instr(void)
|
||||||
case BEH:
|
case BEH:
|
||||||
case BEH_D:
|
case BEH_D:
|
||||||
if (cpu_z_flag() == 1) {
|
if (cpu_z_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BEB:
|
case BEB:
|
||||||
case BEB_D:
|
case BEB_D:
|
||||||
if (cpu_z_flag() == 1) {
|
if (cpu_z_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGH:
|
case BGH:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGB:
|
case BGB:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGEH:
|
case BGEH:
|
||||||
if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
|
if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGEB:
|
case BGEB:
|
||||||
if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
|
if ((cpu_n_flag() == 0) | (cpu_z_flag() == 1)) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGEUH:
|
case BGEUH:
|
||||||
if (cpu_c_flag() == 0) {
|
if (cpu_c_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGEUB:
|
case BGEUB:
|
||||||
if (cpu_c_flag() == 0) {
|
if (cpu_c_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGUH:
|
case BGUH:
|
||||||
if ((cpu_c_flag() | cpu_z_flag()) == 0) {
|
if ((cpu_c_flag() | cpu_z_flag()) == 0) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BGUB:
|
case BGUB:
|
||||||
if ((cpu_c_flag() | cpu_z_flag()) == 0) {
|
if ((cpu_c_flag() | cpu_z_flag()) == 0) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BITW:
|
case BITW:
|
||||||
|
@ -1661,118 +1644,104 @@ t_stat sim_instr(void)
|
||||||
break;
|
break;
|
||||||
case BLH:
|
case BLH:
|
||||||
if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
|
if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLB:
|
case BLB:
|
||||||
if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
|
if ((cpu_n_flag() == 1) && (cpu_z_flag() == 0)) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLEH:
|
case BLEH:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLEB:
|
case BLEB:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLEUH:
|
case BLEUH:
|
||||||
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLEUB:
|
case BLEUB:
|
||||||
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLUH:
|
case BLUH:
|
||||||
if (cpu_c_flag() == 1) {
|
if (cpu_c_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BLUB:
|
case BLUB:
|
||||||
if (cpu_c_flag() == 1) {
|
if (cpu_c_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BNEH:
|
case BNEH:
|
||||||
case BNEH_D:
|
case BNEH_D:
|
||||||
if (cpu_z_flag() == 0) {
|
if (cpu_z_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BNEB:
|
case BNEB:
|
||||||
case BNEB_D:
|
case BNEB_D:
|
||||||
if (cpu_z_flag() == 0) {
|
if (cpu_z_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BPT:
|
case BPT:
|
||||||
/* TODO: Confirm that a breakpoint trap will increment the
|
case HALT:
|
||||||
PC. Otherwise, change 'break' to 'continue' */
|
trap = BREAKPOINT_TRAP;
|
||||||
cpu_abort(NORMAL_EXCEPTION, BREAKPOINT_TRAP);
|
|
||||||
break;
|
break;
|
||||||
case BRH:
|
case BRH:
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
break;
|
||||||
case BRB:
|
case BRB:
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
break;
|
||||||
case BSBH:
|
case BSBH:
|
||||||
cpu_push_word(R[NUM_PC] + cpu_ilen);
|
cpu_push_word(R[NUM_PC] + pc_incr);
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
break;
|
||||||
case BSBB:
|
case BSBB:
|
||||||
cpu_push_word(R[NUM_PC] + cpu_ilen);
|
cpu_push_word(R[NUM_PC] + pc_incr);
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
break;
|
||||||
case BVCH:
|
case BVCH:
|
||||||
if (cpu_v_flag() == 0) {
|
if (cpu_v_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BVCB:
|
case BVCB:
|
||||||
if (cpu_v_flag() == 0) {
|
if (cpu_v_flag() == 0) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BVSH:
|
case BVSH:
|
||||||
if (cpu_v_flag() == 1) {
|
if (cpu_v_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_h(dst->embedded.h);
|
pc_incr = sign_extend_h(dst->embedded.h);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BVSB:
|
case BVSB:
|
||||||
if (cpu_v_flag() == 1) {
|
if (cpu_v_flag() == 1) {
|
||||||
R[NUM_PC] += sign_extend_b(dst->embedded.b);
|
pc_incr = sign_extend_b(dst->embedded.b);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CALL:
|
case CALL:
|
||||||
a = cpu_effective_address(src1);
|
a = cpu_effective_address(src1);
|
||||||
b = cpu_effective_address(dst);
|
b = cpu_effective_address(dst);
|
||||||
write_w(R[NUM_SP] + 4, R[NUM_AP]);
|
write_w(R[NUM_SP] + 4, R[NUM_AP]);
|
||||||
write_w(R[NUM_SP], R[NUM_PC] + cpu_ilen);
|
write_w(R[NUM_SP], R[NUM_PC] + pc_incr);
|
||||||
R[NUM_SP] += 8;
|
R[NUM_SP] += 8;
|
||||||
R[NUM_PC] = b;
|
R[NUM_PC] = b;
|
||||||
R[NUM_AP] = a;
|
R[NUM_AP] = a;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case CFLUSH:
|
case CFLUSH:
|
||||||
break;
|
break;
|
||||||
case CALLPS:
|
case CALLPS:
|
||||||
|
@ -1808,7 +1777,8 @@ t_stat sim_instr(void)
|
||||||
abort_context = C_NONE;
|
abort_context = C_NONE;
|
||||||
|
|
||||||
cpu_km = FALSE;
|
cpu_km = FALSE;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case CLRW:
|
case CLRW:
|
||||||
case CLRH:
|
case CLRH:
|
||||||
case CLRB:
|
case CLRB:
|
||||||
|
@ -1975,7 +1945,8 @@ t_stat sim_instr(void)
|
||||||
}
|
}
|
||||||
mmu_enable();
|
mmu_enable();
|
||||||
R[NUM_PC] = R[0];
|
R[NUM_PC] = R[0];
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case DISVJMP:
|
case DISVJMP:
|
||||||
if (cpu_execution_level() != EX_LVL_KERN) {
|
if (cpu_execution_level() != EX_LVL_KERN) {
|
||||||
cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
|
cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
|
||||||
|
@ -1983,7 +1954,8 @@ t_stat sim_instr(void)
|
||||||
}
|
}
|
||||||
mmu_disable();
|
mmu_disable();
|
||||||
R[NUM_PC] = R[0];
|
R[NUM_PC] = R[0];
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case EXTFW:
|
case EXTFW:
|
||||||
case EXTFH:
|
case EXTFH:
|
||||||
case EXTFB:
|
case EXTFB:
|
||||||
|
@ -2039,27 +2011,21 @@ t_stat sim_instr(void)
|
||||||
break;
|
break;
|
||||||
case JMP:
|
case JMP:
|
||||||
R[NUM_PC] = cpu_effective_address(dst);
|
R[NUM_PC] = cpu_effective_address(dst);
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case JSB:
|
case JSB:
|
||||||
cpu_push_word(R[NUM_PC] + cpu_ilen);
|
cpu_push_word(R[NUM_PC] + pc_incr);
|
||||||
R[NUM_PC] = cpu_effective_address(dst);
|
R[NUM_PC] = cpu_effective_address(dst);
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case LLSW3:
|
case LLSW3:
|
||||||
result = (t_uint64)cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
|
|
||||||
cpu_write_op(dst, (uint32)(result & WORD_MASK));
|
|
||||||
cpu_set_nz_flags((uint32)(result & WORD_MASK), dst);
|
|
||||||
break;
|
|
||||||
case LLSH3:
|
case LLSH3:
|
||||||
a = cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
|
|
||||||
cpu_write_op(dst, a);
|
|
||||||
cpu_set_nz_flags(a, dst);
|
|
||||||
break;
|
|
||||||
case LLSB3:
|
case LLSB3:
|
||||||
a = cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
|
result = (t_uint64)cpu_read_op(src2) << (cpu_read_op(src1) & 0x1f);
|
||||||
cpu_write_op(dst, a);
|
cpu_write_op(dst, result);
|
||||||
cpu_set_nz_flags(a, dst);
|
cpu_set_nz_flags(result, dst);
|
||||||
cpu_set_c_flag(0);
|
cpu_set_c_flag(0);
|
||||||
cpu_set_v_flag_op(a, dst);
|
cpu_set_v_flag_op(result, dst);
|
||||||
break;
|
break;
|
||||||
case ARSW3:
|
case ARSW3:
|
||||||
case ARSH3:
|
case ARSH3:
|
||||||
|
@ -2135,10 +2101,11 @@ t_stat sim_instr(void)
|
||||||
|
|
||||||
/* Finish push of PC and PSW */
|
/* Finish push of PC and PSW */
|
||||||
R[NUM_SP] += 8;
|
R[NUM_SP] += 8;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case MCOMW:
|
case MCOMW:
|
||||||
case MCOMH:
|
case MCOMH:
|
||||||
case MCOMB:
|
case MCOMB: /* One's complement */
|
||||||
a = ~(cpu_read_op(src1));
|
a = ~(cpu_read_op(src1));
|
||||||
cpu_write_op(dst, a);
|
cpu_write_op(dst, a);
|
||||||
cpu_set_nz_flags(a, dst);
|
cpu_set_nz_flags(a, dst);
|
||||||
|
@ -2147,7 +2114,7 @@ t_stat sim_instr(void)
|
||||||
break;
|
break;
|
||||||
case MNEGW:
|
case MNEGW:
|
||||||
case MNEGH:
|
case MNEGH:
|
||||||
case MNEGB:
|
case MNEGB: /* Two's complement */
|
||||||
a = ~cpu_read_op(src1) + 1;
|
a = ~cpu_read_op(src1) + 1;
|
||||||
cpu_write_op(dst, a);
|
cpu_write_op(dst, a);
|
||||||
cpu_set_nz_flags(a, dst);
|
cpu_set_nz_flags(a, dst);
|
||||||
|
@ -2220,7 +2187,7 @@ t_stat sim_instr(void)
|
||||||
/* However, if a move to PSW set the O bit, we have to
|
/* However, if a move to PSW set the O bit, we have to
|
||||||
generate an overflow exception trap */
|
generate an overflow exception trap */
|
||||||
if (op_is_psw(dst) && (R[NUM_PSW] & PSW_OE_MASK)) {
|
if (op_is_psw(dst) && (R[NUM_PSW] & PSW_OE_MASK)) {
|
||||||
cpu_abort(NORMAL_EXCEPTION, INTEGER_OVERFLOW);
|
trap = INTEGER_OVERFLOW;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MODW2:
|
case MODW2:
|
||||||
|
@ -2347,10 +2314,10 @@ t_stat sim_instr(void)
|
||||||
case NOP:
|
case NOP:
|
||||||
break;
|
break;
|
||||||
case NOP2:
|
case NOP2:
|
||||||
cpu_ilen += 1;
|
pc_incr += 1;
|
||||||
break;
|
break;
|
||||||
case NOP3:
|
case NOP3:
|
||||||
cpu_ilen += 2;
|
pc_incr += 2;
|
||||||
break;
|
break;
|
||||||
case ORW2:
|
case ORW2:
|
||||||
case ORH2:
|
case ORH2:
|
||||||
|
@ -2399,26 +2366,26 @@ t_stat sim_instr(void)
|
||||||
case RGEQ:
|
case RGEQ:
|
||||||
if (cpu_n_flag() == 0 || cpu_z_flag() == 1) {
|
if (cpu_n_flag() == 0 || cpu_z_flag() == 1) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RGEQU:
|
case RGEQU:
|
||||||
if (cpu_c_flag() == 0) {
|
if (cpu_c_flag() == 0) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RGTR:
|
case RGTR:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 0) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RNEQ:
|
case RNEQ:
|
||||||
case RNEQU:
|
case RNEQU:
|
||||||
if (cpu_z_flag() == 0) {
|
if (cpu_z_flag() == 0) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RET:
|
case RET:
|
||||||
|
@ -2428,7 +2395,8 @@ t_stat sim_instr(void)
|
||||||
R[NUM_AP] = b;
|
R[NUM_AP] = b;
|
||||||
R[NUM_PC] = c;
|
R[NUM_PC] = c;
|
||||||
R[NUM_SP] = a;
|
R[NUM_SP] = a;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case RETG:
|
case RETG:
|
||||||
abort_context = C_STACK_FAULT;
|
abort_context = C_STACK_FAULT;
|
||||||
a = read_w(R[NUM_SP] - 4, ACC_AF); /* PSW */
|
a = read_w(R[NUM_SP] - 4, ACC_AF); /* PSW */
|
||||||
|
@ -2465,7 +2433,8 @@ t_stat sim_instr(void)
|
||||||
R[NUM_PC] = b;
|
R[NUM_PC] = b;
|
||||||
|
|
||||||
R[NUM_SP] -= 8;
|
R[NUM_SP] -= 8;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case RETPS:
|
case RETPS:
|
||||||
if (cpu_execution_level() != EX_LVL_KERN) {
|
if (cpu_execution_level() != EX_LVL_KERN) {
|
||||||
cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
|
cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
|
||||||
|
@ -2512,12 +2481,21 @@ t_stat sim_instr(void)
|
||||||
|
|
||||||
/* Un-force kernel memory access */
|
/* Un-force kernel memory access */
|
||||||
cpu_km = FALSE;
|
cpu_km = FALSE;
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case SPOP:
|
case SPOP:
|
||||||
|
case SPOPD2:
|
||||||
|
case SPOPS2:
|
||||||
|
case SPOPT2:
|
||||||
case SPOPRD:
|
case SPOPRD:
|
||||||
case SPOPRS:
|
case SPOPRS:
|
||||||
|
case SPOPRT:
|
||||||
|
case SPOPWD:
|
||||||
|
case SPOPWS:
|
||||||
|
case SPOPWT:
|
||||||
/* Memory fault is signaled when no support processor is
|
/* Memory fault is signaled when no support processor is
|
||||||
active */
|
active */
|
||||||
|
csr_data |= CSRTIMO;
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
break;
|
break;
|
||||||
case SUBW2:
|
case SUBW2:
|
||||||
|
@ -2550,36 +2528,37 @@ t_stat sim_instr(void)
|
||||||
case RLEQ:
|
case RLEQ:
|
||||||
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_n_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RLEQU:
|
case RLEQU:
|
||||||
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
if ((cpu_c_flag() | cpu_z_flag()) == 1) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RLSS:
|
case RLSS:
|
||||||
if ((cpu_n_flag() == 1) & (cpu_z_flag() == 0)) {
|
if ((cpu_n_flag() == 1) & (cpu_z_flag() == 0)) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REQL:
|
case REQL:
|
||||||
if (cpu_z_flag() == 1) {
|
if (cpu_z_flag() == 1) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REQLU:
|
case REQLU:
|
||||||
if (cpu_z_flag() == 1) {
|
if (cpu_z_flag() == 1) {
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RSB:
|
case RSB:
|
||||||
R[NUM_PC] = cpu_pop_word();
|
R[NUM_PC] = cpu_pop_word();
|
||||||
continue;
|
pc_incr = 0;
|
||||||
|
break;
|
||||||
case SAVE:
|
case SAVE:
|
||||||
/* Save the FP register */
|
/* Save the FP register */
|
||||||
write_w(R[NUM_SP], R[NUM_FP]);
|
write_w(R[NUM_SP], R[NUM_FP]);
|
||||||
|
@ -2626,6 +2605,10 @@ t_stat sim_instr(void)
|
||||||
cpu_set_v_flag(0);
|
cpu_set_v_flag(0);
|
||||||
break;
|
break;
|
||||||
case WAIT:
|
case WAIT:
|
||||||
|
if (cpu_execution_level() != EX_LVL_KERN) {
|
||||||
|
cpu_abort(NORMAL_EXCEPTION, PRIVILEGED_OPCODE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
cpu_in_wait = TRUE;
|
cpu_in_wait = TRUE;
|
||||||
break;
|
break;
|
||||||
case XORW2:
|
case XORW2:
|
||||||
|
@ -2652,7 +2635,21 @@ t_stat sim_instr(void)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Increment the PC appropriately */
|
/* Increment the PC appropriately */
|
||||||
R[NUM_PC] += cpu_ilen;
|
R[NUM_PC] += pc_incr;
|
||||||
|
|
||||||
|
/* If TE and TM are both set, generate a trace trap */
|
||||||
|
if ((R[NUM_PSW] & PSW_TE_MASK) && (R[NUM_PSW] & PSW_TM_MASK)) {
|
||||||
|
trap = TRACE_TRAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle traps */
|
||||||
|
if (trap) {
|
||||||
|
R[NUM_PSW] &= ~(PSW_ET_MASK);
|
||||||
|
R[NUM_PSW] &= ~(PSW_ISC_MASK);
|
||||||
|
R[NUM_PSW] |= NORMAL_EXCEPTION;
|
||||||
|
R[NUM_PSW] |= (uint32) (trap << PSW_ISC);
|
||||||
|
cpu_on_normal_exception(trap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stop_reason;
|
return stop_reason;
|
||||||
|
@ -2661,6 +2658,9 @@ t_stat sim_instr(void)
|
||||||
static SIM_INLINE void cpu_on_process_exception(uint8 isc)
|
static SIM_INLINE void cpu_on_process_exception(uint8 isc)
|
||||||
{
|
{
|
||||||
/* TODO: Handle */
|
/* TODO: Handle */
|
||||||
|
sim_debug(ERR_MSG, &cpu_dev,
|
||||||
|
"[%08x] CPU_ON_PROCESS_EXCEPTION not yet implemented.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
stop_reason = STOP_EX;
|
stop_reason = STOP_EX;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2751,13 +2751,14 @@ static SIM_INLINE void cpu_on_normal_exception(uint8 isc)
|
||||||
|
|
||||||
/* Set context for STACK (FAULT) */
|
/* Set context for STACK (FAULT) */
|
||||||
abort_context = C_STACK_FAULT;
|
abort_context = C_STACK_FAULT;
|
||||||
|
/* Save address of next instruction to stack */
|
||||||
write_w(R[NUM_SP], R[NUM_PC]);
|
write_w(R[NUM_SP], R[NUM_PC]);
|
||||||
|
|
||||||
/* Write 0, 3 to TM, ET fields of PSW */
|
/* Write 0, 3 to TM, ET fields of PSW */
|
||||||
R[NUM_PSW] &= ~(PSW_TM_MASK|PSW_ET_MASK);
|
R[NUM_PSW] &= ~(PSW_TM_MASK|PSW_ET_MASK);
|
||||||
R[NUM_PSW] |= (3 << PSW_ET);
|
R[NUM_PSW] |= (3 << PSW_ET);
|
||||||
|
|
||||||
/* Save address of next instruction and PSW to stack */
|
/* Save PSW to stack */
|
||||||
write_w(R[NUM_SP] + 4, R[NUM_PSW]);
|
write_w(R[NUM_SP] + 4, R[NUM_PSW]);
|
||||||
|
|
||||||
/* Set context for RESET (GATE VECTOR) */
|
/* Set context for RESET (GATE VECTOR) */
|
||||||
|
@ -2865,7 +2866,7 @@ static uint32 cpu_effective_address(operand *op)
|
||||||
return read_w(R[op->reg] + sign_extend_b(op->embedded.b), ACC_AF);
|
return read_w(R[op->reg] + sign_extend_b(op->embedded.b), ACC_AF);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
stop_reason = STOP_OPCODE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3405,11 +3406,13 @@ void cpu_abort(uint8 et, uint8 isc)
|
||||||
{
|
{
|
||||||
/* We don't trap Integer Overflow if the OE bit is not set */
|
/* We don't trap Integer Overflow if the OE bit is not set */
|
||||||
if ((R[NUM_PSW] & PSW_OE_MASK) || isc != INTEGER_OVERFLOW) {
|
if ((R[NUM_PSW] & PSW_OE_MASK) || isc != INTEGER_OVERFLOW) {
|
||||||
R[NUM_PSW] &= ~(PSW_ISC_MASK); /* Clear ISC */
|
|
||||||
R[NUM_PSW] &= ~(PSW_ET_MASK); /* Clear ET */
|
R[NUM_PSW] &= ~(PSW_ET_MASK); /* Clear ET */
|
||||||
|
R[NUM_PSW] &= ~(PSW_ISC_MASK); /* Clear ISC */
|
||||||
R[NUM_PSW] |= et; /* Set ET */
|
R[NUM_PSW] |= et; /* Set ET */
|
||||||
R[NUM_PSW] |= (uint32) (isc << PSW_ISC); /* Set ISC */
|
R[NUM_PSW] |= (uint32) (isc << PSW_ISC); /* Set ISC */
|
||||||
|
|
||||||
|
/* TODO: We no longer use ABORT_TRAP or ABORT_EXC, so
|
||||||
|
* it would be nice to clean this up. */
|
||||||
if (et == 3 && (isc == BREAKPOINT_TRAP ||
|
if (et == 3 && (isc == BREAKPOINT_TRAP ||
|
||||||
isc == INTEGER_OVERFLOW ||
|
isc == INTEGER_OVERFLOW ||
|
||||||
isc == TRACE_TRAP)) {
|
isc == TRACE_TRAP)) {
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
* Opcodes
|
* Opcodes
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
HALT = 0x00, /* Undocumented instruction */
|
||||||
SPOPRD = 0x02,
|
SPOPRD = 0x02,
|
||||||
SPOPD2 = 0x03,
|
SPOPD2 = 0x03,
|
||||||
MOVAW = 0x04,
|
MOVAW = 0x04,
|
||||||
|
|
|
@ -124,14 +124,15 @@ noret __libc_longjmp (jmp_buf buf, int val);
|
||||||
#define C_STACK_FAULT 9
|
#define C_STACK_FAULT 9
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define READ_MSG 0x01
|
#define READ_MSG 0x001
|
||||||
#define WRITE_MSG 0x02
|
#define WRITE_MSG 0x002
|
||||||
#define DECODE_MSG 0x04
|
#define DECODE_MSG 0x004
|
||||||
#define EXECUTE_MSG 0x08
|
#define EXECUTE_MSG 0x008
|
||||||
#define INIT_MSG 0x10
|
#define INIT_MSG 0x010
|
||||||
#define IRQ_MSG 0x20
|
#define IRQ_MSG 0x020
|
||||||
#define IO_D_MSG 0x40
|
#define IO_D_MSG 0x040
|
||||||
#define TRACE_MSG 0x80
|
#define TRACE_MSG 0x080
|
||||||
|
#define ERR_MSG 0x100
|
||||||
|
|
||||||
/* Data types operated on by instructions. NB: These integer values
|
/* Data types operated on by instructions. NB: These integer values
|
||||||
have meaning when decoding instructions, so this is not just an
|
have meaning when decoding instructions, so this is not just an
|
||||||
|
|
|
@ -302,7 +302,7 @@ t_stat contty_reset(DEVICE *dtpr)
|
||||||
|
|
||||||
memset(&iu_state, 0, sizeof(IU_STATE));
|
memset(&iu_state, 0, sizeof(IU_STATE));
|
||||||
memset(&iu_contty, 0, sizeof(IU_PORT));
|
memset(&iu_contty, 0, sizeof(IU_PORT));
|
||||||
tmxr_set_config_line(&contty_ldsc[0], "115200-8N1");
|
tmxr_set_config_line(&contty_ldsc[0], "9600-8N1");
|
||||||
|
|
||||||
/* Start the CONTTY polling loop */
|
/* Start the CONTTY polling loop */
|
||||||
if (!sim_is_active(contty_rcv_unit)) {
|
if (!sim_is_active(contty_rcv_unit)) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue