mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-08 14:25:05 +00:00
Made an attempt at properly pumping timers during hmove.
This commit is contained in:
@@ -77,60 +77,95 @@ Machine::~Machine()
|
|||||||
close_output();
|
close_output();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::update_upcoming_events()
|
void Machine::update_timers(int mask)
|
||||||
{
|
{
|
||||||
unsigned int upcomingEventsPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
|
unsigned int upcomingEventsPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
|
||||||
unsigned int upcomingEventsPointerPlus5 = (_upcomingEventsPointer + 5)%number_of_upcoming_events;
|
unsigned int upcomingEventsPointerPlus5 = (_upcomingEventsPointer + 5)%number_of_upcoming_events;
|
||||||
unsigned int upcomingEventsPointerPlus6 = (_upcomingEventsPointer + 6)%number_of_upcoming_events;
|
unsigned int upcomingEventsPointerPlus6 = (_upcomingEventsPointer + 6)%number_of_upcoming_events;
|
||||||
unsigned int upcomingEventsPointerPlus7 = (_upcomingEventsPointer + 7)%number_of_upcoming_events;
|
// unsigned int upcomingEventsPointerPlus7 = (_upcomingEventsPointer + 7)%number_of_upcoming_events;
|
||||||
unsigned int upcomingEventsPointerPlus8 = (_upcomingEventsPointer + 8)%number_of_upcoming_events;
|
// unsigned int upcomingEventsPointerPlus8 = (_upcomingEventsPointer + 8)%number_of_upcoming_events;
|
||||||
|
|
||||||
// grab the background now, for display in four clocks
|
// grab the background now, for display in four clocks
|
||||||
if(!(_horizontalTimer&3))
|
if(mask & (1 << 5))
|
||||||
{
|
{
|
||||||
unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
|
if(!(_horizontalTimer&3))
|
||||||
_upcomingEvents[upcomingEventsPointerPlus4].updates |= Event::Action::Playfield;
|
{
|
||||||
_upcomingEvents[upcomingEventsPointerPlus4].playfieldOutput = _playfield[(offset >> 2)%40];
|
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
|
// the ball becomes visible whenever it hits zero, regardless of whether its status
|
||||||
// is the result of a counter rollover or a programmatic reset
|
// is the result of a counter rollover or a programmatic reset
|
||||||
if(!_objectCounter[4])
|
if(mask & (1 << 4))
|
||||||
{
|
{
|
||||||
_upcomingEvents[upcomingEventsPointerPlus6].updates |= Event::Action::ResetPixelCounter;
|
if(!_objectCounter[4])
|
||||||
_upcomingEvents[upcomingEventsPointerPlus6].pixelCounterMask |= (1 << 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
|
// check for player and missle triggers
|
||||||
for(int c = 0; c < 4; c++)
|
for(int c = 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
// the players and missles become visible only upon overflow to zero, so schedule for
|
if(mask & (1 << c))
|
||||||
// 5/6 clocks ahead from 159
|
|
||||||
if(_objectCounter[c] == 159)
|
|
||||||
{
|
{
|
||||||
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus6 : upcomingEventsPointerPlus5;
|
// the players and missles become visible only upon overflow to zero, so schedule for
|
||||||
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
|
// 5/6 clocks ahead from 159
|
||||||
_upcomingEvents[actionSlot].pixelCounterMask |= (1 << c);
|
if(_objectCounter[c] == 159)
|
||||||
}
|
|
||||||
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;
|
unsigned int actionSlot = (c < 2) ? upcomingEventsPointerPlus6 : upcomingEventsPointerPlus5;
|
||||||
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
|
_upcomingEvents[actionSlot].updates |= Event::Action::ResetPixelCounter;
|
||||||
_upcomingEvents[actionSlot].pixelCounterMask |= (1 << c);
|
_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);
|
int ballSize = 1 << ((_playfieldControl >> 4)&3);
|
||||||
ballPixel = (_pixelCounter[4] < ballSize) ? 1 : 0;
|
ballPixel = (_pixelCounter[4] < ballSize) ? 1 : 0;
|
||||||
}
|
}
|
||||||
_pixelCounter[4] ++;
|
|
||||||
|
|
||||||
// deal with the sprites
|
// deal with the sprites
|
||||||
uint8_t playerPixels[2] = {0, 0}, missilePixels[2] = {0, 0};
|
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);
|
int missileSize = 1 << ((_playerAndMissileSize[c] >> 4)&3);
|
||||||
missilePixels[c] = (_pixelCounter[c+2] < missileSize) ? 1 : 0;
|
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
|
// accumulate collisions
|
||||||
@@ -248,7 +267,7 @@ void Machine::output_pixels(unsigned int count)
|
|||||||
|
|
||||||
// grab background colour and schedule pixel counter resets
|
// grab background colour and schedule pixel counter resets
|
||||||
if(state == OutputState::Pixel)
|
if(state == OutputState::Pixel)
|
||||||
update_upcoming_events();
|
update_timers(~0);
|
||||||
|
|
||||||
// apply any queued changes and flush the record
|
// apply any queued changes and flush the record
|
||||||
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::Playfield)
|
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)
|
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::HMoveDecrement)
|
||||||
{
|
{
|
||||||
for(int c = 0; c < 5; c++)
|
update_timers(_hMoveFlags);
|
||||||
{
|
|
||||||
if(_hMoveFlags & (1 << c))
|
|
||||||
{
|
|
||||||
_objectCounter[c] = (_objectCounter[c] + 1)%160;
|
|
||||||
_pixelCounter[c] ++; // TODO: this isn't always a straight increment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_upcomingEvents[_upcomingEventsPointer].updates = 0;
|
_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 0x01: _vBlankEnabled = !!(*value & 0x02); break;
|
||||||
|
|
||||||
case 0x02:
|
case 0x02:
|
||||||
set_ready_line(true);
|
// printf("%d\n", _horizontalTimer);
|
||||||
|
if(_horizontalTimer) set_ready_line(true);
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
_horizontalTimer = 0;
|
_horizontalTimer = 0;
|
||||||
|
@@ -118,7 +118,7 @@ class Machine: public CPU6502::Processor<Machine> {
|
|||||||
|
|
||||||
void output_pixels(unsigned int count);
|
void output_pixels(unsigned int count);
|
||||||
uint8_t get_output_pixel();
|
uint8_t get_output_pixel();
|
||||||
void update_upcoming_events();
|
void update_timers(int mask);
|
||||||
Outputs::CRT::CRT *_crt;
|
Outputs::CRT::CRT *_crt;
|
||||||
|
|
||||||
// latched output state
|
// latched output state
|
||||||
|
Reference in New Issue
Block a user