summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/tms1000/tms1k_base.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/tms1000/tms1k_base.cpp')
-rw-r--r--src/devices/cpu/tms1000/tms1k_base.cpp358
1 files changed, 177 insertions, 181 deletions
diff --git a/src/devices/cpu/tms1000/tms1k_base.cpp b/src/devices/cpu/tms1000/tms1k_base.cpp
index f669a349662..f885532d813 100644
--- a/src/devices/cpu/tms1000/tms1k_base.cpp
+++ b/src/devices/cpu/tms1000/tms1k_base.cpp
@@ -4,13 +4,6 @@
TMS1000 family - base/shared
- TODO:
- - accurate INIT pin (currently, just use INPUT_LINE_RESET)
- - emulate newer die revisions? TMS1xxx rev. E and up have 4 cycles
- per opcode instead of 6. But which steps go where, is unknown.
- For now, just overclock the MCU instead.
-
-
The TMS0980 and TMS1000-family MCU cores are very similar. The TMS0980 has a
slightly bigger addressable area and uses 9bit instructions where the TMS1000
family uses 8bit instruction. The instruction set themselves are very similar
@@ -70,34 +63,42 @@ unknown cycle: CME, SSE, SSS
#include "emu.h"
#include "tms1k_base.h"
-#include "debugger.h"
-
-tms1k_base_device::tms1k_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 o_pins, u8 r_pins, u8 pc_bits, u8 byte_bits, u8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data)
- : cpu_device(mconfig, type, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_BIG, byte_bits > 8 ? 16 : 8, prgwidth, byte_bits > 8 ? -1 : 0, program)
- , m_data_config("data", ENDIANNESS_BIG, 8, datawidth, 0, data)
- , m_mpla(*this, "mpla")
- , m_ipla(*this, "ipla")
- , m_opla(*this, "opla")
- , m_opla_b(*this, "opla_b")
- , m_spla(*this, "spla")
- , m_o_pins(o_pins)
- , m_r_pins(r_pins)
- , m_pc_bits(pc_bits)
- , m_byte_bits(byte_bits)
- , m_x_bits(x_bits)
- , m_output_pla_table(nullptr)
- , m_read_k(*this)
- , m_write_o(*this)
- , m_write_r(*this)
- , m_power_off(*this)
- , m_read_ctl(*this)
- , m_write_ctl(*this)
- , m_write_pdc(*this)
-{
-}
-
-// disasm
+
+tms1k_base_device::tms1k_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 o_pins, u8 r_pins, u8 pc_bits, u8 byte_bits, u8 x_bits, u8 stack_levels, int rom_width, address_map_constructor rom_map, int ram_width, address_map_constructor ram_map) :
+ cpu_device(mconfig, type, tag, owner, clock),
+ m_program_config("program", ENDIANNESS_BIG, byte_bits > 8 ? 16 : 8, rom_width, byte_bits > 8 ? -1 : 0, rom_map),
+ m_data_config("data", ENDIANNESS_BIG, 8, ram_width, 0, ram_map),
+ m_mpla(*this, "mpla"),
+ m_ipla(*this, "ipla"),
+ m_opla(*this, "opla"),
+ m_opla_b(*this, "opla_b"),
+ m_spla(*this, "spla"),
+ m_o_pins(o_pins),
+ m_r_pins(r_pins),
+ m_pc_bits(pc_bits),
+ m_byte_bits(byte_bits),
+ m_x_bits(x_bits),
+ m_stack_levels(stack_levels),
+ m_option_dec_div(0),
+ m_read_k(*this, 0),
+ m_write_o(*this),
+ m_write_r(*this),
+ m_read_j(*this, 0),
+ m_read_r(*this, 0),
+ m_power_off(*this),
+ m_read_ctl(*this, 0),
+ m_write_ctl(*this),
+ m_write_pdc(*this),
+ m_output_pla_table(nullptr),
+ m_decode_micro(*this, 0)
+{ }
+
+
+
+//-------------------------------------------------
+// disasm
+//-------------------------------------------------
+
void tms1k_base_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
switch (entry.index())
@@ -106,20 +107,27 @@ void tms1k_base_device::state_string_export(const device_state_entry &entry, std
case STATE_GENPCBASE:
str = string_format("%03X", m_rom_address << ((m_byte_bits > 8) ? 1 : 0));
break;
+
+ case STATE_GENFLAGS:
+ // not a single flags register, first 3 are TMS0980-family
+ str = string_format("%c%c%c %c%c%c",
+ m_bl ? 'B':'b',
+ m_add ? 'A':'a',
+ m_eac ? 'E':'e',
+ (m_clatch & 1) ? 'C':'c',
+ m_status ? 'S':'s',
+ m_status_latch ? 'L':'l'
+ );
+ break;
}
}
+
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
-enum
-{
- TMS1XXX_PC=1, TMS1XXX_SR, TMS1XXX_PA, TMS1XXX_PB,
- TMS1XXX_A, TMS1XXX_X, TMS1XXX_Y, TMS1XXX_STATUS
-};
-
void tms1k_base_device::device_start()
{
m_program = &space(AS_PROGRAM);
@@ -130,15 +138,6 @@ void tms1k_base_device::device_start()
m_pc_mask = (1 << m_pc_bits) - 1;
m_x_mask = (1 << m_x_bits) - 1;
- // resolve callbacks
- m_read_k.resolve_safe(0);
- m_write_o.resolve_safe();
- m_write_r.resolve_safe();
- m_power_off.resolve_safe();
- m_read_ctl.resolve_safe(0);
- m_write_ctl.resolve_safe();
- m_write_pdc.resolve_safe();
-
if (m_opla_b != nullptr && m_output_pla_table == nullptr)
set_output_pla(&m_opla_b->as_u16());
@@ -221,28 +220,20 @@ void tms1k_base_device::device_start()
save_item(NAME(m_subcycle));
// register state for debugger
- state_add(TMS1XXX_PC, "PC", m_pc ).formatstr("%02X");
- state_add(TMS1XXX_SR, "SR", m_sr ).formatstr("%01X");
- state_add(TMS1XXX_PA, "PA", m_pa ).formatstr("%01X");
- state_add(TMS1XXX_PB, "PB", m_pb ).formatstr("%01X");
- state_add(TMS1XXX_A, "A", m_a ).formatstr("%01X");
- state_add(TMS1XXX_X, "X", m_x ).formatstr("%01X");
- state_add(TMS1XXX_Y, "Y", m_y ).formatstr("%01X");
- state_add(TMS1XXX_STATUS, "STATUS", m_status).formatstr("%01X");
-
state_add(STATE_GENPC, "GENPC", m_rom_address).formatstr("%03X").noshow();
state_add(STATE_GENPCBASE, "CURPC", m_rom_address).formatstr("%03X").noshow();
- state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%8s").noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_status).formatstr("%7s").noshow();
- set_icountptr(m_icount);
-}
+ m_state_count = 0;
+ state_add(++m_state_count, "PC", m_pc).formatstr("%02X"); // 1
+ state_add(++m_state_count, "SR", m_sr).formatstr("%01X"); // 2
+ state_add(++m_state_count, "PA", m_pa).formatstr("%01X"); // 3
+ state_add(++m_state_count, "PB", m_pb).formatstr("%01X"); // 4
+ state_add(++m_state_count, "A", m_a).formatstr("%01X"); // 5
+ state_add(++m_state_count, "X", m_x).formatstr("%01X"); // 6
+ state_add(++m_state_count, "Y", m_y).formatstr("%01X"); // 7
-device_memory_interface::space_config_vector tms1k_base_device::memory_space_config() const
-{
- return space_config_vector {
- std::make_pair(AS_PROGRAM, &m_program_config),
- std::make_pair(AS_DATA, &m_data_config)
- };
+ set_icountptr(m_icount);
}
@@ -274,15 +265,59 @@ void tms1k_base_device::device_reset()
// clear outputs
m_r = 0;
- m_write_r(0, m_r & m_r_mask, 0xffff);
- write_o_output(0);
- m_write_r(0, m_r & m_r_mask, 0xffff);
+ write_r_output(0);
+ write_o_reg(0);
+ write_r_output(0);
m_power_off(0);
}
//-------------------------------------------------
+// common internal memory maps
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector tms1k_base_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_DATA, &m_data_config)
+ };
+}
+
+void tms1k_base_device::rom_10bit(address_map &map)
+{
+ map(0x000, 0x3ff).rom();
+}
+
+void tms1k_base_device::rom_11bit(address_map &map)
+{
+ map(0x000, 0x7ff).rom();
+}
+
+void tms1k_base_device::rom_12bit(address_map &map)
+{
+ map(0x000, 0xfff).rom();
+}
+
+void tms1k_base_device::ram_6bit(address_map &map)
+{
+ map(0x00, 0x3f).ram();
+}
+
+void tms1k_base_device::ram_7bit(address_map &map)
+{
+ map(0x00, 0x7f).ram();
+}
+
+void tms1k_base_device::ram_8bit(address_map &map)
+{
+ map(0x00, 0xff).ram();
+}
+
+
+
+//-------------------------------------------------
// program counter/opcode decode
//-------------------------------------------------
@@ -319,18 +354,12 @@ void tms1k_base_device::read_opcode()
// i/o handling
//-------------------------------------------------
-void tms1k_base_device::write_o_output(u8 index)
+void tms1k_base_device::write_o_reg(u8 index)
{
// a hardcoded table is supported if the output pla is unknown
m_o_index = index;
m_o = (m_output_pla_table == nullptr) ? m_opla->read(index) : m_output_pla_table[index];
- m_write_o(0, m_o & m_o_mask, 0xffff);
-}
-
-u8 tms1k_base_device::read_k_input()
-{
- // K1,2,4,8 (KC test pin is not emulated)
- return m_read_k(0, 0xff) & 0xf;
+ write_o_output(m_o);
}
void tms1k_base_device::set_cki_bus()
@@ -367,77 +396,62 @@ void tms1k_base_device::set_cki_bus()
// handle branches:
-// TMS1000/common
-// note: add(latch) and bl(branch latch) are specific to 0980 series,
-// c(chapter) bits are specific to 1100(and 1400) series
+// add(latch) and bl(branch latch) are specific to 0980 series, c(chapter) bits are specific to 1100(and 1400) series
+// TMS1400 and up and the CMOS chips have multiple stack levels, branches work a bit differently
-void tms1k_base_device::op_br()
+// BR/BL: conditional branch
+
+void tms1k_base_device::op_br1()
{
- // BR/BL: conditional branch
if (m_status)
{
if (m_clatch == 0)
m_pa = m_pb;
+
m_ca = m_cb;
m_pc = m_opcode & m_pc_mask;
}
}
-void tms1k_base_device::op_call()
+void tms1k_base_device::op_brn()
{
- // CALL/CALLL: conditional call
if (m_status)
{
- u8 prev_pa = m_pa;
-
- if (m_clatch == 0)
- {
- m_clatch = 1;
- m_sr = m_pc;
- m_pa = m_pb;
- m_cs = m_ca;
- }
+ m_pa = m_pb; // don't care about clatch
m_ca = m_cb;
- m_pb = prev_pa;
m_pc = m_opcode & m_pc_mask;
}
}
-void tms1k_base_device::op_retn()
-{
- // RETN: return from subroutine
- if (m_clatch == 1)
- {
- m_clatch = 0;
- m_pc = m_sr;
- m_ca = m_cs;
- }
- m_add = 0;
- m_bl = 0;
- m_pa = m_pb;
-}
-
+// CALL/CALLL: conditional call
-// TMS1400/TMS1000C 3-level stack version
-
-void tms1k_base_device::op_br3()
+void tms1k_base_device::op_call1()
{
- // BR/BL: conditional branch
if (m_status)
{
- m_pa = m_pb; // don't care about clatch
+ u8 prev_pa = m_pa;
+
+ if (!m_clatch)
+ {
+ m_clatch = 1;
+ m_sr = m_pc;
+ m_pa = m_pb;
+ m_cs = m_ca;
+ }
+
m_ca = m_cb;
+ m_pb = prev_pa;
m_pc = m_opcode & m_pc_mask;
}
}
-void tms1k_base_device::op_call3()
+void tms1k_base_device::op_calln()
{
- // CALL/CALLL: conditional call
if (m_status)
{
- // mask clatch 3 bits (no need to mask others)
- m_clatch = (m_clatch << 1 | 1) & 7;
+ // mask clatch bits (no need to mask others)
+ u8 smask = (1 << m_stack_levels) - 1;
+ m_clatch = (m_clatch << 1 | 1) & smask;
m_sr = m_sr << m_pc_bits | m_pc;
m_pc = m_opcode & m_pc_mask;
@@ -455,9 +469,24 @@ void tms1k_base_device::op_call3()
}
}
-void tms1k_base_device::op_retn3()
+// RETN: return from subroutine
+
+void tms1k_base_device::op_retn1()
+{
+ if (m_clatch)
+ {
+ m_clatch = 0;
+ m_pc = m_sr;
+ m_ca = m_cs;
+ }
+
+ m_add = 0;
+ m_bl = 0;
+ m_pa = m_pb;
+}
+
+void tms1k_base_device::op_retnn()
{
- // RETN: return from subroutine
if (m_clatch & 1)
{
m_clatch >>= 1;
@@ -498,32 +527,32 @@ void tms1k_base_device::op_setr()
{
// SETR: set one R-output line
m_r = m_r | (1 << m_y);
- m_write_r(0, m_r & m_r_mask, 0xffff);
+ write_r_output(m_r);
}
void tms1k_base_device::op_rstr()
{
// RSTR: reset one R-output line
m_r = m_r & ~(1 << m_y);
- m_write_r(0, m_r & m_r_mask, 0xffff);
+ write_r_output(m_r);
}
void tms1k_base_device::op_tdo()
{
- // TDO: transfer accumulator and status latch to O-output
- write_o_output(m_status_latch << 4 | m_a);
+ // TDO: transfer accumulator and status latch to O-register
+ write_o_reg(m_status_latch << 4 | m_a);
}
void tms1k_base_device::op_clo()
{
- // CLO: clear O-output
- write_o_output(0);
+ // CLO: clear O-register
+ write_o_reg(0);
}
void tms1k_base_device::op_ldx()
{
// LDX: load X register with (x_bits) constant
- m_x = m_c4 >> (4-m_x_bits);
+ m_x = m_c4 >> (4 - m_x_bits);
}
void tms1k_base_device::op_comx()
@@ -536,7 +565,7 @@ void tms1k_base_device::op_comx8()
{
// COMX8: complement MSB of X register
// note: on TMS1100, the mnemonic is simply called "COMX"
- m_x ^= 1 << (m_x_bits-1);
+ m_x ^= 1 << (m_x_bits - 1);
}
void tms1k_base_device::op_ldp()
@@ -545,18 +574,12 @@ void tms1k_base_device::op_ldp()
m_pb = m_c4;
}
-
-// TMS1100-specific
-
void tms1k_base_device::op_comc()
{
// COMC: complement chapter buffer
m_cb ^= 1;
}
-
-// TMS1400-specific
-
void tms1k_base_device::op_tpc()
{
// TPC: transfer page buffer to chapter buffer
@@ -564,54 +587,14 @@ void tms1k_base_device::op_tpc()
}
-// TMS0980-specific (and possibly child classes)
-
-void tms1k_base_device::op_xda()
-{
- // XDA: exchange DAM and A
- // note: setting A to DAM is done with DMTP and AUTA during this instruction
- m_ram_address |= (0x10 << (m_x_bits-1));
-}
-
-void tms1k_base_device::op_off()
-{
- // OFF: request auto power-off
- m_power_off(1);
-}
-
-void tms1k_base_device::op_seac()
-{
- // SEAC: set end around carry
- m_eac = 1;
-}
-
-void tms1k_base_device::op_reac()
-{
- // REAC: reset end around carry
- m_eac = 0;
-}
-
-void tms1k_base_device::op_sal()
-{
- // SAL: set add latch (reset is done with RETN)
- m_add = 1;
-}
-
-void tms1k_base_device::op_sbl()
-{
- // SBL: set branch latch (reset is done with RETN)
- m_bl = 1;
-}
-
-
//-------------------------------------------------
// execute
//-------------------------------------------------
-void tms1k_base_device::execute_one()
+void tms1k_base_device::execute_one(int subcycle)
{
- switch (m_subcycle)
+ switch (subcycle)
{
case 0:
// fetch: rom address 1/2
@@ -625,7 +608,7 @@ void tms1k_base_device::execute_one()
dynamic_output();
set_cki_bus();
m_ram_in = m_data->read_byte(m_ram_address) & 0xf;
- m_dam_in = m_data->read_byte(m_ram_address | (0x10 << (m_x_bits-1))) & 0xf;
+ m_dam_in = m_data->read_byte(m_ram_address | (0x10 << (m_x_bits - 1))) & 0xf;
m_p = 0;
m_n = 0;
m_carry_in = 0;
@@ -697,6 +680,12 @@ void tms1k_base_device::execute_one()
if (m_fixed & F_LDP) op_ldp();
if (m_fixed & F_COMC) op_comc();
if (m_fixed & F_TPC) op_tpc();
+
+ if (m_fixed & F_TAX) op_tax();
+ if (m_fixed & F_TAC) op_tac();
+ if (m_fixed & F_TADM) op_tadm();
+ if (m_fixed & F_TMA) op_tma();
+
if (m_fixed & F_OFF) op_off();
if (m_fixed & F_SEAC) op_seac();
if (m_fixed & F_REAC) op_reac();
@@ -704,6 +693,8 @@ void tms1k_base_device::execute_one()
if (m_fixed & F_SBL) op_sbl();
if (m_fixed & F_XDA) op_xda();
+ if (m_fixed & F_EXTRA) op_extra();
+
// after fixed opcode handling: store status, write ram
m_status = status;
if (m_ram_out != -1)
@@ -723,6 +714,11 @@ void tms1k_base_device::execute_one()
if (m_micro & M_AUTY) m_y = m_adder_out & 0xf;
if (m_micro & M_STSL) m_status_latch = m_status;
+ // fixed opcodes with accumulator as destination
+ if (m_fixed & F_TXA) op_txa();
+ if (m_fixed & F_TRA) op_tra();
+ if (m_fixed & F_TCA) op_tca();
+
// fetch: update pc, ram address 2/2
read_opcode();
m_ram_address = m_x << 4 | m_y;
@@ -733,8 +729,6 @@ void tms1k_base_device::execute_one()
// execute: br/call 1/2
break;
}
-
- m_subcycle = (m_subcycle + 1) % 6;
}
void tms1k_base_device::execute_run()
@@ -742,6 +736,8 @@ void tms1k_base_device::execute_run()
while (m_icount > 0)
{
m_icount--;
- execute_one();
+
+ execute_one(m_subcycle);
+ m_subcycle = (m_subcycle + 1) % 6;
}
}