diff --git a/app/windows/Disassembler.js b/app/windows/Disassembler.js index 8693e27..0b07f11 100644 --- a/app/windows/Disassembler.js +++ b/app/windows/Disassembler.js @@ -88,8 +88,8 @@ { format: 6, mnemonic: "ST.W" }, { format: 6, mnemonic: "IN.B" }, { format: 6, mnemonic: "IN.H" }, - { format: 6, mnemonic: "IN.W" }, { format: 6, mnemonic: "CAXI" }, + { format: 6, mnemonic: "IN.W" }, { format: 6, mnemonic: "OUT.B" }, { format: 6, mnemonic: "OUT.H" }, { format: 7, mnemonic: null }, @@ -258,9 +258,6 @@ case 0b000110: // JMP inst.operands = "[" + reg1 + "]"; break; - case 0b001111: // NOT - inst.operands = reg1; - break; default: // All others inst.operands = reg1 + ", " + this.PROREGNAMES[bits >> 5 & 31]; } @@ -275,7 +272,7 @@ case 0b010010: // SETF inst.operands = this.SETFS[other & 15] + ", " + reg2; break; - case 0b011001: // TRAP + case 0b011000: // TRAP inst.operands = other; break; case 0b011100: // LDSR @@ -355,6 +352,7 @@ case 0b110011: // LD.W case 0b111000: // IN.B case 0b111001: // IN.H + case 0b111010: // CAXI case 0b111011: // IN.W inst.operands = disp + "[" + reg1 + "], " + reg2; break; diff --git a/app/windows/MemoryWindow.js b/app/windows/MemoryWindow.js index dba4387..a33e7c3 100644 --- a/app/windows/MemoryWindow.js +++ b/app/windows/MemoryWindow.js @@ -194,6 +194,7 @@ globalThis.MemoryWindow = class MemoryWindow extends Toolkit.Window { case "ArrowLeft" : change = - 1 ; break; case "ArrowRight": change = 1 ; break; case "ArrowUp" : change = -16 ; break; + case "Enter" : change = 0 ; break; case "PageDown" : change = visible; break; case "PageUp" : change = -visible; break; case "0": case "1": case "2": case "3": case "4": diff --git a/app/windows/Register.js b/app/windows/Register.js index 7dc0d1d..7bcaf6c 100644 --- a/app/windows/Register.js +++ b/app/windows/Register.js @@ -137,9 +137,35 @@ let text; switch (this.format) { case "float": - text = CPUWindow.Register.intBitsToFloat(value).toString(); + let e = value >> 23 & 0xFF; + let s = value & 0x007FFFFF; + + // Check for denormal number + if (e == 0x00 & s != 0) { + text = "Denormal"; + break; + } + + // Check for reserved operand + if (e == 0xFF) { + text = s!=0 ? "NaN" : value<0 ? "-Infinity" : "Infinity"; + break; + } + + // Check for negative zero + if ((value & 0xFFFFFFFF) >>> 0 == 0x80000000) { + text = "-0.0"; + break; + } + + // Format the number + text = CPUWindow.Register.intBitsToFloat(value).toFixed(6); if (text.indexOf(".") == -1) text += ".0"; + while (text.endsWith("0")) + text = text.substring(0, text.length - 1); + if (text.endsWith(".")) + text += "0"; break; case "hex": text = ("0000000" + diff --git a/core/cpu.c b/core/cpu.c index 3add6d5..37caad7 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -229,24 +229,24 @@ static int32_t cpuAdd(VB *emu, int32_t left, int32_t right) { } /* Bit string search */ -static int cpuBitSearch(VB *emu, int bit, int dir) { +static int cpuBitSearch(VB *emu, int32_t bit, int32_t dir) { int32_t offset; /* Bit offset in source word */ int32_t value; /* Alias of source word */ - /* The bit string is of zero length */ - if (emu->cpu.program[28] == 0) { - emu->cpu.clocks = dir == 1 ? 13 : 15; - return 0; - } - /* Read the source word */ - if (!emu->cpu.busWait && !emu->cpu.substring) { + if (!emu->cpu.busWait) { /* Initialize state */ emu->cpu.program[30] &= 0xFFFFFFFC; emu->cpu.program[27] &= 0x0000001F; emu->cpu.psw.z = 1; + /* The bit string is of zero length */ + if (emu->cpu.program[28] == 0) { + emu->cpu.clocks = dir == 1 ? 13 : 15; + return 0; + } + /* Read the data unit from the bus */ if (cpuRead(emu, emu->cpu.program[30], VB_S32)) return 1; @@ -260,6 +260,10 @@ static int cpuBitSearch(VB *emu, int bit, int dir) { return 0; } + /* Update state */ + emu->cpu.busWait = 0; + emu->cpu.substring = 0; + /* Search the bit string */ for ( offset = emu->cpu.program[27], value = emu->cpu.access.value; @@ -268,31 +272,36 @@ static int cpuBitSearch(VB *emu, int bit, int dir) { ) { /* The current bit does not match */ - if ((value >> bit & 1) != bit) + if ((value >> offset & 1) != bit) continue; /* The current bit matches */ - emu->cpu.substring = 0; - emu->cpu.clocks = dir == 1 ? 46 : 51; - emu->cpu.psw.z = 0; + emu->cpu.program[27] = offset; + emu->cpu.clocks = dir == 1 ? 45 : 50; + emu->cpu.psw.z = 0; return 0; } /* No bit in the current word matches */ - emu->cpu.substring = 1; - emu->cpu.clocks = 5; - emu->cpu.program[30] += dir << 2; - emu->cpu.program[27] &= 0x0000001F; + emu->cpu.program[27] = offset & 31; + if (emu->cpu.program[27] != offset) + emu->cpu.program[30] += (uint32_t) dir << 2; + if (emu->cpu.program[28] != 0) { + emu->cpu.substring = 1; + emu->cpu.clocks = 5; + } else emu->cpu.clocks = dir == 1 ? 46 : 51; return 0; } /* Bit string bitwise operation */ static int cpuBitString(VB *emu, VB_INSTRUCTION *inst) { - int32_t dest; /* Destination word value */ - int32_t src; /* Source word value */ + uint64_t bits; /* Shift register */ + int32_t dest; /* Destination word value */ + int32_t mask; /* Bit mask */ + int32_t src; /* Source word value */ /* Initial invocation */ - if (emu->cpu.busWait == 0 && !emu->cpu.substring) { + if (emu->cpu.busWait == 0) { /* Initialize state */ emu->cpu.program[30] &= 0xFFFFFFFC; @@ -355,9 +364,12 @@ static int cpuBitString(VB *emu, VB_INSTRUCTION *inst) { /* Compute and store the destination word */ if (emu->cpu.busWait == 3) { + bits = ((uint64_t) inst->aux[1] << 32 | (uint32_t) inst->aux[0]); dest = emu->cpu.access.value; - src = ((int64_t) inst->aux[1] << 32 | (uint32_t) inst->aux[0]) >> - (32 + emu->cpu.program[27] - emu->cpu.program[26]); + src = emu->cpu.program[27] <= emu->cpu.program[26] ? + bits << (emu->cpu.program[26] - emu->cpu.program[27]) : + bits >> (emu->cpu.program[27] - emu->cpu.program[26]) + ; /* Perform the operation */ switch (inst->bits[0] & 7) { @@ -372,13 +384,13 @@ static int cpuBitString(VB *emu, VB_INSTRUCTION *inst) { } /* Incorporate only the bits occupied by the bit string */ - src = (int32_t) 0xFFFFFFFF << emu->cpu.program[26]; + mask = (uint32_t) 0xFFFFFFFF << emu->cpu.program[26]; if ((uint32_t)emu->cpu.program[28] < (uint32_t)32-emu->cpu.program[26]) - src &= (1 << (emu->cpu.program[28] + emu->cpu.program[26])) - 1; - dest = (dest & src) | (emu->cpu.access.value & ~src); + mask &= (1 << (emu->cpu.program[28] + emu->cpu.program[26])) - 1; + dest = (dest & mask) | (emu->cpu.access.value & ~mask); /* Write the data unit to the bus */ - if (cpuWrite(emu, emu->cpu.program[30], VB_S32, dest)) + if (cpuWrite(emu, emu->cpu.program[29], VB_S32, dest)) return 1; /* Update state */ @@ -391,23 +403,30 @@ static int cpuBitString(VB *emu, VB_INSTRUCTION *inst) { } /* Working variables */ - dest = 32 - emu->cpu.program[26]; /* Bits processed this invocation */ - if ((uint32_t) emu->cpu.program[28] < (uint32_t) dest) - dest = emu->cpu.program[28]; - src = emu->cpu.program[30] + dest; /* New source bit offset */ + mask = 32 - emu->cpu.program[26]; /* Bits processed this invocation */ + if ((uint32_t) emu->cpu.program[28] < (uint32_t) mask) + mask = emu->cpu.program[28]; + dest = emu->cpu.program[26] + mask; /* New destination bit offset */ + src = emu->cpu.program[27] + mask; /* New source bit offset */ /* Update state */ emu->cpu.busWait = 0; - emu->cpu.substring = dest != emu->cpu.program[28]; - if (src >= 32) { - inst->aux[0] = inst->aux[1]; + emu->cpu.substring = mask != emu->cpu.program[28]; + emu->cpu.program[26] = dest & 31; + emu->cpu.program[27] = src & 31; + emu->cpu.program[28] -= mask; + if (dest >= 32) + emu->cpu.program[29] += 4; + if (src >= 32) emu->cpu.program[30] += 4; + if (emu->cpu.substring) { + emu->cpu.busWait = 1; + emu->cpu.clocks = 6; + inst->aux[0] = inst->aux[1]; + } else { + emu->cpu.busWait = 0; + emu->cpu.clocks = 36; } - emu->cpu.program[29] += 4; - emu->cpu.program[28] -= dest; - emu->cpu.program[27] = src & 0x1F; - emu->cpu.program[26] = 0; - emu->cpu.clocks = emu->cpu.substring ? 6 : 36; return 0; } @@ -502,7 +521,8 @@ static int32_t cpuFloatResult(VB *emu, double resultd) { static void cpuFloatToWord(VB *emu, VB_INSTRUCTION *inst, int truncate) { int32_t bits = emu->cpu.program[inst->bits[0] & 0x1F]; int32_t result; /* Output value */ - int32_t x; /* Working variable field */ + int32_t x; /* Working variable */ + int32_t y; /* Working variable */ /* Zero */ if ((bits & 0x7FFFFFFF) == 0) @@ -524,7 +544,7 @@ static void cpuFloatToWord(VB *emu, VB_INSTRUCTION *inst, int truncate) { } /* Invalid operation */ - if (x >= 135) { + if (x >= 158) { emu->cpu.causeCode = 0xFF70; emu->cpu.psw.fiv = 1; return; @@ -534,22 +554,22 @@ static void cpuFloatToWord(VB *emu, VB_INSTRUCTION *inst, int truncate) { result = (bits & 0x007FFFFF) | 0x00800000; /* Left shift */ - if (x >= 127) - result <<= x - 127; + if (x >= 150) + result <<= x - 150; /* Right shift */ else { - x = 127 - x; /* Number of bits to shift */ - result >>= x; /* Update state */ - x = 1 << x; /* Position of the "one halfths" bit */ + y = result; /* Significant bits */ + x = 150 - x; /* Number of bits to shift */ + result >>= x; /* Update state */ /* Precision degradation */ - if ((bits & (x - 1)) != 0) { + if ((y & ((1 << x) - 1)) != 0) { emu->cpu.psw.fpr = 1; /* Apply rounding */ - if (!truncate && (bits & x) != 0) - result += x; + if (!truncate) + result += y >> (x - 1) & 1; } } @@ -885,6 +905,7 @@ static void cpuCVT_WS(VB *emu, VB_INSTRUCTION *inst) { /* Divide */ static void cpuDIV(VB *emu, VB_INSTRUCTION *inst) { int32_t right = emu->cpu.program[inst->bits[0] & 0x1F]; + int32_t *r30; /* Program register r30 */ int32_t *reg2; /* Program register reg2 */ /* Zero division */ @@ -902,9 +923,12 @@ static void cpuDIV(VB *emu, VB_INSTRUCTION *inst) { /* Perform the operation */ else { - emu->cpu.program[30] = *reg2 % right; - *reg2 /= right; - emu->cpu.psw.ov = 0; + r30 = &emu->cpu.program[30]; + *r30 = *reg2 % right; + if ((*r30 ^ *reg2) < 0) + *r30 = -*r30; + *reg2 /= right; + emu->cpu.psw.ov = 0; } /* Update state */ @@ -1592,7 +1616,7 @@ static int cpuException(VB *emu) { emu->cpu.eipcTo = emu->cpu.pcTo; emu->cpu.psw.ep = 1; emu->cpu.pc = (causeCode & 0x0040) != 0 ? - 0xFFFFFF60 : ((uint32_t) 0xFFFF0000 | causeCode); + 0xFFFFFF60 : ((uint32_t) 0xFFFF0000 | (causeCode & 0xFFF0)); } /* Interrupt */ @@ -1658,8 +1682,8 @@ static int cpuFetch(VB *emu) { /* Determine the internal ID of the instruction */ inst->id = CPU_OPCODES[opcode]; switch (inst->id) { - case CPU_BITSTRING: inst->id = CPU_BITSTRINGS[inst->id & 0x1F]; break; - case CPU_FLOATENDO: inst->id = CPU_FLOATENDOS[inst->bits[1]>>10&0x3F]; + case CPU_BITSTRING: inst->id=CPU_BITSTRINGS[inst->bits[0]&0x1F]; break; + case CPU_FLOATENDO: inst->id=CPU_FLOATENDOS[inst->bits[1]>>10&0x3F]; } /* Update state */