diff options
author | 2024-12-27 21:56:18 -0500 | |
---|---|---|
committer | 2024-12-27 21:56:18 -0500 | |
commit | 07cc2cf76ab85656a11aee05c308176e4e1c9105 (patch) | |
tree | a79068c6042d8446826c34fd199e414fd2251dfa /src/devices/cpu | |
parent | 39aac1bc7035c10a41bcf0547139279651249519 (diff) |
cpu/mpk1839/kl1839vm1.cpp: Improved VAX-11 code decoder in user space (#13107)
Diffstat (limited to 'src/devices/cpu')
-rw-r--r-- | src/devices/cpu/mpk1839/kl1839vm1.cpp | 672 | ||||
-rw-r--r-- | src/devices/cpu/mpk1839/kl1839vm1.h | 61 | ||||
-rw-r--r-- | src/devices/cpu/mpk1839/kl1839vm1dasm.cpp | 34 | ||||
-rw-r--r-- | src/devices/cpu/vax/vaxdasm.cpp | 46 | ||||
-rw-r--r-- | src/devices/cpu/vax/vaxdasm.h | 14 |
5 files changed, 626 insertions, 201 deletions
diff --git a/src/devices/cpu/mpk1839/kl1839vm1.cpp b/src/devices/cpu/mpk1839/kl1839vm1.cpp index 00c30e8a5f2..5be6b534f6d 100644 --- a/src/devices/cpu/mpk1839/kl1839vm1.cpp +++ b/src/devices/cpu/mpk1839/kl1839vm1.cpp @@ -5,22 +5,26 @@ #include "kl1839vm1.h" #include "kl1839vm1dasm.h" +#include "cpu/vax/vaxdasm.h" +#include <regex> -#define VERBOSE ( LOG_GENERAL ) +#define LOG_VAX (1U << 1) + +//#define VERBOSE ( LOG_GENERAL | LOG_VAX ) #include "logmacro.h" #define UNIMPLEMENTED(msg) LOG("Unimplemented: %s\n", msg) +#define LOGVAX(...) LOGMASKED(LOG_VAX, __VA_ARGS__) -#define MCA m_mca.w.l // Micro Command Address -#define VMA m_vma.d // Virtual Memory Address -#define RV m_rv.d -#define SCH m_sch.b.l // Program Counter -#define RSP m_rsp.b.l +#define AMC m_amc.d // Microcode PC +#define RV m_rv.d // Return Address +#define SCH m_sch.b.l // Counter +#define RSP m_rsp.b.l // Flags #define K(x) m_consts[x & 0x0f] #define PCM K(5) -#define RC K(6) +#define RC K(6) // Constant /* registers of various sizes */ #define R(x) m_reg[x].d @@ -65,8 +69,13 @@ device_memory_interface::space_config_vector kl1839vm1_device::memory_space_conf void kl1839vm1_device::flag(u32 op) { - const u8 copwt = BIT(op, 15, 1); + const bool tou = BIT(op, 16); + if (tou) + { + // TODO Stop BO till the end of DP (Memory Manager?) + } + const bool copwt = BIT(op, 15); if (copwt) { RNK = PC; @@ -94,7 +103,7 @@ u32 kl1839vm1_device::shr(u32 val, bool va, u8 fo, bool a_c, bool l_r) { case 0b00: left_bit = 31; break; case 0b01: left_bit = 15; break; - case 0b10: left_bit = 31; break; // ??? dd + case 0b10: left_bit = 31; break; case 0b11: left_bit = 7; break; } const u8 rd = l_r ? left_bit : 0; @@ -105,14 +114,13 @@ u32 kl1839vm1_device::shr(u32 val, bool va, u8 fo, bool a_c, bool l_r) res &= ~(1 << wr); if (!a_c) { - res |= (va ? (RSP & CF) : carry_out) << wr; + res |= (va ? (PSW & CF) : carry_out) << wr; } else if (l_r && !va) { res |= carry_out << wr; } - RSP &= ~(VF | CF); RSP |= carry_out; if (a_c && l_r && (fo == 0b10) && (carry_out != BIT(res, rd))) { @@ -121,23 +129,34 @@ u32 kl1839vm1_device::shr(u32 val, bool va, u8 fo, bool a_c, bool l_r) return res; } -void kl1839vm1_device::kop(u8 kop, u8 fd, u32 x, u32 y, u32 &z, u8 ps, bool va = false, u8 fo = 0) +void kl1839vm1_device::kop(u8 kop, u8 fd, u32 x, u32 y, u8 rz, u8 ps, bool va = false, u8 fo = 0) { - u32 res = 0; - RSP &= ~(NF | ZF | VF); - if ((kop & 0b1001) == 0b1001) // shr + u64 res = 0; + switch(fd) { - RSP &= ~CF; + case 0b11: + x = s8(x); + y = s8(y); + break; + case 0b01: + x = s16(x); + y = s16(y); + break; + case 0b00: + default: // 0b10 + break; } + + RSP &= ~(VF | CF); switch(kop) { case 0b0000: res = y; break; // 0b0001: - case 0b0010: res = x + y; break; + case 0b0010: res = u64(x) + y; break; case 0b0011: res = x; break; - case 0b0100: res = x - y; break; + case 0b0100: res = u64(x) - y; break; // 0b0101 - case 0b0110: res = y - x; break; + case 0b0110: res = u64(y) - x; break; case 0b0111: res = ~x; break; case 0b1000: res = x ^ y; break; case 0b1001: res = shr(x, va, fo, 1, 1); break; // AL @@ -150,40 +169,54 @@ void kl1839vm1_device::kop(u8 kop, u8 fd, u32 x, u32 y, u32 &z, u8 ps, bool va = default: break; // 0b0001, 0b0101 - reserved } - switch(fd) - { - case 0b00: - z = res; - RSP |= BIT(res, 31) ? NF : 0; - break; - case 0b01: - z = (z & 0xffff0000) | (res & 0x0000ffff); - RSP |= BIT(res, 15) ? NF : 0; - break; - case 0b11: - z = (z & 0xffffff00) | (res & 0x000000ff); - RSP |= BIT(res, 7) ? NF : 0; - break; - default: RKA = res; break; // 0b10 - } + // flags + RSP &= ~(NF | ZF); + RSP |= BIT(res, 31) ? NF : 0; RSP |= (res == 0) ? ZF : 0; + if (kop && ((kop & 0b1001) == 0b0000)) // +/- + { + const bool sig_y = BIT(y, 31); + const bool sig_x = BIT(x, 31); + RSP |= (kop == 0b0010) // + + ? (((sig_y == sig_x) && (BIT(res, 31) != sig_y)) ? VF : 0) + : (((sig_y != sig_x) && (BIT(res, 31) != ((kop == 0b0110) ? sig_y : sig_x))) ? VF : 0); + RSP |= (((kop & 0b1001) != 0b1001) && BIT(res, 32)) ? CF : 0; + } switch (ps) { case 0b00: PSW = (PSW & ~0x0f) | (RSP & 0x0f); break; - case 0b01: PSW = (PSW & ~0x0e) | (RSP & 0x0e); break; - case 0b10: PSW = (PSW & ~0x0f) | (RSP & 0x0c); break; + case 0b01: PSW = (PSW & ~0x0f) | (RSP & 0x0c); break; + case 0b10: PSW = (PSW & ~0x0e) | (RSP & 0x0e); break; default: break; } + + switch(fd) + { + case 0b11: + res &= 0x000000ff; + R(rz) &= 0xffffff00; + break; + case 0b01: + res &= 0x0000ffff; + R(rz) &= 0xffff0000; + break; + case 0b00: + default: // 0b10 + R(rz) = 0; + break; + } + R(rz) |= res; + if (rz == 0x1f) mreg_w(); } -void kl1839vm1_device::mreg_r() +bool kl1839vm1_device::mreg_r() { - const u8 kob_tmp = BIT(m_vma_tmp.d, 24, 3); - if (kob_tmp == 0b001) + const u8 kob = BIT(m_vma_tmp.d, 24, 3); + if ((kob & 0b101) == 0b001) { - const u8 no_tmp = BIT(m_vma_tmp.d, 30, 2); - switch (no_tmp) + const u8 no = BIT(m_vma_tmp.d, 30, 2); + switch (no) { case 0b00: BO = m_ram.read_dword(m_vma_tmp.d); @@ -198,16 +231,20 @@ void kl1839vm1_device::mreg_r() UNIMPLEMENTED("Read w/ catch BRA"); break; } + + return true; } + + return false; } void kl1839vm1_device::mreg_w() { - const u8 kob_tmp = BIT(m_vma_tmp.d, 24, 3); - if (kob_tmp == 0b010) + const u8 kob = BIT(m_vma_tmp.d, 24, 3); + if ((kob & 0b110) == 0b010) { - const u8 no_tmp = BIT(m_vma_tmp.d, 30, 2); - switch (no_tmp) + const u8 no = BIT(m_vma_tmp.d, 30, 2); + switch (no) { case 0b00: m_ram.write_dword(m_vma_tmp.d, BO); @@ -229,8 +266,8 @@ void kl1839vm1_device::ma(u32 op) { const u8 fd = BIT(op, 28, 2); const u8 kop1 = BIT(op, 24, 4); - const u8 am = BIT(op, 20, 4); - const u8 x = BIT(op, 15, 5); + u8 am = BIT(op, 20, 4); + u8 x = BIT(op, 15, 5); const u8 ps = BIT(op, 13, 2); const bool va = BIT(op, 12); const u8 no = BIT(op, 10, 2); @@ -241,28 +278,55 @@ void kl1839vm1_device::ma(u32 op) const bool py = BIT(op, 2); const bool px = BIT(op, 1); - if (am==5 || am==8 || am>=0xd) - UNIMPLEMENTED("Read regs with data mirror"); + if (am>=0xd) + UNIMPLEMENTED("Read const with data mirror K>0x0d"); + else if (am == 8) + UNIMPLEMENTED("Read const with data mirror K=8"); // CRM priveleges check - if (po | py | px) - UNIMPLEMENTED("MA: P*"); + if (po) + UNIMPLEMENTED("MA: PO"); u32 kob_data = kop1 ? R(x) : K(am); - kop(kop1, fd, R(x), K(am), R(x), ps, va, fo); - if (pd || x == 0x1f) mreg_w(); + + if (!m_pcm_queue.empty()) + { + if (py) + am = vax_pcm_pull(); + else if (am == 5) // PCM + K(5) = vax_pcm_pull(1); + else if (pd && (am == 0x1f)) + BO = vax_pcm_pull(1); + if (px) + x = vax_pcm_pull(); + else if (pd && (x == 0x1f)) + BO = vax_pcm_pull(1); + } + else if (pd) + { + mreg_r(); + } + + kop(kop1, fd, R(x), K(am), x, ps, va, fo); if (va) { kob_data = R(x); } - kob_process(no, fo, kob, kob_data); + if (fd == 0b10) + { + RKA = m_sysram.read_dword(R(x)); + } + else + { + kob_process(no, fo, kob, kob_data, R(x)); + } } void kl1839vm1_device::mb(u32 op) { const u8 fd = BIT(op, 28, 2); const u8 kop2 = BIT(op, 25, 3); - const u8 y = BIT(op, 20, 5); - const u8 x = BIT(op, 15, 5); + u8 y = BIT(op, 20, 5); + u8 x = BIT(op, 15, 5); const u8 ps = BIT(op, 13, 2); const bool va = BIT(op, 12); const u8 no = BIT(op, 10, 2); @@ -273,41 +337,70 @@ void kl1839vm1_device::mb(u32 op) const bool py = BIT(op, 2); const bool px = BIT(op, 1); - if (po | py | px) - UNIMPLEMENTED("MB: P*"); + if (po) + UNIMPLEMENTED("MB: PO"); u32 kob_data = kop2 ? R(x) : R(y); - if (pd || y == 0x1f) mreg_r(); - kop(kop2 << 1, fd, R(x), R(y), R(x), ps, va, fo); - if (pd || x == 0x1f) mreg_w(); + + if (!m_pcm_queue.empty()) + { + if (py) + y = vax_pcm_pull(); + else if (pd && !mreg_r() && (y == 0x1f)) + BO = vax_pcm_pull(1); + if (px) + x = vax_pcm_pull(); + else if (pd && (x == 0x1f)) + BO = vax_pcm_pull(1); + } + else if (pd) + { + mreg_r(); + } + + kop(kop2 << 1, fd, R(x), R(y), x, ps, va, fo); if (va) { kob_data = R(x); } - kob_process(no, fo, kob, kob_data); + kob_process(no, fo, kob, kob_data, R(x)); } void kl1839vm1_device::mc(u32 op) { const u8 fd = BIT(op, 28, 2); const u8 kop2 = BIT(op, 25, 3); - const u8 y = BIT(op, 20, 5); - const u8 x = BIT(op, 15, 5); + u8 y = BIT(op, 20, 5); + u8 x = BIT(op, 15, 5); const u8 ps = BIT(op, 13, 2); - - const u8 z = BIT(op, 7, 5); + u8 z = BIT(op, 7, 5); const bool pd = BIT(op, 4); const bool pz = BIT(op, 3); const bool py = BIT(op, 2); const bool px = BIT(op, 1); - if (pz | py | px) - UNIMPLEMENTED("MC: P*"); + if (!m_pcm_queue.empty()) + { + if (py) + y = vax_pcm_pull(); + else if (pd && !mreg_r() && (y == 0x1f)) + BO = vax_pcm_pull(1); + if (px) + x = vax_pcm_pull(); + else if (pd && !mreg_r() && (x == 0x1f)) + BO = vax_pcm_pull(1); + if (pz) + z = vax_pcm_pull(); + else if (pd && (z == 0x1f)) + BO = vax_pcm_pull(1); + } + else if (pd) + { + mreg_r(); + } - if (pd || x == 0x1f) mreg_r(); - kop(kop2 << 1, fd, R(x), kop2 ? R(y) : R(x), R(z), ps); - if (pd || z == 0x1f) mreg_w(); + kop(kop2 << 1, fd, R(x), kop2 ? R(y) : R(x), z, ps); } void kl1839vm1_device::mk(u32 op) @@ -315,7 +408,7 @@ void kl1839vm1_device::mk(u32 op) const bool ret = BIT(op, 17); if (!ret) { - RV = MCA; + RV = AMC; } if ((op & 0xfe000000) == 0xe0000000) @@ -323,19 +416,19 @@ void kl1839vm1_device::mk(u32 op) if (BIT(~op, 16)) // madr == 0 { const u16 addr = BIT(op, 2, 14); - MCA = addr; + AMC = addr; } else { u16 addr_hi = BIT(op, 8, 8) << 6; - MCA = addr_hi | (R(0x18) & 0x3f); + AMC = addr_hi | (R(0x18) & 0x3f); } } else if ((op & 0xfe000000) == 0xe2000000) { u16 addr_hi = BIT(op, 8, 8) << 6; //u8 rpp = BIT(op, 2, 4); // TODO rpp irq code - MCA = addr_hi; + AMC = addr_hi; } } @@ -347,7 +440,7 @@ void kl1839vm1_device::yp(u32 op) const bool v = BIT(op, 25); const bool c = BIT(op, 24); const bool fp = BIT(op, 23); - //const bool fpd = BIT(op, 22); + const bool fpd = BIT(op, 22); //const bool prb = BIT(op, 21); //const bool rst = BIT(op, 20); //const bool rd = BIT(op, 19); @@ -358,10 +451,16 @@ void kl1839vm1_device::yp(u32 op) bool jump = false; if (fp) { + // Jump based on SRF flags jump = uv == m_fp; } + else if (fpd) + { + jump = true; + } else { + // zhs=1 - don't wait for the state completed const u8 mask = (n << 3) | (z << 2) | (v << 1) | (c << 0); const u8 reg = zhs ? RSP : PSW; jump = uv ? ((reg & mask) != 0) : ((reg & mask) == 0); @@ -371,49 +470,56 @@ void kl1839vm1_device::yp(u32 op) { if (!ret) { - RV = MCA; + RV = AMC; } - MCA = addr; + AMC = addr; } } void kl1839vm1_device::zsch(u32 op) { - const bool madr = BIT(op, 16); - if (madr) + if (m_jzdra_waiting) { - const u8 cnst_hi = BIT(op, 8, 2) << 6; - SCH = cnst_hi | (R(0x18) & 0x3f); + SCH = R(0x19); + m_jzdra_waiting = false; } else { - const u8 cnst = BIT(op, 2, 8); - SCH = cnst; + const bool madr = BIT(op, 16); + if (madr) + { + const u8 cnst_hi = BIT(op, 8, 2) << 6; + SCH = cnst_hi | (R(0x18) & 0x3f); + } + else + { + const u8 cnst = BIT(op, 2, 8); + SCH = cnst; + } } } void kl1839vm1_device::psch(u32 op) { - const bool madr = BIT(op, 16); - if (madr) - { - const u16 addr_hi = BIT(op, 8, 8) << 6; - MCA = addr_hi | (R(0x18) & 0x3f); - } - else + if (SCH--) { - if (SCH--) + const bool madr = BIT(op, 16); + if (madr) + { + const u16 addr_hi = BIT(op, 8, 8) << 6; + AMC = addr_hi | (R(0x18) & 0x3f); + } + else { const u16 addr = BIT(op, 2, 14); - MCA = addr; + AMC = addr; } - } } void kl1839vm1_device::rts(u32 op) { - MCA = RV; + AMC = RV; } void kl1839vm1_device::acc(u32 op) @@ -463,11 +569,10 @@ void kl1839vm1_device::srf(u32 op) } if (BIT(op, 4)) // OCT { - --MCA; } if (BIT(op, 2)) // JDZRA { - UNIMPLEMENTED("SRF: JDZRA"); + m_jzdra_waiting = true; } if (BIT(op, 1)) // INC { @@ -479,23 +584,31 @@ void kl1839vm1_device::invalid(u32 op) { } -void kl1839vm1_device::kob_process(u8 no, u8 fo, u8 kob, u32 data) +void kl1839vm1_device::kob_process(u8 no, u8 fo, u8 kob, u32 kob_data, u32 data) { switch (kob) { + case 0b000: // NOP + break; case 0b001: // Data Read case 0b010: // Data Write case 0b011: // Read-Modify-Write - m_vma_tmp.d = (no << 30) | (fo << 28) | (kob << 24) | data; + m_vma_tmp.d = (no << 30) | (fo << 28) | (kob << 24) | kob_data; break; case 0b100: // Write Accum R(17) + R(0x17) = data; + break; case 0b101: // Read Command + m_vma_tmp.d = 0; + PC = data; + break; case 0b110: // Offset Write UNIMPLEMENTED("KOB"); break; - case 0b000: // NOP case 0b111: // Reserve - default: break; + default: + m_vma_tmp.d = 0; + break; } } @@ -539,43 +652,289 @@ void kl1839vm1_device::decode_op(u32 op) else if ((op & 0xfc000000) == 0xfc000000) srf(op); else - invalid(op); + UNIMPLEMENTED(op); } } +void kl1839vm1_device::vax_decode_pc() +{ + if (!m_pcm_queue.empty()) + { + LOGVAX("Unused decoded data\n"); + } + m_vma_tmp.d = 0; + + const u8 op = m_ram.read_byte(PC); + m_op_size = 1; + AMC = op << 4; + + m_pcm_queue.clear(); + const vax_disassembler::mode* args = vax_disassembler::get_operands(op); + u8 arg_n = 0; + do + { + m_mem_reg[arg_n] = ~0; // Default to unknown + + const vax_disassembler::mode mode = args[arg_n]; + switch (mode) + { + case vax_disassembler::mode::none: + break; + + // byte + case vax_disassembler::mode::bb: + m_pcm_queue.push_back(s8(m_ram.read_byte(PC + m_op_size))); + m_mem_reg[arg_n] = 0x8f; + m_op_size += 1; + break; + + case vax_disassembler::mode::cntb: + case vax_disassembler::mode::mb: + case vax_disassembler::mode::urb: + case vax_disassembler::mode::srb: + case vax_disassembler::mode::wb: + { + u8 p = m_ram.read_byte(PC + m_op_size); + if (p == 0x8f) // M + { + m_pcm_queue.push_back(m_ram.read_byte(PC + m_op_size + 1)); + m_mem_reg[arg_n] = p; + m_op_size += 2; + } + else if ((p & 0xf0) == 0x80) // M = R(n)+ + { + m_pcm_queue.push_back(p & 0x0f); + m_mem_reg[arg_n] = p; + m_op_size += 1; + } + else if ((p & 0xf0) == 0x50) // R + { + m_pcm_queue.push_back(p & 0x0f); + m_mem_reg[arg_n] = p; + m_op_size += 1; + } + else // ? + { + LOGVAX("OP=%02x unknown prefix %02x in operand mode::%02d\n", op, p, u8(mode)); + m_op_size = 0; + } + break; + } + + // word + case vax_disassembler::mode::bw: + m_pcm_queue.push_back(s16(m_ram.read_word(PC + m_op_size))); + m_mem_reg[arg_n] = 0x8f; + m_op_size += 2; + break; + + // dword + case vax_disassembler::mode::rl: + case vax_disassembler::mode::url: + case vax_disassembler::mode::ml: + case vax_disassembler::mode::prl: + case vax_disassembler::mode::srl: + case vax_disassembler::mode::wl: + { + u8 p = m_ram.read_byte(PC + m_op_size); + if (p == 0x8f) // M + { + m_pcm_queue.push_back(m_ram.read_dword(PC + m_op_size + 1)); + m_mem_reg[arg_n] = p; + m_op_size += 5; + } + else if ((p & 0xf0) == 0x80) // M = R(n)+ + { + m_pcm_queue.push_back(p & 0x0f); + m_mem_reg[arg_n] = p; + m_op_size += 1; + } + else if ((p & 0xf0) == 0x50) // R + { + m_pcm_queue.push_back(p & 0x0f); + m_mem_reg[arg_n] = p; + m_op_size += 1; + } + else // ? + { + LOGVAX("OP=%02x unknown prefix %02x in operand mode::%02d\n", op, p, u8(mode)); + m_op_size = 0; + } + break; + } + + default: + LOGVAX("(%x): unknown operand mode %02d in OP=%02x (n=%d)\n", PC, u8(mode), op, arg_n + 1); + m_pcm_queue.clear(); + m_op_size = 0; + break; + } + + ++arg_n; + } while ((arg_n < 6) && (args[arg_n] != vax_disassembler::mode::none)); + + if (m_op_size > 0) // above completed without failure + { + u8 args_type = 0; + if (!m_pcm_queue.empty()) + { + for (u8 i = 0; i < arg_n; ++i) + { + args_type <<= 1; + if ((m_mem_reg[i] & 0xf0) == 0x80) + args_type |= 1; + else if ((m_mem_reg[i] & 0xf0) == 0x50) + args_type |= 0; + else + LOGVAX("Unknown argument type: %02x\n", m_mem_reg[i]); + } + } + + switch (op) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + assert(m_op_size == 1); // no operands + break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x30: case 0x31: + assert(arg_n == 1); + break; + + case 0x94: case 0x95: case 0x96: case 0x97: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + assert(arg_n == 1); + AMC += 0x0c * args_type; + break; + + case 0xda: + case 0xe8: case 0xe9: + assert(arg_n == 2); + break; + + case 0xdb: + assert(arg_n == 2); + AMC += BIT(args_type, 0) ? 0x0 : 0x2; + break; + + case 0x80: case 0x82: case 0x84: case 0x86: case 0x88: case 0x8a: case 0x8c: + case 0x90: case 0x92: + case 0xa0: case 0xa2: case 0xa4: case 0xa6: case 0xa8: case 0xaa: case 0xac: + case 0xb0: case 0xb2: + case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: + case 0xd0: case 0xd2: + assert(arg_n == 2); + switch (args_type) + { + case 0b00: AMC += 0x0; break; // RR + case 0b01: AMC += 0x4; break; // RM + case 0b10: AMC += 0xe; break; // MR + case 0b11: AMC += 0xc; break; // MM + } + break; + + case 0x91: case 0x93: + case 0xb1: case 0xb3: + case 0xd1: case 0xd3: + assert(arg_n == 2); + switch (args_type) + { + case 0b00: AMC += 0x0; break; // RR + case 0b01: AMC += 0x4; break; // RM + case 0b10: + case 0b11: AMC += 0xc; break; // MM, MR + } + break; + + case 0x78: + assert(arg_n == 3); + AMC += BIT(args_type, 0) ? 0x0 : 0x2; + break; + + case 0x81: case 0x83: case 0x85: case 0x87: case 0x89: case 0x8b: case 0x8d: + case 0xa1: case 0xa3: case 0xa5: case 0xa7: case 0xa9: case 0xab: case 0xad: + case 0xc1: case 0xc3: case 0xc5: case 0xc7: case 0xc9: case 0xcb: case 0xcd: + assert(arg_n == 3); + switch (args_type) + { + case 0b000: AMC += 0x0; break; // RRR + case 0b011: AMC += 0x4; break; // RMM + case 0b010: AMC += 0x6; break; // RMR + case 0b001: AMC += 0x8; break; // RRM + case 0b110: AMC += 0xe; break; // MMR + case 0b111: AMC += 0xc; break; // MMM + } + break; + + default: + LOGVAX("(%x): OP=%02x with %d operands is not implemented or supported\n", PC, op, arg_n); + } + } + + if (!m_op_size) + LOGVAX("(%x): undecoded OP=%02x .. EXIT\n", PC, op); + else + PC += m_op_size; // move to a next op + ;//LOGVAX("(%x): Decoded: OP=%02x args:%d \n", PC, op, m_pcm_queue.size()); +} + +u32 kl1839vm1_device::vax_pcm_pull(bool is_bo) +{ + if (m_pcm_queue.empty()) + { + LOGVAX("Pooling empty decoder queue\n"); + } + else + { + PCM = m_pcm_queue.front(); + m_pcm_queue.pop_front(); + + bool is_mem = (m_mem_reg[0] & 0xf0) == 0x80; + if (is_bo && !is_mem) + { + PCM = R(PCM); + } + else if (is_mem && ((m_mem_reg[0] & 0x0f) != 0x0f)) + { + u8 r = PCM; + PCM = R(PCM); + R(r) = PCM + 1; + } + std::copy(std::begin(m_mem_reg) + 1, std::end(m_mem_reg), std::begin(m_mem_reg)); + } + + return PCM; +} + + void kl1839vm1_device::device_start() { + m_vax_dasm = std::make_unique<vax_disassembler>(); + space(AS_OPCODES).cache(m_microcode); space(AS_DATA).specific(m_sysram); space(AS_PROGRAM).specific(m_ram); space(AS_IO).specific(m_io); - save_item(NAME(m_mca)); - save_item(NAME(m_vma)); save_item(NAME(m_vma_tmp)); save_item(NAME(m_rv)); save_item(NAME(m_sch)); save_item(NAME(m_rsp)); + save_item(NAME(m_amc)); save_item(NAME(m_ppc)); save_item(NAME(m_fp)); save_pointer(NAME(m_reg), 0x20); save_pointer(NAME(m_consts), 0x10); // Register debugger state - state_add(KL1839_MCA, "MCA", MCA).formatstr("%04X"); - state_add(KL1839_VMA, "VMA", VMA).formatstr("%08X"); - state_add_divider(-1); - state_add(KL1839_IF, "cond", m_fp).formatstr("%08s"); - state_add(KL1839_RSP, "RSP", RSP).formatstr("%08s"); - state_add(KL1839_PCM, "PCM", PCM).formatstr("%08X"); - state_add(KL1839_RC, "RC", RC).formatstr("%08X"); - state_add(KL1839_RV, "RV", RV).formatstr("%08X"); - state_add(KL1839_SCH, "SCH", SCH).formatstr("%02X"); - state_add_divider(-1); - state_add(VAX_AP, "AP", AP).formatstr("%08X"); - state_add(VAX_FP, "FP", FP).formatstr("%08X"); - state_add(VAX_SP, "SP", SP).formatstr("%08X"); - state_add(VAX_PC, "PC", PC).formatstr("%08X"); + state_add(KL1839_AMC, "AMC", AMC).formatstr("%08X"); + state_add(KL1839_PSW, "PSW", PSW).formatstr("%08s"); + state_add(KL1839_IF, "cond", m_fp).formatstr("%08s"); + state_add(KL1839_RC, "RC", RC).formatstr("%08X"); + state_add(KL1839_RV, "RV", RV).formatstr("%08X"); + state_add(KL1839_SCH, "SCH", SCH).formatstr("%02X"); state_add_divider(-1); state_add(VAX_R0, "R0", R(0)).formatstr("%08X"); state_add(VAX_R1, "R1", R(1)).formatstr("%08X"); @@ -587,8 +946,15 @@ void kl1839vm1_device::device_start() state_add(VAX_R7, "R7", R(7)).formatstr("%08X"); state_add(VAX_R8, "R8", R(8)).formatstr("%08X"); state_add(VAX_R9, "R9", R(9)).formatstr("%08X"); - state_add(VAX_RA, "RA", R(0x0a)).formatstr("%08X"); - state_add(VAX_RB, "RB", R(0x0b)).formatstr("%08X"); + state_add(VAX_R10, "R10", R(10)).formatstr("%08X"); + state_add(VAX_R11, "R11", R(11)).formatstr("%08X"); + state_add_divider(-1); + state_add(VAX_AP, "AP", AP).formatstr("%08X"); + state_add(VAX_FP, "FP", FP).formatstr("%08X"); + state_add(VAX_SP, "SP", SP).formatstr("%08X"); + state_add(VAX_PC, "PC", PC).formatstr("%08X"); + state_add_divider(-1); + state_add(VAX_INST, "INST", PC).formatstr("%20s"); state_add_divider(-1); state_add(VAX_AK0, "AK0", R(0x14)).formatstr("%08X"); state_add(VAX_AK1, "AK1", R(0x15)).formatstr("%08X"); @@ -605,9 +971,9 @@ void kl1839vm1_device::device_start() state_add(VAX_PSL, "PSL", PSL).formatstr("%08X"); state_add(VAX_BO, "BO", BO).formatstr("%08X"); - state_add(STATE_GENPC, "GENPC", MCA).noshow(); // ??? - state_add(STATE_GENPCBASE, "CURPC", m_ppc.d).noshow(); - state_add(STATE_GENFLAGS, "GENFLAGS", PSW).formatstr("%8s").noshow(); + state_add(STATE_GENPC, "GENPC", AMC).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_ppc.d).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", RSP).formatstr("%8s").noshow(); set_icountptr(m_icount); } @@ -618,18 +984,6 @@ void kl1839vm1_device::state_string_export(const device_state_entry &entry, std: { case STATE_GENFLAGS: str = string_format("%c%c%c%c%c%c%c%c", - PSW & 0x80 ? '?' : '.', - PSW & 0x40 ? '?' : '.', - PSW & 0x20 ? '?' : '.', - PSW & 0x10 ? '?' : '.', - PSW & NF ? 'N' : '.', - PSW & ZF ? 'Z' : '.', - PSW & VF ? 'V' : '.', - PSW & CF ? 'C' : '.' - ); - break; - case KL1839_RSP: - str = string_format("%c%c%c%c%c%c%c%c", RSP & 0x80 ? '?' : '.', RSP & 0x40 ? '?' : '.', RSP & 0x20 ? '?' : '.', @@ -640,9 +994,37 @@ void kl1839vm1_device::state_string_export(const device_state_entry &entry, std: RSP & CF ? 'C' : '.' ); break; + case KL1839_PSW: + str = string_format("%c%c%c%c%c%c%c%c", + PSW & 0x80 ? '?' : '.', + PSW & 0x40 ? '?' : '.', + PSW & 0x20 ? '?' : '.', + PSW & 0x10 ? '?' : '.', + PSW & NF ? 'N' : '.', + PSW & ZF ? 'Z' : '.', + PSW & VF ? 'V' : '.', + PSW & CF ? 'C' : '.' + ); + break; case KL1839_IF: str = string_format("FP%d", m_fp); break; + case VAX_INST: + if (m_op_size) + { + address_space &space_prg = space(AS_PROGRAM); + std::ostringstream buffer; + disasm_data_buffer databuf(space_prg); + m_vax_dasm->disassemble(buffer, PC - m_op_size, databuf, databuf); + + const std::regex reg("\\s+"); + str = regex_replace(buffer.str(), reg, " "); + } + else + { + str = "--------"; + } + break; } } @@ -651,13 +1033,15 @@ void kl1839vm1_device::device_reset() for (auto ® : m_reg) reg.d = 0; - m_ppc.d = MCA = 0x2000; - VMA = 0; + m_ppc.d = AMC = 0x2000; m_fp = false; + m_jzdra_waiting = false; RSP = 0; m_vma_tmp.d = 0; RV = 0; SCH = 0; + m_pcm_queue.clear(); + m_op_size = 0; } void kl1839vm1_device::execute_set_input(int irqline, int state) @@ -668,14 +1052,19 @@ void kl1839vm1_device::execute_run() { do { - m_ppc.d = MCA; + m_ppc.d = AMC; debugger_instruction_hook(m_ppc.d); - u32 op = m_microcode.read_dword(MCA); + u32 op = m_microcode.read_dword(AMC); m_icount -= 2; - ++MCA &= 0x3fff; + ++AMC &= 0x3fff; decode_op(op); + + if (op & 1) // S-bit + { + vax_decode_pc(); + } } while (m_icount > 0); } @@ -683,4 +1072,3 @@ std::unique_ptr<util::disasm_interface> kl1839vm1_device::create_disassembler() { return std::make_unique<kl1839vm1_disassembler>(); } - diff --git a/src/devices/cpu/mpk1839/kl1839vm1.h b/src/devices/cpu/mpk1839/kl1839vm1.h index d04320cf838..4ee4d9eaeae 100644 --- a/src/devices/cpu/mpk1839/kl1839vm1.h +++ b/src/devices/cpu/mpk1839/kl1839vm1.h @@ -6,14 +6,15 @@ #pragma once +#include <deque> enum { - KL1839_MCA = STATE_GENPC, KL1839_VMA, KL1839_IF, KL1839_RSP, KL1839_PCM, KL1839_RC, KL1839_RV, KL1839_SCH, - VAX_R0, VAX_R1, VAX_R2, VAX_R3, VAX_R4, VAX_R5, VAX_R6, VAX_R7, VAX_R8, VAX_R9, VAX_RA, VAX_RB, + KL1839_AMC = STATE_GENPC, KL1839_IF, KL1839_PSW, KL1839_RC, KL1839_RV, KL1839_SCH, + VAX_R0, VAX_R1, VAX_R2, VAX_R3, VAX_R4, VAX_R5, VAX_R6, VAX_R7, VAX_R8, VAX_R9, VAX_R10, VAX_R11, VAX_AP, VAX_FP, VAX_SP, VAX_PC, VAX_AK0, VAX_AK1, VAX_AK2, VAX_AK3, VAX_AK4, VAX_AK5, VAX_AK6, VAX_AK7, VAX_AK8, - VAX_RNK, VAX_RKA, VAX_PSL, VAX_BO + VAX_RNK, VAX_RKA, VAX_PSL, VAX_BO, VAX_INST }; @@ -43,6 +44,22 @@ protected: virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; private: + class disasm_data_buffer : public util::disasm_interface::data_buffer + { + public: + disasm_data_buffer(address_space &space) : m_space(space) + { + } + + virtual u8 r8(offs_t pc) const override { return m_space.read_byte(pc); } + virtual u16 r16(offs_t pc) const override { return m_space.read_word(pc); } + virtual u32 r32(offs_t pc) const override { return m_space.read_dword(pc); } + virtual u64 r64(offs_t pc) const override { return m_space.read_qword(pc); } + + private: + address_space &m_space; + }; + void flag(u32 op); void rest(u32 op); void ma(u32 op); @@ -60,12 +77,15 @@ private: void invalid(u32 op); u32 shr(u32 val, bool va, u8 fo, bool a_c, bool l_r); - void kob_process(u8 no, u8 fd, u8 kob, u32 data); - void kop(u8 kop, u8 fd, u32 x, u32 y, u32 &z, u8 ps, bool va, u8 fo); + void kob_process(u8 no, u8 fd, u8 kob, u32 kob_data, u32 data); + void kop(u8 kop, u8 fd, u32 x, u32 y, u8 rz, u8 ps, bool va, u8 fo); void mreg_w(); - void mreg_r(); + bool mreg_r(); void decode_op(u32 op); + void vax_decode_pc(); + u32 vax_pcm_pull(bool is_bo = 0); + address_space_config m_microcode_config; address_space_config m_sysram_config; address_space_config m_ram_config; @@ -75,17 +95,24 @@ private: memory_access<24, 0, 0, ENDIANNESS_BIG>::specific m_sysram; memory_access<24, 0, 0, ENDIANNESS_LITTLE>::specific m_ram; memory_access<6, 2, -2, ENDIANNESS_LITTLE>::specific m_io; - PAIR m_mca; - PAIR m_vma; - PAIR m_vma_tmp; // does we have int reg for this? - PAIR m_rv; - PAIR m_sch; - PAIR m_rsp; - PAIR m_ppc; // previous program counter - bool m_fp; - u32 m_consts[0x10] = { 0x4, 0x2, 0x8, 0x1, 0x0, 0, 0, 0x66, 0, 0xc00000, 0xffffffff, 0x1f0000, 0x4000000, 0, 0, 0 }; - PAIR m_reg[0x20]; - int m_icount; + + std::unique_ptr<util::disasm_interface> m_vax_dasm; + + PAIR m_vma_tmp; // do we have int reg for this? + PAIR m_rv; + PAIR m_sch; + PAIR m_rsp; + PAIR m_amc; // Microdode PC + PAIR m_ppc; // previous program counter + bool m_fp; + bool m_jzdra_waiting; + u32 m_consts[0x10] = { 0x4, 0x2, 0x8, 0x1, 0x0, 0, 0, 0x66, 0, 0xc00000, 0xffffffff, 0x1f0000, 0x4000000, 0, 0, 0 }; + PAIR m_reg[0x20]; + int m_icount; + u32 m_op_size; + + std::deque<u32> m_pcm_queue; + u8 m_mem_reg[6]; }; DECLARE_DEVICE_TYPE(KL1839VM1, kl1839vm1_device) diff --git a/src/devices/cpu/mpk1839/kl1839vm1dasm.cpp b/src/devices/cpu/mpk1839/kl1839vm1dasm.cpp index 1b9ad4e7dc1..ea80d7a0613 100644 --- a/src/devices/cpu/mpk1839/kl1839vm1dasm.cpp +++ b/src/devices/cpu/mpk1839/kl1839vm1dasm.cpp @@ -12,6 +12,7 @@ static const std::string r_name(u8 id) std::ostringstream ss; switch (id) { + case 0x0f: ss << "PC"; break; case 0x14: ss << "AK0"; break; case 0x15: ss << "AK1"; break; case 0x16: ss << "AK2"; break; @@ -98,7 +99,7 @@ static const void ma(std::ostream &stream, u32 op) const bool py = BIT(op, 2); const bool px = BIT(op, 1); - m_base(stream, op, 'A', kop1, r_name(x), k_name(am), r_name(x)); + m_base(stream, op, 'A', kop1, px ? "RX" : r_name(x), py ? "RY" : k_name(am), px ? "RX" : r_name(x)); if (kob) { @@ -128,7 +129,7 @@ static const void ma(std::ostream &stream, u32 op) case 0b001: stream << "4D "; break; case 0b010: stream << "ZD "; break; case 0b011: stream << "4Z "; break; - case 0b100: stream << "?R(17)==ACC "; break; + case 0b100: stream << "WDAK "; break; case 0b101: stream << "4K "; break; case 0b110: break; // reserved case 0b111: stream << "BRD "; break; @@ -136,8 +137,8 @@ static const void ma(std::ostream &stream, u32 op) } } - if (px | po | py) - stream << "?:" << (px ? "PX " : "") << (po ? "PO " : "") << (py ? "PY " : ""); + if (po) + stream << "?:" << (po ? "RO" : ""); } static const void mb(std::ostream &stream, u32 op) @@ -150,11 +151,11 @@ static const void mb(std::ostream &stream, u32 op) const u8 no = BIT(op, 10, 2); const u8 fo = BIT(op, 8, 2); const u8 kob = BIT(op, 5, 3); - const bool pz = BIT(op, 3); + const bool po = BIT(op, 3); const bool py = BIT(op, 2); const bool px = BIT(op, 1); - m_base(stream, op, 'B', kop2 << 1, r_name(x), r_name(y), r_name(x)); + m_base(stream, op, 'B', kop2 << 1, px ? "RX" : r_name(x), py ? "RY" : r_name(y), px ? "RX" : r_name(x)); if (kob) { @@ -192,7 +193,7 @@ static const void mb(std::ostream &stream, u32 op) case 0b001: stream << "4D "; break; case 0b010: stream << "ZD "; break; case 0b011: stream << "4Z "; break; - case 0b100: stream << "?R(17)==ACC "; break; + case 0b100: stream << "WDAK "; break; case 0b101: stream << "4K "; break; case 0b110: break; // reserved case 0b111: stream << "BRD "; break; @@ -200,8 +201,8 @@ static const void mb(std::ostream &stream, u32 op) } } - if (px | pz | py) - stream << "?:" << (px ? "PX " : "") << (pz ? "PZ " : "") << (py ? "PY " : ""); + if (po) + stream << "?:" << (po ? "RO" : ""); } static const void mc(std::ostream &stream, u32 op) @@ -214,10 +215,7 @@ static const void mc(std::ostream &stream, u32 op) const bool py = BIT(op, 2); const bool px = BIT(op, 1); - m_base(stream, op, 'C', kop2 << 1, r_name(x), kop2 ? r_name(y) : r_name(x), r_name(z)); - - if (px | pz | py) - stream << "?:" << (px ? "PX " : "") << (pz ? "PZ " : "") << (py ? "PY " : ""); + m_base(stream, op, 'C', kop2 << 1, px ? "RX" : r_name(x), kop2 ? (py ? "RY" : r_name(y)) : (px ? "RX" : r_name(x)), pz ? "RZ" : r_name(z)); } static const u32 mk(std::ostream &stream, u32 op) @@ -228,11 +226,12 @@ static const u32 mk(std::ostream &stream, u32 op) if (BIT(~op, 16)) // madr == 0 { const u16 addr = BIT(op, 2, 14); - util::stream_format(stream, "BP%s : ;A=%04X", ret ? " " : "B" ,addr); + util::stream_format(stream, "BP%s : ;A=(%04X)", ret ? " " : "B" , addr); } else { - stream << "??MK-2"; + u16 addr_hi = BIT(op, 8, 8) << 6; + util::stream_format(stream, "BPV%s : ;A=(%04X+%s)", ret ? " " : "D" , addr_hi, r_name(0x18)); } } else if ((op & 0xfe000000) == 0xe2000000) @@ -437,5 +436,10 @@ offs_t kl1839vm1_disassembler::disassemble(std::ostream &stream, offs_t pc, cons stream << "<invalid>"; } + if (op & 1) + { + stream << "S"; + } + return 1 | SUPPORTED | step; } diff --git a/src/devices/cpu/vax/vaxdasm.cpp b/src/devices/cpu/vax/vaxdasm.cpp index 423f5746ebc..229d3972fda 100644 --- a/src/devices/cpu/vax/vaxdasm.cpp +++ b/src/devices/cpu/vax/vaxdasm.cpp @@ -23,37 +23,11 @@ u32 vax_disassembler::opcode_alignment() const return 1; } -enum class vax_disassembler::mode : u8 -{ - none, - rb, srb, urb, cntb, rw, srw, urw, mskw, rl, srl, url, posl, prl, rq, srq, urq, ro, uro, - mb, mw, ml, mq, mo, - wb, ww, wl, wq, wo, - ab, aw, al, aq, ao, - bb, bw, - vb -}; - namespace { using namespace std::literals; using mode = vax_disassembler::mode; -static constexpr bool is_read_mode(mode m) -{ - switch (m) - { - case mode::rb: case mode::srb: case mode::urb: case mode::cntb: - case mode::rw: case mode::srw: case mode::urw: case mode::mskw: - case mode::rl: case mode::srl: case mode::url: case mode::posl: case mode::prl: - case mode::rq: case mode::urq: - case mode::ro: case mode::uro: - return true; - default: - return false; - } -} - static constexpr bool is_address_mode(mode m) { return m == mode::ab || m == mode::aw || m == mode::al || m == mode::aq || m == mode::ao; @@ -1119,3 +1093,23 @@ offs_t vax_disassembler::disassemble(std::ostream &stream, offs_t pc, const vax_ else return disassemble_inst(stream, s_nonprefix_ops[op], pc, ppc, opcodes); } + +bool vax_disassembler::is_read_mode(vax_disassembler::mode m) +{ + switch (m) + { + case mode::rb: case mode::srb: case mode::urb: case mode::cntb: + case mode::rw: case mode::srw: case mode::urw: case mode::mskw: + case mode::rl: case mode::srl: case mode::url: case mode::posl: case mode::prl: + case mode::rq: case mode::urq: + case mode::ro: case mode::uro: + return true; + default: + return false; + } +} + +const vax_disassembler::mode* vax_disassembler::get_operands(u8 op) +{ + return s_nonprefix_ops[op].operand; +} diff --git a/src/devices/cpu/vax/vaxdasm.h b/src/devices/cpu/vax/vaxdasm.h index e5549d4d59f..e12657daab9 100644 --- a/src/devices/cpu/vax/vaxdasm.h +++ b/src/devices/cpu/vax/vaxdasm.h @@ -9,7 +9,16 @@ class vax_disassembler : public util::disasm_interface { public: - enum class mode : u8; + enum class mode : u8 + { + none, + rb, srb, urb, cntb, rw, srw, urw, mskw, rl, srl, url, posl, prl, rq, srq, urq, ro, uro, + mb, mw, ml, mq, mo, + wb, ww, wl, wq, wo, + ab, aw, al, aq, ao, + bb, bw, + vb + }; struct opdef { @@ -21,6 +30,9 @@ public: // construction/destruction vax_disassembler(); + static bool is_read_mode(mode m); + static const mode* get_operands(u8 op); + protected: // disassembler overrides virtual u32 opcode_alignment() const override; |