mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Made an attempt better to generalise the idea of things with 4 CLK delays.
This commit is contained in:
parent
4ad074fc78
commit
3d003070b3
@ -23,7 +23,8 @@ Machine::Machine() :
|
|||||||
_rom(nullptr),
|
_rom(nullptr),
|
||||||
_hMoveWillCount(false),
|
_hMoveWillCount(false),
|
||||||
_piaDataValue{0xff, 0xff},
|
_piaDataValue{0xff, 0xff},
|
||||||
_tiaInputValue{0xff, 0xff}
|
_tiaInputValue{0xff, 0xff},
|
||||||
|
_upcomingEventsPointer(0)
|
||||||
{
|
{
|
||||||
memset(_collisions, 0xff, sizeof(_collisions));
|
memset(_collisions, 0xff, sizeof(_collisions));
|
||||||
set_reset_line(true);
|
set_reset_line(true);
|
||||||
@ -77,17 +78,33 @@ Machine::~Machine()
|
|||||||
close_output();
|
close_output();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Machine::get_output_pixel()
|
void Machine::update_upcoming_event()
|
||||||
{
|
{
|
||||||
// get the playfield pixel and hence a proposed colour
|
_upcomingEvents[_upcomingEventsPointer].updates = 0;
|
||||||
unsigned int offset = _horizontalTimer - (horizontalTimerPeriod - 160);
|
|
||||||
|
unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
|
||||||
if(!(offset&3))
|
if(!(offset&3))
|
||||||
{
|
{
|
||||||
_playfieldPixel = _nextPlayfieldPixel;
|
_upcomingEvents[_upcomingEventsPointer].updates |= Event::Action::Playfield;
|
||||||
_nextPlayfieldPixel = _playfield[(1 + (offset >> 2))%40];
|
_upcomingEvents[_upcomingEventsPointer].playfieldOutput = _playfield[(offset >> 2)%40];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Machine::get_output_pixel()
|
||||||
|
{
|
||||||
|
unsigned int offset = _horizontalTimer - (horizontalTimerPeriod - 160);
|
||||||
|
|
||||||
|
// get the playfield pixel and hence a proposed colour
|
||||||
uint8_t playfieldColour = ((_playfieldControl&6) == 2) ? _playerColour[offset / 80] : _playfieldColour;
|
uint8_t playfieldColour = ((_playfieldControl&6) == 2) ? _playerColour[offset / 80] : _playfieldColour;
|
||||||
|
|
||||||
|
// get the ball proposed colour
|
||||||
|
// uint8_t ballPixel = 0;
|
||||||
|
// if(_ballGraphicsEnable&2) {
|
||||||
|
// int ballIndex = _objectCounter[4];
|
||||||
|
// int ballSize = 1 << ((_playfieldControl >> 4)&3);
|
||||||
|
// ballPixel = (ballIndex >= 0 && ballIndex < ballSize) ? 1 : 0;
|
||||||
|
// }
|
||||||
|
|
||||||
// get player and missile proposed pixels
|
// get player and missile proposed pixels
|
||||||
/* uint8_t playerPixels[2] = {0, 0}, missilePixels[2] = {0, 0};
|
/* uint8_t playerPixels[2] = {0, 0}, missilePixels[2] = {0, 0};
|
||||||
for(int c = 0; c < 2; c++)
|
for(int c = 0; c < 2; c++)
|
||||||
@ -141,14 +158,6 @@ uint8_t Machine::get_output_pixel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the ball proposed colour
|
|
||||||
uint8_t ballPixel = 0;
|
|
||||||
if(_ballGraphicsEnable&2) {
|
|
||||||
int ballIndex = _objectCounter[4] - 4;
|
|
||||||
int ballSize = 1 << ((_playfieldControl >> 4)&3);
|
|
||||||
ballPixel = (ballIndex >= 0 && ballIndex < ballSize) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// accumulate collisions
|
// accumulate collisions
|
||||||
if(playerPixels[0] | playerPixels[1]) {
|
if(playerPixels[0] | playerPixels[1]) {
|
||||||
_collisions[0] |= ((missilePixels[0] & playerPixels[1]) << 7) | ((missilePixels[0] & playerPixels[0]) << 6);
|
_collisions[0] |= ((missilePixels[0] & playerPixels[1]) << 7) | ((missilePixels[0] & playerPixels[0]) << 6);
|
||||||
@ -180,12 +189,12 @@ uint8_t Machine::get_output_pixel()
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// return colour
|
// return colour
|
||||||
return _playfieldPixel ? playfieldColour : _backgroundColour;
|
return _playfieldOutput ? playfieldColour : _backgroundColour;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in imputing the knowledge that all we're dealing with is the rollover from 159 to 0,
|
// in imputing the knowledge that all we're dealing with is the rollover from 159 to 0,
|
||||||
// this is faster than the straightforward +1)%160 per profiling
|
// this is faster than the straightforward +1)%160 per profiling
|
||||||
#define increment_object_counter(c) _objectCounter[c] = (_objectCounter[c]+1)&~((158-_objectCounter[c]) >> 8)
|
//#define increment_object_counter(c) _objectCounter[c] = (_objectCounter[c]+1)&~((158-_objectCounter[c]) >> 8)
|
||||||
|
|
||||||
void Machine::output_pixels(unsigned int count)
|
void Machine::output_pixels(unsigned int count)
|
||||||
{
|
{
|
||||||
@ -193,13 +202,14 @@ void Machine::output_pixels(unsigned int count)
|
|||||||
{
|
{
|
||||||
OutputState state;
|
OutputState state;
|
||||||
|
|
||||||
|
// determine which output will start this cycle; all outputs are delayed by 4 CLKs momentarily...
|
||||||
switch(_horizontalTimer >> 2)
|
switch(_horizontalTimer >> 2)
|
||||||
{
|
{
|
||||||
case 0: case 1: case 2: case 3: state = OutputState::Blank; break;
|
case 227: case 0: case 1: case 2: state = OutputState::Blank; break;
|
||||||
case 4: case 5: case 6: case 7: state = OutputState::Sync; break;
|
case 3: case 4: case 5: case 6: state = OutputState::Sync; break;
|
||||||
case 8: case 9: case 10: case 11: state = OutputState::ColourBurst; break;
|
case 7: case 8: case 9: case 10: state = OutputState::ColourBurst; break;
|
||||||
case 12: case 13: case 14: case 15: case 16: state = OutputState::Blank; break;
|
case 11: case 12: case 13: case 14: case 15: state = OutputState::Blank; break;
|
||||||
case 17: case 18: state = _vBlankExtend ? OutputState::Blank : OutputState::Pixel; break;
|
case 16: case 17: state = _vBlankExtend ? OutputState::Blank : OutputState::Pixel; break;
|
||||||
default: state = OutputState::Pixel; break;
|
default: state = OutputState::Pixel; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +218,57 @@ void Machine::output_pixels(unsigned int count)
|
|||||||
state = (state = OutputState::Sync) ? OutputState::Blank : OutputState::Sync;
|
state = (state = OutputState::Sync) ? OutputState::Blank : OutputState::Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write that state as the one that will become effective in four clocks
|
||||||
|
_upcomingEvents[_upcomingEventsPointer].state = state;
|
||||||
|
|
||||||
|
// grab pixel state if desired
|
||||||
|
if(state == OutputState::Pixel)
|
||||||
|
{
|
||||||
|
update_upcoming_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance, hitting the state that will become active now
|
||||||
|
_upcomingEventsPointer = (_upcomingEventsPointer + 1)&3;
|
||||||
|
|
||||||
|
// apply any queued changes
|
||||||
|
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::Playfield)
|
||||||
|
{
|
||||||
|
_playfieldOutput = _upcomingEvents[_upcomingEventsPointer].playfieldOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read that state
|
||||||
|
state = _upcomingEvents[_upcomingEventsPointer].state;
|
||||||
|
|
||||||
|
// decide what that means needs to be communicated to the CRT
|
||||||
|
_lastOutputStateDuration++;
|
||||||
|
if(state != _lastOutputState) {
|
||||||
|
switch(_lastOutputState) {
|
||||||
|
case OutputState::Blank: _crt->output_blank(_lastOutputStateDuration); break;
|
||||||
|
case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break;
|
||||||
|
case OutputState::ColourBurst: _crt->output_colour_burst(_lastOutputStateDuration, 96, 0); break;
|
||||||
|
case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, 1); break;
|
||||||
|
}
|
||||||
|
_lastOutputStateDuration = 0;
|
||||||
|
_lastOutputState = state;
|
||||||
|
|
||||||
|
if(state == OutputState::Pixel) {
|
||||||
|
_outputBuffer = _crt->allocate_write_area(160);
|
||||||
|
} else {
|
||||||
|
_outputBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decide on a pixel colour if that's what's happening
|
||||||
|
if(state == OutputState::Pixel)
|
||||||
|
{
|
||||||
|
uint8_t colour = get_output_pixel();
|
||||||
|
if(_outputBuffer)
|
||||||
|
{
|
||||||
|
*_outputBuffer = colour;
|
||||||
|
_outputBuffer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update hmove
|
// update hmove
|
||||||
// if(!(_horizontalTimer&3)) {
|
// if(!(_horizontalTimer&3)) {
|
||||||
//
|
//
|
||||||
@ -225,43 +286,24 @@ void Machine::output_pixels(unsigned int count)
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// if(state == OutputState::Pixel)
|
||||||
_lastOutputStateDuration++;
|
// {
|
||||||
if(state != _lastOutputState) {
|
// uint8_t colour = get_output_pixel();
|
||||||
switch(_lastOutputState) {
|
// if(_outputBuffer)
|
||||||
case OutputState::Blank: _crt->output_blank(_lastOutputStateDuration); break;
|
// {
|
||||||
case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break;
|
// *_outputBuffer = colour;
|
||||||
case OutputState::ColourBurst: _crt->output_colour_burst(_lastOutputStateDuration, 96, 0); break;
|
// _outputBuffer++;
|
||||||
case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, 1); break;
|
// }
|
||||||
}
|
// }
|
||||||
_lastOutputStateDuration = 0;
|
// else
|
||||||
_lastOutputState = state;
|
// {
|
||||||
|
|
||||||
if(state == OutputState::Pixel) {
|
|
||||||
_outputBuffer = _crt->allocate_write_area(160);
|
|
||||||
} else {
|
|
||||||
_outputBuffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(state == OutputState::Pixel)
|
|
||||||
{
|
|
||||||
uint8_t colour = get_output_pixel();
|
|
||||||
if(_outputBuffer)
|
|
||||||
{
|
|
||||||
*_outputBuffer = colour;
|
|
||||||
_outputBuffer++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// fetch this for the entire blank period just to ensure it's in place when needed
|
// fetch this for the entire blank period just to ensure it's in place when needed
|
||||||
if(!(_horizontalTimer&3))
|
// if(!(_horizonta lTimer&3))
|
||||||
{
|
// {
|
||||||
unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
|
// unsigned int offset = 4 + _horizontalTimer - (horizontalTimerPeriod - 160);
|
||||||
_nextPlayfieldPixel = _playfield[(offset >> 2)%40];
|
// _nextPlayfieldPixel = _playfield[(offset >> 2)%40];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* if(_horizontalTimer < (_vBlankExtend ? 152 : 160)) {
|
/* if(_horizontalTimer < (_vBlankExtend ? 152 : 160)) {
|
||||||
uint8_t throwaway_pixel;
|
uint8_t throwaway_pixel;
|
||||||
@ -275,6 +317,7 @@ void Machine::output_pixels(unsigned int count)
|
|||||||
increment_object_counter(4);
|
increment_object_counter(4);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
// advance horizontal timer, perform reset actions if requested
|
||||||
_horizontalTimer = (_horizontalTimer + 1) % horizontalTimerPeriod;
|
_horizontalTimer = (_horizontalTimer + 1) % horizontalTimerPeriod;
|
||||||
if(!_horizontalTimer)
|
if(!_horizontalTimer)
|
||||||
{
|
{
|
||||||
|
@ -48,9 +48,26 @@ class Machine: public CPU6502::Processor<Machine> {
|
|||||||
uint8_t _backgroundColour;
|
uint8_t _backgroundColour;
|
||||||
uint8_t _playfield[40];
|
uint8_t _playfield[40];
|
||||||
|
|
||||||
// playfield outputs
|
// delayed clock events
|
||||||
uint8_t _playfieldPixel; // the pixel currently being output
|
enum OutputState {
|
||||||
uint8_t _nextPlayfieldPixel; // the next pixel to be output; latched ahead of time
|
Sync,
|
||||||
|
Blank,
|
||||||
|
ColourBurst,
|
||||||
|
Pixel
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Event {
|
||||||
|
enum Action {
|
||||||
|
OutputSate = 1 << 0,
|
||||||
|
Playfield = 1 << 1,
|
||||||
|
};
|
||||||
|
unsigned int updates;
|
||||||
|
uint8_t playfieldOutput;
|
||||||
|
OutputState state;
|
||||||
|
} _upcomingEvents[4];
|
||||||
|
unsigned int _upcomingEventsPointer;
|
||||||
|
|
||||||
|
uint8_t _playfieldOutput;
|
||||||
|
|
||||||
// player registers
|
// player registers
|
||||||
uint8_t _playerColour[2];
|
uint8_t _playerColour[2];
|
||||||
@ -86,15 +103,9 @@ class Machine: public CPU6502::Processor<Machine> {
|
|||||||
// collisions
|
// collisions
|
||||||
uint8_t _collisions[8];
|
uint8_t _collisions[8];
|
||||||
|
|
||||||
enum OutputState {
|
|
||||||
Sync,
|
|
||||||
Blank,
|
|
||||||
ColourBurst,
|
|
||||||
Pixel
|
|
||||||
};
|
|
||||||
|
|
||||||
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_event();
|
||||||
Outputs::CRT::CRT *_crt;
|
Outputs::CRT::CRT *_crt;
|
||||||
|
|
||||||
// latched output state
|
// latched output state
|
||||||
|
Loading…
Reference in New Issue
Block a user