diff options
author | 2016-10-27 12:02:40 +0200 | |
---|---|---|
committer | 2016-11-03 14:52:41 +0100 | |
commit | 5f54097e533a6acaa36147511604d01bd7835d87 (patch) | |
tree | c444e1c4b2627e7e9d26c0ce3f7206e63328efa9 /src | |
parent | 07588d32057e517197af069251c33f0bcb9ddb58 (diff) |
nanoprocessor: initial support. Disassembler only is known to work at this point.
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor.cpp | 517 | ||||
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor.h | 85 | ||||
-rw-r--r-- | src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp | 137 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
4 files changed, 741 insertions, 0 deletions
diff --git a/src/devices/cpu/nanoprocessor/nanoprocessor.cpp b/src/devices/cpu/nanoprocessor/nanoprocessor.cpp new file mode 100644 index 00000000000..4c4e8cb7607 --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor.cpp @@ -0,0 +1,517 @@ +// 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_IE_BIT (NANO_DC0_BIT + 7) // DC7 is usually interrupt enable +#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_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(); +} + +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); + BIT_CLR(m_flags, NANO_IE_BIT); + dc_update(); + // 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(NANO_IE_BIT); + // 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(NANO_IE_BIT); + // 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 + if (BIT(m_flags , NANO_DC0_BIT + (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 + if (!BIT(m_flags , NANO_DC0_BIT + (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..ad7351f8f3a --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +// +// ***************************** +// Emulator for HP nanoprocessor +// ***************************** +// +#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) + +// 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); + +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); } + + // 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; + 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..73c53231940 --- /dev/null +++ b/src/devices/cpu/nanoprocessor/nanoprocessor_dasm.cpp @@ -0,0 +1,137 @@ +// 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)(char *buffer , 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(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + *buffer++ = '0' + (opcode & 7); + *buffer = '\0'; +} + +static void param_ds(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + sprintf(buffer , "DS%u" , opcode & 0xf); +} + +static void param_reg(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + sprintf(buffer , "R%u" , opcode & 0xf); +} + +static void param_11bit(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + unsigned tmp = ((unsigned)(opcode & 7) << 8) | *opram; + sprintf(buffer , "0x%03x" , tmp); +} + +static void param_page_no(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + *buffer++ = '0' + (opcode & 7); + *buffer = '\0'; +} + +static void param_byte(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + sprintf(buffer , "0x%02x" , *opram); +} + +static void param_ds_byte(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + sprintf(buffer , "DS%u,0x%02x" , opcode & 0xf , *opram); +} + +static void param_reg_byte(char *buffer , uint8_t opcode , const uint8_t* opram) +{ + sprintf(buffer , "R%u,0x%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) +{ + const uint8_t opcode = *oprom; + char operand[ 16 ]; + + opram++; + + for (const dis_entry_t& ent : dis_table) { + if ((opcode & ent.m_op_mask) == ent.m_opcode) { + strcpy(buffer , ent.m_mnemonic); + strcat(buffer , " "); + if (ent.m_param_fn != nullptr) { + ent.m_param_fn(operand , opcode , opram); + strcat(buffer , operand); + } + return ent.m_dasm_flags | DASMFLAG_SUPPORTED; + } + } + // Should never ever happen + return 0; +} 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) }, |