diff options
author | 2016-11-05 14:22:46 -0400 | |
---|---|---|
committer | 2016-11-05 14:22:46 -0400 | |
commit | f05e7ffad0fce71293f65d142b7c13084ad48215 (patch) | |
tree | 197bc76b15349e8cc3d3be04e6f070ad4aa7a639 | |
parent | aff3588a0458ec6d538375f5a235c82a934020ad (diff) | |
parent | f60621bbd443493b0e24aad355482ec77f781a9c (diff) |
Merge pull request #1637 from fulivi/hp9845_dev7
Hp9845: re-implemented 98035 module with a nanoprocessor driver
-rw-r--r-- | scripts/src/cpu.lua | 16 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 1 | ||||
-rw-r--r-- | src/devices/bus/hp9845_io/98035.cpp | 1031 | ||||
-rw-r--r-- | src/devices/bus/hp9845_io/98035.h | 125 | ||||
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor.cpp | 525 | ||||
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor.h | 138 | ||||
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp | 135 | ||||
-rw-r--r-- | src/mame/drivers/hp9845.cpp | 1 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
9 files changed, 1399 insertions, 575 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index c472fd4d8e0..c9639d1d7a1 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -704,6 +704,22 @@ if (CPUS["HPHYBRID"]~=null or _OPTIONS["with-tools"]) then end -------------------------------------------------- +-- HP Nanoprocessor +--@src/devices/cpu/nanoprocessor/nanoprocessor.h,CPUS["NANOPROCESSOR"] = true +-------------------------------------------------- + +if (CPUS["NANOPROCESSOR"]~=null) then + files { + MAME_DIR .. "src/devices/cpu/nanoprocessor/nanoprocessor.cpp", + MAME_DIR .. "src/devices/cpu/nanoprocessor/nanoprocessor.h", + } +end + +if (CPUS["NANOPROCESSOR"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp") +end + +-------------------------------------------------- -- Hudsonsoft 6280 --@src/devices/cpu/h6280/h6280.h,CPUS["H6280"] = true -------------------------------------------------- diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index a9607474e80..fe26b9885c8 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -133,6 +133,7 @@ CPUS["MELPS4"] = true CPUS["HPHYBRID"] = true CPUS["SM510"] = true CPUS["MB86901"] = true +CPUS["NANOPROCESSOR"] = true -------------------------------------------------- -- specify available sound cores; some of these are diff --git a/src/devices/bus/hp9845_io/98035.cpp b/src/devices/bus/hp9845_io/98035.cpp index c3338add89a..28004e6d04f 100644 --- a/src/devices/bus/hp9845_io/98035.cpp +++ b/src/devices/bus/hp9845_io/98035.cpp @@ -26,19 +26,53 @@ For further info on this module see also: http://www.hp9825.com/html/real-time_clock.html - This driver tries to reproduce in C++ the behaviour of the - nanoprocessor because I couldn't find any dump of the firmware ROM - (HP part-no 1818-0469). - The following commands are recognized in my "imitation": - A Halt all timer units - B Warm reset - E Read & clear interface errors - F Activate all timer units - R Read real time clock - S Set real time clock - T Read trigger status - U Control timer units - W Read lost interrupts + Here's what I know about the clock chip. + * Packaged in a 24-pin DIP + * Runs on a 2.4V NiCd battery + * Keeps time with a standard 32.768 kHz oscillator + * Drives a 3 1/2 digit LED display with 7-segment digits + * Multiplexes digits with a 32768 Hz / 64 clock + * Has 3 buttons to read/set time (READ, SET & CHG) + * Counts month, day, hour, minute & seconds (no year) + * Doesn't support leap years + * On Tony Duell's schematics the chip is marked "AC5954" + + All my attempts to find something like a datasheet of this chip + failed. + + This driver emulates the clock chip with a FSM that reacts to + "short" and "long" pressings of keys. Here's a summary of the FSM. + + | State | Key pressed | New state | Display | + |-------+-------------+-----------+--------------------------------| + | OFF | | | Blank, no multiplexing | + | | Short READ | HHMM | | + | | Short SET | HH | | + | HHMM | | | "HH:mm" (Hours 1-12 and mins.) | + | | | | On real chip it probably | + | | | | returns to OFF after a couple | + | | | | of seconds. | + | | Long READ | SS | | + | SS | | | " :SS" (just seconds) | + | | Short SET | HH | | + | | Long SET | OFF | | + | | READ + CHG | | seconds++ | + | HH | | | "HH: A/P" (hours & AM/PM) | + | | Short SET | MIN | | + | | Long SET | OFF | | + | | READ + CHG | | hours++ | + | MIN | | | " :mm" (just minutes) | + | | Short SET | MON | | + | | Long SET | OFF | | + | | READ + CHG | | minutes++ | + | MON | | | "MM: " (just month) | + | | Short SET | DOM | | + | | Long SET | OFF | | + | | READ + CHG | | month++ | + | DOM | | | " :DD" (just day of month) | + | | Short SET | OFF | | + | | Long SET | OFF | | + | | READ + CHG | | day++ | The main reference for this module is this manual: HP, 98035A Real Time Clock Installation and Operation Manual @@ -58,26 +92,59 @@ #define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n)) #define BIT_SET(w , n) ((w) |= BIT_MASK(n)) -// Possible delimiters -#define DELIM_CH_0 '/' -#define DELIM_CH_1 '\n' +// Frequency of digit multiplexing in clock chip +#define DIGIT_MUX_FREQ (XTAL_32_768kHz / 64) -// Error masks in m_error -#define ERR_MASK_INT_MISSED BIT_MASK(0) -#define ERR_MASK_WRONG_INS BIT_MASK(1) -#define ERR_MASK_WRONG_UNIT BIT_MASK(2) -#define ERR_MASK_CANT_EXEC BIT_MASK(3) +// Duration of key presses +#define KEY_PRESS_SHORT 1 // 1.95 ms +#define KEY_PRESS_LONG 512 // 1 s -// Empty date/time fields -#define EMPTY_FIELD 0xff +// Mask of keys in m_clock_keys +#define KEY_READ_MASK 1 +#define KEY_SET_MASK 2 +#define KEY_CHG_MASK 4 // Timers enum { - MSEC_TMR_ID + MSEC_TMR_ID, + CLOCK_TMR_ID +}; + +// 7-segment display +// Mapping of 7 segments on NP input port is as follows: +// Bit Segment +// ============ +// 7 N/U (1) +// 6 N/U (1) +// 5 Seg "G" +// 4 Seg "F" +// 3 Seg "E" +// 2 Seg "C" +// 1 Seg "B" +// 0 Seg "A" +// +// Segment "D" is not mapped as it's not needed to tell decimal digits apart. +// A segment is ON when its bit is "0". +#define SEVEN_SEG_OFF 0xff // All segments off +#define SEVEN_SEG_A 0xc0 // "A" +#define SEVEN_SEG_P 0xc4 // "P" +static const uint8_t dec_2_seven_segs[] = { + 0xe0, // 0 + 0xf9, // 1 + 0xd4, // 2 + 0xd8, // 3 + 0xc9, // 4 + 0xca, // 5 + 0xc2, // 6 + 0xf8, // 7 + 0xc0, // 8 + 0xc8 // 9 }; hp98035_io_card::hp98035_io_card(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : hp9845_io_card_device(mconfig , HP98035_IO_CARD , "HP98035 card" , tag , owner , clock , "hp98035" , __FILE__) + : hp9845_io_card_device(mconfig , HP98035_IO_CARD , "HP98035 card" , tag , owner , clock , "hp98035" , __FILE__), + device_rtc_interface(mconfig , *this), + m_cpu(*this , "np") { } @@ -96,7 +163,29 @@ ioport_constructor hp98035_io_card::device_input_ports() const void hp98035_io_card::device_start() { + save_item(NAME(m_np_ram)); + save_item(NAME(m_ram_addr)); + save_item(NAME(m_ram_data_in)); + save_item(NAME(m_dc)); + save_item(NAME(m_np_irq)); + save_item(NAME(m_flg)); + save_item(NAME(m_inten)); + save_item(NAME(m_intflag)); + save_item(NAME(m_irq)); + save_item(NAME(m_idr_full)); + save_item(NAME(m_idr)); + save_item(NAME(m_odr)); + save_item(NAME(m_clock_1s_div)); + //save_item(NAME(m_clock_state)); + save_item(NAME(m_clock_digits)); + save_item(NAME(m_clock_mux)); + save_item(NAME(m_clock_segh)); + save_item(NAME(m_clock_keys)); + save_item(NAME(m_prev_clock_keys)); + save_item(NAME(m_clock_key_cnt)); + m_msec_timer = timer_alloc(MSEC_TMR_ID); + m_clock_timer = timer_alloc(CLOCK_TMR_ID); } void hp98035_io_card::device_reset() @@ -107,112 +196,62 @@ void hp98035_io_card::device_reset() m_idr_full = false; m_idr = 0; m_odr = 0; - m_ibuffer_ptr = 0; - m_obuffer_len = 0; - m_obuffer_ptr = 0; sts_w(true); set_flg(true); - // Set real time from the real world - system_time systime; - machine().base_datetime(systime); - m_msec = 0; - m_sec = systime.local_time.second; - m_min = systime.local_time.minute; - m_hrs = systime.local_time.hour; - m_dom = systime.local_time.mday; - m_mon = systime.local_time.month + 1; - attotime period(attotime::from_msec(1)); m_msec_timer->adjust(period , 0 , period); + period = attotime::from_hz(DIGIT_MUX_FREQ); + m_clock_timer->adjust(period , 0 , period); + half_init(); } void hp98035_io_card::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { if (id == MSEC_TMR_ID) { - // Update real time - m_msec++; - if (m_msec >= 1000) { - m_msec = 0; - m_sec++; - if (m_sec >= 60) { - m_sec = 0; - m_min++; - if (m_min >= 60) { - m_min = 0; - m_hrs++; - if (m_hrs >= 24) { - m_hrs = 0; - m_dom++; - // Use year 1: this RTC doesn't know the year and so it never advances - // the date to february 29th - if (m_dom > gregorian_days_in_month(m_mon , 1)) { - m_dom = 1; - m_mon++; - if (m_mon > 12) { - m_mon = 1; - } - } - } - } - } - - // Every second: check if new real time matches in any active output unit - for (timer_unit_t& unit : m_units) { - if (!unit.m_input && unit.m_state == UNIT_ACTIVE && - m_sec == unit.m_match_datetime[ 3 ] && - (unit.m_match_datetime[ 2 ] == EMPTY_FIELD || - (m_min == unit.m_match_datetime[ 2 ] && - (unit.m_match_datetime[ 1 ] == EMPTY_FIELD || - (m_hrs == unit.m_match_datetime[ 1 ] && - (unit.m_match_datetime[ 0 ] == EMPTY_FIELD || - m_dom == unit.m_match_datetime[ 0 ])))))) { - // Matched - unit.adv_state(); - LOG(("matched %02u:%03u %p %d %u\n" , m_sec , m_msec , &unit , unit.m_state , unit.m_value)); - } + // On real hw there's a full 4-bit decimal counter, but only the LSB is used to + // generate interrupts + m_np_irq = !m_np_irq; + update_dc(); + } else if (id == CLOCK_TMR_ID) { + // Update digit multiplexer + if (m_clock_state == CLOCK_OFF) { + m_clock_mux = 0; + } else { + m_clock_mux <<= 1; + if ((m_clock_mux & 7) == 0) { + m_clock_mux = 1; } } - - // Every ms: advance active units - uint8_t triggered = 0; - for (timer_unit_t& unit : m_units) { - if (unit.m_state != UNIT_IDLE) { - if (unit.m_input && unit.m_state == UNIT_ACTIVE) { - // Input unit: it just counts msecs - // In the real 98035 there is a limit value of 1E+10: not simulated here - unit.m_value++; - } else if (!unit.m_input && unit.m_state == UNIT_WAIT_FOR_TO && - (unit.m_value == 0 || --unit.m_value == 0)) { - // Output unit that is not waiting for real time match and that just reached timeout - // Triggered! - LOG(("triggered %02u:%03u %p\n" , m_sec , m_msec , &unit)); - BIT_SET(triggered, unit.m_port - 1); - unit.adv_state(); - if (unit.m_value == 0) { - LOG(("deact %p\n" , &unit)); - unit.deactivate(); - } - } + // Act on clock chip "keys" + if (m_clock_keys == 0 || m_clock_keys != m_prev_clock_keys) { + m_clock_key_cnt = 0; + if (m_clock_keys == 0 && m_clock_state == CLOCK_HHMM) { + // Keys released in HHMM state -> turn display off + // In real hw there is probably 1 s delay + m_clock_state = CLOCK_OFF; + regen_clock_image(); } - } - // Generate IRQ - if (triggered) { - // Store which output(s) triggered - m_triggered = triggered; - if (m_inten) { - m_irq = true; - update_irq(); - LOG(("IRQ %02x\n" , m_triggered)); - } else if (m_intflag) { - set_error(ERR_MASK_INT_MISSED); - // Record lost interrupts - m_lost_irq = triggered; - LOG(("lost %02x\n" , m_triggered)); + } else if (m_clock_key_cnt < KEY_PRESS_LONG) { + m_clock_key_cnt++; + if (m_clock_key_cnt == KEY_PRESS_SHORT) { + /// Short key press + clock_short_press(); + } else if (m_clock_key_cnt == KEY_PRESS_LONG) { + // Long key press + clock_long_press(); } } + m_prev_clock_keys = m_clock_keys; + // Count seconds + m_clock_1s_div++; + if (m_clock_1s_div >= DIGIT_MUX_FREQ) { + m_clock_1s_div = 0; + advance_seconds(); + regen_clock_image(); + } } } @@ -223,7 +262,7 @@ READ16_MEMBER(hp98035_io_card::reg_r) switch (offset) { case 0: // R4: ODR - res = m_odr; + res = ~m_odr & 0xff; break; case 1: @@ -235,7 +274,7 @@ READ16_MEMBER(hp98035_io_card::reg_r) if (m_intflag) { BIT_SET(res , 1); } - if (m_error) { + if (!BIT(m_dc , 5)) { BIT_SET(res , 0); } break; @@ -256,9 +295,8 @@ WRITE16_MEMBER(hp98035_io_card::reg_w) switch (offset) { case 0: // R4: IDR - m_idr = (uint8_t)data; + m_idr = (uint8_t)(~data); m_idr_full = true; - update_ibuffer(); break; case 1: @@ -274,503 +312,458 @@ WRITE16_MEMBER(hp98035_io_card::reg_w) case 3: // R7: trigger set_flg(false); - update_ibuffer(); - update_obuffer(); break; } LOG(("write R%u=%04x\n" , offset + 4 , data)); } -void hp98035_io_card::half_init(void) +WRITE8_MEMBER(hp98035_io_card::ram_addr_w) { - m_inten = false; - m_intflag = false; - m_irq = false; - m_error = 0; - m_triggered = 0; - m_lost_irq = 0; - update_irq(); + m_ram_addr = data; +} + +READ8_MEMBER(hp98035_io_card::ram_data_r) +{ + return m_np_ram[ m_ram_addr ]; +} + +WRITE8_MEMBER(hp98035_io_card::ram_addr_data_w) +{ + m_ram_addr = data; + m_np_ram[ m_ram_addr ] = m_ram_data_in; +} - for (timer_unit_t& unit : m_units) { - unit.init(); +WRITE8_MEMBER(hp98035_io_card::ram_data_w) +{ + m_ram_data_in = data; +} + +WRITE8_MEMBER(hp98035_io_card::clock_key_w) +{ + m_clock_keys = data & 7; +} + +READ8_MEMBER(hp98035_io_card::clock_digit_r) +{ + switch (m_clock_mux) { + case 1: + return m_clock_digits[ 0 ]; + + case 2: + return m_clock_digits[ 1 ]; + + case 4: + return m_clock_digits[ 2 ]; + + default: + return SEVEN_SEG_OFF; } - // Unit 1 defaults to output 1 - // Unit 2 defaults to input 1 - m_units[ 0 ].m_input = false; - m_units[ 0 ].m_port = 1; - m_units[ 1 ].m_input = true; - m_units[ 1 ].m_port = 1; +} - set_obuffer('\n'); +WRITE8_MEMBER(hp98035_io_card::odr_w) +{ + m_odr = data; + set_flg(true); } -void hp98035_io_card::set_flg(bool value) +READ8_MEMBER(hp98035_io_card::idr_r) { - m_flg = value; - flg_w(m_flg); + set_flg(true); + m_idr_full = false; + return m_idr; } -void hp98035_io_card::update_irq(void) +READ8_MEMBER(hp98035_io_card::np_status_r) { + // Bit 2 = 0: use US date format + uint8_t res = 0x03; + + if (!m_intflag) { + BIT_SET(res, 7); + } if (!m_inten) { - m_irq = false; + BIT_SET(res, 6); } - irq_w(m_inten && m_irq); + if (!m_flg) { + BIT_SET(res, 5); + } + if (m_idr_full) { + BIT_SET(res, 4); + } + if (!m_irq) { + BIT_SET(res, 3); + } + return res; } -void hp98035_io_card::update_ibuffer(void) +WRITE8_MEMBER(hp98035_io_card::clear_np_irq_w) { - if (m_idr_full && !m_flg) { - // New input byte, put in ibuffer if it's a valid char (A-Z 0-9 = / \n) - if (m_idr == DELIM_CH_0 || m_idr == DELIM_CH_1) { - process_ibuffer(); - } else if (((m_idr >= 'A' && m_idr <= 'Z') || (m_idr >= '0' && m_idr <= '9') || m_idr == '=') && - m_ibuffer_ptr < HP98035_IBUFFER_LEN) { - m_ibuffer[ m_ibuffer_ptr++ ] = m_idr; - } - m_idr_full = false; - set_flg(true); + m_np_irq = false; + update_dc(); +} + +READ8_MEMBER(hp98035_io_card::clock_mux_r) +{ + // External input lines are always active (bits 7-4) + uint8_t res = 0xf0 | m_clock_mux; + + if (m_clock_mux == 4 && m_clock_segh) { + BIT_SET(res, 3); } + return res; } -void hp98035_io_card::process_ibuffer(void) +WRITE8_MEMBER(hp98035_io_card::set_irq_w) { - m_ibuffer[ m_ibuffer_ptr ] = '\0'; - const uint8_t *p = &m_ibuffer[ 0 ]; + m_irq = true; + update_irq(); +} - clear_obuffer(); +READ8_MEMBER(hp98035_io_card::clr_inten_r) +{ + m_intflag = false; + m_inten = false; + update_irq(); - bool get_out = false; + return 0xff; +} - while (*p != '\0' && !get_out) { - std::ostringstream out; - uint8_t datetime[ 5 ]; - unsigned unit_no; +WRITE8_MEMBER(hp98035_io_card::clr_inten_w) +{ + m_intflag = false; + m_inten = false; + update_irq(); +} - switch (*p++) { - case 'A': - // Halt all timer units - for (timer_unit_t& unit : m_units) { - unit.deactivate(); - } - m_inten = false; - m_intflag = false; - update_irq(); - break; - - case 'B': - // Warm reset - half_init(); - get_out = true; - break; - - case 'E': - // Read and clear errors - set_obuffer(m_error); - m_error = 0; - break; - - case 'F': - // Activate all timer units - for (timer_unit_t& unit : m_units) { - if (unit.m_port) { - unit.adv_state(true); - } - } - break; - - case 'R': - // Read time - // Assume US format of dates - util::stream_format(out , "%02u:%02u:%02u:%02u:%02u" , m_mon , m_dom , m_hrs , m_min , m_sec); - set_obuffer(out.str().c_str()); - break; - - case 'S': - // Set time - if (parse_datetime(p , datetime)) { - // Cannot set time when there's one or more active output units - if (std::any_of(std::begin(m_units) , std::end(m_units) , [](const timer_unit_t& u) { return u.m_state != UNIT_IDLE && !u.m_input; })) { - set_error(ERR_MASK_CANT_EXEC); - } else { - m_msec = 0; - m_sec = datetime[ 4 ]; - if (datetime[ 3 ] != EMPTY_FIELD) { - m_min = datetime[ 3 ]; - if (datetime[ 2 ] != EMPTY_FIELD) { - m_hrs = datetime[ 2 ]; - if (datetime[ 1 ] != EMPTY_FIELD) { - m_dom = datetime[ 1 ]; - if (datetime[ 0 ] != EMPTY_FIELD) { - m_mon = datetime[ 0 ]; - } - } - } - } - } - } else { - set_error(ERR_MASK_WRONG_INS); - get_out = true; - } - break; - - case 'T': - // Read triggered outputs - set_obuffer(m_triggered); - m_triggered = 0; - break; - - case 'U': - // Control timer units - if (parse_unit_no(p , unit_no)) { - get_out = parse_unit_command(p , unit_no); - } else { - set_error(ERR_MASK_WRONG_INS); - get_out = true; - } - break; - - case 'W': - // Read unserviced interrupts - set_obuffer(m_lost_irq); - m_lost_irq = 0; - break; - - default: - set_error(ERR_MASK_WRONG_INS); - get_out = true; - break; - } +WRITE8_MEMBER(hp98035_io_card::dc_w) +{ + if (data != m_dc) { + //LOG(("DC=%02x\n" , data)); + m_dc = data; + update_dc(); } +} + +void hp98035_io_card::half_init(void) +{ + m_inten = false; + m_intflag = false; + m_irq = false; + update_irq(); + m_np_irq = false; + update_dc(); - m_ibuffer_ptr = 0; + m_clock_1s_div = 0; + m_clock_state = CLOCK_OFF; + m_clock_mux = 0; + regen_clock_image(); } -bool hp98035_io_card::assign_unit(timer_unit_t& unit , const uint8_t*& p , bool input) +void hp98035_io_card::set_flg(bool value) { - unsigned port_no; + m_flg = value; + flg_w(m_flg); +} - if (parse_unit_no(p , port_no)) { - if (unit.m_state == UNIT_IDLE) { - unit.init(); +void hp98035_io_card::update_irq(void) +{ + if (!m_inten) { + m_irq = false; + } + irq_w(m_inten && m_irq); +} - if (std::any_of(std::begin(m_units) , std::end(m_units) , [input , port_no](const timer_unit_t& u) { return u.m_input == input && u.m_port == port_no; })) { - // I/O port already assigned - set_error(ERR_MASK_WRONG_UNIT); - return false; - } +void hp98035_io_card::update_dc(void) +{ + m_cpu->set_input_line(0 , m_np_irq && BIT(m_dc , HP_NANO_IE_DC)); +} - unit.m_input = input; - unit.m_port = port_no; - } else { - set_error(ERR_MASK_CANT_EXEC); - } - return false; +void hp98035_io_card::set_lhs_digits(unsigned v) +{ + if (v < 10) { + m_clock_segh = false; } else { - set_error(ERR_MASK_WRONG_INS); - return true; + v -= 10; + m_clock_segh = true; } + m_clock_digits[ 2 ] = dec_2_seven_segs[ v ]; } -bool hp98035_io_card::parse_unit_command(const uint8_t*& p, unsigned unit_no) +void hp98035_io_card::set_rhs_digits(unsigned v) { - unit_no--; - timer_unit_t& unit = m_units[ unit_no ]; - bool get_out = false; - unsigned msec; - uint8_t to_match[ 5 ]; - std::ostringstream out; + m_clock_digits[ 0 ] = dec_2_seven_segs[ v % 10 ]; + m_clock_digits[ 1 ] = dec_2_seven_segs[ v / 10 ]; +} - LOG(("U %c %u %p\n" , *p , unit_no , &unit)); +void hp98035_io_card::regen_clock_image(void) +{ + int tmp; + bool pm; + + switch (m_clock_state) { + case CLOCK_OFF: + m_clock_digits[ 0 ] = SEVEN_SEG_OFF; + m_clock_digits[ 1 ] = SEVEN_SEG_OFF; + m_clock_digits[ 2 ] = SEVEN_SEG_OFF; + m_clock_segh = false; + break; - switch (*p++) { - case '=': - // Assign unit - if (*p == 'I') { - p++; - get_out = assign_unit(unit , p , true); - } else if (*p == 'O') { - p++; - get_out = assign_unit(unit , p , false); + case CLOCK_HHMM: + tmp = get_clock_register(RTC_HOUR); + if (tmp == 0) { + tmp = 12; + } else if (tmp > 12) { + tmp -= 12; } + set_lhs_digits(tmp); + set_rhs_digits(get_clock_register(RTC_MINUTE)); break; - case 'C': - // Clear input unit - if (unit.m_input && unit.m_port) { - unit.m_value = 0; - } else { - set_error(ERR_MASK_WRONG_UNIT); - } + case CLOCK_SS: + m_clock_segh = false; + m_clock_digits[ 2 ] = SEVEN_SEG_OFF; + set_rhs_digits(get_clock_register(RTC_SECOND)); break; - case 'D': - // Set delay on output unit - if (parse_msec(p , msec)) { - if (!unit.m_input && unit.m_port) { - if (unit.m_state == UNIT_IDLE) { - unit.m_delay = msec; - } else { - set_error(ERR_MASK_CANT_EXEC); - } - } else { - set_error(ERR_MASK_WRONG_UNIT); - } - } else { - set_error(ERR_MASK_WRONG_INS); + case CLOCK_HH: + tmp = get_clock_register(RTC_HOUR); + pm = tmp >= 12; + if (tmp == 0) { + tmp = 12; + } else if (tmp > 12) { + tmp -= 12; } - get_out = true; + set_lhs_digits(tmp); + m_clock_digits[ 1 ] = SEVEN_SEG_OFF; + m_clock_digits[ 0 ] = pm ? SEVEN_SEG_P : SEVEN_SEG_A; break; - case 'G': - // Activate unit - if (unit.m_port && unit.m_state == UNIT_IDLE) { - unit.adv_state(true); + case CLOCK_MIN: + m_clock_segh = false; + m_clock_digits[ 2 ] = SEVEN_SEG_OFF; + set_rhs_digits(get_clock_register(RTC_MINUTE)); + break; - LOG(("act %p %d %d %u %02u:%02u:%02u:%02u %u %u %u\n" , &unit , unit.m_state , unit.m_input , unit.m_port , unit.m_match_datetime[ 0 ] , unit.m_match_datetime[ 1 ] , unit.m_match_datetime[ 2 ] , unit.m_match_datetime[ 3 ] , unit.m_delay , unit.m_period , unit.m_value)); - } else { - set_error(ERR_MASK_WRONG_UNIT); - } + case CLOCK_MON: + tmp = get_clock_register(RTC_MONTH); + set_lhs_digits(tmp); + m_clock_digits[ 0 ] = SEVEN_SEG_OFF; + m_clock_digits[ 1 ] = SEVEN_SEG_OFF; break; - case 'H': - // Halt unit - if (unit.m_port) { - unit.deactivate(); - } else { - set_error(ERR_MASK_WRONG_UNIT); + case CLOCK_DOM: + m_clock_segh = false; + m_clock_digits[ 2 ] = SEVEN_SEG_OFF; + set_rhs_digits(get_clock_register(RTC_DAY)); + break; + + default: + m_clock_state = CLOCK_OFF; + break; + } + LOG(("St=%d segh=%d %02x:%02x:%02x\n" , m_clock_state , m_clock_segh , m_clock_digits[ 2 ] , + m_clock_digits[ 1 ] , m_clock_digits[ 0 ])); +} + +void hp98035_io_card::clock_short_press(void) +{ + LOG(("Short press:%u\n" , m_clock_keys)); + + bool regen = false; + int tmp; + + switch (m_clock_state) { + case CLOCK_OFF: + if (m_clock_keys == KEY_READ_MASK) { + m_clock_state = CLOCK_HHMM; + regen = true; + } else if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_HH; + regen = true; } break; - case 'M': - // Set date/time to match on output unit - if (!unit.m_input && unit.m_port) { - if (unit.m_state == UNIT_IDLE) { - if (*p == '\0') { - unit.m_match_datetime[ 0 ] = EMPTY_FIELD; - unit.m_match_datetime[ 1 ] = EMPTY_FIELD; - unit.m_match_datetime[ 2 ] = EMPTY_FIELD; - unit.m_match_datetime[ 3 ] = EMPTY_FIELD; - } else if (parse_datetime(p , to_match) && *p == '\0') { - unit.m_match_datetime[ 0 ] = to_match[ 1 ]; - unit.m_match_datetime[ 1 ] = to_match[ 2 ]; - unit.m_match_datetime[ 2 ] = to_match[ 3 ]; - unit.m_match_datetime[ 3 ] = to_match[ 4 ]; - } else { - set_error(ERR_MASK_WRONG_INS); - } - } else { - set_error(ERR_MASK_CANT_EXEC); + case CLOCK_SS: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_HH; + regen = true; + } else if (m_clock_keys == (KEY_CHG_MASK | KEY_READ_MASK)) { + tmp = get_clock_register(RTC_SECOND); + tmp++; + if (tmp >= 60) { + tmp = 0; } - } else { - set_error(ERR_MASK_WRONG_UNIT); + set_clock_register(RTC_SECOND , tmp); + log_current_time(); + //m_clock_1s_div = 0; + regen = true; } - get_out = true; break; - case 'P': - // Set period on output unit - if (parse_msec(p , msec)) { - if (!unit.m_input && unit.m_port) { - if (unit.m_state == UNIT_IDLE) { - unit.m_period = msec; - } else { - set_error(ERR_MASK_CANT_EXEC); - } - } else { - set_error(ERR_MASK_WRONG_UNIT); + case CLOCK_HH: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_MIN; + regen = true; + } else if (m_clock_keys == (KEY_CHG_MASK | KEY_READ_MASK)) { + tmp = get_clock_register(RTC_HOUR); + tmp++; + if (tmp >= 24) { + tmp = 0; } - } else { - set_error(ERR_MASK_WRONG_INS); + set_clock_register(RTC_HOUR , tmp); + log_current_time(); + regen = true; } - get_out = true; break; - case 'V': - // Get value of input unit - if (unit.m_input && unit.m_port) { - util::stream_format(out , "%010u" , unit.m_value); - set_obuffer(out.str().c_str()); - } else { - set_error(ERR_MASK_WRONG_UNIT); + case CLOCK_MIN: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_MON; + regen = true; + } else if (m_clock_keys == (KEY_CHG_MASK | KEY_READ_MASK)) { + tmp = get_clock_register(RTC_MINUTE); + tmp++; + if (tmp >= 60) { + tmp = 0; + } + set_clock_register(RTC_MINUTE , tmp); + set_clock_register(RTC_SECOND , 0); + //m_clock_1s_div = 0; + log_current_time(); + regen = true; } break; - } - - return get_out; -} - -void hp98035_io_card::clear_obuffer(void) -{ - m_obuffer_len = 0; - m_obuffer_ptr = 0; -} -void hp98035_io_card::set_obuffer(uint8_t b) -{ - m_obuffer[ 0 ] = b; - m_obuffer_len = 1; - m_obuffer_ptr = 0; -} - -void hp98035_io_card::set_obuffer(const char* s) -{ - unsigned s_len = std::min((unsigned)strlen(s) , (unsigned)(HP98035_OBUFFER_LEN - 1)); + case CLOCK_MON: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_DOM; + regen = true; + } else if (m_clock_keys == (KEY_CHG_MASK | KEY_READ_MASK)) { + tmp = get_clock_register(RTC_MONTH); + tmp++; + if (tmp >= 13) { + tmp = 1; + } + set_clock_register(RTC_MONTH , tmp); + log_current_time(); + regen = true; + } + break; - memcpy(&m_obuffer[ 0 ] , s , s_len); - m_obuffer[ s_len++ ] = '\n'; - m_obuffer_len = s_len; - m_obuffer_ptr = 0; -} + case CLOCK_DOM: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_OFF; + regen = true; + } else if (m_clock_keys == (KEY_CHG_MASK | KEY_READ_MASK)) { + tmp = get_clock_register(RTC_DAY); + tmp++; + if (tmp > gregorian_days_in_month(get_clock_register(RTC_MONTH) , 0)) { + tmp = 1; + } + set_clock_register(RTC_DAY , tmp); + log_current_time(); + regen = true; + } + break; -void hp98035_io_card::update_obuffer(void) -{ - if (!m_idr_full && !m_flg && m_obuffer_ptr < m_obuffer_len) { - m_odr = m_obuffer[ m_obuffer_ptr++ ]; - set_flg(true); + default: + break; } -} -void hp98035_io_card::set_error(uint8_t mask) -{ - m_error |= mask; + if (regen) { + regen_clock_image(); + } } -bool hp98035_io_card::parse_datetime(const uint8_t*& p, uint8_t *out) const +void hp98035_io_card::clock_long_press(void) { - unsigned n_fields = 0; + LOG(("Long press:%u\n" , m_clock_keys)); - // Fill all fields with EMPTY_FIELD - for (unsigned i = 0; i < 5; i++) { - out[ i ] = EMPTY_FIELD; - } + bool regen = false; - while (n_fields < 5 && *p >= '0' && *p <= '9') { - unsigned tmp = *p - '0'; - p++; - if (*p < '0' || *p > '9') { - return false; + switch (m_clock_state) { + case CLOCK_HHMM: + if (m_clock_keys == KEY_READ_MASK) { + m_clock_state = CLOCK_SS; + regen = true; } - // Shift all fields one position to the left - memmove(&out[ 0 ] , &out[ 1 ] , 4 * sizeof(out[ 0 ])); - // Put the new field in the last position - out[ 4 ] = (uint8_t)(tmp * 10 + *p - '0'); - n_fields++; - p++; - } - - if (n_fields == 0) { - return false; - } + break; - // Seconds - if (out[ 4 ] >= 60) { - return false; - } - if (n_fields == 1) { - return true; - } - // Minutes - if (out[ 3 ] >= 60) { - return false; - } - if (n_fields == 2) { - return true; - } - // Hours - if (out[ 2 ] >= 24) { - return false; - } - if (n_fields == 3) { - return true; - } - // Month - uint8_t month; - if (n_fields == 4) { - month = m_mon; - } else { - if (out[ 0 ] < 1 || out[ 0 ] > 12) { - return false; + case CLOCK_SS: + case CLOCK_HH: + case CLOCK_MIN: + case CLOCK_MON: + case CLOCK_DOM: + if (m_clock_keys == KEY_SET_MASK) { + m_clock_state = CLOCK_OFF; + regen = true; } - month = out[ 0 ]; - } - // Day of month - // Use year 0 here to allow for February 29th - if (out[ 1 ] < 1 || out[ 1 ] > gregorian_days_in_month(month , 0)) { - return false; - } - return true; -} + break; -bool hp98035_io_card::parse_unit_no(const uint8_t*& p, unsigned& unit) const -{ - if (*p < '1' || *p > '0' + HP98035_UNIT_COUNT) { - return false; + default: + break; } - unit = *p - '0'; - do { - p++; - } while (*p >= '0' && *p <= '9'); - - return true; + if (regen) { + regen_clock_image(); + } } -bool hp98035_io_card::parse_msec(const uint8_t*& p, unsigned& msec) const +void hp98035_io_card::log_current_time(void) { - msec = 0; - - while (*p >= '0' && *p <= '9') { - msec = msec * 10 + *p - '0'; - p++; - } - - return *p == '\0'; + LOG(("Time = %d:%d:%d:%d:%d\n" , get_clock_register(RTC_MONTH) , + get_clock_register(RTC_DAY) , get_clock_register(RTC_HOUR) , + get_clock_register(RTC_MINUTE) , get_clock_register(RTC_SECOND))); } -void hp98035_io_card::timer_unit_t::init(void) +void hp98035_io_card::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) { - m_state = UNIT_IDLE; - m_port = 0; - m_match_datetime[ 0 ] = EMPTY_FIELD; - m_match_datetime[ 1 ] = EMPTY_FIELD; - m_match_datetime[ 2 ] = EMPTY_FIELD; - m_match_datetime[ 3 ] = EMPTY_FIELD; - m_delay = 0; - m_period = 0; - m_value = 0; + // Do nothing, time is kept in "device_rtc_interface" registers } -void hp98035_io_card::timer_unit_t::deactivate(void) +ROM_START(hp98035) + ROM_REGION(0x800 , "np" , 0) + ROM_LOAD("1818-0469.bin" , 0 , 0x800 , CRC(e16ab3bc) SHA1(34e89a37a2822f27af21969941201317dbff615b)) +ROM_END + +static ADDRESS_MAP_START(np_program_map , AS_PROGRAM , 8 , hp98035_io_card) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x000 , 0x7ff) AM_ROM AM_REGION("np" , 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(np_io_map , AS_IO , 8 , hp98035_io_card) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0 , 0x0) AM_WRITE(ram_addr_w) + AM_RANGE(0x1 , 0x1) AM_READ(ram_data_r) + AM_RANGE(0x2 , 0x2) AM_WRITE(ram_addr_data_w) + AM_RANGE(0x3 , 0x3) AM_WRITE(ram_data_w) + AM_RANGE(0x5 , 0x5) AM_WRITE(clock_key_w) + AM_RANGE(0x7 , 0x7) AM_READ(clock_digit_r) + AM_RANGE(0x8 , 0x8) AM_WRITE(odr_w) + AM_RANGE(0x9 , 0x9) AM_READ(idr_r) + AM_RANGE(0xa , 0xa) AM_READ(np_status_r) + AM_RANGE(0xb , 0xb) AM_WRITE(clear_np_irq_w) + AM_RANGE(0xc , 0xc) AM_READ(clock_mux_r) + AM_RANGE(0xd , 0xd) AM_WRITE(set_irq_w) + AM_RANGE(0xe , 0xe) AM_READWRITE(clr_inten_r , clr_inten_w) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT(hp98035) + MCFG_CPU_ADD("np" , HP_NANOPROCESSOR , XTAL_1MHz) + MCFG_CPU_PROGRAM_MAP(np_program_map) + MCFG_CPU_IO_MAP(np_io_map) + MCFG_HP_NANO_DC_CHANGED(WRITE8(hp98035_io_card , dc_w)) +MACHINE_CONFIG_END + +const tiny_rom_entry *hp98035_io_card::device_rom_region() const { - m_state = UNIT_IDLE; + return ROM_NAME(hp98035); } -void hp98035_io_card::timer_unit_t::adv_state(bool reset) +machine_config_constructor hp98035_io_card::device_mconfig_additions() const { - if (reset) { - m_state = UNIT_IDLE; - } - - if (m_input) { - m_state = UNIT_ACTIVE; - m_value = 0; - } else { - if (m_state == UNIT_IDLE) { - m_state = UNIT_ACTIVE; - if (m_match_datetime[ 3 ] != EMPTY_FIELD) { - // Seconds field is not empty -> there's a date/time to be matched first - return; - } - } - if (m_state == UNIT_ACTIVE) { - m_value = m_delay; - } else { - m_value = m_period; - } - m_state = UNIT_WAIT_FOR_TO; - } + return MACHINE_CONFIG_NAME(hp98035); } // device type definition diff --git a/src/devices/bus/hp9845_io/98035.h b/src/devices/bus/hp9845_io/98035.h index d684b62dedf..e0b034c80ea 100644 --- a/src/devices/bus/hp9845_io/98035.h +++ b/src/devices/bus/hp9845_io/98035.h @@ -14,12 +14,11 @@ #define _98035_H_ #include "hp9845_io.h" +#include "cpu/nanoprocessor/nanoprocessor.h" +#include "dirtc.h" -#define HP98035_IBUFFER_LEN 16 // Totally arbitrary -#define HP98035_OBUFFER_LEN 16 // Totally arbitrary -#define HP98035_UNIT_COUNT 4 // Count of counter/timer units - -class hp98035_io_card : public hp9845_io_card_device +class hp98035_io_card : public hp9845_io_card_device, + public device_rtc_interface { public: // construction/destruction @@ -31,11 +30,48 @@ public: virtual void device_start() override; virtual void device_reset() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual machine_config_constructor device_mconfig_additions() const override; DECLARE_READ16_MEMBER(reg_r); DECLARE_WRITE16_MEMBER(reg_w); + DECLARE_WRITE8_MEMBER(ram_addr_w); + DECLARE_READ8_MEMBER(ram_data_r); + DECLARE_WRITE8_MEMBER(ram_addr_data_w); + DECLARE_WRITE8_MEMBER(ram_data_w); + + DECLARE_WRITE8_MEMBER(clock_key_w); + DECLARE_READ8_MEMBER(clock_digit_r); + + DECLARE_WRITE8_MEMBER(odr_w); + DECLARE_READ8_MEMBER(idr_r); + DECLARE_READ8_MEMBER(np_status_r); + DECLARE_WRITE8_MEMBER(clear_np_irq_w); + DECLARE_READ8_MEMBER(clock_mux_r); + DECLARE_WRITE8_MEMBER(set_irq_w); + DECLARE_READ8_MEMBER(clr_inten_r); + DECLARE_WRITE8_MEMBER(clr_inten_w); + + DECLARE_WRITE8_MEMBER(dc_w); + private: + required_device<hp_nanoprocessor_device> m_cpu; + + // Internal RAM & I/F + uint8_t m_np_ram[ 256 ]; + uint8_t m_ram_addr; + uint8_t m_ram_data_in; + + // DC lines + uint8_t m_dc; + + // NP interrupt + bool m_np_irq; + + // Periodic interrupt + emu_timer *m_msec_timer; + // Interface state bool m_flg; bool m_inten; @@ -44,63 +80,40 @@ private: bool m_idr_full; uint8_t m_idr; // Input Data Register uint8_t m_odr; // Output Data Register - uint8_t m_error; - uint8_t m_triggered; - uint8_t m_lost_irq; - uint8_t m_ibuffer[ HP98035_IBUFFER_LEN + 1 ]; - unsigned m_ibuffer_ptr; - uint8_t m_obuffer[ HP98035_OBUFFER_LEN ]; - unsigned m_obuffer_len; - unsigned m_obuffer_ptr; - - // Clock/timer state - unsigned m_msec; // Milliseconds - uint8_t m_sec; // Seconds - uint8_t m_min; // Minutes - uint8_t m_hrs; // Hours - uint8_t m_dom; // Day of month - uint8_t m_mon; // Month - // Strangely enough this RTC has no notion of current year - emu_timer *m_msec_timer; - // Timer units + // Clock chip emulation typedef enum { - UNIT_IDLE, // Not active - UNIT_ACTIVE, // Active (output units: waiting for date/time match) - UNIT_WAIT_FOR_TO // Active, output units only: waiting for timeout - } unit_state_t; - - typedef struct { - unit_state_t m_state; // State - bool m_input; // Input or output - uint8_t m_port; // Assigned port # (0 if not assigned) - uint8_t m_match_datetime[ 4 ]; // Date&time to match (month is not included) - unsigned m_delay; // Timer delay - unsigned m_period; // Timer period (when != 0) - unsigned m_value; // Current counter value - - void init(void); - void deactivate(void); - void adv_state(bool reset = false); - } timer_unit_t; - - timer_unit_t m_units[ HP98035_UNIT_COUNT ]; + CLOCK_OFF, // Display OFF + CLOCK_HHMM, // Show HH:mm + CLOCK_SS, // Show :SS + CLOCK_HH, // Show HH: A/P + CLOCK_MIN, // Show :mm + CLOCK_MON, // Show MM: + CLOCK_DOM, // Show :DD + } clock_state_t; + + emu_timer *m_clock_timer; + unsigned m_clock_1s_div; + clock_state_t m_clock_state; + uint8_t m_clock_digits[ 3 ]; + uint8_t m_clock_mux; + bool m_clock_segh; + uint8_t m_clock_keys; + uint8_t m_prev_clock_keys; + unsigned m_clock_key_cnt; void half_init(void); void set_flg(bool value); void update_irq(void); - void update_ibuffer(void); - void process_ibuffer(void); - bool assign_unit(timer_unit_t& unit , const uint8_t*& p , bool input); - bool parse_unit_command(const uint8_t*& p, unsigned unit_no); - void clear_obuffer(void); - void set_obuffer(uint8_t b); - void set_obuffer(const char* s); - void update_obuffer(void); - void set_error(uint8_t mask); - bool parse_datetime(const uint8_t*& p, uint8_t *out) const; - bool parse_unit_no(const uint8_t*& p, unsigned& unit) const; - bool parse_msec(const uint8_t*& p, unsigned& msec) const; + void update_dc(void); + + void set_lhs_digits(unsigned v); + void set_rhs_digits(unsigned v); + void regen_clock_image(void); + void clock_short_press(void); + void clock_long_press(void); + void log_current_time(void); + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override; }; // device type definition diff --git a/src/devices/cpu/nanoprocessor/nanoprocessor.cpp b/src/devices/cpu/nanoprocessor/nanoprocessor.cpp new file mode 100644 index 00000000000..273f73f2c48 --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor.cpp @@ -0,0 +1,525 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi + +#include "emu.h" +#include "debugger.h" +#include "nanoprocessor.h" + +// Index of state variables +enum { + NANO_REG_A, + NANO_REG_R0, + NANO_REG_R1, + NANO_REG_R2, + NANO_REG_R3, + NANO_REG_R4, + NANO_REG_R5, + NANO_REG_R6, + NANO_REG_R7, + NANO_REG_R8, + NANO_REG_R9, + NANO_REG_R10, + NANO_REG_R11, + NANO_REG_R12, + NANO_REG_R13, + NANO_REG_R14, + NANO_REG_R15, + NANO_REG_PA, + NANO_REG_SSR, + NANO_REG_ISR, + NANO_REG_FLAGS +}; + +#define BIT_MASK(n) (1U << (n)) + +// Macros to clear/set single bits +#define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n)) +#define BIT_SET(w , n) ((w) |= BIT_MASK(n)) + +// Bits in m_flags +#define NANO_DC0_BIT 0 // DC0 +#define NANO_E_BIT (NANO_DC0_BIT + HP_NANO_DC_NO) // Extend flag +#define NANO_I_BIT (NANO_E_BIT + 1) // Interrupt flag + +const device_type HP_NANOPROCESSOR = &device_creator<hp_nanoprocessor_device>; + +hp_nanoprocessor_device::hp_nanoprocessor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + cpu_device(mconfig , HP_NANOPROCESSOR , "HP-Nanoprocessor" , tag , owner , clock , "nanoprocessor" , __FILE__), + m_dc_changed_func(*this), + m_read_dc_func(*this), + m_program_config("program" , ENDIANNESS_BIG , 8 , 11), + m_io_config("io" , ENDIANNESS_BIG , 8 , 4) +{ +} + +void hp_nanoprocessor_device::device_start() +{ + state_add(NANO_REG_A , "A" , m_reg_A); + state_add(NANO_REG_R0 , "R0" , m_reg_R[ 0 ]); + state_add(NANO_REG_R1 , "R1" , m_reg_R[ 1 ]); + state_add(NANO_REG_R2 , "R2" , m_reg_R[ 2 ]); + state_add(NANO_REG_R3 , "R3" , m_reg_R[ 3 ]); + state_add(NANO_REG_R4 , "R4" , m_reg_R[ 4 ]); + state_add(NANO_REG_R5 , "R5" , m_reg_R[ 5 ]); + state_add(NANO_REG_R6 , "R6" , m_reg_R[ 6 ]); + state_add(NANO_REG_R7 , "R7" , m_reg_R[ 7 ]); + state_add(NANO_REG_R8 , "R8" , m_reg_R[ 8 ]); + state_add(NANO_REG_R9 , "R9" , m_reg_R[ 9 ]); + state_add(NANO_REG_R10 , "R10" , m_reg_R[ 10 ]); + state_add(NANO_REG_R11 , "R11" , m_reg_R[ 11 ]); + state_add(NANO_REG_R12 , "R12" , m_reg_R[ 12 ]); + state_add(NANO_REG_R13 , "R13" , m_reg_R[ 13 ]); + state_add(NANO_REG_R14 , "R14" , m_reg_R[ 14 ]); + state_add(NANO_REG_R15 , "R15" , m_reg_R[ 15 ]); + state_add(NANO_REG_PA , "PA" , m_reg_PA).formatstr("%03X"); + state_add(STATE_GENPC , "GENPC" , m_reg_PA).noshow(); + state_add(STATE_GENPCBASE , "GENPCBASE" , m_reg_PA).noshow(); + state_add(NANO_REG_SSR , "SSR" , m_reg_SSR).formatstr("%03X"); + state_add(NANO_REG_ISR , "ISR" , m_reg_ISR).formatstr("%03X"); + state_add(STATE_GENFLAGS , "GENFLAGS" , m_flags).noshow().formatstr("%10s"); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_reg_A)); + save_item(NAME(m_reg_R)); + save_item(NAME(m_reg_PA)); + save_item(NAME(m_reg_SSR)); + save_item(NAME(m_reg_ISR)); + save_item(NAME(m_flags)); + + m_icountptr = &m_icount; + + m_dc_changed_func.resolve_safe(); + m_read_dc_func.resolve_safe(0xff); +} + +void hp_nanoprocessor_device::device_reset() +{ + m_reg_A = 0; + for (auto& reg : m_reg_R) { + reg = 0; + } + m_reg_PA = 0; + m_reg_SSR = 0; + m_reg_ISR = 0; + m_flags = 0; + dc_update(); +} + +void hp_nanoprocessor_device::execute_run() +{ + do { + // Check for interrupts (interrupt line is always enabled. Masking is done + // outside of the NP, usually by ANDing the DC7 line with the interrupt + // request signal) + if (BIT(m_flags , NANO_I_BIT)) { + m_reg_ISR = m_reg_PA; + m_reg_PA = (uint16_t)(standard_irq_callback(0) & 0xff); + dc_clr(HP_NANO_IE_DC); + // Vector fetching takes 1 cycle + m_icount -= 1; + } else { + debugger_instruction_hook(this , m_reg_PA); + + uint8_t opcode = fetch(); + execute_one(opcode); + // All opcodes execute in 2 cycles + m_icount -= 2; + } + } while (m_icount > 0); +} + +void hp_nanoprocessor_device::execute_set_input(int linenum, int state) +{ + if (linenum == 0) { + if (state) { + BIT_SET(m_flags, NANO_I_BIT); + } else { + BIT_CLR(m_flags, NANO_I_BIT); + } + } +} + +void hp_nanoprocessor_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + if (entry.index() == STATE_GENFLAGS) { + // DC7 is reported as "I" because it is usually used as interrupt enable + str = string_format("%c %c%c%c%c%c%c%c%c" , BIT(m_flags , NANO_E_BIT) ? 'E' : ' ', + BIT(m_flags , NANO_DC0_BIT + 7) ? 'I' : ' ', + BIT(m_flags , NANO_DC0_BIT + 6) ? '6' : ' ', + BIT(m_flags , NANO_DC0_BIT + 5) ? '5' : ' ', + BIT(m_flags , NANO_DC0_BIT + 4) ? '4' : ' ', + BIT(m_flags , NANO_DC0_BIT + 3) ? '3' : ' ', + BIT(m_flags , NANO_DC0_BIT + 2) ? '2' : ' ', + BIT(m_flags , NANO_DC0_BIT + 1) ? '1' : ' ', + BIT(m_flags , NANO_DC0_BIT + 0) ? '0' : ' '); + } + +} + +offs_t hp_nanoprocessor_device::disasm_disassemble(char *buffer, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) +{ + extern CPU_DISASSEMBLE(hp_nanoprocessor); + return CPU_DISASSEMBLE_NAME(hp_nanoprocessor)(this , buffer , pc , oprom , opram , options); +} + +void hp_nanoprocessor_device::execute_one(uint8_t opcode) +{ + // Instructions without mask + switch (opcode) { + case 0x00: + // INB + m_reg_A++; + if (m_reg_A == 0) { + BIT_SET(m_flags, NANO_E_BIT); + } + break; + + case 0x01: + // DEB + m_reg_A--; + if (m_reg_A == 0xff) { + BIT_SET(m_flags, NANO_E_BIT); + } + break; + + case 0x02: + // IND + // Handling of non-decimal digits is entirely arbitrary + m_reg_A++; + if ((m_reg_A & 0x0f) >= 10) { + m_reg_A += 6; + if (m_reg_A >= 0xa0) { + m_reg_A += 0x60; + BIT_SET(m_flags, NANO_E_BIT); + } + } + break; + + case 0x03: + // DED + // Handling of non-decimal digits is entirely arbitrary + m_reg_A--; + if ((m_reg_A & 0x0f) >= 10) { + m_reg_A -= 6; + if (m_reg_A >= 0xa0) { + m_reg_A -= 0x60; + BIT_SET(m_flags, NANO_E_BIT); + } + } + break; + + case 0x04: + // CLA + m_reg_A = 0; + break; + + case 0x05: + // CMA + m_reg_A = ~m_reg_A; + break; + + case 0x06: + // RSA + m_reg_A >>= 1; + break; + + case 0x07: + // LSA + m_reg_A <<= 1; + break; + + case 0x08: + // SGT + if (m_reg_A > m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x09: + // SLT + if (m_reg_A < m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x0a: + // SEQ + if (m_reg_A == m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x0b: + // SAZ + if (m_reg_A == 0) { + skip(); + } + break; + + case 0x0c: + // SLE + if (m_reg_A <= m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x0d: + // SGE + if (m_reg_A >= m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x0e: + // SNE + if (m_reg_A != m_reg_R[ 0 ]) { + skip(); + } + break; + + case 0x0f: + // SAN + if (m_reg_A != 0) { + skip(); + } + break; + + case 0x1f: + // SES + if (BIT(m_flags , NANO_E_BIT)) { + skip(); + } + break; + + case 0x3f: + // SEZ + if (!BIT(m_flags , NANO_E_BIT)) { + skip(); + } + break; + + case 0x5f: + // NOP + break; + + case 0xb1: + // RTE + dc_set(HP_NANO_IE_DC); + // Intentional fall-through to RTI! + + case 0xb0: + // RTI + m_reg_PA = m_reg_ISR; + break; + + case 0xb4: + // STE + BIT_SET(m_flags, NANO_E_BIT); + break; + + case 0xb5: + // CLE + BIT_CLR(m_flags, NANO_E_BIT); + break; + + case 0xb9: + // RSE + dc_set(HP_NANO_IE_DC); + // Intentional fall-through to RTS! + + case 0xb8: + // RTS + { + uint16_t tmp = m_reg_SSR; + m_reg_SSR = pa_offset(1); + m_reg_PA = tmp; + } + break; + + case 0xcf: + // LDR + m_reg_A = fetch(); + break; + + default: + // Instructions with 0xf8 mask + switch (opcode & 0xf8) { + case 0x10: + // SBS + if (BIT(m_reg_A , opcode & 7)) { + skip(); + } + break; + + case 0x18: + // SFS + { + uint8_t tmp = m_read_dc_func(); + tmp &= (uint8_t)(m_flags >> NANO_DC0_BIT); + if (BIT(tmp , opcode & 7)) { + skip(); + } + } + break; + + case 0x20: + // SBN + BIT_SET(m_reg_A, opcode & 7); + break; + + case 0x28: + // STC + dc_set(opcode & 7); + break; + + case 0x30: + // SBZ + if (!BIT(m_reg_A , opcode & 7)) { + skip(); + } + break; + + case 0x38: + // SFZ + { + uint8_t tmp = m_read_dc_func(); + tmp &= (uint8_t)(m_flags >> NANO_DC0_BIT); + if (!BIT(tmp , opcode & 7)) { + skip(); + } + } + break; + + case 0x80: + // JMP + m_reg_PA = ((uint16_t)(opcode & 7) << 8) | fetch(); + break; + + case 0x88: + // JSB + { + uint16_t tmp = ((uint16_t)(opcode & 7) << 8) | fetch(); + m_reg_SSR = m_reg_PA; + m_reg_PA = tmp; + } + break; + + case 0x98: + // JAS + m_reg_SSR = pa_offset(1); + // Intentional fall-through to JAI! + + case 0x90: + // JAI + // On HP doc there's a mysterious warning about JAI: + // "Due to the indexing structure, a JAI instruction executed with + // R03 set will be executed as a JAS instruction" + // My idea on the meaning: NP recycles the instruction register to form + // the bitwise OR of bits 3-0 of R0 and of opcode (see LDI/STI + // instructions). Presumably this was done to save on flip-flop count. + // So, if bit 3 of R0 (R03) is set when executing JAI the instruction + // register turns JAI into JAS. + // This effect is not simulated here at the moment. + { + uint16_t tmp = (uint16_t)((m_reg_R[ 0 ] | opcode) & 7) << 8; + m_reg_PA = tmp | m_reg_A; + } + break; + + case 0xa0: + // CBN + BIT_CLR(m_reg_A, opcode & 7); + break; + + case 0xa8: + // CLC + dc_clr(opcode & 7); + break; + + default: + // Instructions with 0xf0 mask + switch (opcode & 0xf0) { + case 0x40: + // INA + m_reg_A = m_io->read_byte(opcode & 0xf); + break; + + case 0x50: + // OTA + m_io->write_byte(opcode & 0xf , m_reg_A); + break; + + case 0x60: + // LDA + m_reg_A = m_reg_R[ opcode & 0xf ]; + break; + + case 0x70: + // STA + m_reg_R[ opcode & 0xf ] = m_reg_A; + break; + + case 0xc0: + // OTR + m_io->write_byte(opcode & 0xf , fetch()); + break; + + case 0xd0: + // STR + m_reg_R[ opcode & 0xf ] = fetch(); + break; + + case 0xe0: + // LDI + m_reg_A = m_reg_R[ (m_reg_R[ 0 ] | opcode) & 0xf ]; + break; + + case 0xf0: + // STI + m_reg_R[ (m_reg_R[ 0 ] | opcode) & 0xf ] = m_reg_A; + break; + + default: + logerror("Unknown opcode %02x @ 0x03x\n" , opcode , m_reg_PA); + break; + } + } + } +} + +uint16_t hp_nanoprocessor_device::pa_offset(unsigned off) const +{ + return (uint16_t)((m_reg_PA + off) & HP_NANO_PC_MASK); +} + +uint8_t hp_nanoprocessor_device::fetch(void) +{ + uint8_t res = m_direct->read_byte(m_reg_PA); + m_reg_PA = pa_offset(1); + return res; +} + +void hp_nanoprocessor_device::skip(void) +{ + m_reg_PA = pa_offset(2); +} + +void hp_nanoprocessor_device::dc_update(void) +{ + m_dc_changed_func((uint8_t)(m_flags & ((1U << HP_NANO_DC_NO) - 1))); +} + +void hp_nanoprocessor_device::dc_set(unsigned bit_no) +{ + BIT_SET(m_flags, NANO_DC0_BIT + bit_no); + dc_update(); +} + +void hp_nanoprocessor_device::dc_clr(unsigned bit_no) +{ + BIT_CLR(m_flags, NANO_DC0_BIT + bit_no); + dc_update(); +} diff --git a/src/devices/cpu/nanoprocessor/nanoprocessor.h b/src/devices/cpu/nanoprocessor/nanoprocessor.h new file mode 100644 index 00000000000..9193e1b5302 --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor.h @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +// +// ***************************** +// Emulator for HP nanoprocessor +// ***************************** +// +// Nanoprocessor is a very simple microcontroller developed by HP in 1974 for +// its own internal use. It's used, for example, in HP9845 built-in printer, in +// 98034 & 98035 modules, etc. +// Here's a summary of its features: +// * 8-bit word size +// * 1 Accumulator +// * 16 general purpose registers +// * 11-bit Program Counter +// * 2048 bytes of program space +// * 16 input 8-bit ports (DS0-DS15) +// * 15 output 8-bit ports (DS0-DS14) +// * 8 "direct control" I/O lines that can be individually tested/set/cleared +// * 1 interrupt input with 8-bit vector +// * One level nesting of subroutine call through a 11-bit subroutine stack register (SSR) +// * One level nesting of interruption through a 11-bit interrupt stack register (ISR) +// * No built-in ROM or RAM +// * All instructions execute in 2 clock cycles +// * NO arithmetic capabilities, except binary/BCD increment/decrement, bit +// manipulation, left/right shift and comparison between A and R0 +// * Register access can be indexed to use GP registers as a "poor man's RAM" +// _____ _____ +// PA0 1 |* \_/ | 40 VGG +// PA1 2 | | 39 VDD +// PA2 3 | | 38 VBG +// PA3 4 | | 37 DC0 +// PA4 5 | | 36 DC1 +// PA5 6 | | 35 DC2 +// PA6 7 | | 34 DC3 +// PA7 8 | | 33 DC4 +// PA8 9 | | 32 DC5 +// PA9 10 |Nanoprocessor| 31 DC6 +// PA10 11 | | 30 DC7/INT ENA +// DS3 12 | | 29 _INT +// DS2 13 | | 28 ACK +// DS1 14 | | 27 CLK +// DS0 15 | | 26 STM +// _R/W 16 | | 25 DB7 +// GND 17 | | 24 DB6 +// DB0 18 | | 23 DB5 +// DB1 19 | | 22 DB4 +// DB2 20 |_____________| 21 DB3 +// +// The HP manual of Nanoprocessor is available here: +// http://www.hp9845.net/9845/downloads/manuals/Nanoprocessor.pdf +// Thanks to anyone who made the manual available. +#ifndef _NANOPROCESSOR_H_ +#define _NANOPROCESSOR_H_ + +#define HP_NANO_REGS 16 // Number of GP registers +#define HP_NANO_PC_MASK 0x7ff // Mask of PC meaningful bits: 11 bits available +#define HP_NANO_DC_NO 8 // Number of direct control lines (DC7 is typically used as interrupt mask) +#define HP_NANO_IE_DC 7 // DC line used as interrupt enable/mask (DC7) + +// DC changed callback +// The callback receives a 8-bit word holding the state of all DC lines. +// DC0 is in bit 0, DC1 in bit 1 and so on. +// Keep in mind that DC7 usually masks the interrupt signal. +#define MCFG_HP_NANO_DC_CHANGED(_devcb) \ + hp_nanoprocessor_device::set_dc_changed_func(*device , DEVCB_##_devcb); + +// Callback to read the input state of DC lines +// All lines that are not in input are to be reported at "1" +#define MCFG_HP_NANO_READ_DC_CB(_devcb) \ + hp_nanoprocessor_device::set_read_dc_func(*device , DEVCB_##_devcb); + +class hp_nanoprocessor_device : public cpu_device +{ +public: + hp_nanoprocessor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template<class _Object> static devcb_base &set_dc_changed_func(device_t &device, _Object object) { return downcast<hp_nanoprocessor_device &>(device).m_dc_changed_func.set_callback(object); } + template<class _Object> static devcb_base &set_read_dc_func(device_t &device, _Object object) { return downcast<hp_nanoprocessor_device &>(device).m_read_dc_func.set_callback(object); } + + // device_t overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual uint32_t execute_min_cycles() const override { return 2; } + // 3 cycles is for int. acknowledge + 1 instruction + virtual uint32_t execute_max_cycles() const override { return 3; } + virtual uint32_t execute_input_lines() const override { return 1; } + virtual uint32_t execute_default_irq_vector() const override { return 0xff; } + virtual void execute_run() override; + virtual void execute_set_input(int linenum, int state) override; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const override { + return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_IO) ? &m_io_config : nullptr); + } + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + // device_disasm_interface overrides + virtual uint32_t disasm_min_opcode_bytes() const override { return 1; } + virtual uint32_t disasm_max_opcode_bytes() const override { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override; + +private: + devcb_write8 m_dc_changed_func; + devcb_read8 m_read_dc_func; + int m_icount; + + // State of processor + uint8_t m_reg_A; // Accumulator + uint8_t m_reg_R[ HP_NANO_REGS ]; // General purpose registers + uint16_t m_reg_PA; // Program counter ("Program Address" in HP doc) + uint16_t m_reg_SSR; // Subroutine stack register + uint16_t m_reg_ISR; // Interrupt stack register + uint16_t m_flags; // Flags: extend flag (E) & direct control lines (DC0-7) + + address_space_config m_program_config; + address_space_config m_io_config; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + void execute_one(uint8_t opcode); + uint16_t pa_offset(unsigned off) const; + uint8_t fetch(void); + void skip(void); + void dc_update(void); + void dc_set(unsigned bit_no); + void dc_clr(unsigned bit_no); +}; + +extern const device_type HP_NANOPROCESSOR; + +#endif /* _NANOPROCESSOR_H_ */ diff --git a/src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp b/src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp new file mode 100644 index 00000000000..4c38d248936 --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +// ******************************* +// * HP nanoprocessor disassembler +// ******************************* + +#include "emu.h" +#include "debugger.h" +#include "nanoprocessor.h" + +typedef void (*fn_dis_param)(std::ostream& stream , uint8_t opcode , const uint8_t* opram); + +typedef struct { + uint8_t m_op_mask; + uint8_t m_opcode; + const char *m_mnemonic; + fn_dis_param m_param_fn; + uint32_t m_dasm_flags; +} dis_entry_t; + +static void param_bitno(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + stream << (char)('0' + (opcode & 7)); +} + +static void param_ds(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + util::stream_format(stream , "DS%u" , opcode & 0xf); +} + +static void param_reg(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + util::stream_format(stream , "R%u" , opcode & 0xf); +} + +static void param_11bit(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + unsigned tmp = ((unsigned)(opcode & 7) << 8) | *opram; + util::stream_format(stream , "$%03x" , tmp); +} + +static void param_page_no(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + stream << (char)('0' + (opcode & 7)); +} + +static void param_byte(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + util::stream_format(stream , "$%02x" , *opram); +} + +static void param_ds_byte(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + util::stream_format(stream , "DS%u,$%02x" , opcode & 0xf , *opram); +} + +static void param_reg_byte(std::ostream& stream , uint8_t opcode , const uint8_t* opram) +{ + util::stream_format(stream , "R%u,$%02x" , opcode & 0xf , *opram); +} + +static const dis_entry_t dis_table[] = { + {0xff , 0x00 , "INB" , nullptr , 1}, + {0xff , 0x01 , "DEB" , nullptr , 1}, + {0xff , 0x02 , "IND" , nullptr , 1}, + {0xff , 0x03 , "DED" , nullptr , 1}, + {0xff , 0x04 , "CLA" , nullptr , 1}, + {0xff , 0x05 , "CMA" , nullptr , 1}, + {0xff , 0x06 , "RSA" , nullptr , 1}, + {0xff , 0x07 , "LSA" , nullptr , 1}, + {0xff , 0x08 , "SGT" , nullptr , 1}, + {0xff , 0x09 , "SLT" , nullptr , 1}, + {0xff , 0x0a , "SEQ" , nullptr , 1}, + {0xff , 0x0b , "SAZ" , nullptr , 1}, + {0xff , 0x0c , "SLE" , nullptr , 1}, + {0xff , 0x0d , "SGE" , nullptr , 1}, + {0xff , 0x0e , "SNE" , nullptr , 1}, + {0xff , 0x0f , "SAN" , nullptr , 1}, + {0xf8 , 0x10 , "SBS" , param_bitno , 1}, + {0xff , 0x1f , "SES" , nullptr , 1}, + {0xf8 , 0x18 , "SFS" , param_bitno , 1}, + {0xf8 , 0x20 , "SBN" , param_bitno , 1}, + {0xff , 0x2f , "ENI" , nullptr , 1}, + {0xf8 , 0x28 , "STC" , param_bitno , 1}, + {0xf8 , 0x30 , "SBZ" , param_bitno , 1}, + {0xff , 0x3f , "SEZ" , nullptr , 1}, + {0xf8 , 0x38 , "SFZ" , param_bitno , 1}, + {0xf0 , 0x40 , "INA" , param_ds , 1}, + {0xff , 0x5f , "NOP" , nullptr , 1}, + {0xf0 , 0x50 , "OTA" , param_ds , 1}, + {0xf0 , 0x60 , "LDA" , param_reg , 1}, + {0xf0 , 0x70 , "STA" , param_reg , 1}, + {0xf8 , 0x80 , "JMP" , param_11bit , 2}, + {0xf8 , 0x88 , "JSB" , param_11bit , 2 | DASMFLAG_STEP_OVER}, + {0xf8 , 0x90 , "JAI" , param_page_no , 1}, + {0xf8 , 0x98 , "JAS" , param_page_no , 1 | DASMFLAG_STEP_OVER}, + {0xf8 , 0xa0 , "CBN" , param_bitno , 1}, + {0xff , 0xaf , "DSI" , nullptr , 1}, + {0xf8 , 0xa8 , "CLC" , param_bitno , 1}, + {0xff , 0xb0 , "RTI" , nullptr , 1 | DASMFLAG_STEP_OUT}, + {0xff , 0xb1 , "RTE" , nullptr , 1 | DASMFLAG_STEP_OUT}, + {0xff , 0xb4 , "STE" , nullptr , 1}, + {0xff , 0xb5 , "CLE" , nullptr , 1}, + {0xff , 0xb8 , "RTS" , nullptr , 1 | DASMFLAG_STEP_OUT}, + {0xff , 0xb9 , "RSE" , nullptr , 1 | DASMFLAG_STEP_OUT}, + {0xff , 0xcf , "LDR" , param_byte , 2}, + {0xf0 , 0xc0 , "OTR" , param_ds_byte , 2}, + {0xf0 , 0xd0 , "STR" , param_reg_byte , 2}, + {0xf0 , 0xe0 , "LDI" , param_reg , 1}, + {0xf0 , 0xf0 , "STI" , param_reg , 1}, + // Catchall for undefined opcodes + {0x00 , 0x00 , "???" , nullptr , 1} +}; + +CPU_DISASSEMBLE(hp_nanoprocessor) +{ + std::ostringstream stream; + const uint8_t opcode = *oprom; + + opram++; + + for (const dis_entry_t& ent : dis_table) { + if ((opcode & ent.m_op_mask) == ent.m_opcode) { + stream << ent.m_mnemonic << ' '; + if (ent.m_param_fn != nullptr) { + ent.m_param_fn(stream , opcode , opram); + } + std::string stream_str = stream.str(); + strcpy(buffer, stream_str.c_str()); + return ent.m_dasm_flags | DASMFLAG_SUPPORTED; + } + } + // Should never ever happen + return 0; +} diff --git a/src/mame/drivers/hp9845.cpp b/src/mame/drivers/hp9845.cpp index b6cff8a6343..dbccd3757e7 100644 --- a/src/mame/drivers/hp9845.cpp +++ b/src/mame/drivers/hp9845.cpp @@ -315,6 +315,7 @@ void hp9845b_state::machine_reset() m_pa = 0; sts_w(GVIDEO_PA , true); + update_graphic_bits(); memset(&m_kb_state[ 0 ] , 0 , sizeof(m_kb_state)); m_kb_scancode = 0x7f; diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 98d6a4f2c91..f72a5734f23 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -104,6 +104,7 @@ CPU_DISASSEMBLE( hd63701 ); CPU_DISASSEMBLE( hmcs40 ); CPU_DISASSEMBLE( hp_hybrid ); CPU_DISASSEMBLE( hp_5061_3001 ); +CPU_DISASSEMBLE( hp_nanoprocessor ); CPU_DISASSEMBLE( hyperstone_generic ); CPU_DISASSEMBLE( i4004 ); CPU_DISASSEMBLE( i8008 ); @@ -313,6 +314,7 @@ static const dasm_table_entry dasm_table[] = { "mips3be", _32be, 0, CPU_DISASSEMBLE_NAME(mips3be) }, { "mips3le", _32le, 0, CPU_DISASSEMBLE_NAME(mips3le) }, { "mn10200", _16le, 0, CPU_DISASSEMBLE_NAME(mn10200) }, + { "nanoprocessor",_8bit, 0, CPU_DISASSEMBLE_NAME(hp_nanoprocessor) }, { "nec", _8bit, 0, CPU_DISASSEMBLE_NAME(nec) }, { "nsc8105", _8bit, 0, CPU_DISASSEMBLE_NAME(nsc8105) }, { "pdp1", _32be, 0, CPU_DISASSEMBLE_NAME(pdp1) }, |