spectrum48: fix floating int (#9637)

This commit is contained in:
holub 2022-04-27 16:34:40 -04:00 committed by GitHub
parent 72de111bf2
commit ab65448fdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 45 deletions

View File

@ -33,12 +33,7 @@
* Now: * Now:
* + fetch opcode * + fetch opcode
* + call EXEC() * + call EXEC()
* + read cc_* value to m_icount_executing + execute instruction adjusting icount per each Read (arg(), recursive rop()) and Write
* + execute instruction adjusting icount per each Read (arg(), recursive rop())
* + before M*Write use rest of m_icount_executing except count required for write
* + adjust write icount
* Next:
* If gracefully adjust icount for each operation after read and before write we can receive precise M timings without cc_* tables.
* Changes in 3.9: * Changes in 3.9:
* - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow] * - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow]
* - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap] * - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap]
@ -337,7 +332,7 @@ static const uint8_t cc_ex[0x100] = {
/*************************************************************** /***************************************************************
* adjust cycle count by n T-states * adjust cycle count by n T-states
***************************************************************/ ***************************************************************/
#define CC(prefix,opcode) do { m_icount_executing += m_cc_##prefix[opcode]; } while (0) #define CC(prefix,opcode) do { m_icount_executing += m_cc_##prefix == nullptr ? 0 : m_cc_##prefix[opcode]; } while (0)
#define T(icount) do { \ #define T(icount) do { \
m_icount -= icount; \ m_icount -= icount; \
@ -345,7 +340,7 @@ static const uint8_t cc_ex[0x100] = {
} while (0) } while (0)
// T Memory Address // T Memory Address
#define MTM (m_cc_op[0]-1) #define MTM ((m_cc_op == nullptr ? 4 : m_cc_op[0])-1)
#define EXEC(prefix,opcode) do { \ #define EXEC(prefix,opcode) do { \
unsigned op = opcode; \ unsigned op = opcode; \
@ -417,7 +412,7 @@ static const uint8_t cc_ex[0x100] = {
case 0xf8:prefix##_##f8();break; case 0xf9:prefix##_##f9();break; case 0xfa:prefix##_##fa();break; case 0xfb:prefix##_##fb();break; \ case 0xf8:prefix##_##f8();break; case 0xf9:prefix##_##f9();break; case 0xfa:prefix##_##fa();break; case 0xfb:prefix##_##fb();break; \
case 0xfc:prefix##_##fc();break; case 0xfd:prefix##_##fd();break; case 0xfe:prefix##_##fe();break; case 0xff:prefix##_##ff();break; \ case 0xfc:prefix##_##fc();break; case 0xfd:prefix##_##fd();break; case 0xfe:prefix##_##fe();break; case 0xff:prefix##_##ff();break; \
} \ } \
if(m_icount_executing) { T(m_icount_executing); } \ if(m_icount_executing > 0) T(m_icount_executing); else m_icount_executing = 0; \
} while (0) } while (0)
/*************************************************************** /***************************************************************
@ -512,14 +507,16 @@ inline void z80_device::wm16(uint16_t addr, PAIR &r)
} }
/*************************************************************** /***************************************************************
* Write a word to given memory location (backword) * Write a word to (SP)
***************************************************************/ ***************************************************************/
inline void z80_device::wm16back(uint16_t addr, PAIR &r) inline void z80_device::wm16_sp(PAIR &r)
{ {
SP--;
m_icount_executing -= MTM; m_icount_executing -= MTM;
wm(addr+1, r.b.h); wm(SPD, r.b.h);
m_icount_executing += MTM; m_icount_executing += MTM;
wm(addr, r.b.l); SP--;
wm(SPD, r.b.l);
} }
/*************************************************************** /***************************************************************
@ -592,8 +589,7 @@ inline void z80_device::pop(PAIR &r)
inline void z80_device::push(PAIR &r) inline void z80_device::push(PAIR &r)
{ {
nomreq_ir(1); nomreq_ir(1);
SP -= 2; wm16_sp(r);
wm16back(SPD, r);
} }
/*************************************************************** /***************************************************************
@ -656,7 +652,7 @@ inline void z80_device::call()
m_ea = arg16(); m_ea = arg16();
nomreq_addr(PCD-1, 1); nomreq_addr(PCD-1, 1);
WZ = m_ea; WZ = m_ea;
push(m_pc); wm16_sp(m_pc);
PCD = m_ea; PCD = m_ea;
} }
@ -671,7 +667,7 @@ inline void z80_device::call_cond(bool cond, uint8_t opcode)
m_ea = arg16(); m_ea = arg16();
nomreq_addr(PCD-1, 1); nomreq_addr(PCD-1, 1);
WZ = m_ea; WZ = m_ea;
push(m_pc); wm16_sp(m_pc);
PCD = m_ea; PCD = m_ea;
} }
else else
@ -1002,10 +998,10 @@ inline void z80_device::exx()
inline void z80_device::ex_sp(PAIR &r) inline void z80_device::ex_sp(PAIR &r)
{ {
PAIR tmp = { { 0, 0, 0, 0 } }; PAIR tmp = { { 0, 0, 0, 0 } };
rm16(SPD, tmp); pop(tmp);
nomreq_addr(SPD + 1, 1); nomreq_addr(SPD - 1, 1);
m_icount_executing -= 2; m_icount_executing -= 2;
wm16back(SPD, r); wm16_sp(r);
m_icount_executing += 2; m_icount_executing += 2;
nomreq_addr(SPD, 2); nomreq_addr(SPD, 2);
r = tmp; r = tmp;
@ -3239,7 +3235,8 @@ void z80_device::take_nmi()
m_r++; m_r++;
m_icount_executing = 11; m_icount_executing = 11;
push(m_pc); T(m_icount_executing - MTM * 2);
wm16_sp(m_pc);
PCD = 0x0066; PCD = 0x0066;
WZ=PCD; WZ=PCD;
m_nmi_pending = false; m_nmi_pending = false;
@ -3264,7 +3261,9 @@ void z80_device::take_interrupt()
LOG(("Z80 single int. irq_vector $%02x\n", irq_vector)); LOG(("Z80 single int. irq_vector $%02x\n", irq_vector));
/* 'interrupt latency' cycles */ /* 'interrupt latency' cycles */
m_icount_executing = cc_ex[0xff]; m_icount_executing = 0;
CC(ex, 0xff); // 2
T(m_icount_executing);
/* Interrupt mode 2. Call [i:databyte] */ /* Interrupt mode 2. Call [i:databyte] */
if( m_im == 2 ) if( m_im == 2 )
@ -3273,11 +3272,13 @@ void z80_device::take_interrupt()
// However, experiments have confirmed that IM 2 vectors do not have to be // However, experiments have confirmed that IM 2 vectors do not have to be
// even, and all 8 bits will be used; even $FF is handled normally. // even, and all 8 bits will be used; even $FF is handled normally.
/* CALL opcode timing */ /* CALL opcode timing */
m_icount_executing += m_cc_op[0xcd]; CC(op, 0xcd); // 17+2=19
T(m_icount_executing - MTM * 4);
m_icount_executing -= MTM * 2; // save for rm16
wm16_sp(m_pc);
m_icount_executing += MTM * 2;
irq_vector = (irq_vector & 0xff) | (m_i << 8); irq_vector = (irq_vector & 0xff) | (m_i << 8);
PAIR tmp = m_pc;
rm16(irq_vector, m_pc); rm16(irq_vector, m_pc);
push(tmp);
LOG(("Z80 IM2 [$%04x] = $%04x\n", irq_vector, PCD)); LOG(("Z80 IM2 [$%04x] = $%04x\n", irq_vector, PCD));
} }
else else
@ -3286,8 +3287,9 @@ void z80_device::take_interrupt()
{ {
LOG(("Z80 '%s' IM1 $0038\n", tag())); LOG(("Z80 '%s' IM1 $0038\n", tag()));
/* RST $38 */ /* RST $38 */
m_icount_executing += m_cc_op[0xff]; CC(op, 0xff); // 11+2=13
push(m_pc); T(m_icount_executing - MTM * 2);
wm16_sp(m_pc);
PCD = 0x0038; PCD = 0x0038;
} }
else else
@ -3304,19 +3306,22 @@ void z80_device::take_interrupt()
{ {
case 0xcd0000: /* call */ case 0xcd0000: /* call */
/* CALL $xxxx cycles */ /* CALL $xxxx cycles */
m_icount_executing += m_cc_op[0xcd]; CC(op, 0xcd);
push(m_pc); T(m_icount_executing - MTM * 2);
wm16_sp(m_pc);
PCD = irq_vector & 0xffff; PCD = irq_vector & 0xffff;
break; break;
case 0xc30000: /* jump */ case 0xc30000: /* jump */
/* JP $xxxx cycles */ /* JP $xxxx cycles */
m_icount_executing += m_cc_op[0xc3]; CC(op, 0xc3);
T(m_icount_executing);
PCD = irq_vector & 0xffff; PCD = irq_vector & 0xffff;
break; break;
default: /* rst (or other opcodes?) */ default: /* rst (or other opcodes?) */
/* RST $xx cycles */ /* RST $xx cycles */
m_icount_executing += m_cc_op[0xff]; CC(op, 0xff);
push(m_pc); T(m_icount_executing - MTM * 2);
wm16_sp(m_pc);
PCD = irq_vector & 0x0038; PCD = irq_vector & 0x0038;
break; break;
} }
@ -3352,24 +3357,28 @@ void nsc800_device::take_interrupt_nsc800()
/* Clear both interrupt flip flops */ /* Clear both interrupt flip flops */
m_iff1 = m_iff2 = 0; m_iff1 = m_iff2 = 0;
/* 'interrupt latency' cycles */
m_icount_executing = 0;
CC(op, 0xff);
CC(ex, 0xff); //2
T(m_icount_executing - MTM * 2);
if (m_nsc800_irq_state[NSC800_RSTA]) if (m_nsc800_irq_state[NSC800_RSTA])
{ {
push(m_pc); wm16_sp(m_pc);
PCD = 0x003c; PCD = 0x003c;
} }
else if (m_nsc800_irq_state[NSC800_RSTB]) else if (m_nsc800_irq_state[NSC800_RSTB])
{ {
push(m_pc); wm16_sp(m_pc);
PCD = 0x0034; PCD = 0x0034;
} }
else if (m_nsc800_irq_state[NSC800_RSTC]) else if (m_nsc800_irq_state[NSC800_RSTC])
{ {
push(m_pc); wm16_sp(m_pc);
PCD = 0x002c; PCD = 0x002c;
} }
T(m_icount_executing);
/* 'interrupt latency' cycles */
m_icount -= m_cc_op[0xff] + cc_ex[0xff];
WZ=PCD; WZ=PCD;
@ -3624,7 +3633,7 @@ void z80_device::execute_run()
// check for interrupts before each instruction // check for interrupts before each instruction
check_interrupts(); check_interrupts();
T(m_icount_executing); m_icount_executing = 0;
m_after_ei = false; m_after_ei = false;
m_after_ldair = false; m_after_ldair = false;
@ -3668,6 +3677,7 @@ void z80_device::execute_set_input(int inputnum, int state)
break; break;
case INPUT_LINE_IRQ0: case INPUT_LINE_IRQ0:
if(state && !m_irq_state) m_irq_at = total_cycles() + m_icount;
/* update the IRQ state via the daisy chain */ /* update the IRQ state via the daisy chain */
m_irq_state = state; m_irq_state = state;
if (daisy_chain_present()) if (daisy_chain_present())

