1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-26 11:29:09 +00:00

Made an attempt at properly pumping timers during hmove.

This commit is contained in:
Thomas Harte 2016-05-21 10:18:15 -04:00
parent a952813036
commit 36d19cb6cf
2 changed files with 70 additions and 57 deletions

View File

@ -77,60 +77,95 @@ Machine::~Machine()
close_output();
}
void Machine::update_upcoming_events()
void Machine::update_timers(int mask)
{
unsigned int upcomingEventsPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
unsigned int upcomingEventsPointerPlus5 = (_upcomingEventsPointer + 5)%number_of_upcoming_events;
unsigned int upcomingEventsPointerPlus6 = (_upcomingEventsPointer + 6)%number_of_upcoming_events;
unsigned int upcomingEventsPointerPlus7 = (_upcomingEventsPointer + 7)%number_of_upcoming_events;
unsigned int upcomingEventsPointerPlus8 = (_upcomingEventsPointer + 8)%number_of_upcoming_events;
// unsigned int upcomingEventsPointerPlus7 = (_upcomingEventsPointer + 7)%number_of_upcoming_events;
// unsigned int upcomingEventsPointerPlus8 = (_upcomingEventsPointer + 8)%number_of_upcoming_events;
// grab the background now, for display in four clocks
if(!(_horizontalTimer&3))
if(mask & (1 << 5))
{
unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
_upcomingEvents[upcomingEventsPointerPlus4].updates |= Event::Action::Playfield;
_upcomingEvents[upcomingEventsPointerPlus4].playfieldOutput = _playfield[(offset >> 2)%40];
if(!(_horizontalTimer&3))
{
unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
_upcomingEvents[upcomingEventsPointerPlus4].updates |= Event::Action::Playfield;
_upcomingEvents[upcomingEventsPointerPlus4].playfieldOutput = _playfield[(offset >> 2)%40];
}
}
// the ball becomes visible whenever it hits zero, regardless of whether its status
// is the result of a counter rollover or a programmatic reset
if(!_objectCounter[4])
if(mask & (1 << 4))
{
_upcomingEvents[upcomingEventsPointerPlus6].updates |= Event::Action::ResetPixelCounter;
_upcomingEvents[upcomingEventsPointerPlus6].pixelCounterMask |= (1 << 4);
if(!_objectCounter[4])
{
_upcomingEvents[upcomingEventsPointerPlus4].updates |= Event::Action::ResetPixelCounter;
_upcomingEvents[upcomingEventsPointerPlus4].pixelCounterMask |= (1 << 4);
}
_objectCounter[4] = (_objectCounter[4] + 1)%160;
_pixelCounter[4] ++;
}
_objectCounter[4] = (_objectCounter[4] + 1)%160;
// check for player and missle triggers
for(int c = 0; c < 4; c++)
{
// the players and missles become visible only upon overflow to zero, so schedule for
// 5/6 clocks ahead from 159
if(_objectCounter[c] == 159)
if(mask & (1 << c))
{
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus6 : upcomingEventsPointerPlus5;
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
_upcomingEvents[actionSlot].pixelCounterMask |= (1 << c);
}
else
{
// otherwise visibility is determined by an appropriate repeat mask and hitting any of 12, 28 or 60,
// in which case the counter reset (and hence the start of drawing) will occur in 4/5 cycles
uint8_t repeatMask = _playerAndMissileSize[c&1] & 7;
if(
( _objectCounter[c] == 16 && ((repeatMask == 1) || (repeatMask == 3)) ) ||
( _objectCounter[c] == 32 && ((repeatMask == 2) || (repeatMask == 3) || (repeatMask == 6)) ) ||
( _objectCounter[c] == 64 && ((repeatMask == 4) || (repeatMask == 6)) )
)
// the players and missles become visible only upon overflow to zero, so schedule for
// 5/6 clocks ahead from 159
if(_objectCounter[c] == 159)
{
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus5 : upcomingEventsPointerPlus4;
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus6 : upcomingEventsPointerPlus5;
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
_upcomingEvents[actionSlot].pixelCounterMask |= (1 << c);
}
else
{
// otherwise visibility is determined by an appropriate repeat mask and hitting any of 12, 28 or 60,
// in which case the counter reset (and hence the start of drawing) will occur in 4/5 cycles
uint8_t repeatMask = _playerAndMissileSize[c&1] & 7;
if(
( _objectCounter[c] == 16 && ((repeatMask == 1) || (repeatMask == 3)) ) ||
( _objectCounter[c] == 32 && ((repeatMask == 2) || (repeatMask == 3) || (repeatMask == 6)) ) ||
( _objectCounter[c] == 64 && ((repeatMask == 4) || (repeatMask == 6)) )
)
{
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus5 : upcomingEventsPointerPlus4;
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
_upcomingEvents[actionSlot].pixelCounterMask |= (1 << c);
}
}
}
}
for(int c = 0; c < 2; c++)
{
if(mask & (1 << c))
{
uint8_t repeatMask = _playerAndMissileSize[c] & 7;
switch(repeatMask)
{
default:
_pixelCounter[c] += 4;
break;
case 5:
_pixelCounter[c] += 2;
break;
case 7:
_pixelCounter[c] += 1;
break;
}
_objectCounter[c] = (_objectCounter[c] + 1)%160;
}
_objectCounter[c] = (_objectCounter[c] + 1)%160;
if(mask & (1 << (c + 2)))
{
_objectCounter[c+2] = (_objectCounter[c+2] + 1)%160;
_pixelCounter[c+2] ++;
}
}
}
@ -147,7 +182,6 @@ uint8_t Machine::get_output_pixel()
int ballSize = 1 << ((_playfieldControl >> 4)&3);
ballPixel = (_pixelCounter[4] < ballSize) ? 1 : 0;
}
_pixelCounter[4] ++;
// deal with the sprites
uint8_t playerPixels[2] = {0, 0}, missilePixels[2] = {0, 0};
@ -164,21 +198,6 @@ uint8_t Machine::get_output_pixel()
int missileSize = 1 << ((_playerAndMissileSize[c] >> 4)&3);
missilePixels[c] = (_pixelCounter[c+2] < missileSize) ? 1 : 0;
}
uint8_t repeatMask = _playerAndMissileSize[c] & 7;
switch(repeatMask)
{
default:
_pixelCounter[c] += 4;
break;
case 5:
_pixelCounter[c] += 2;
break;
case 7:
_pixelCounter[c] += 1;
break;
}
_pixelCounter[c+2] ++;
}
// accumulate collisions
@ -248,7 +267,7 @@ void Machine::output_pixels(unsigned int count)
// grab background colour and schedule pixel counter resets
if(state == OutputState::Pixel)
update_upcoming_events();
update_timers(~0);
// apply any queued changes and flush the record
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::Playfield)
@ -283,14 +302,7 @@ void Machine::output_pixels(unsigned int count)
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveDecrement)
{
for(int c = 0; c < 5; c++)
{
if(_hMoveFlags & (1 << c))
{
_objectCounter[c] = (_objectCounter[c] + 1)%160;
_pixelCounter[c] ++; // TODO: this isn't always a straight increment
}
}
update_timers(_hMoveFlags);
}
_upcomingEvents[_upcomingEventsPointer].updates = 0;
@ -438,7 +450,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
case 0x01: _vBlankEnabled = !!(*value & 0x02); break;
case 0x02:
set_ready_line(true);
// printf("%d\n", _horizontalTimer);
if(_horizontalTimer) set_ready_line(true);
break;
case 0x03:
_horizontalTimer = 0;

View File

@ -118,7 +118,7 @@ class Machine: public CPU6502::Processor<Machine> {
void output_pixels(unsigned int count);
uint8_t get_output_pixel();
void update_upcoming_events();
void update_timers(int mask);
Outputs::CRT::CRT *_crt;
// latched output state