diff options
author | 2024-02-10 23:36:25 +0100 | |
---|---|---|
committer | 2024-02-10 23:36:35 +0100 | |
commit | 2aee7dcc5d164297ea3fa13565c1689bd9c0c7c4 (patch) | |
tree | 1700465c35c46c8d2c37e4b1278798bc6c3104aa | |
parent | 3b5a2f9cbc8f63cf09263071d601b1b8d2b42b0c (diff) |
h8: add software standby mode and optional nvram
-rw-r--r-- | src/devices/cpu/h8/h8.cpp | 87 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8.h | 50 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8.lst | 6 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8325.cpp | 19 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8325.h | 1 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8_port.cpp | 32 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8_port.h | 5 | ||||
-rw-r--r-- | src/devices/cpu/h8/h8_sci.cpp | 4 | ||||
-rw-r--r-- | src/devices/cpu/m6800/m6801.cpp | 14 | ||||
-rw-r--r-- | src/mame/saitek/prisma.cpp | 17 |
10 files changed, 198 insertions, 37 deletions
diff --git a/src/devices/cpu/h8/h8.cpp b/src/devices/cpu/h8/h8.cpp index a3aaaf9303f..ce62b41f066 100644 --- a/src/devices/cpu/h8/h8.cpp +++ b/src/devices/cpu/h8/h8.cpp @@ -2,10 +2,12 @@ // copyright-holders:Olivier Galibert /*************************************************************************** - h8.h + h8.cpp H8-300 base cpu emulation + TODO: + - add STBY pin (hardware standby mode) ***************************************************************************/ @@ -13,19 +15,25 @@ #include "h8.h" #include "h8_dma.h" #include "h8_dtc.h" +#include "h8_port.h" #include "h8d.h" h8_device::h8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor map_delegate) : cpu_device(mconfig, type, tag, owner, clock), + device_nvram_interface(mconfig, *this), m_program_config("program", ENDIANNESS_BIG, 16, 16, 0, map_delegate), + m_internal_ram(*this, "internal_ram"), m_read_adc(*this, 0), m_read_port(*this, 0), m_write_port(*this), m_sci(*this, "sci%u", 0), m_sci_tx(*this), m_sci_clk(*this), + m_standby_cb(*this), m_PPC(0), m_NPC(0), m_PC(0), m_PIR(0), m_EXR(0), m_CCR(0), m_MAC(0), m_MACF(0), - m_TMP1(0), m_TMP2(0), m_TMPR(0), m_inst_state(0), m_inst_substate(0), m_icount(0), m_bcount(0), m_irq_vector(0), m_taken_irq_vector(0), m_irq_level(0), m_taken_irq_level(0), m_irq_required(false), m_irq_nmi(false) + m_TMP1(0), m_TMP2(0), m_TMPR(0), m_inst_state(0), m_inst_substate(0), m_icount(0), m_bcount(0), + m_irq_vector(0), m_taken_irq_vector(0), m_irq_level(0), m_taken_irq_level(0), m_irq_required(false), m_irq_nmi(false), + m_standby_pending(false), m_nvram_defval(0), m_nvram_battery(true) { m_supports_advanced = false; m_mode_advanced = false; @@ -35,6 +43,7 @@ h8_device::h8_device(const machine_config &mconfig, device_type type, const char m_mac_saturating = false; m_has_trace = false; m_has_hc = true; + nvram_enable_backup(false); // disable nvram by default for(unsigned int i=0; i != m_read_adc.size(); i++) m_read_adc[i].bind().set([this, i]() { return adc_default(i); }); @@ -146,6 +155,8 @@ void h8_device::device_start() save_item(NAME(m_taken_irq_level)); save_item(NAME(m_irq_nmi)); save_item(NAME(m_current_dma)); + save_item(NAME(m_standby_pending)); + save_item(NAME(m_nvram_battery)); set_icountptr(m_icount); @@ -182,8 +193,74 @@ void h8_device::device_reset() m_taken_irq_level = -1; m_current_dma = -1; m_current_dtc = nullptr; + + m_standby_pending = false; + m_standby_cb(0); +} + + +// nvram handling + +bool h8_device::nvram_write(util::write_stream &file) +{ + // if it's currently not battery-backed, don't save at all + if(!m_nvram_battery) + return true; + + size_t actual; + + // internal RAM + if(m_internal_ram) { + if(file.write(&m_internal_ram[0], m_internal_ram.bytes(), actual) || m_internal_ram.bytes() != actual) + return false; + } + + // I/O ports + for(h8_port_device &port : h8_port_device_enumerator(*this)) { + if (!port.nvram_write(file)) + return false; + } + + return true; } +bool h8_device::nvram_read(util::read_stream &file) +{ + size_t actual; + + // internal RAM + if(m_internal_ram) { + if(file.read(&m_internal_ram[0], m_internal_ram.bytes(), actual) || m_internal_ram.bytes() != actual) + return false; + } + + // I/O ports + for(h8_port_device &port : h8_port_device_enumerator(*this)) { + if (!port.nvram_read(file)) + return false; + } + + return true; +} + +void h8_device::nvram_default() +{ + if(!nvram_backup_enabled() || !m_internal_ram) + return; + + // default nvram from mytag:nvram region if it exists (only the internal RAM for now) + memory_region *region = memregion("nvram"); + if(region != nullptr) { + if(region->bytes() != m_internal_ram.bytes()) + fatalerror("%s: Wrong region size (expected 0x%x, found 0x%x)", region->name(), m_internal_ram.bytes(), region->bytes()); + + std::copy_n(®ion->as_u16(), m_internal_ram.length(), &m_internal_ram[0]); + } + else + std::fill_n(&m_internal_ram[0], m_internal_ram.length(), m_nvram_defval); +} + + bool h8_device::trigger_dma(int vector) { bool dma_triggered = false; @@ -458,6 +535,12 @@ void h8_device::prefetch_done_noirq_notrace() void h8_device::set_irq(int irq_vector, int irq_level, bool irq_nmi) { + // wake up from software standby with an external interrupt + if(standby() && (irq_vector || irq_nmi)) { + resume(SUSPEND_REASON_CLOCK); + m_standby_cb(0); + } + m_irq_vector = irq_vector; m_irq_level = irq_level; m_irq_nmi = irq_nmi; diff --git a/src/devices/cpu/h8/h8.h b/src/devices/cpu/h8/h8.h index 6b01f781c45..6bd1289a2bb 100644 --- a/src/devices/cpu/h8/h8.h +++ b/src/devices/cpu/h8/h8.h @@ -6,7 +6,6 @@ H8-300 base cpu emulation - ***************************************************************************/ #ifndef MAME_CPU_H8_H8_H @@ -23,7 +22,7 @@ class h8_device; #include "h8_sci.h" -class h8_device : public cpu_device { +class h8_device : public cpu_device, public device_nvram_interface { public: enum { STATE_RESET = 0x10000, @@ -46,6 +45,11 @@ public: template<int Sci> void sci_rx_w(int state) { m_sci[Sci]->do_rx_w(state); } template<int Sci> void sci_clk_w(int state) { m_sci[Sci]->do_clk_w(state); } + void nvram_set_battery(int state) { m_nvram_battery = bool(state); } // default is 1 (nvram_enable_backup needs to be true) + void nvram_set_default_value(uint8_t val) { m_nvram_defval = val; } // default is 0 + auto standby_cb() { return m_standby_cb.bind(); } // notifier (not an output pin) + int standby() { return suspended(SUSPEND_REASON_CLOCK) ? 1 : 0; } + void internal_update(); void set_irq(int irq_vector, int irq_level, bool irq_nmi); bool trigger_dma(int vector); @@ -104,12 +108,12 @@ protected: h8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor map_delegate); - // device-level overrides + // device_t implementation virtual void device_config_complete() override; virtual void device_start() override; virtual void device_reset() override; - // device_execute_interface overrides + // device_execute_interface implementation virtual bool cpu_is_interruptible() const override { return true; } virtual uint32_t execute_min_cycles() const noexcept override { return 2; } virtual uint32_t execute_max_cycles() const noexcept override { return 12; } @@ -117,25 +121,32 @@ protected: virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == INPUT_LINE_NMI; } virtual void execute_run() override; - // device_memory_interface overrides + // device_memory_interface implementation virtual space_config_vector memory_space_config() const override; - // device_state_interface overrides + // device_state_interface implementation virtual void state_import(const device_state_entry &entry) override; virtual void state_export(const device_state_entry &entry) override; virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; - // device_disasm_interface overrides + // device_disasm_interface implementation virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + // device_nvram_interface implementation + virtual void nvram_default() override; + virtual bool nvram_read(util::read_stream &file) override; + virtual bool nvram_write(util::write_stream &file) override; + address_space_config m_program_config; memory_access<32, 1, 0, ENDIANNESS_BIG>::cache m_cache; memory_access<32, 1, 0, ENDIANNESS_BIG>::specific m_program; + optional_shared_ptr<uint16_t> m_internal_ram; // for nvram devcb_read16::array<8> m_read_adc; devcb_read8::array<PORT_COUNT> m_read_port; devcb_write8::array<PORT_COUNT> m_write_port; optional_device_array<h8_sci_device, 3> m_sci; devcb_write_line::array<3> m_sci_tx, m_sci_clk; + devcb_write_line m_standby_cb; h8gen_dma_device *m_dma_device; h8_dtc_device *m_dtc_device; @@ -143,18 +154,18 @@ protected: int m_current_dma; h8_dtc_state *m_current_dtc; - uint32_t m_PPC; /* previous program counter */ - uint32_t m_NPC; /* next start-of-instruction program counter */ - uint32_t m_PC; /* program counter */ - uint16_t m_PIR; /* Prefetched word */ - uint16_t m_IR[5]; /* Fetched instruction */ - uint16_t m_R[16]; /* Rn (0-7), En (8-15, h8-300h+) */ - uint8_t m_EXR; /* Interrupt/trace register (h8s/2000+) */ - uint8_t m_CCR; /* Condition-code register */ - int64_t m_MAC; /* Multiply accumulator (h8s/2600+) */ - uint8_t m_MACF; /* MAC flags (h8s/2600+) */ + uint32_t m_PPC; // previous program counter + uint32_t m_NPC; // next start-of-instruction program counter + uint32_t m_PC; // program counter + uint16_t m_PIR; // Prefetched word + uint16_t m_IR[5]; // Fetched instruction + uint16_t m_R[16]; // Rn (0-7), En (8-15, h8-300h+) + uint8_t m_EXR; // Interrupt/trace register (h8s/2000+) + uint8_t m_CCR; // Condition-code register + int64_t m_MAC; // Multiply accumulator (h8s/2600+) + uint8_t m_MACF; // MAC flags (h8s/2600+) uint32_t m_TMP1, m_TMP2; - uint32_t m_TMPR; /* For debugger ER register import */ + uint32_t m_TMPR; // For debugger ER register import bool m_has_exr, m_has_mac, m_has_trace, m_supports_advanced, m_mode_advanced, m_mode_a20, m_mac_saturating; bool m_has_hc; // GT913's CCR bit 5 is I, not H @@ -164,6 +175,9 @@ protected: int m_irq_vector, m_taken_irq_vector; int m_irq_level, m_taken_irq_level; bool m_irq_required, m_irq_nmi; + bool m_standby_pending; + uint16_t m_nvram_defval; + bool m_nvram_battery; virtual void do_exec_full(); virtual void do_exec_partial(); diff --git a/src/devices/cpu/h8/h8.lst b/src/devices/cpu/h8/h8.lst index c09caa3d904..88637e0d38a 100644 --- a/src/devices/cpu/h8/h8.lst +++ b/src/devices/cpu/h8/h8.lst @@ -741,7 +741,11 @@ macro jsr32 %opc %spreg 0180 ffff 0 sleep - - prefetch_start - while(!m_irq_vector) { + if(m_standby_pending) { + suspend(SUSPEND_REASON_CLOCK, true); + m_standby_cb(1); + } + else while(!m_irq_vector) { eat-all-cycles; } prefetch_done(); diff --git a/src/devices/cpu/h8/h8325.cpp b/src/devices/cpu/h8/h8325.cpp index e2cc665405d..fa45bb16985 100644 --- a/src/devices/cpu/h8/h8325.cpp +++ b/src/devices/cpu/h8/h8325.cpp @@ -7,10 +7,9 @@ H8/325 family emulation TODO: - - nvram and standby emulation, but that's a thing for more H8 types? - serial controllers are slightly different, has 3 interrupt sources instead of 4 - - SYSCR register (RAM disable, NMI edge invert, standby) + - SYSCR NMI edge invert - HCSR register @ 0xfffe (port 3 handshake) - FNCR register @ 0xffff (16-bit timer noise canceler) @@ -42,6 +41,7 @@ h8325_device::h8325_device(const machine_config &mconfig, device_type type, cons m_timer16(*this, "timer16"), m_timer16_0(*this, "timer16:0"), m_read_md(*this, 3), + m_ram_view(*this, "ram_view"), m_syscr(0), m_mds(0), m_ram_start(start) @@ -80,7 +80,8 @@ h8322_device::h8322_device(const machine_config &mconfig, const char *tag, devic void h8325_device::map(address_map &map) { - map(m_ram_start, 0xff7f).ram(); + map(m_ram_start, 0xff7f).view(m_ram_view); + m_ram_view[0](m_ram_start, 0xff7f).ram().share(m_internal_ram); map(0xff90, 0xff90).rw(m_timer16_0, FUNC(h8325_timer16_channel_device::tcr_r), FUNC(h8325_timer16_channel_device::tcr_w)); map(0xff91, 0xff91).rw(m_timer16_0, FUNC(h8325_timer16_channel_device::tsr_r), FUNC(h8325_timer16_channel_device::tsr_w)); @@ -199,6 +200,9 @@ void h8325_device::device_reset() h8_device::device_reset(); m_syscr = 0x01; + m_ram_view.select(0); + + // MD pins are latched at reset m_mds = m_read_md() & 3; } @@ -211,6 +215,15 @@ void h8325_device::syscr_w(uint8_t data) { logerror("syscr = %02x\n", data); m_syscr = data; + + // RAME + if (data & 1) + m_ram_view.select(0); + else + m_ram_view.disable(); + + // SSBY + m_standby_pending = bool(data & 0x80); } uint8_t h8325_device::mdcr_r() diff --git a/src/devices/cpu/h8/h8325.h b/src/devices/cpu/h8/h8325.h index 5c18b2e1cbf..fba31ce4ce7 100644 --- a/src/devices/cpu/h8/h8325.h +++ b/src/devices/cpu/h8/h8325.h @@ -74,6 +74,7 @@ protected: required_device<h8325_timer16_channel_device> m_timer16_0; devcb_read8 m_read_md; + memory_view m_ram_view; uint8_t m_syscr; uint8_t m_mds; diff --git a/src/devices/cpu/h8/h8_port.cpp b/src/devices/cpu/h8/h8_port.cpp index 6f65bfa6ced..4aeb446c85d 100644 --- a/src/devices/cpu/h8/h8_port.cpp +++ b/src/devices/cpu/h8/h8_port.cpp @@ -98,3 +98,35 @@ void h8_port_device::device_reset() { update_output(); } + +bool h8_port_device::nvram_write(util::write_stream &file) +{ + size_t actual; + u8 buf[4]; + + buf[0] = m_ddr; + buf[1] = m_dr; + buf[2] = m_pcr; + buf[3] = m_odr; + + if(file.write(&buf, sizeof(buf), actual) || (sizeof(buf) != actual)) + return false; + + return true; +} + +bool h8_port_device::nvram_read(util::read_stream &file) +{ + size_t actual; + u8 buf[4]; + + if(file.read(&buf, sizeof(buf), actual) || (sizeof(buf) != actual)) + return false; + + m_ddr = buf[0]; + m_dr = buf[1]; + m_pcr = buf[2]; + m_odr = buf[3]; + + return true; +} diff --git a/src/devices/cpu/h8/h8_port.h b/src/devices/cpu/h8/h8_port.h index cc809b633af..a9b224d2289 100644 --- a/src/devices/cpu/h8/h8_port.h +++ b/src/devices/cpu/h8/h8_port.h @@ -38,6 +38,9 @@ public: void odr_w(uint8_t data); uint8_t odr_r(); + bool nvram_read(util::read_stream &file); + bool nvram_write(util::write_stream &file); + protected: required_device<h8_device> m_cpu; @@ -54,4 +57,6 @@ protected: DECLARE_DEVICE_TYPE(H8_PORT, h8_port_device) +typedef device_type_enumerator<h8_port_device> h8_port_device_enumerator; + #endif // MAME_CPU_H8_H8_PORT_H diff --git a/src/devices/cpu/h8/h8_sci.cpp b/src/devices/cpu/h8/h8_sci.cpp index d78eb04f83e..1bf59ee2d08 100644 --- a/src/devices/cpu/h8/h8_sci.cpp +++ b/src/devices/cpu/h8/h8_sci.cpp @@ -313,7 +313,7 @@ void h8_sci_device::do_rx_w(int state) { m_rx_value = state; if(V>=2) logerror("rx=%d\n", state); - if(!m_rx_value && !(m_clock_state & CLK_RX) && m_rx_state != ST_IDLE) + if(!m_rx_value && !(m_clock_state & CLK_RX) && m_rx_state != ST_IDLE && !m_cpu->standby()) clock_start(CLK_RX); } @@ -321,7 +321,7 @@ void h8_sci_device::do_clk_w(int state) { if(m_ext_clock_value != state) { m_ext_clock_value = state; - if(m_clock_state) { + if(m_clock_state && !m_cpu->standby()) { switch(m_clock_mode) { case clock_mode_t::EXTERNAL_ASYNC: if(m_ext_clock_value) { diff --git a/src/devices/cpu/m6800/m6801.cpp b/src/devices/cpu/m6800/m6801.cpp index d799d737c1b..cff7f922245 100644 --- a/src/devices/cpu/m6800/m6801.cpp +++ b/src/devices/cpu/m6800/m6801.cpp @@ -274,7 +274,7 @@ void m6801_cpu_device::m6801_io(address_map &map) void m6801_cpu_device::m6803_mem(address_map &map) { m6801_io(map); - map(0x0080, 0x00ff).ram().share("internal"); + map(0x0080, 0x00ff).ram().share(m_internal_ram); } void m6801_cpu_device::m6801_mem(address_map &map) @@ -300,7 +300,7 @@ void m6801u4_cpu_device::m6801u4_io(address_map &map) void m6801u4_cpu_device::m6801u4_mem(address_map &map) { m6801u4_io(map); - map(0x0040, 0x00ff).ram().share("internal"); + map(0x0040, 0x00ff).ram().share(m_internal_ram); map(0xf000, 0xffff).rom().region(DEVICE_SELF, 0); } @@ -351,13 +351,13 @@ void hd6301x_cpu_device::hd6301x_io(address_map &map) void hd6301x_cpu_device::hd6303x_mem(address_map &map) { hd6303x_io(map); - map(0x0040, 0x00ff).ram().share("internal"); + map(0x0040, 0x00ff).ram().share(m_internal_ram); } void hd6301x_cpu_device::hd6301x_mem(address_map &map) { hd6301x_io(map); - map(0x0040, 0x00ff).ram().share("internal"); + map(0x0040, 0x00ff).ram().share(m_internal_ram); map(0xf000, 0xffff).rom().region(DEVICE_SELF, 0); } @@ -387,13 +387,13 @@ void hd6301y_cpu_device::hd6301y_io(address_map &map) void hd6301y_cpu_device::hd6303y_mem(address_map &map) { hd6303y_io(map); - map(0x0040, 0x013f).ram().share("internal"); + map(0x0040, 0x013f).ram().share(m_internal_ram); } void hd6301y_cpu_device::hd6301y_mem(address_map &map) { hd6301y_io(map); - map(0x0040, 0x013f).ram().share("internal"); + map(0x0040, 0x013f).ram().share(m_internal_ram); map(0xc000, 0xffff).rom().region(DEVICE_SELF, 0); } @@ -428,7 +428,7 @@ m6801_cpu_device::m6801_cpu_device(const machine_config &mconfig, device_type ty , m_out_sc2_func(*this) , m_out_sertx_func(*this) , m_standby_func(*this) - , m_internal_ram(*this, "internal") + , m_internal_ram(*this, "internal_ram") , m_nvram_bytes(nvram_bytes) , m_nvram_defval(0) , m_nvram_battery(true) diff --git a/src/mame/saitek/prisma.cpp b/src/mame/saitek/prisma.cpp index d3aae90a4a3..d53720e4917 100644 --- a/src/mame/saitek/prisma.cpp +++ b/src/mame/saitek/prisma.cpp @@ -14,10 +14,7 @@ Hardware notes: It was also sold by Tandy as Chess Champion 2150L, with a slower CPU (16MHz XTAL). TODO: -- does not work, it's unresponsive and will lock up after pressing buttons, irq - or opcode bug? (hold S to boot it up for now, that's not how it's supposed to be) -- add nvram, should be internal to H8, but it's missing standby emulation -- everything else +- finish driver *******************************************************************************/ @@ -55,6 +52,8 @@ public: void prisma(machine_config &config); + DECLARE_INPUT_CHANGED_MEMBER(go_button); + protected: virtual void machine_start() override; @@ -108,6 +107,10 @@ void prisma_state::machine_start() I/O *******************************************************************************/ +INPUT_CHANGED_MEMBER(prisma_state::go_button) +{ +} + void prisma_state::lcd_pwm_w(offs_t offset, u8 data) { m_out_lcd[offset & 0x3f][offset >> 6] = data; @@ -253,6 +256,9 @@ static INPUT_PORTS_START( prisma ) PORT_CONFNAME( 0x01, 0x01, "Battery Status" ) PORT_CONFSETTING( 0x00, "Low" ) PORT_CONFSETTING( 0x01, DEF_STR( Normal ) ) + + PORT_START("RESET") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Z) PORT_CHANGED_MEMBER(DEVICE_SELF, prisma_state, go_button, 0) PORT_NAME("Go") INPUT_PORTS_END @@ -265,6 +271,8 @@ void prisma_state::prisma(machine_config &config) { // basic machine hardware H8325(config, m_maincpu, 20_MHz_XTAL / 2); + m_maincpu->nvram_enable_backup(true); + m_maincpu->nvram_set_default_value(~0); m_maincpu->set_addrmap(AS_PROGRAM, &prisma_state::main_map); m_maincpu->write_port1().set(FUNC(prisma_state::p1_w)); m_maincpu->write_port2().set(FUNC(prisma_state::p2_w)); @@ -279,6 +287,7 @@ void prisma_state::prisma(machine_config &config) SENSORBOARD(config, m_board).set_type(sensorboard_device::BUTTONS); m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess)); m_board->set_delay(attotime::from_msec(150)); + m_board->set_nvram_enable(true); // video hardware SED1502(config, m_lcd, 32768).write_segs().set(FUNC(prisma_state::lcd_output_w)); |