mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-08 03:54:27 +00:00
Merge pull request #63 from TomHarte/OricVideoOptimisation
Reduces 6522 emulation costs
This commit is contained in:
commit
b64ae904a5
@ -230,61 +230,97 @@ template <class T> class MOS6522 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define phase2() \
|
||||||
|
_registers.last_timer[0] = _registers.timer[0];\
|
||||||
|
_registers.last_timer[1] = _registers.timer[1];\
|
||||||
|
\
|
||||||
|
if(_registers.timer_needs_reload)\
|
||||||
|
{\
|
||||||
|
_registers.timer_needs_reload = false;\
|
||||||
|
_registers.timer[0] = _registers.timer_latch[0];\
|
||||||
|
}\
|
||||||
|
else\
|
||||||
|
_registers.timer[0] --;\
|
||||||
|
\
|
||||||
|
_registers.timer[1] --;
|
||||||
|
|
||||||
|
// IRQ is raised on the half cycle after overflow
|
||||||
|
#define phase1() \
|
||||||
|
if((_registers.timer[1] == 0xffff) && !_registers.last_timer[1] && _timer_is_running[1])\
|
||||||
|
{\
|
||||||
|
_timer_is_running[1] = false;\
|
||||||
|
_registers.interrupt_flags |= InterruptFlag::Timer2;\
|
||||||
|
reevaluate_interrupts();\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
if((_registers.timer[0] == 0xffff) && !_registers.last_timer[0] && _timer_is_running[0])\
|
||||||
|
{\
|
||||||
|
_registers.interrupt_flags |= InterruptFlag::Timer1;\
|
||||||
|
reevaluate_interrupts();\
|
||||||
|
\
|
||||||
|
if(_registers.auxiliary_control&0x40)\
|
||||||
|
_registers.timer_needs_reload = true;\
|
||||||
|
else\
|
||||||
|
_timer_is_running[0] = false;\
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Runs for a specified number of half cycles.
|
Runs for a specified number of half cycles.
|
||||||
|
|
||||||
Although the original chip accepts only a phase-2 input, timer reloads are specified as occuring
|
Although the original chip accepts only a phase-2 input, timer reloads are specified as occuring
|
||||||
1.5 cycles after the timer hits zero. It is therefore necessary to emulate at half-cycle precision.
|
1.5 cycles after the timer hits zero. It therefore may be necessary to emulate at half-cycle precision.
|
||||||
|
|
||||||
The first emulated half-cycle will be the period between the trailing edge of a phase-2 input and the
|
The first emulated half-cycle will be the period between the trailing edge of a phase-2 input and the
|
||||||
next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be
|
next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be
|
||||||
that which occurs during phase-2.
|
that which occurs during phase-2.
|
||||||
|
|
||||||
|
Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not
|
||||||
|
intermingle usage.
|
||||||
*/
|
*/
|
||||||
inline void run_for_half_cycles(unsigned int number_of_cycles)
|
inline void run_for_half_cycles(unsigned int number_of_cycles)
|
||||||
{
|
{
|
||||||
while(number_of_cycles--)
|
if(_is_phase2)
|
||||||
{
|
{
|
||||||
if(_is_phase2)
|
phase2();
|
||||||
{
|
number_of_cycles--;
|
||||||
_registers.last_timer[0] = _registers.timer[0];
|
}
|
||||||
_registers.last_timer[1] = _registers.timer[1];
|
|
||||||
|
|
||||||
if(_registers.timer_needs_reload)
|
while(number_of_cycles > 2)
|
||||||
{
|
{
|
||||||
_registers.timer_needs_reload = false;
|
phase1();
|
||||||
_registers.timer[0] = _registers.timer_latch[0];
|
phase2();
|
||||||
}
|
number_of_cycles -= 2;
|
||||||
else
|
}
|
||||||
_registers.timer[0] --;
|
|
||||||
|
|
||||||
_registers.timer[1] --;
|
if(number_of_cycles)
|
||||||
}
|
{
|
||||||
else
|
phase1();
|
||||||
{
|
_is_phase2 = true;
|
||||||
// IRQ is raised on the half cycle after overflow
|
}
|
||||||
if((_registers.timer[1] == 0xffff) && !_registers.last_timer[1] && _timer_is_running[1])
|
else
|
||||||
{
|
{
|
||||||
_timer_is_running[1] = false;
|
_is_phase2 = false;
|
||||||
_registers.interrupt_flags |= InterruptFlag::Timer2;
|
|
||||||
reevaluate_interrupts();
|
|
||||||
}
|
|
||||||
|
|
||||||
if((_registers.timer[0] == 0xffff) && !_registers.last_timer[0] && _timer_is_running[0])
|
|
||||||
{
|
|
||||||
_registers.interrupt_flags |= InterruptFlag::Timer1;
|
|
||||||
reevaluate_interrupts();
|
|
||||||
|
|
||||||
if(_registers.auxiliary_control&0x40)
|
|
||||||
_registers.timer_needs_reload = true;
|
|
||||||
else
|
|
||||||
_timer_is_running[0] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_is_phase2 ^= true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Runs for a specified number of cycles.
|
||||||
|
|
||||||
|
Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not
|
||||||
|
intermingle usage.
|
||||||
|
*/
|
||||||
|
inline void run_for_cycles(unsigned int number_of_cycles)
|
||||||
|
{
|
||||||
|
while(number_of_cycles--)
|
||||||
|
{
|
||||||
|
phase1();
|
||||||
|
phase2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef phase1
|
||||||
|
#undef phase2
|
||||||
|
|
||||||
/*! @returns @c true if the IRQ line is currently active; @c false otherwise. */
|
/*! @returns @c true if the IRQ line is currently active; @c false otherwise. */
|
||||||
inline bool get_interrupt_line()
|
inline bool get_interrupt_line()
|
||||||
{
|
{
|
||||||
|
@ -91,8 +91,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
_driveVIA.set_register(address, *value);
|
_driveVIA.set_register(address, *value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_serialPortVIA->run_for_half_cycles(2);
|
_serialPortVIA->run_for_cycles(1);
|
||||||
_driveVIA.run_for_half_cycles(2);
|
_driveVIA.run_for_cycles(1);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
{
|
{
|
||||||
while(!_userPortVIA->get_interrupt_line() && !_keyboardVIA->get_interrupt_line() && !_tape.get_tape()->is_at_end())
|
while(!_userPortVIA->get_interrupt_line() && !_keyboardVIA->get_interrupt_line() && !_tape.get_tape()->is_at_end())
|
||||||
{
|
{
|
||||||
_userPortVIA->run_for_half_cycles(2);
|
_userPortVIA->run_for_cycles(1);
|
||||||
_keyboardVIA->run_for_half_cycles(2);
|
_keyboardVIA->run_for_cycles(1);
|
||||||
_tape.run_for_cycles(1);
|
_tape.run_for_cycles(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,8 +157,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_userPortVIA->run_for_half_cycles(2);
|
_userPortVIA->run_for_cycles(1);
|
||||||
_keyboardVIA->run_for_half_cycles(2);
|
_keyboardVIA->run_for_cycles(1);
|
||||||
if(_typer && operation == CPU6502::BusOperation::ReadOpcode && address == 0xEB1E)
|
if(_typer && operation == CPU6502::BusOperation::ReadOpcode && address == 0xEB1E)
|
||||||
{
|
{
|
||||||
if(!_typer->type_next_character())
|
if(!_typer->type_next_character())
|
||||||
|
@ -61,7 +61,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_via.run_for_half_cycles(2);
|
_via.run_for_cycles(1);
|
||||||
_via.tape->run_for_cycles(1);
|
_via.tape->run_for_cycles(1);
|
||||||
_cycles_since_video_update++;
|
_cycles_since_video_update++;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -51,7 +51,7 @@ std::shared_ptr<Outputs::CRT::CRT> VideoOutput::get_crt()
|
|||||||
|
|
||||||
void VideoOutput::run_for_cycles(int number_of_cycles)
|
void VideoOutput::run_for_cycles(int number_of_cycles)
|
||||||
{
|
{
|
||||||
// Vertical: 0–39: pixels; otherwise blank; 48–53 sync
|
// Vertical: 0–39: pixels; otherwise blank; 48–53 sync, 54–56 colour burst
|
||||||
// Horizontal: 0–223: pixels; otherwise blank; 256–259 sync
|
// Horizontal: 0–223: pixels; otherwise blank; 256–259 sync
|
||||||
|
|
||||||
while(number_of_cycles--)
|
while(number_of_cycles--)
|
||||||
@ -78,6 +78,7 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
State new_state = Blank;
|
State new_state = Blank;
|
||||||
if(
|
if(
|
||||||
(h_counter >= 48 && h_counter <= 53) ||
|
(h_counter >= 48 && h_counter <= 53) ||
|
||||||
|
Loading…
Reference in New Issue
Block a user