hphybrid: implemented all EMC instructions, seem ok

This commit is contained in:
fulivi 2015-12-05 18:45:38 +01:00
parent 1160765942
commit 03b2a58b94
3 changed files with 259 additions and 7 deletions

View File

@ -936,7 +936,16 @@ void hp_hybrid_cpu_device::do_pw(UINT16 opcode)
tmp_addr |= 0x10000;
}
if (tmp_addr <= (HP_REG_LAST_ADDR * 2 + 1)) {
// Cannot write bytes to registers
// Single bytes can be written to registers.
// The addressed register gets the written byte in the proper position
// and a 0 in the other byte because access to registers is always done in
// 16 bits units.
if (BIT(tmp_addr , 0)) {
tmp &= 0xff;
} else {
tmp <<= 8;
}
WM(tmp_addr >> 1 , tmp);
} else {
// Extend address, preserve LSB & form byte address
tmp_addr = (add_mae(AEC_CASE_C , tmp_addr >> 1) << 1) | (tmp_addr & 1);
@ -1095,12 +1104,147 @@ void hp_5061_3001_cpu_device::device_reset()
hp_hybrid_cpu_device::device_reset();
}
UINT8 hp_5061_3001_cpu_device::do_dec_shift_r(UINT8 d1 , UINT64& mantissa)
{
UINT8 d12 = (UINT8)(mantissa & 0xf);
mantissa = (mantissa >> 4) | ((UINT64)d1 << 44);
return d12;
}
UINT8 hp_5061_3001_cpu_device::do_dec_shift_l(UINT8 d12 , UINT64& mantissa)
{
UINT8 d1 = (UINT8)((mantissa >> 44) & 0xf);
mantissa = (mantissa << 4) | ((UINT64)d12);
mantissa &= 0xffffffffffffULL;
return d1;
}
UINT64 hp_5061_3001_cpu_device::get_ar1(void)
{
UINT32 addr;
UINT64 tmp;
addr = add_mae(AEC_CASE_B , HP_REG_AR1_ADDR + 1);
tmp = (UINT64)RM(addr++);
tmp <<= 16;
tmp |= (UINT64)RM(addr++);
tmp <<= 16;
tmp |= (UINT64)RM(addr);
return tmp;
}
void hp_5061_3001_cpu_device::set_ar1(UINT64 v)
{
UINT32 addr;
addr = add_mae(AEC_CASE_B , HP_REG_AR1_ADDR + 3);
WM(addr-- , (UINT16)(v & 0xffff));
v >>= 16;
WM(addr-- , (UINT16)(v & 0xffff));
v >>= 16;
WM(addr , (UINT16)(v & 0xffff));
}
UINT64 hp_5061_3001_cpu_device::get_ar2(void) const
{
UINT64 tmp;
tmp = (UINT64)m_reg_ar2[ 1 ];
tmp <<= 16;
tmp |= (UINT64)m_reg_ar2[ 2 ];
tmp <<= 16;
tmp |= (UINT64)m_reg_ar2[ 3 ];
return tmp;
}
void hp_5061_3001_cpu_device::set_ar2(UINT64 v)
{
m_reg_ar2[ 3 ] = (UINT16)(v & 0xffff);
v >>= 16;
m_reg_ar2[ 2 ] = (UINT16)(v & 0xffff);
v >>= 16;
m_reg_ar2[ 1 ] = (UINT16)(v & 0xffff);
}
UINT64 hp_5061_3001_cpu_device::do_mrxy(UINT64 ar)
{
UINT8 n;
n = m_reg_B & 0xf;
m_reg_A &= 0xf;
m_reg_se = m_reg_A;
while (n--) {
m_reg_se = do_dec_shift_r(m_reg_A , ar);
m_reg_A = 0;
m_icount -= 4;
}
m_reg_A = m_reg_se;
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
return ar;
}
bool hp_5061_3001_cpu_device::do_dec_add(bool carry_in , UINT64& a , UINT64 b)
{
UINT64 tmp = 0;
unsigned i;
UINT8 digit_a , digit_b;
for (i = 0; i < 12; i++) {
digit_a = (UINT8)(a & 0xf);
digit_b = (UINT8)(b & 0xf);
if (carry_in) {
digit_a++;
}
digit_a += digit_b;
carry_in = digit_a >= 10;
if (carry_in) {
digit_a = (digit_a - 10) & 0xf;
}
tmp |= (UINT64)digit_a << (4 * i);
a >>= 4;
b >>= 4;
}
a = tmp;
return carry_in;
}
void hp_5061_3001_cpu_device::do_mpy(void)
{
INT32 a = (INT16)m_reg_A;
INT32 b = (INT16)m_reg_B;
INT32 p = a * b;
m_reg_A = (UINT16)(p & 0xffff);
m_reg_B = (UINT16)((p >> 16) & 0xffff);
// Not entirely correct
m_icount -= 65;
}
UINT16 hp_5061_3001_cpu_device::execute_no_bpc_ioc(UINT16 opcode)
{
// EMC instructions
UINT8 n;
UINT16 tmp1;
UINT16 tmp2;
UINT64 tmp_ar;
UINT64 tmp_ar2;
bool carry;
switch (opcode & 0xfff0) {
case 0x7300:
@ -1133,61 +1277,155 @@ UINT16 hp_5061_3001_cpu_device::execute_no_bpc_ioc(UINT16 opcode)
switch (opcode) {
case 0x7200:
// MWA
m_icount -= 28;
tmp_ar2 = get_ar2();
carry = do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , m_reg_B);
set_ar2(tmp_ar2);
if (carry) {
BIT_SET(m_flags, HPHYBRID_DC_BIT);
} else {
BIT_CLR(m_flags, HPHYBRID_DC_BIT);
}
break;
case 0x7220:
// CMY
m_icount -= 23;
tmp_ar2 = get_ar2();
tmp_ar2 = 0x999999999999ULL - tmp_ar2;
do_dec_add(true , tmp_ar2 , 0);
set_ar2(tmp_ar2);
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
break;
case 0x7260:
// CMX
m_icount -= 59;
tmp_ar = get_ar1();
tmp_ar = 0x999999999999ULL - tmp_ar;
do_dec_add(true , tmp_ar , 0);
set_ar1(tmp_ar);
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
break;
case 0x7280:
// FXA
m_icount -= 40;
tmp_ar2 = get_ar2();
carry = do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , get_ar1());
set_ar2(tmp_ar2);
if (carry) {
BIT_SET(m_flags, HPHYBRID_DC_BIT);
} else {
BIT_CLR(m_flags, HPHYBRID_DC_BIT);
}
break;
case 0x7340:
// NRM
tmp_ar2 = get_ar2();
m_icount -= 23;
for (n = 0; n < 12 && (tmp_ar2 & 0xf00000000000ULL) == 0; n++) {
do_dec_shift_l(0 , tmp_ar2);
m_icount--;
}
m_reg_B = n;
if (n < 12) {
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
set_ar2(tmp_ar2);
} else {
BIT_SET(m_flags , HPHYBRID_DC_BIT);
// When ar2 is 0, total time is 69 cycles
// (salcazzo che cosa fa per altri 34 cicli)
m_icount -= 34;
}
break;
case 0x73c0:
// CDC
m_icount -= 11;
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
break;
case 0x7a00:
// FMP
m_icount -= 42;
m_reg_A = 0;
tmp_ar = get_ar1();
tmp_ar2 = get_ar2();
for (n = m_reg_B & 0xf; n > 0; n--) {
m_icount -= 13;
if (do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , tmp_ar)) {
m_reg_A++;
}
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
}
set_ar2(tmp_ar2);
break;
case 0x7a21:
// FDV
// No doc mentions any limit on the iterations done by this instruction.
// Here we stop at 15 (after all there are only 4 bits in the loop counter). But is it correct?
m_icount -= 37;
m_reg_B = 0;
tmp_ar = get_ar1();
tmp_ar2 = get_ar2();
while (m_reg_B < 15 && !do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , tmp_ar)) {
m_icount -= 13;
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
m_reg_B++;
}
set_ar2(tmp_ar2);
break;
case 0x7b00:
// MRX
set_ar1(do_mrxy(get_ar1()));
m_icount -= 62;
break;
case 0x7b21:
// DRS
tmp_ar = get_ar1();
m_icount -= 56;
m_reg_A = m_reg_se = do_dec_shift_r(0 , tmp_ar);
set_ar1(tmp_ar);
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
break;
case 0x7b40:
// MRY
set_ar2(do_mrxy(get_ar2()));
m_icount -= 33;
break;
case 0x7b61:
// MLY
tmp_ar2 = get_ar2();
m_icount -= 32;
m_reg_A = m_reg_se = do_dec_shift_l(m_reg_A & 0xf , tmp_ar2);
set_ar2(tmp_ar2);
BIT_CLR(m_flags , HPHYBRID_DC_BIT);
break;
case 0x7b8f:
// MPY
do_mpy();
break;
default:
// Unrecognized instructions: NOP
// Execution time is fictional
logerror("hp-5061-3001: unknown opcode %04x\n" , opcode);
m_icount -= 6;
if ((opcode & 0xfec0) == 0x74c0) {
// SDS
// SDC
m_icount -= 14;
return get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_DC_BIT));
} else {
// Unrecognized instructions: NOP
// Execution time is fictional
logerror("hp-5061-3001: unknown opcode %04x\n" , opcode);
m_icount -= 6;
}
break;
}
}