View File

@ -32,6 +32,7 @@ class z80_device : public cpu_device, public z80_daisy_chain_interface
public: public:
z80_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); z80_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
int cycles_from_irq() { return total_cycles() - m_irq_at; }
void z80_set_cycle_tables(const uint8_t *op, const uint8_t *cb, const uint8_t *ed, const uint8_t *xy, const uint8_t *xycb, const uint8_t *ex); void z80_set_cycle_tables(const uint8_t *op, const uint8_t *cb, const uint8_t *ed, const uint8_t *xy, const uint8_t *xycb, const uint8_t *ex);
template <typename... T> void set_memory_map(T &&... args) { set_addrmap(AS_PROGRAM, std::forward<T>(args)...); } template <typename... T> void set_memory_map(T &&... args) { set_addrmap(AS_PROGRAM, std::forward<T>(args)...); }
template <typename... T> void set_m1_map(T &&... args) { set_addrmap(AS_OPCODES, std::forward<T>(args)...); } template <typename... T> void set_m1_map(T &&... args) { set_addrmap(AS_OPCODES, std::forward<T>(args)...); }
@ -154,7 +155,7 @@ protected:
void rm16(uint16_t addr, PAIR &r); void rm16(uint16_t addr, PAIR &r);
virtual void wm(uint16_t addr, uint8_t value); virtual void wm(uint16_t addr, uint8_t value);
void wm16(uint16_t addr, PAIR &r); void wm16(uint16_t addr, PAIR &r);
void wm16back(uint16_t addr, PAIR &r); void wm16_sp(PAIR &r);
virtual uint8_t rop(); virtual uint8_t rop();
virtual uint8_t arg(); virtual uint8_t arg();
virtual uint16_t arg16(); virtual uint16_t arg16();
@ -282,6 +283,7 @@ protected:
uint8_t m_after_ldair; /* same, but for LD A,I or LD A,R */ uint8_t m_after_ldair; /* same, but for LD A,I or LD A,R */
uint32_t m_ea; uint32_t m_ea;
int m_irq_at;
int m_icount; int m_icount;
int m_icount_executing; int m_icount_executing;
uint8_t m_rtemp; uint8_t m_rtemp;

