Merge pull request #1637 from fulivi/hp9845_dev7

Hp9845: re-implemented 98035 module with a nanoprocessor driver
This commit is contained in:
R. Belmont 2016-11-05 14:22:46 -04:00 committed by GitHub
commit f05e7ffad0
9 changed files with 1435 additions and 611 deletions

View File

@ -703,6 +703,22 @@ if (CPUS["HPHYBRID"]~=null or _OPTIONS["with-tools"]) then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/hphybrid/hphybrid_dasm.cpp")
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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;
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;
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 ];
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

View File

@ -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();
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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) },