View File

@ -137,6 +137,8 @@ protected:
UINT16 fetch(void);
UINT16 get_skip_addr(UINT16 opcode , bool condition) const;
int m_icount;
// State of processor
@ -166,7 +168,6 @@ private:
UINT32 get_ea(UINT16 opcode);
void do_add(UINT16& addend1 , UINT16 addend2);
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);
@ -184,7 +185,18 @@ public:
protected:
virtual void device_start();
virtual void device_reset();
virtual UINT32 execute_max_cycles() const { return 213; } // XFR 16
virtual UINT32 execute_max_cycles() const { return 237; } // FMP 15
static UINT8 do_dec_shift_r(UINT8 d1 , UINT64& mantissa);
static UINT8 do_dec_shift_l(UINT8 d12 , UINT64& mantissa);
UINT64 get_ar1(void);
void set_ar1(UINT64 v);
UINT64 get_ar2(void) const;
void set_ar2(UINT64 v);
UINT64 do_mrxy(UINT64 ar);
bool do_dec_add(bool carry_in , UINT64& a , UINT64 b);
void do_mpy(void);
virtual UINT16 execute_no_bpc_ioc(UINT16 opcode);
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
virtual UINT32 add_mae(aec_cases_t aec_case , UINT16 addr);

View File

@ -346,6 +346,8 @@ static const dis_entry_t dis_table_emc[] = {
{0xffff , 0x7340 , "NRM" , param_none , 0 },
{0xfff0 , 0x7380 , "CLR" , param_n16 , 0 },
{0xffff , 0x73c0 , "CDC" , param_none , 0 },
{0xffc0 , 0x74c0 , "SDS" , param_skip , 0 },
{0xffc0 , 0x75c0 , "SDC" , param_skip , 0 },
{0xffff , 0x7a00 , "FMP" , param_none , 0 },
{0xffff , 0x7a21 , "FDV" , param_none , 0 },
{0xffff , 0x7b00 , "MRX" , param_none , 0 },