From 731d99cf659eee50c9da5f0eacc082dd3d8eb34d Mon Sep 17 00:00:00 2001 From: Seth Morabito Date: Sun, 1 Sep 2019 11:45:45 -0700 Subject: [PATCH] 3b2: CMP{W|H|B} instruction fix The WE32100 supports expanded datatypes for its opcodes, allowing an opcode to override the default size (byte/halfword/word) expected by the instruction. For example: CMPH &0x10000,{uword}-8(%fp) Without the {uword} marker, this instruction would only compare the lower 2 bytes of -8(%fp) against the lower two bytes of the constant value 0x10000, since the CMPH instruction compares halfwords. However, with the {uword} marker, the CMPH instruction promotes the opcode from a halfword to an unsigned word, sign extending if appropriate. The CMP{W|H|B} instruction implementation in the 3B2 simulator was ignoring any expanded type markers on its opcodes when checking whether to set the "N" (negative) bit in the PSW, leading to a failure in compiling GCC. This fix causes the instruction to honor the expanded datatype in this case. --- 3B2/3b2_cpu.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/3B2/3b2_cpu.c b/3B2/3b2_cpu.c index 07056322..895473ce 100644 --- a/3B2/3b2_cpu.c +++ b/3B2/3b2_cpu.c @@ -2220,30 +2220,31 @@ t_stat sim_instr(void) cpu_set_v_flag(0); break; case CMPW: - a = cpu_read_op(src1); - b = cpu_read_op(src2); - - cpu_set_z_flag((uint32)b == (uint32)a); - cpu_set_n_flag((int32)b < (int32)a); - cpu_set_c_flag((uint32)b < (uint32)a); - cpu_set_v_flag(0); - break; case CMPH: - a = cpu_read_op(src1); - b = cpu_read_op(src2); - - cpu_set_z_flag((uint16)b == (uint16)a); - cpu_set_n_flag((int16)b < (int16)a); - cpu_set_c_flag((uint16)b < (uint16)a); - cpu_set_v_flag(0); - break; case CMPB: a = cpu_read_op(src1); b = cpu_read_op(src2); - cpu_set_z_flag((uint8)b == (uint8)a); - cpu_set_n_flag((int8)b < (int8)a); - cpu_set_c_flag((uint8)b < (uint8)a); + switch(op_type(src2)) { + case WD: + case UW: + cpu_set_n_flag((int32)b < (int32)a); + break; + case HW: + case UH: + cpu_set_n_flag((int16)b < (int16)a); + break; + case BT: + case SB: + cpu_set_n_flag((int8)b < (int8)a); + break; + default: + /* Unreachable */ + break; + } + + cpu_set_z_flag(b == a); + cpu_set_c_flag(b < a); cpu_set_v_flag(0); break; case DECW: