1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-09 17:29:36 +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();
_timestamp = 0;
_horizontalTimer = 0;
_pixelPosition = 0;
_lastOutputStateDuration = 0;
_lastOutputState = OutputState::Sync;
_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)
{
while(count--) {
const int x = _pixelPosition >> 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));
while(count--)
{
// logic: if in vsync, output that; otherwise if in vblank then output that;
// otherwise output a pixel
if(_vSyncEnabled) {
output_state(OutputState::Sync, nullptr);
} else {
_playFieldPixel = (_playField[byte] >> bit)&1;
// blank is decoded as 68 counts; sync and colour burst as 16 counts
// if(!(_pixelPosition&3))
// printf("[%d %d]\n", byte, bit);
// fputc(_playFieldPixel && !_vblank ? '*' : ' ', stdout);
// guesses, until I can find information: 26 cycles blank, 16 sync, 26 blank, 160 pixels
if(_horizontalTimer < 26) output_state(OutputState::Blank, nullptr);
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)
{
static int lines = 0;
uint8_t returnValue = 0xff;
output_pixels(3);
_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
if ((address&0x1000) && isReadOperation(operation)) {
// 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)) {
} else {
switch(address & 0x3f) {
case 0: {
bool newVsync = !!(*value & 0x02);
if (newVsync != _vsync) {
_vsync = newVsync;
}
} break;
case 1: {
bool newVblank = !!(*value & 0x02);
if (newVblank != _vblank) {
_vblank = newVblank;
}
} break;
case 0: _vSyncEnabled = !!(*value & 0x02); break;
case 1: _vBlankEnabled = !!(*value & 0x02); break;
case 2: {

View File

@ -27,21 +27,35 @@ class Machine: public CPU6502::Processor<Machine> {
private:
uint8_t _rom[4096], _ram[128];
uint16_t _romMask;
uint8_t _playField[3], _playFieldControl;
uint64_t _timestamp;
bool _vsync, _vblank;
// the timer
unsigned int _piaTimerValue;
unsigned int _piaTimerShift;
// graphics registers
uint8_t _playField[3], _playFieldControl;
// graphics output
int _horizontalTimer;
bool _vSyncEnabled, _vBlankEnabled;
enum OutputState {
Sync,
Blank,
Pixel
};
int _pixelPosition;
uint8_t _playFieldPixel;
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;
// 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)
{
printf("[%d]\n", number_of_cycles);
}
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)
{
printf("[+++:%d]", number_of_cycles);
}