HP9825: added 9825T variant (#4629)

* hphybrid: added cbs to expose memory cycles & fetched opcodes

* hp9825: 9825T variant added
This commit is contained in:
fulivi 2019-02-16 16:48:41 +01:00 committed by R. Belmont
parent 7da2a8feaf
commit a3bf00db9e
4 changed files with 362 additions and 21 deletions

View File

@ -175,6 +175,8 @@ uint8_t hp_hybrid_cpu_device::pa_r() const
hp_hybrid_cpu_device::hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t addrwidth)
: cpu_device(mconfig, type, tag, owner, clock)
, m_pa_changed_func(*this)
, m_opcode_func(*this)
, m_stm_func(*this)
, m_addr_mask((1U << addrwidth) - 1)
, m_relative_mode(true)
, m_r_cycles(DEF_MEM_R_CYCLES)
@ -241,6 +243,11 @@ void hp_hybrid_cpu_device::device_start()
set_icountptr(m_icount);
m_pa_changed_func.resolve_safe();
m_opcode_func.resolve();
m_stm_func.resolve();
// Cache active state of m_stm_func & m_opcode_func
m_opcode_func_defd = bool(m_opcode_func);
m_stm_func_defd = bool(m_stm_func);
}
void hp_hybrid_cpu_device::device_reset()
@ -260,6 +267,7 @@ void hp_hybrid_cpu_device::device_reset()
m_dmapa = 0;
m_dmama = 0;
m_dmac = 0;
m_curr_cycle = 0;
m_forced_bsc_25 = m_boot_mode;
m_last_pa = ~0;
@ -312,7 +320,7 @@ uint16_t hp_hybrid_cpu_device::execute_one(uint16_t opcode)
}
// Indirect addressing in EXE instruction seems to use AEC case A instead of case C
// (because it's an opcode fetch)
return RM(add_mae(AEC_CASE_A , fetch_addr));
return fetch_at(add_mae(AEC_CASE_A , fetch_addr));
} else {
uint16_t next_P;
if (!execute_one_bpc(opcode , next_P) &&
@ -952,6 +960,11 @@ uint16_t hp_hybrid_cpu_device::RM(uint32_t addr)
// Any access to internal registers removes forcing of BSC 2x
m_forced_bsc_25 = false;
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_RAL_MASK | CYCLE_RD_MASK);
m_curr_cycle = 0;
}
// Memory mapped BPC registers
uint16_t tmp;
switch (addr_wo_bsc) {
@ -1016,6 +1029,10 @@ uint16_t hp_hybrid_cpu_device::RM(uint32_t addr)
return tmp;
} else {
m_icount -= m_r_cycles;
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_RD_MASK);
m_curr_cycle = 0;
}
return m_cache->read_word(addr);
}
}
@ -1065,6 +1082,11 @@ void hp_hybrid_cpu_device::WM(uint32_t addr , uint16_t v)
// Any access to internal registers removes forcing of BSC 2x
m_forced_bsc_25 = false;
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_RAL_MASK | CYCLE_WR_MASK);
m_curr_cycle = 0;
}
// Memory mapped BPC registers
switch (addr_wo_bsc) {
case HP_REG_A_ADDR:
@ -1130,6 +1152,10 @@ void hp_hybrid_cpu_device::WM(uint32_t addr , uint16_t v)
m_icount -= REGISTER_RW_CYCLES;
} else {
m_icount -= m_w_cycles;
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
m_curr_cycle = 0;
}
m_program->write_word(addr , v);
}
}
@ -1168,7 +1194,17 @@ bool hp_hybrid_cpu_device::write_emc_reg(uint16_t addr , uint16_t v)
uint16_t hp_hybrid_cpu_device::fetch()
{
m_genpc = add_mae(AEC_CASE_A , m_reg_P);
return RM(m_genpc);
return fetch_at(m_genpc);
}
uint16_t hp_hybrid_cpu_device::fetch_at(uint32_t addr)
{
m_curr_cycle |= CYCLE_IFETCH_MASK;
uint16_t opcode = RM(addr);
if (m_opcode_func_defd) {
m_opcode_func(opcode);
}
return opcode;
}
uint16_t hp_hybrid_cpu_device::get_indirect_target(uint32_t addr)
@ -1586,6 +1622,10 @@ bool hp_5061_3011_cpu_device::execute_no_bpc(uint16_t opcode , uint16_t& next_pc
// 16 bits units.
WM(tmp_addr >> 1 , tmp);
} else {
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
m_curr_cycle = 0;
}
// Extend address, form byte address
uint16_t mask = BIT(tmp_addr , 0) ? 0x00ff : 0xff00;
tmp_addr = add_mae(AEC_CASE_C , tmp_addr >> 1);
@ -1674,6 +1714,7 @@ void hp_5061_3011_cpu_device::handle_dma()
bool tc = BIT(--m_dmac , 15) != 0;
uint16_t tmp;
m_curr_cycle |= CYCLE_DMA_MASK;
// Timing here assumes that DMA transfers are isolated and not done in bursts
if (BIT(m_flags , HPHYBRID_DMADIR_BIT)) {
// "Outward" DMA: memory -> peripheral
@ -1955,6 +1996,10 @@ bool hp_09825_67907_cpu_device::execute_no_bpc(uint16_t opcode , uint16_t& next_
// 16 bits units.
WM(tmp_addr , tmp);
} else {
if (m_stm_func_defd) {
m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
m_curr_cycle = 0;
}
uint16_t mask = BIT(*ptr_reg , 15) ? 0xff00 : 0x00ff;
m_program->write_word(tmp_addr , tmp , mask);
m_icount -= m_w_cycles;
@ -2037,6 +2082,7 @@ void hp_09825_67907_cpu_device::handle_dma()
uint16_t tmp;
// Timing here assumes that DMA transfers are isolated and not done in bursts
m_curr_cycle |= CYCLE_DMA_MASK;
if (BIT(m_dmama , 15)) {
// "Outward" DMA: memory -> peripheral
tmp = RM(AEC_CASE_D , m_dmama);

View File

@ -64,6 +64,29 @@ public:
void set_relative_mode(bool rela) { m_relative_mode = rela; }
void set_rw_cycles(unsigned read_cycles , unsigned write_cycles) { m_r_cycles = read_cycles; m_w_cycles = write_cycles; }
// Possible combinations:
// 00 No r/w cycle in progress
// 01 Non-ifetch rd cycle
// 05 Ifetch rd cycle
// 09 DMA rd cycle
// 02 Wr cycle
// 0a DMA wr cycle
//
// CYCLE_RAL_MASK is set when access is into register space [0..1f]
enum : uint8_t {
CYCLE_RD_MASK = 0x01,
CYCLE_WR_MASK = 0x02,
CYCLE_IFETCH_MASK = 0x04,
CYCLE_DMA_MASK = 0x08,
CYCLE_RAL_MASK = 0x10
};
// Called at start of each memory access
auto stm_cb() { return m_stm_func.bind(); }
// Tap into fetched opcodes
auto opcode_cb() { return m_opcode_func.bind(); }
protected:
hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t addrwidth);
@ -123,6 +146,7 @@ protected:
void WIO(uint8_t pa , uint8_t ic , uint16_t v);
uint16_t fetch();
uint16_t fetch_at(uint32_t addr);
virtual uint16_t get_indirect_target(uint32_t addr);
virtual void enter_isr();
virtual void handle_dma() = 0;
@ -133,6 +157,10 @@ protected:
devcb_write8 m_pa_changed_func;
uint8_t m_last_pa;
bool m_opcode_func_defd;
devcb_write16 m_opcode_func;
bool m_stm_func_defd;
devcb_write8 m_stm_func;
int m_icount;
uint32_t m_addr_mask;
@ -159,6 +187,8 @@ protected:
uint16_t m_dmac; // DMA counter
uint16_t m_reg_I; // Instruction register
uint32_t m_genpc; // Full PC
uint8_t m_curr_cycle; // Current cycle type
// EMC registers
uint16_t m_reg_ar2[ 4 ]; // AR2 register
uint16_t m_reg_se; // SE register (4 bits)

View File

@ -8,8 +8,8 @@
// **** Temporary header, will hopefully evolve into proper doc ****
//
// What's in:
// - Emulation of 9825B system
// - 12 kw of RAMs
// - Emulation of 9825B and 9825T systems
// - 12 kw (9825B) or 31kw (9825T) of RAM
// - 12 kw of system ROM
// - Keyboard (SHIFT LOCK & RESET not implemented)
// - Display & run light
@ -18,6 +18,8 @@
// - Beeper
// - Internal expansion ROMs
// - I/O expansion slots: 98032, 98034 & 98035 modules can be connected
// - For 9825T: the so-called SKOAL mechanism that transparently overlays RAM & ROM
// in the same address space
// What's not yet in:
// - External expansion ROMs
// - Configurable RAM size
@ -27,8 +29,11 @@
// by re-assembling the source code (this is the reason why it's marked as
// a BAD_DUMP). And thanks to Ansgar Kueckes for adapting his assembler to
// handle HP9825 source files.
// For what regards the 9825T, I'd like to thank again Dyke Shaffer for
// publishing a lot of internal HP docs about the SKOAL card. I recovered the
// content of SKOAL ROM from its printed & scanned dump.
//
// 9825A & 9825T can also be emulated. At the moment I haven't all the necessary
// 9825A can also be emulated. At the moment I haven't all the necessary
// ROM dumps, though.
#include "emu.h"
@ -42,6 +47,10 @@
#include "sound/beep.h"
#include "hp9825.lh"
// Debugging
#define VERBOSE 0
#include "logmacro.h"
// CPU clock (generated by a trimmered RC oscillator)
constexpr unsigned MAIN_CLOCK = 6000000;
@ -81,6 +90,9 @@ namespace {
}
}
// +--------------+
// | hp9825_state |
// +--------------+
class hp9825_state : public driver_device
{
public:
@ -103,15 +115,16 @@ public:
{
}
void hp9825b(machine_config &config);
void hp9825_base(machine_config &config);
protected:
virtual void machine_start() override;
virtual void device_reset() override;
virtual void machine_reset() override;
private:
required_device<hp_09825_67907_cpu_device> m_cpu;
private:
required_device<hp98x5_io_sys_device> m_io_sys;
required_device<timer_device> m_cursor_timer;
required_device<hp9825_tape_device> m_tape;
@ -144,7 +157,6 @@ private:
int m_slot_sc[ 3 ];
void cpu_io_map(address_map &map);
void cpu_mem_map(address_map &map);
DECLARE_READ16_MEMBER(kb_scancode_r);
DECLARE_WRITE16_MEMBER(disp_w);
@ -228,16 +240,6 @@ void hp9825_state::cpu_io_map(address_map &map)
// TODO:
}
void hp9825_state::cpu_mem_map(address_map &map)
{
map.unmap_value_low();
// map(0x0000 , 0x2fff).rom();
// map(0x3400 , 0x3bff).rom();
map(0x0000 , 0x3bff).rom();
map(0x4000 , 0x4fff).rom();
map(0x5000 , 0x7fff).ram();
}
READ16_MEMBER(hp9825_state::kb_scancode_r)
{
uint8_t res = m_scancode;
@ -620,12 +622,11 @@ void hp9825_state::set_dmar_slot(unsigned slot , int state)
m_io_sys->set_dmar(uint8_t(sc) , state);
}
MACHINE_CONFIG_START(hp9825_state::hp9825b)
MACHINE_CONFIG_START(hp9825_state::hp9825_base)
HP_09825_67907(config , m_cpu , MAIN_CLOCK);
// Just guessing... settings borrowed from hp9845
m_cpu->set_rw_cycles(6 , 6);
m_cpu->set_relative_mode(false);
m_cpu->set_addrmap(AS_PROGRAM , &hp9825_state::cpu_mem_map);
m_cpu->set_addrmap(AS_IO , &hp9825_state::cpu_io_map);
m_cpu->set_irq_acknowledge_callback("io_sys" , FUNC(hp98x5_io_sys_device::irq_callback));
m_cpu->pa_changed_cb().set(m_io_sys , FUNC(hp98x5_io_sys_device::pa_w));
@ -826,6 +827,251 @@ static INPUT_PORTS_START(hp9825)
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // Shift
INPUT_PORTS_END
// +---------------+
// | hp9825b_state |
// +---------------+
class hp9825b_state : public hp9825_state
{
public:
hp9825b_state(const machine_config &mconfig, device_type type, const char *tag)
: hp9825_state(mconfig , type , tag)
{
}
void hp9825b(machine_config &config);
private:
void cpu_mem_map(address_map &map);
};
MACHINE_CONFIG_START(hp9825b_state::hp9825b)
hp9825_base(config);
m_cpu->set_addrmap(AS_PROGRAM , &hp9825b_state::cpu_mem_map);
MACHINE_CONFIG_END
void hp9825b_state::cpu_mem_map(address_map &map)
{
map.unmap_value_low();
map(0x0000 , 0x3bff).rom();
map(0x4000 , 0x4fff).rom();
map(0x5000 , 0x7fff).ram();
}
// +---------------+
// | hp9825t_state |
// +---------------+
class hp9825t_state : public hp9825_state
{
public:
hp9825t_state(const machine_config &mconfig, device_type type, const char *tag)
: hp9825_state(mconfig , type , tag)
, m_rom_region(*this , "rom")
, m_skoalrom(*this , "skoalrom")
{
}
void hp9825t(machine_config &config);
protected:
virtual void machine_start() override;
virtual void device_reset() override;
private:
required_memory_region m_rom_region;
required_memory_region m_skoalrom;
std::unique_ptr<uint16_t[]> m_ram;
uint8_t m_cycle_type;
// SKOAL state
bool m_skoalbit; // U53
bool m_second_access; // U57-3
bool m_mref; // U57-4
bool m_ifetch_4400; // U57-5
uint8_t m_special_opt; // U42
uint16_t m_fetch_addr;
void cpu_mem_map(address_map &map);
DECLARE_READ16_MEMBER(cpu_mem_r);
DECLARE_WRITE16_MEMBER(cpu_mem_w);
void stm(uint8_t cycle_type);
void on_cycle_end();
void opcode_fetch(uint16_t opcode);
uint8_t get_skoalrom(uint16_t addr);
bool is_rom(uint16_t addr , uint8_t cycle_type) const;
};
MACHINE_CONFIG_START(hp9825t_state::hp9825t)
hp9825_base(config);
m_cpu->set_addrmap(AS_PROGRAM , &hp9825t_state::cpu_mem_map);
m_cpu->stm_cb().set(FUNC(hp9825t_state::stm));
m_cpu->opcode_cb().set(FUNC(hp9825t_state::opcode_fetch));
MACHINE_CONFIG_END
void hp9825t_state::machine_start()
{
hp9825_state::machine_start();
// 32kw of RAM (the 1st kw is not accessible in normal operation)
m_ram = std::make_unique<uint16_t[]>(32768);
save_pointer(NAME(m_ram) , 32768);
}
void hp9825t_state::device_reset()
{
hp9825_state::device_reset();
// This has to be done before CPU reset or first instruction won't be fetched correctly
m_cycle_type = 0;
m_special_opt = 0xf;
}
void hp9825t_state::cpu_mem_map(address_map &map)
{
map.unmap_value_low();
map(0x0000 , 0x7fff).rw(FUNC(hp9825t_state::cpu_mem_r) , FUNC(hp9825t_state::cpu_mem_w));
}
READ16_MEMBER(hp9825t_state::cpu_mem_r)
{
bool from_rom;
if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_RD_MASK) {
if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) {
m_fetch_addr = offset;
}
from_rom = is_rom(offset , m_cycle_type);
LOG("rd @%04x CYC=%x %d%d%d%d ROM=%d\n" , offset , m_cycle_type , m_skoalbit , m_second_access , m_mref , m_ifetch_4400 , from_rom);
if (!(m_cycle_type & (hp_hybrid_cpu_device::CYCLE_IFETCH_MASK | hp_hybrid_cpu_device::CYCLE_DMA_MASK))) {
on_cycle_end();
}
m_cycle_type = 0;
// TODO: diagnostic read
} else {
// Read coming from debugger and not from CPU: fake an ifetch
from_rom = is_rom(offset , hp_hybrid_cpu_device::CYCLE_IFETCH_MASK);
}
return from_rom ? m_rom_region->as_u16(offset) : m_ram[ offset ];
}
WRITE16_MEMBER(hp9825t_state::cpu_mem_w)
{
if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_WR_MASK) {
if (!(m_cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK)) {
on_cycle_end();
}
m_cycle_type = 0;
}
// All write cycles go to RAM
m_ram[ offset ] = (m_ram[ offset ] & ~mem_mask) | (data & mem_mask);
}
void hp9825t_state::stm(uint8_t cycle_type)
{
LOG("stm %x\n" , cycle_type);
m_cycle_type = cycle_type;
if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) {
m_second_access = false;
m_mref = false;
m_ifetch_4400 = false;
// In case of ifetch from register area this is kept at 0 (because cpu_mem_r is not called)
// In case of ifetch from RAM/ROM this is set by cpu_mem_r to the fetch address
m_fetch_addr = 0;
} else if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_RAL_MASK) {
if (!(m_cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK)) {
on_cycle_end();
}
m_cycle_type = 0;
}
}
void hp9825t_state::on_cycle_end()
{
m_second_access = false;
}
void hp9825t_state::opcode_fetch(uint16_t opcode)
{
LOG("oc %04x\n" , opcode);
m_cycle_type = 0;
// memory referencing instructions
m_mref = (opcode & 0x7000) != 0x7000;
m_second_access = true;
m_ifetch_4400 = (m_fetch_addr & 0x7f00) == 0x0900;
if (BIT(m_special_opt , 3) && BIT(m_special_opt , 2)) {
// Set SKOAL bit
if (m_fetch_addr < 0x20) {
// Fetch from registers -> SKOAL bit = 0
m_skoalbit = false;
} else if ((m_fetch_addr & 0x6000) == 0x6000) {
// Fetch in [6000..7fff] range -> SKOAL bit = 0
m_skoalbit = false;
} else {
uint8_t tmp = get_skoalrom(m_fetch_addr);
m_skoalbit = (tmp >> ((~m_fetch_addr >> 12) & 7)) & 1;
}
}
// Decode SKOAL instructions. They are ignored by the hybrid processor
// as they are not recognized.
if ((opcode & 0xffc0) == 0x7040) {
m_special_opt = opcode & 0xf;
if (!BIT(m_special_opt , 3)) {
// RAM/ == 0
m_skoalbit = false;
} else if (!BIT(m_special_opt , 2)) {
// ROM/ == 0
m_skoalbit = true;
}
}
}
uint8_t hp9825t_state::get_skoalrom(uint16_t addr)
{
return m_skoalrom->as_u8(~addr & 0x0fff);
}
bool hp9825t_state::is_rom(uint16_t addr , uint8_t cycle_type) const
{
if ((addr & 0x6000) == 0x6000) {
// [6000..7fff] -> always RAM
return false;
} else if ((cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK) != 0 ||
!BIT(m_special_opt , 1)) {
// DMA cycle or BIT/ == 0 -> RAM
return false;
} else if (addr >= 0x400 && !BIT(m_special_opt , 0)) {
// [0400..5fff] and BIN/ == 0 -> RAM
return false;
} else {
bool addr_0800_7fff = (addr & 0x7800) != 0;
bool addr_0400_07ff = !addr_0800_7fff && BIT(addr , 10);
bool addr_0000_03ff = !addr_0800_7fff && !BIT(addr , 10);
// U58-6
bool force_rom;
// ROM when one or more of these is true:
// - addr in [0000..03ff]
// - Ifetch cycle and addr in [0800..5fff]
// - 2nd access of a memory-referencing instruction not in [0400..07ff] range
// - skoalbit = 1 and instruction fetched in [0900..09ff] range
force_rom =
addr_0000_03ff ||
((cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) != 0 && addr_0800_7fff) ||
(m_second_access && m_mref && (!BIT(m_special_opt , 2) || !addr_0400_07ff)) ||
(m_skoalbit && m_ifetch_4400);
if (force_rom) {
return true;
} else if (addr_0400_07ff && BIT(m_special_opt , 2)) {
return false;
} else {
return m_skoalbit;
}
}
}
ROM_START(hp9825b)
ROM_REGION(0xa000 , "cpu" , ROMREGION_16BIT | ROMREGION_BE)
ROM_LOAD("sysrom1.bin" , 0x0000 , 0x2000 , CRC(fe429268) SHA1(f2fe7c5abca92bd13f81b4385fc4fce0cafb0da0))
@ -839,5 +1085,23 @@ ROM_START(hp9825b)
ROM_LOAD("strings_t.bin",0x9800 , 0x0800 , CRC(b5ca5da5) SHA1(af13abb3c15836c566863c656e1659f7e6f96d04))
ROM_END
ROM_START(hp9825t)
ROM_REGION(0xc000 , "rom" , ROMREGION_16BIT | ROMREGION_BE | ROMREGION_ERASE | ROMREGION_ERASE00)
ROM_LOAD("sysrom1.bin" , 0x0000 , 0x2000 , CRC(fe429268) SHA1(f2fe7c5abca92bd13f81b4385fc4fce0cafb0da0))
ROM_LOAD("sysrom2.bin" , 0x2000 , 0x2000 , CRC(96093b5d) SHA1(c6ec4cafd019887df0fa849b3c7070bb74faee54))
ROM_LOAD("sysrom3.bin" , 0x4000 , 0x2000 , CRC(f9470f67) SHA1(b80cb4a366d93bd7acc3508ce987bb11c5986b2a))
ROM_LOAD("98217.bin" , 0x6000 , 0x0800 , BAD_DUMP CRC(ea1fcf63) SHA1(e535c82897210a1c67c1ca16f44f936d4c470463))
ROM_LOAD("genio_t.bin" , 0x6800 , 0x0800 , CRC(ade1d1ed) SHA1(9af74a65b29ef1885f74164238ecf8d16ac995d6))
ROM_LOAD("plot72.bin" , 0x7000 , 0x0800 , CRC(0a9cb8db) SHA1(d0d126fca108f2715e1e408cb31b09ba69385ac4))
ROM_LOAD("advpgm_t.bin", 0x8000 , 0x0800 , CRC(965b5e5a) SHA1(ff44dd15f8fa4ca03dfd970ed8b200e8a071ec13))
ROM_LOAD("extio_t.bin" , 0x8800 , 0x1000 , CRC(a708b978) SHA1(baf53c8a2b24d059f95252baf1452188eaf6e4be))
ROM_LOAD("strings_t.bin",0x9800 , 0x0800 , CRC(b5ca5da5) SHA1(af13abb3c15836c566863c656e1659f7e6f96d04))
ROM_LOAD("syspgm.bin" , 0xa000 , 0x0800 , CRC(8915588f) SHA1(037f497b5ecc3216fb6b8356767cc361fb0b2945))
ROM_REGION(0x1000 , "skoalrom" , 0)
ROM_LOAD("skoalrom.bin" , 0 , 0x1000 , CRC(5e8124d5) SHA1(dedf7f8a10c62b444f04213956083089e97bf219))
ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP(1980, hp9825b, 0, 0, hp9825b, hp9825, hp9825_state, empty_init, "Hewlett-Packard", "HP 9825B", 0)
COMP(1980, hp9825b, 0, 0, hp9825b, hp9825, hp9825b_state,empty_init, "Hewlett-Packard", "HP 9825B", 0)
COMP(1980, hp9825t, 0, 0, hp9825t, hp9825, hp9825t_state,empty_init, "Hewlett-Packard", "HP 9825T", 0)

View File

@ -15426,6 +15426,7 @@ hp95lx //
@source:hp9825.cpp
hp9825b // HP 9825B
hp9825t // HP 9825T
@source:hp9845.cpp
hp9835a //