mirror of
https://github.com/holub/mame
synced 2025-10-08 09:30:17 +03:00
hp64k: Improved HP Hybrid CPU (still no DMA)
This commit is contained in:
parent
7717489f3e
commit
eecc50b48a
@ -1,5 +1,8 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:F. Ulivi
|
// copyright-holders:F. Ulivi
|
||||||
|
//
|
||||||
|
// TODO:
|
||||||
|
// - DMA
|
||||||
|
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
@ -46,12 +49,10 @@ enum {
|
|||||||
|
|
||||||
#define HP_RESET_ADDR 0x0020
|
#define HP_RESET_ADDR 0x0020
|
||||||
|
|
||||||
#define MAKE_IOADDR(pa , ic) (((pa) << HP_IOADDR_PA_SHIFT) | ((ic) << HP_IOADDR_IC_SHIFT))
|
|
||||||
|
|
||||||
const device_type HP_5061_3011 = &device_creator<hp_5061_3011_cpu_device>;
|
const device_type HP_5061_3011 = &device_creator<hp_5061_3011_cpu_device>;
|
||||||
|
|
||||||
hp_hybrid_cpu_device::hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname)
|
hp_hybrid_cpu_device::hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname)
|
||||||
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
|
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
|
||||||
m_program_config("program", ENDIANNESS_BIG, 16, 16, -1),
|
m_program_config("program", ENDIANNESS_BIG, 16, 16, -1),
|
||||||
m_io_config("io", ENDIANNESS_BIG, 16, 6, -1)
|
m_io_config("io", ENDIANNESS_BIG, 16, 6, -1)
|
||||||
{
|
{
|
||||||
@ -127,7 +128,10 @@ void hp_hybrid_cpu_device::execute_run()
|
|||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
debugger_instruction_hook(this, m_reg_P);
|
debugger_instruction_hook(this, m_reg_P);
|
||||||
// TODO: check interrupts
|
|
||||||
|
// Check for interrupts
|
||||||
|
check_for_interrupts();
|
||||||
|
|
||||||
// TODO: check dma
|
// TODO: check dma
|
||||||
m_reg_I = execute_one(m_reg_I);
|
m_reg_I = execute_one(m_reg_I);
|
||||||
} while (m_icount > 0);
|
} while (m_icount > 0);
|
||||||
@ -135,6 +139,13 @@ void hp_hybrid_cpu_device::execute_run()
|
|||||||
|
|
||||||
void hp_hybrid_cpu_device::execute_set_input(int inputnum, int state)
|
void hp_hybrid_cpu_device::execute_set_input(int inputnum, int state)
|
||||||
{
|
{
|
||||||
|
if (inputnum < HPHYBRID_INT_LVLS) {
|
||||||
|
if (state) {
|
||||||
|
BIT_SET(m_flags , HPHYBRID_IRH_BIT + inputnum);
|
||||||
|
} else {
|
||||||
|
BIT_CLR(m_flags , HPHYBRID_IRH_BIT + inputnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -706,6 +717,57 @@ void hp_hybrid_cpu_device::do_pw(UINT16 opcode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hp_hybrid_cpu_device::check_for_interrupts(void)
|
||||||
|
{
|
||||||
|
if (!BIT(m_flags , HPHYBRID_INTEN_BIT) || BIT(m_flags , HPHYBRID_IRH_SVC_BIT)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int irqline;
|
||||||
|
|
||||||
|
if (BIT(m_flags , HPHYBRID_IRH_BIT)) {
|
||||||
|
// Service high-level interrupt
|
||||||
|
BIT_SET(m_flags , HPHYBRID_IRH_SVC_BIT);
|
||||||
|
irqline = HPHYBRID_IRH;
|
||||||
|
} else if (BIT(m_flags , HPHYBRID_IRL_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
|
||||||
|
// Service low-level interrupt
|
||||||
|
BIT_SET(m_flags , HPHYBRID_IRL_SVC_BIT);
|
||||||
|
irqline = HPHYBRID_IRL;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get interrupt vector in low byte
|
||||||
|
UINT8 vector = (UINT8)standard_irq_callback(irqline);
|
||||||
|
UINT8 new_PA;
|
||||||
|
|
||||||
|
// Get highest numbered 1
|
||||||
|
// Don't know what happens if vector is 0, here we assume bit 7 = 1
|
||||||
|
if (vector == 0) {
|
||||||
|
new_PA = 7;
|
||||||
|
} else {
|
||||||
|
for (new_PA = 7; new_PA && !BIT(vector , 7); new_PA--, vector <<= 1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (irqline == HPHYBRID_IRH) {
|
||||||
|
BIT_SET(new_PA , 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push PA stack
|
||||||
|
memmove(&m_reg_PA[ 1 ] , &m_reg_PA[ 0 ] , HPHYBRID_INT_LVLS);
|
||||||
|
|
||||||
|
CURRENT_PA = new_PA;
|
||||||
|
|
||||||
|
// Is this correct? Patent @ pg 210 suggests that the whole interrupt recognition sequence
|
||||||
|
// lasts for 32 cycles (6 are already accounted for in get_ea for one indirection)
|
||||||
|
m_icount -= 26;
|
||||||
|
|
||||||
|
// Do a double-indirect JSM IV,I instruction
|
||||||
|
WM(++m_reg_R , m_reg_P);
|
||||||
|
m_reg_P = RM(get_ea(0xc008));
|
||||||
|
m_reg_I = RM(m_reg_P);
|
||||||
|
}
|
||||||
|
|
||||||
UINT16 hp_hybrid_cpu_device::RM(UINT16 addr)
|
UINT16 hp_hybrid_cpu_device::RM(UINT16 addr)
|
||||||
{
|
{
|
||||||
UINT16 tmp;
|
UINT16 tmp;
|
||||||
@ -732,7 +794,12 @@ UINT16 hp_hybrid_cpu_device::RM(UINT16 addr)
|
|||||||
return RIO(CURRENT_PA , addr - HP_REG_R4_ADDR);
|
return RIO(CURRENT_PA , addr - HP_REG_R4_ADDR);
|
||||||
|
|
||||||
case HP_REG_IV_ADDR:
|
case HP_REG_IV_ADDR:
|
||||||
|
// Correct?
|
||||||
|
if (!BIT(m_flags , HPHYBRID_IRH_SVC_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
|
||||||
return m_reg_IV;
|
return m_reg_IV;
|
||||||
|
} else {
|
||||||
|
return m_reg_IV | CURRENT_PA;
|
||||||
|
}
|
||||||
|
|
||||||
case HP_REG_PA_ADDR:
|
case HP_REG_PA_ADDR:
|
||||||
return CURRENT_PA;
|
return CURRENT_PA;
|
||||||
@ -844,16 +911,15 @@ void hp_hybrid_cpu_device::WMB(UINT32 addr , UINT8 v)
|
|||||||
|
|
||||||
UINT16 hp_hybrid_cpu_device::RIO(UINT8 pa , UINT8 ic)
|
UINT16 hp_hybrid_cpu_device::RIO(UINT8 pa , UINT8 ic)
|
||||||
{
|
{
|
||||||
return m_io->read_word(MAKE_IOADDR(pa, ic) << 1);
|
return m_io->read_word(HP_MAKE_IOADDR(pa, ic) << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hp_hybrid_cpu_device::WIO(UINT8 pa , UINT8 ic , UINT16 v)
|
void hp_hybrid_cpu_device::WIO(UINT8 pa , UINT8 ic , UINT16 v)
|
||||||
{
|
{
|
||||||
m_io->write_word(MAKE_IOADDR(pa, ic) << 1 , v);
|
m_io->write_word(HP_MAKE_IOADDR(pa, ic) << 1 , v);
|
||||||
}
|
}
|
||||||
|
|
||||||
hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||||
: hp_hybrid_cpu_device(mconfig, HP_5061_3011, "HP_5061_3011", tag, owner, clock, "5061-3011")
|
: hp_hybrid_cpu_device(mconfig, HP_5061_3011, "HP_5061_3011", tag, owner, clock, "5061-3011")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,11 @@
|
|||||||
// discrete implementation of the 1960s into a multi-chip module (hence the "hybrid" name).
|
// discrete implementation of the 1960s into a multi-chip module (hence the "hybrid" name).
|
||||||
// This emulator currently supports the 5061-3011 version only.
|
// This emulator currently supports the 5061-3011 version only.
|
||||||
//
|
//
|
||||||
// There is very little information around on this processor.
|
|
||||||
// For this emulator I mainly relied on these sources:
|
// For this emulator I mainly relied on these sources:
|
||||||
// - http://www.hp9845.net/ website
|
// - http://www.hp9845.net/ website
|
||||||
// - HP manual "Assembly development ROM manual for the HP9845": this is the most precious
|
// - HP manual "Assembly development ROM manual for the HP9845": this is the most precious
|
||||||
// and "enabling" resource of all
|
// and "enabling" resource of all
|
||||||
// - US Patent 4,180,854 describing the HP9845 system
|
// - US Patent 4,180,854 describing the HP9845 system
|
||||||
// - Some manual for the 2116 processor
|
|
||||||
// - Study of disassembly of firmware of HP64000 system
|
// - Study of disassembly of firmware of HP64000 system
|
||||||
// - A lot of "educated" guessing
|
// - A lot of "educated" guessing
|
||||||
|
|
||||||
@ -40,6 +38,9 @@
|
|||||||
#define HP_IOADDR_PA_SHIFT 2
|
#define HP_IOADDR_PA_SHIFT 2
|
||||||
#define HP_IOADDR_IC_SHIFT 0
|
#define HP_IOADDR_IC_SHIFT 0
|
||||||
|
|
||||||
|
// Compose an I/O address from PA & IC
|
||||||
|
#define HP_MAKE_IOADDR(pa , ic) (((pa) << HP_IOADDR_PA_SHIFT) | ((ic) << HP_IOADDR_IC_SHIFT))
|
||||||
|
|
||||||
// Addresses of memory mapped registers
|
// Addresses of memory mapped registers
|
||||||
#define HP_REG_A_ADDR 0x0000
|
#define HP_REG_A_ADDR 0x0000
|
||||||
#define HP_REG_B_ADDR 0x0001
|
#define HP_REG_B_ADDR 0x0001
|
||||||
@ -93,7 +94,7 @@ protected:
|
|||||||
virtual UINT32 disasm_max_opcode_bytes() const { return 2; }
|
virtual UINT32 disasm_max_opcode_bytes() const { return 2; }
|
||||||
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
address_space_config m_program_config;
|
address_space_config m_program_config;
|
||||||
address_space_config m_io_config;
|
address_space_config m_io_config;
|
||||||
|
|
||||||
@ -122,6 +123,7 @@ protected:
|
|||||||
UINT16 get_skip_addr(UINT16 opcode , bool condition) const;
|
UINT16 get_skip_addr(UINT16 opcode , bool condition) const;
|
||||||
UINT16 get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n);
|
UINT16 get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n);
|
||||||
void do_pw(UINT16 opcode);
|
void do_pw(UINT16 opcode);
|
||||||
|
void check_for_interrupts(void);
|
||||||
|
|
||||||
UINT16 RM(UINT16 addr);
|
UINT16 RM(UINT16 addr);
|
||||||
void WM(UINT16 addr , UINT16 v);
|
void WM(UINT16 addr , UINT16 v);
|
||||||
|
Loading…
Reference in New Issue
Block a user