summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/vt61
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2020-11-21 11:04:53 -0500
committer AJR <ajrhacker@users.noreply.github.com>2020-11-21 11:04:53 -0500
commit28b0086184efe64053c0b0be3fb17f759faf6b4d (patch)
tree79d4041f7f126e8ce077106b00a7a79a05c14745 /src/devices/cpu/vt61
parent74eeef58d8f71cf0da448fb8426d7215279ca0a6 (diff)
vt61_cpu: Add preliminary execution core
Diffstat (limited to 'src/devices/cpu/vt61')
-rw-r--r--src/devices/cpu/vt61/vt61.cpp532
-rw-r--r--src/devices/cpu/vt61/vt61.h26
-rw-r--r--src/devices/cpu/vt61/vt61dasm.cpp54
3 files changed, 582 insertions, 30 deletions
diff --git a/src/devices/cpu/vt61/vt61.cpp b/src/devices/cpu/vt61/vt61.cpp
index 377d9e58244..bcd91776b88 100644
--- a/src/devices/cpu/vt61/vt61.cpp
+++ b/src/devices/cpu/vt61/vt61.cpp
@@ -15,14 +15,21 @@
// device type definition
DEFINE_DEVICE_TYPE(VT61_CPU, vt61_cpu_device, "vt61_cpu", "DEC VT61 CPU")
+ALLOW_SAVE_TYPE(vt61_cpu_device::state);
+ALLOW_SAVE_TYPE(vt61_cpu_device::pc_mode);
+
vt61_cpu_device::vt61_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: cpu_device(mconfig, VT61_CPU, tag, owner, clock)
, m_program_config("microprogram", ENDIANNESS_LITTLE, 16, 10, -1)
, m_memory_config("memory", ENDIANNESS_LITTLE, 8, 16, 0)
, m_idr_config("IDR", ENDIANNESS_LITTLE, 8, 6, 0)
+ , m_time_state(state::T1)
, m_pc(0)
+ , m_pc_mode(pc_mode::CLR)
+ , m_pv_flags(0)
, m_ac(0)
, m_mar(0)
+ , m_md(0)
, m_mdr(0)
, m_ir(0)
, m_sp{0}
@@ -61,6 +68,7 @@ void vt61_cpu_device::device_start()
state_add(VT61_PC, "PC", m_pc).mask(01777).formatstr("%5s");
state_add(STATE_GENPC, "GENPC", m_pc).mask(01777).noshow();
state_add(STATE_GENPCBASE, "CURPC", m_pc).mask(01777).noshow();
+ state_add(STATE_GENFLAGS, "FLAGS", m_pv_flags).mask(7).noshow().formatstr("%3s");
state_add(VT61_AC, "AC", m_ac).formatstr("%03O");
state_add(VT61_MAR, "MAR", m_mar).formatstr("%06O");
state_add<u8>(VT61_MALO, "MALO",
@@ -71,6 +79,7 @@ void vt61_cpu_device::device_start()
[this]() { return (m_mar & 0177400) >> 8; },
[this](u8 data) { m_mar = (m_mar & 000377) | (data << 8); }
).noshow();
+ state_add(VT61_MD, "MD", m_md).formatstr("%03O");
state_add(VT61_MDR, "MDR", m_mdr).formatstr("%03O");
state_add(VT61_IR, "IR", m_ir).mask(6);
for (int i = 0; i < 16; i++)
@@ -79,9 +88,13 @@ void vt61_cpu_device::device_start()
state_add(VT61_MOD, "MOD", m_modem_flags).formatstr("%02O").mask(017);
state_add(VT61_INTRC, "INTRC", m_intrpt_control).formatstr("%02O").mask(017);
+ save_item(NAME(m_time_state));
save_item(NAME(m_pc));
+ save_item(NAME(m_pc_mode));
+ save_item(NAME(m_pv_flags));
save_item(NAME(m_ac));
save_item(NAME(m_mar));
+ save_item(NAME(m_md));
save_item(NAME(m_mdr));
save_item(NAME(m_ir));
save_item(NAME(m_sp));
@@ -92,6 +105,8 @@ void vt61_cpu_device::device_start()
void vt61_cpu_device::device_reset()
{
+ m_time_state = state::T1;
+ m_pc_mode = pc_mode::CLR;
m_pc = 0;
m_misc_flags = 0;
@@ -99,11 +114,517 @@ void vt61_cpu_device::device_reset()
m_intrpt_control = 0;
}
+u8 vt61_cpu_device::get_db(u16 i)
+{
+ // Source decode
+ if ((i >= 0140000) || (i & 03000) == 03000)
+ {
+ // SEL ROM
+ return i & 0377;
+ }
+ else if ((i & 03400) == 02400)
+ {
+ // SEL SPM
+ u8 addr = bitswap<4>(i, 5, 4, 3, 7);
+ if (BIT(i, 6))
+ addr = (addr & 014) | m_ir;
+ return m_sp[addr];
+ }
+ else switch (BIT(i, 7, 4))
+ {
+ case 0:
+ // SEL AC
+ return m_ac;
+
+ case 1:
+ // SEL STATUS 1 (TODO)
+ return 0xff;
+
+ case 2:
+ // SEL SWITCHES (TODO)
+ return 0xff;
+
+ case 3:
+ // CAS 1 (TODO)
+ return 0xff;
+
+ case 4:
+ // CAS 2 (TODO)
+ return 0xff;
+
+ case 5:
+ // SEL RAM
+ return m_md;
+
+ case 6:
+ // SEL IDR
+ return m_idr_cache.read_byte(m_md & 077);
+
+ case 7:
+ // SEL UART (TODO)
+ return 0xff;
+
+ case 9:
+ // SEL TB SW (TODO)
+ return 0xff;
+
+ default:
+ return 0xff;
+ }
+}
+
+bool vt61_cpu_device::branch_mux(u8 cond)
+{
+ // "A" (0-15) and "B" (16-23) branch multiplexers
+ switch (cond)
+ {
+ case 0:
+ // INTR 1 (TODO: other conditions)
+ return !BIT(m_misc_flags, 7) || BIT(m_modem_flags, 1);
+
+ case 1:
+ // NBX (TODO)
+ return true;
+
+ case 2:
+ // NBR (TODO)
+ return true;
+
+ case 3:
+ // F1
+ return !BIT(m_intrpt_control, 2);
+
+ case 4:
+ // F2
+ return !BIT(m_intrpt_control, 3);
+
+ case 5:
+ // C (TODO)
+ return true;
+
+ case 6:
+ // UART R FLAG (TODO)
+ return true;
+
+ case 7:
+ // UART T BUFF (TODO)
+ return true;
+
+ case 8:
+ // DO X OFF (TODO)
+ return true;
+
+ case 9:
+ // GOUT SER RQ (TODO)
+ return true;
+
+ case 10:
+ // F3
+ return !BIT(m_modem_flags, 1);
+
+ case 11:
+ // INTR 2 (TODO)
+ return true;
+
+ case 12:
+ // KEY DOWN (TODO)
+ return true;
+
+ case 13:
+ // PWR UP
+ return BIT(m_misc_flags, 7);
+
+ case 14:
+ // SYNC ENA (TODO)
+ return true;
+
+ case 15:
+ // PARITY ERROR (TODO)
+ return false;
+
+ case 16:
+ // MEM BZY (TODO)
+ return false;
+
+ case 17:
+ // EQUAL
+ return (m_pv_flags & EQUAL) != 0;
+
+ case 18:
+ // CARRY OUT
+ return (m_pv_flags & CARRY_OUT) == 0;
+
+ case 19:
+ // MDR O.F. OUT
+ return (m_pv_flags & MDR_OF_OUT) != 0;
+
+ case 20:
+ // COPIER SER REQ (TODO)
+ return true;
+
+ case 21:
+ // C-PCF (TODO)
+ return true;
+
+ case 22:
+ // TRUE
+ return true;
+
+ case 23:
+ // VID SERV REQ (TODO)
+ return true;
+
+ default:
+ logerror("%04o: Undefined branch condition\n", m_pc);
+ return false;
+ }
+}
+
+void vt61_cpu_device::operate_t5(u16 i)
+{
+ if (i >= 0140000)
+ {
+ if (branch_mux(BIT(i, 8, 5)) != BIT(i, 13))
+ m_pc_mode = pc_mode::LD;
+ }
+ else if ((i & 0140000) == 040000)
+ {
+ // Destination decode
+ switch (BIT(i, 11, 3))
+ {
+ case 0:
+ // LD MA LO (MA HI is cleared)
+ m_mar = get_db(i);
+ break;
+
+ case 1:
+ // LD MA HI
+ m_mar = u16(get_db(i)) << 8 | (m_mar & 0377);
+ break;
+
+ case 2:
+ // LD PC
+ m_pc_mode = pc_mode::LD;
+ break;
+
+ case 3:
+ // LD UART (TODO)
+ break;
+
+ case 4:
+ // CAS3 (TODO)
+ break;
+
+ case 5:
+ // LD MDR
+ m_mdr = get_db(i);
+ break;
+
+ case 6: case 7:
+ // LD SP
+ if ((i & 02400) == 02400)
+ logerror("%04o: SP load from SP!?\n", m_pc);
+ else
+ {
+ u8 addr = bitswap<4>(i, 5, 4, 3, 11);
+ if (BIT(i, 6))
+ addr = (addr & 011) | (m_ir << 1);
+ m_sp[addr] = get_db(i);
+ }
+ break;
+ }
+ }
+ else if ((i & 060000) == 0 && (BIT(i, 15) || !BIT(i, 12)))
+ {
+ u8 b = get_db(i);
+ if (BIT(i, 15))
+ {
+ bool cin = BIT(i, 11) && !BIT(i, 12) && BIT(i, 2) && (m_pv_flags & CARRY_OUT) != 0;
+ bool cout = false;
+ u8 f = m_ac;
+ switch (BIT(i, 12) ? 6 : i & 7)
+ {
+ case 0:
+ // 74LS181: M = 1, Sn = 0000
+ f = ~m_ac;
+ break;
+
+ case 1:
+ // 74LS181: M = 1, Sn = 1110
+ f = m_ac | b;
+ break;
+
+ case 2:
+ // 74LS181: M = 1, Sn = 0110
+ f = m_ac ^ b;
+ break;
+
+ case 3:
+ // 74LS181: M = 1, Sn = 1011
+ f = m_ac & b;
+ break;
+
+ case 4:
+ // 74LS181: M = 0, Sn = 1111
+ cout = !cin && m_ac == 0;
+ f = m_ac - (cin ? 0 : 1);
+ break;
+
+ case 5:
+ // 74LS181: M = 0, Sn = 1001
+ cout = (m_ac + b + (cin ? 1 : 0)) >= 0400;
+ f = m_ac + b + (cin ? 1 : 0);
+ break;
+
+ case 6:
+ // 74LS181: M = 0, Sn = 0110
+ cout = m_ac >= (b + (cin ? 0 : 1));
+ f = m_ac - b - (cin ? 0 : 1);
+ break;
+
+ case 7:
+ // 74LS181: M = 0, Sn = 1100
+ cout = m_ac >= 0200;
+ f = m_ac + m_ac + (cin ? 1 : 0);
+ break;
+ }
+ m_pv_flags &= ~(CARRY_OUT | EQUAL);
+ if (cout)
+ m_pv_flags |= CARRY_OUT;
+ if (f == 0377)
+ m_pv_flags |= EQUAL;
+ if (!BIT(i, 12))
+ m_ac = f;
+ }
+ else
+ m_ac = get_db(i);
+ }
+}
+
+void vt61_cpu_device::operate_t8(u16 i)
+{
+ // Note that only dynamic RAM outputs are latched like this; static RAM and macrocode PROMs are not latched
+ u8 next_md = m_memory_cache.read_byte(m_mar);
+
+ bool op_ins = (i & 0160000) == 0120000;
+ if (op_ins)
+ {
+ // "B" micro-operations on I/O board
+ switch (BIT(i, 8, 4))
+ {
+ case 0:
+ // No-op
+ break;
+
+ case 2:
+ // RESET C (TODO)
+ break;
+
+ case 5:
+ // LOAD MISC F
+ m_misc_flags = m_ac;
+ break;
+
+ case 6:
+ // LD LED (TODO)
+ break;
+
+ case 7:
+ // LOAD MOD F
+ m_modem_flags = m_ac & 017;
+ break;
+
+ case 8:
+ // SET KEY (TODO)
+ break;
+
+ case 9:
+ // LD INTRPT CONT
+ m_intrpt_control = m_ac & 017;
+ break;
+
+ case 11:
+ // CLR NBR (TODO)
+ break;
+
+ case 12:
+ // LD SYNC + CLR NBX (TODO)
+ break;
+
+ case 13:
+ // PLD (TODO)
+ break;
+
+ case 14:
+ // CLR VID SER REQ (TODO)
+ break;
+
+ case 15:
+ // ENABLE VID LD (TODO)
+ break;
+ }
+ }
+
+ if (op_ins || ((!BIT(i, 15) || (i & 070000) == 010000) && (i & 03000) != 03000))
+ {
+ // "A" micro-operations
+ switch (i & 7)
+ {
+ case 0:
+ // No-op
+ break;
+
+ case 1:
+ // INC AC
+ ++m_ac;
+ break;
+
+ case 2:
+ // LD IR
+ m_ir = m_md >> 6;
+ m_pc = (m_pc + 0400) & 01777;
+ break;
+
+ case 3:
+ // INC MA
+ ++m_mar;
+ break;
+
+ case 4:
+ // SHIFT MDR (TODO: serial input)
+ if (BIT(m_mdr, 0))
+ m_pv_flags |= MDR_OF_OUT;
+ else
+ m_pv_flags &= ~MDR_OF_OUT;
+ m_mdr >>= 1;
+ break;
+
+ case 5:
+ // CLR PC
+ m_pc_mode = pc_mode::CLR;
+ break;
+
+ case 6:
+ // COMP PC 8
+ m_pc = (m_pc + 0400) & 01777;
+ break;
+
+ case 7:
+ // LD RAM
+ m_memory_cache.write_byte(m_mar, m_mdr);
+ break;
+ }
+ }
+
+ m_md = next_md;
+ switch (m_pc_mode)
+ {
+ case pc_mode::CLR:
+ m_pc = 0;
+ break;
+
+ case pc_mode::INC:
+ m_pc = (m_pc & 01400) | ((m_pc + 1) & 0377);
+ break;
+
+ case pc_mode::LD:
+ m_pc = (m_pc & 01400) | get_db(i);
+ break;
+ }
+}
+
void vt61_cpu_device::execute_run()
{
- debugger_instruction_hook(m_pc);
+ switch (m_time_state)
+ {
+ while (true)
+ {
+ [[fallthrough]];
+
+ case state::T1:
+ debugger_instruction_hook(m_pc);
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T2;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T2:
+ m_pc_mode = pc_mode::INC;
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T3;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T3:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T4;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T4:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T5;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T5:
+ operate_t5(m_program_cache.read_word(m_pc));
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T6;
+ return;
+ }
+ [[fallthrough]];
- m_icount = 0;
+ case state::T6:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T7;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T7:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T8;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T8:
+ operate_t8(m_program_cache.read_word(m_pc));
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T9;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T9:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T10;
+ return;
+ }
+ [[fallthrough]];
+
+ case state::T10:
+ if (--m_icount <= 0)
+ {
+ m_time_state = state::T1;
+ return;
+ }
+ }
+ }
}
void vt61_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
@@ -113,5 +634,12 @@ void vt61_cpu_device::state_string_export(const device_state_entry &entry, std::
case VT61_PC:
str = string_format("%o:%03o", m_pc >> 8, m_pc & 0377);
break;
+
+ case STATE_GENFLAGS:
+ str = string_format("%c%c%c",
+ (m_pv_flags & MDR_OF_OUT) != 0 ? 'O' : '.',
+ (m_pv_flags & EQUAL) != 0 ? '=' : '.',
+ (m_pv_flags & CARRY_OUT) != 0 ? 'C' : '.');
+ break;
}
}
diff --git a/src/devices/cpu/vt61/vt61.h b/src/devices/cpu/vt61/vt61.h
index c2aa2d39f6b..971343fe095 100644
--- a/src/devices/cpu/vt61/vt61.h
+++ b/src/devices/cpu/vt61/vt61.h
@@ -13,7 +13,7 @@ public:
VT61_PC,
VT61_AC,
VT61_MAR, VT61_MALO, VT61_MAHI,
- VT61_MDR,
+ VT61_MD, VT61_MDR,
VT61_IR,
VT61_R0, VT61_R1, VT61_R2, VT61_R3,
VT61_R4, VT61_R5, VT61_R6, VT61_R7,
@@ -47,6 +47,26 @@ protected:
void state_string_export(const device_state_entry &entry, std::string &str) const override;
private:
+ enum class state : u8 {
+ T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
+ };
+
+ enum class pc_mode : u8 {
+ CLR, INC, LD
+ };
+
+ enum pv_flags : u8 {
+ CARRY_OUT = 1 << 0,
+ EQUAL = 1 << 1,
+ MDR_OF_OUT = 1 << 2
+ };
+
+ // instruction helpers
+ u8 get_db(u16 i);
+ bool branch_mux(u8 cond);
+ void operate_t5(u16 i);
+ void operate_t8(u16 i);
+
// address spaces
address_space_config m_program_config;
address_space_config m_memory_config;
@@ -56,9 +76,13 @@ private:
memory_access< 6, 0, 0, ENDIANNESS_LITTLE>::cache m_idr_cache;
// processor state
+ state m_time_state;
u16 m_pc;
+ pc_mode m_pc_mode;
+ u8 m_pv_flags;
u8 m_ac;
u16 m_mar;
+ u8 m_md; // memory output
u8 m_mdr;
u8 m_ir;
u8 m_sp[16]; // scratchpad memory
diff --git a/src/devices/cpu/vt61/vt61dasm.cpp b/src/devices/cpu/vt61/vt61dasm.cpp
index 1471cf0a918..7c89354b3e3 100644
--- a/src/devices/cpu/vt61/vt61dasm.cpp
+++ b/src/devices/cpu/vt61/vt61dasm.cpp
@@ -65,31 +65,31 @@ const char *const vt61_disassembler::s_sources[12] = {
};
const char *const vt61_disassembler::s_conditions[32][2] = {
- { "NINTR1", "INTR1" }, // INTR 1 L
- { "NBXF", "NBXT" }, // NBX L
- { "NBRF", "NBRT" }, // NBR L
- { "NF1", "F1" }, // F1 L
- { "NF2", "F2" }, // F2 L
- { "NCF", "CF" }, // C L
- { "NURF", "URF" }, // UART R FLAG L
- { "NUTB", "UTB" }, // UART T BUFF L
- { "NXOFF", "XOFF" }, // DO X OFF L
- { "NGOSR", "GOSR" }, // GOUT SER RQ L
- { "NF3", "F3" }, // F3 L
- { "NINTR2", "INTR2" }, // INTR 2 L
- { "KEYUP", "KEYDN" }, // KEY DOWN L
- { "NPWRUP", "PWRUP" }, // PWR UP L
- { "NSYNC", "SYNC" }, // SYNC ENA L
- { "PE", "NPE" }, // PARITY ERROR H
- { "BZY", "NBZY" }, // MEM BZY H
- { "EQ", "NE" }, // EQUAL H
- { "CC", "CS" }, // CARRY OUT L
- { "MDOFO", "MDOFZ" }, // MDR O.F. OUT H
- { "NCSR", "CSR" }, // COPIER SER REQ L
- { "NCPCF", "CPCF" }, // C-PCF L
- { "T", "F" }, // TRUE H
- { "NVSR", "VSR" }, // VID SERV REQ L
- { "?H", "?L" },
+ { "INTR1", "NINTR1" }, // INTR 1 L (actually active high)
+ { "NBXF", "NBXT" }, // NBX L
+ { "NBRF", "NBRT" }, // NBR L
+ { "NF1", "F1" }, // F1 L
+ { "NF2", "F2" }, // F2 L
+ { "NCF", "CF" }, // C L
+ { "NURF", "URF" }, // UART R FLAG L
+ { "NUTB", "UTB" }, // UART T BUFF L
+ { "NXOFF", "XOFF" }, // DO X OFF L
+ { "NGOSR", "GOSR" }, // GOUT SER RQ L
+ { "NF3", "F3" }, // F3 L
+ { "NINTR2", "INTR2" }, // INTR 2 L
+ { "KEYUP", "KEYDN" }, // KEY DOWN L
+ { "NPWRUP", "PWRUP" }, // PWR UP L
+ { "NSYNC", "SYNC" }, // SYNC ENA L
+ { "PE", "NPE" }, // PARITY ERROR H
+ { "BZY", "NBZY" }, // MEM BZY H
+ { "EQ", "NE" }, // EQUAL H
+ { "CC", "CS" }, // CARRY OUT L
+ { "MDOFO", "MDOFZ" }, // MDR O.F. OUT H
+ { "NCSR", "CSR" }, // COPIER SER REQ L
+ { "NCPCF", "CPCF" }, // C-PCF L
+ { "T", "F" }, // TRUE H
+ { "NVSR", "VSR" }, // VID SERV REQ L
+ { "?H", "?L" },
{ "?H", "?L" },
{ "?H", "?L" },
{ "?H", "?L" },
@@ -167,7 +167,7 @@ offs_t vt61_disassembler::disassemble(std::ostream &stream, offs_t pc, const vt6
break;
case 050000:
- stream << "JMP ";
+ stream << "JUMP ";
break;
case 060000:
@@ -195,7 +195,7 @@ offs_t vt61_disassembler::disassemble(std::ostream &stream, offs_t pc, const vt6
}
else if (BIT(inst, 14))
{
- util::stream_format(stream, "BR %s,%03o", s_conditions[(inst & 017400) >> 8][BIT(inst, 13)], inst & 000377);
+ util::stream_format(stream, "JMP %s,%03o", s_conditions[(inst & 017400) >> 8][BIT(inst, 13)], inst & 000377);
}
else if (BIT(inst, 13))
{