1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-13 00:25:26 +00:00

Made first genuine attempt at outputting a meaningful CRT stream. Which shows some significant errors. So work to do.

This commit is contained in:
Thomas Harte
2015-07-19 16:48:14 -04:00
parent 2d0f861474
commit 6f78ecdc9c
3 changed files with 94 additions and 52 deletions

View File

@@ -17,55 +17,93 @@ Machine::Machine()
reset(); reset();
_timestamp = 0; _timestamp = 0;
_horizontalTimer = 0; _horizontalTimer = 0;
_pixelPosition = 0; _lastOutputStateDuration = 0;
_lastOutputState = OutputState::Sync;
_crt = new Outputs::CRT(228); _crt = new Outputs::CRT(228);
} }
void Machine::get_output_pixel(uint8_t *pixel, int offset)
{
// get the playfield pixel
const int x = offset >> 2;
const int mirrored = (x / 20) & (_playFieldControl&1);
const int index = mirrored ? x - 20 : 19 - (x%20);
const int byte = 2 - (index >> 3);
const int lowestBit = (byte&1)^1;
const int bit = (index & 7)^(lowestBit | (lowestBit << 1) | (lowestBit << 2));
uint8_t playFieldPixel = (_playField[byte] >> bit)&1;
// TODO: almost everything!
pixel[0] = playFieldPixel ? 0xff : 0x00;
pixel[1] = playFieldPixel ? 0xff : 0x00;
pixel[2] = playFieldPixel ? 0xff : 0x00;
}
void Machine::output_pixels(int count) void Machine::output_pixels(int count)
{ {
while(count--) { while(count--)
const int x = _pixelPosition >> 2; {
const int mirrored = (x / 20) & (_playFieldControl&1); // logic: if in vsync, output that; otherwise if in vblank then output that;
const int index = mirrored ? x - 20 : 19 - (x%20); // otherwise output a pixel
const int byte = 2 - (index >> 3); if(_vSyncEnabled) {
const int lowestBit = (byte&1)^1; output_state(OutputState::Sync, nullptr);
const int bit = (index & 7)^(lowestBit | (lowestBit << 1) | (lowestBit << 2)); } else {
_playFieldPixel = (_playField[byte] >> bit)&1; // blank is decoded as 68 counts; sync and colour burst as 16 counts
// if(!(_pixelPosition&3)) // guesses, until I can find information: 26 cycles blank, 16 sync, 26 blank, 160 pixels
// printf("[%d %d]\n", byte, bit); if(_horizontalTimer < 26) output_state(OutputState::Blank, nullptr);
// fputc(_playFieldPixel && !_vblank ? '*' : ' ', stdout); else if (_horizontalTimer < 42) output_state(OutputState::Sync, nullptr);
else if (_horizontalTimer < 68) output_state(OutputState::Blank, nullptr);
else {
if(_vBlankEnabled) {
output_state(OutputState::Blank, nullptr);
} else {
uint8_t outputPixel[3];
get_output_pixel(outputPixel, _horizontalTimer - 68);
output_state(OutputState::Pixel, outputPixel);
}
}
}
_pixelPosition++; _horizontalTimer = (_horizontalTimer + 1)%228;
} }
} }
void Machine::output_state(OutputState state, uint8_t *pixel)
{
_lastOutputStateDuration++;
if(state != _lastOutputState)
{
static uint8_t blankingLevel[3] = {0, 0, 0};
switch(_lastOutputState)
{
case OutputState::Blank: _crt->output_level(_lastOutputStateDuration, blankingLevel, "Atari2600"); break;
case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break;
case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, _outPixels, "Atari2600"); break;
}
_lastOutputStateDuration = 0;
_lastOutputState = state;
}
if(state == OutputState::Pixel)
{
_outPixels[(_lastOutputStateDuration * 3) + 0] = pixel[0];
_outPixels[(_lastOutputStateDuration * 3) + 1] = pixel[1];
_outPixels[(_lastOutputStateDuration * 3) + 2] = pixel[2];
}
}
void Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) void Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
{ {
static int lines = 0;
uint8_t returnValue = 0xff; uint8_t returnValue = 0xff;
output_pixels(3);
_timestamp++; _timestamp++;
if (_horizontalTimer == 228) {
_horizontalTimer = 0;
_pixelPosition = 0;
// printf("\n");
lines++;
}
if (_horizontalTimer == 69) {
output_pixels(1);
}
if (_horizontalTimer >= 70) {
output_pixels(3);
}
_horizontalTimer += 3;
// check for a ROM access // check for a ROM access
if ((address&0x1000) && isReadOperation(operation)) { if ((address&0x1000) && isReadOperation(operation)) {
// if(operation == CPU6502::BusOperation::ReadOpcode) printf("[%04x]\n", address); // if(operation == CPU6502::BusOperation::ReadOpcode) printf("[%04x]\n", address);
@@ -87,21 +125,8 @@ void Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t ad
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
} else { } else {
switch(address & 0x3f) { switch(address & 0x3f) {
case 0: { case 0: _vSyncEnabled = !!(*value & 0x02); break;
bool newVsync = !!(*value & 0x02); case 1: _vBlankEnabled = !!(*value & 0x02); break;
if (newVsync != _vsync) {
_vsync = newVsync;
}
} break;
case 1: {
bool newVblank = !!(*value & 0x02);
if (newVblank != _vblank) {
_vblank = newVblank;
}
} break;
case 2: { case 2: {

View File

@@ -27,21 +27,35 @@ class Machine: public CPU6502::Processor<Machine> {
private: private:
uint8_t _rom[4096], _ram[128]; uint8_t _rom[4096], _ram[128];
uint16_t _romMask; uint16_t _romMask;
uint8_t _playField[3], _playFieldControl;
uint64_t _timestamp; uint64_t _timestamp;
bool _vsync, _vblank;
// the timer
unsigned int _piaTimerValue; unsigned int _piaTimerValue;
unsigned int _piaTimerShift; unsigned int _piaTimerShift;
// graphics registers
uint8_t _playField[3], _playFieldControl;
// graphics output
int _horizontalTimer; int _horizontalTimer;
bool _vSyncEnabled, _vBlankEnabled;
enum OutputState {
Sync,
Blank,
Pixel
};
int _pixelPosition;
uint8_t _playFieldPixel;
void output_pixels(int count); void output_pixels(int count);
void get_output_pixel(uint8_t *pixel, int offset);
void output_state(OutputState state, uint8_t *pixel);
Outputs::CRT *_crt; Outputs::CRT *_crt;
// latched output state
uint8_t _outPixels[480];
int _lastOutputStateDuration;
OutputState _lastOutputState;
}; };
} }

View File

@@ -16,12 +16,15 @@ CRT::CRT(int cycles_per_line)
void CRT::output_sync(int number_of_cycles) void CRT::output_sync(int number_of_cycles)
{ {
printf("[%d]\n", number_of_cycles);
} }
void CRT::output_level(int number_of_cycles, uint8_t *level, std::string type) void CRT::output_level(int number_of_cycles, uint8_t *level, std::string type)
{ {
printf("[---:%d]", number_of_cycles);
} }
void CRT::output_data(int number_of_cycles, uint8_t *data, std::string type) void CRT::output_data(int number_of_cycles, uint8_t *data, std::string type)
{ {
printf("[+++:%d]", number_of_cycles);
} }