hp64k: Improved HP Hybrid CPU (still no DMA)

This commit is contained in:
fulivi 2015-06-10 12:22:17 +02:00
parent 7717489f3e
commit eecc50b48a
3 changed files with 1041 additions and 973 deletions

View File

@ -1,5 +1,8 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
//
// TODO:
// - DMA
#include "emu.h"
#include "debugger.h"
@ -46,12 +49,10 @@ enum {
#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>;
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_io_config("io", ENDIANNESS_BIG, 16, 6, -1)
{
@ -127,7 +128,10 @@ void hp_hybrid_cpu_device::execute_run()
{
do {
debugger_instruction_hook(this, m_reg_P);
// TODO: check interrupts
// Check for interrupts
check_for_interrupts();
// TODO: check dma
m_reg_I = execute_one(m_reg_I);
} 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)
{
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 tmp;
@ -732,7 +794,12 @@ UINT16 hp_hybrid_cpu_device::RM(UINT16 addr)
return RIO(CURRENT_PA , addr - HP_REG_R4_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;
} else {
return m_reg_IV | CURRENT_PA;
}
case HP_REG_PA_ADDR:
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)
{
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)
{
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_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")
{
}

View File

@ -10,13 +10,11 @@
// discrete implementation of the 1960s into a multi-chip module (hence the "hybrid" name).
// 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:
// - http://www.hp9845.net/ website
// - HP manual "Assembly development ROM manual for the HP9845": this is the most precious
// and "enabling" resource of all
// - US Patent 4,180,854 describing the HP9845 system
// - Some manual for the 2116 processor
// - Study of disassembly of firmware of HP64000 system
// - A lot of "educated" guessing
@ -40,6 +38,9 @@
#define HP_IOADDR_PA_SHIFT 2
#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
#define HP_REG_A_ADDR 0x0000
#define HP_REG_B_ADDR 0x0001
@ -93,7 +94,7 @@ protected:
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);
private:
private:
address_space_config m_program_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_sc(UINT16 opcode , UINT16& v , unsigned n);
void do_pw(UINT16 opcode);
void check_for_interrupts(void);
UINT16 RM(UINT16 addr);
void WM(UINT16 addr , UINT16 v);