View File

@ -174,12 +174,13 @@ void spectrum_128_state::video_start()
uint8_t spectrum_128_state::spectrum_128_pre_opcode_fetch_r(offs_t offset) uint8_t spectrum_128_state::spectrum_128_pre_opcode_fetch_r(offs_t offset)
{ {
if (is_contended(offset)) content_early();
/* this allows expansion devices to act upon opcode fetches from MEM addresses /* this allows expansion devices to act upon opcode fetches from MEM addresses
for example, interface1 detection fetches requires fetches at 0008 / 0708 to for example, interface1 detection fetches requires fetches at 0008 / 0708 to
enable paged ROM and then fetches at 0700 to disable it enable paged ROM and then fetches at 0700 to disable it
*/ */
m_exp->pre_opcode_fetch(offset); m_exp->pre_opcode_fetch(offset);
if (is_contended(offset)) content_early();
uint8_t retval = m_maincpu->space(AS_PROGRAM).read_byte(offset); uint8_t retval = m_maincpu->space(AS_PROGRAM).read_byte(offset);
m_exp->post_opcode_fetch(offset); m_exp->post_opcode_fetch(offset);
return retval; return retval;

View File

@ -769,7 +769,6 @@ void spectrum_state::device_timer(emu_timer &timer, device_timer_id id, int para
case TIMER_IRQ_ON: case TIMER_IRQ_ON:
m_maincpu->set_input_line(0, HOLD_LINE); m_maincpu->set_input_line(0, HOLD_LINE);
timer_set(m_maincpu->clocks_to_attotime(32), TIMER_IRQ_OFF, 0); timer_set(m_maincpu->clocks_to_attotime(32), TIMER_IRQ_OFF, 0);
m_irq_start_cycle = m_maincpu->total_cycles();
break; break;
case TIMER_IRQ_OFF: case TIMER_IRQ_OFF:
m_maincpu->set_input_line(0, CLEAR_LINE); m_maincpu->set_input_line(0, CLEAR_LINE);

View File

@ -180,7 +180,6 @@ protected:
optional_ioport m_io_joy1; optional_ioport m_io_joy1;
optional_ioport m_io_joy2; optional_ioport m_io_joy2;
u64 m_irq_start_cycle;
virtual u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0); virtual u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0);
// Defines position of main screen excluding border // Defines position of main screen excluding border
virtual rectangle get_screen_area(); virtual rectangle get_screen_area();

View File

@ -183,7 +183,7 @@ void spectrum_state::content_early(s8 shift)
if (m_contention_pattern.empty() || vpos < get_screen_area().top() || vpos > get_screen_area().bottom()) if (m_contention_pattern.empty() || vpos < get_screen_area().top() || vpos > get_screen_area().bottom())
return; return;
u64 now = m_maincpu->total_cycles() - m_irq_start_cycle + shift; u64 now = m_maincpu->cycles_from_irq() + shift;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1; u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1;
u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock(); u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock();
@ -201,7 +201,7 @@ void spectrum_state::content_late()
if (m_contention_pattern.empty() || vpos < get_screen_area().top() || vpos > get_screen_area().bottom()) if (m_contention_pattern.empty() || vpos < get_screen_area().top() || vpos > get_screen_area().bottom())
return; return;
u64 now = m_maincpu->total_cycles() - m_irq_start_cycle + 1; u64 now = m_maincpu->cycles_from_irq() + 1;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1; u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1;
u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock(); u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock();
for(auto i = 0x04; i; i >>= 1) for(auto i = 0x04; i; i >>= 1)