mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-27 15:29:34 +00:00
Merge pull request #20 from TomHarte/6560Accuracy
Adds some documentation and support for inverted cells in the 6560
This commit is contained in:
commit
dbdd05afb8
@ -25,7 +25,6 @@ MOS6560::MOS6560() :
|
|||||||
"uint yC = c & 15u;"
|
"uint yC = c & 15u;"
|
||||||
"float phaseOffset = 6.283185308 * float(yC) / 16.0;"
|
"float phaseOffset = 6.283185308 * float(yC) / 16.0;"
|
||||||
|
|
||||||
// "float chroma = step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654);"
|
|
||||||
"float chroma = cos(phase + phaseOffset);"
|
"float chroma = cos(phase + phaseOffset);"
|
||||||
"return mix(y, step(yC, 14) * chroma, amplitude);"
|
"return mix(y, step(yC, 14) * chroma, amplitude);"
|
||||||
"}");
|
"}");
|
||||||
@ -108,7 +107,7 @@ void MOS6560::set_register(int address, uint8_t value)
|
|||||||
output_border(_cycles_in_state * 4);
|
output_border(_cycles_in_state * 4);
|
||||||
_cycles_in_state = 0;
|
_cycles_in_state = 0;
|
||||||
}
|
}
|
||||||
_invertedCells = !!((value >> 3)&1);
|
_invertedCells = !((value >> 3)&1);
|
||||||
_borderColour = _colours[value & 0x07];
|
_borderColour = _colours[value & 0x07];
|
||||||
_backgroundColour = _colours[value >> 4];
|
_backgroundColour = _colours[value >> 4];
|
||||||
break;
|
break;
|
||||||
@ -140,12 +139,17 @@ void MOS6560::output_border(unsigned int number_of_cycles)
|
|||||||
|
|
||||||
uint16_t MOS6560::get_address()
|
uint16_t MOS6560::get_address()
|
||||||
{
|
{
|
||||||
|
// keep track of the amount of time since the speaker was updated; lazy updates are applied
|
||||||
_cycles_since_speaker_update++;
|
_cycles_since_speaker_update++;
|
||||||
|
|
||||||
|
// keep track of internal time relative to this scanline
|
||||||
_horizontal_counter++;
|
_horizontal_counter++;
|
||||||
|
|
||||||
|
// check for end of scanline
|
||||||
if(_horizontal_counter == 65)
|
if(_horizontal_counter == 65)
|
||||||
{
|
{
|
||||||
_horizontal_counter = 0;
|
_horizontal_counter = 0;
|
||||||
|
|
||||||
_vertical_counter++;
|
_vertical_counter++;
|
||||||
_column_counter = -1;
|
_column_counter = -1;
|
||||||
|
|
||||||
@ -276,14 +280,25 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value)
|
|||||||
uint8_t cell_colour = _colours[_character_colour & 0x7];
|
uint8_t cell_colour = _colours[_character_colour & 0x7];
|
||||||
if(!(_character_colour&0x8))
|
if(!(_character_colour&0x8))
|
||||||
{
|
{
|
||||||
pixel_pointer[0] = ((_character_value >> 7)&1) ? cell_colour : _backgroundColour;
|
uint8_t colours[2];
|
||||||
pixel_pointer[1] = ((_character_value >> 6)&1) ? cell_colour : _backgroundColour;
|
if(_invertedCells)
|
||||||
pixel_pointer[2] = ((_character_value >> 5)&1) ? cell_colour : _backgroundColour;
|
{
|
||||||
pixel_pointer[3] = ((_character_value >> 4)&1) ? cell_colour : _backgroundColour;
|
colours[0] = cell_colour;
|
||||||
pixel_pointer[4] = ((_character_value >> 3)&1) ? cell_colour : _backgroundColour;
|
colours[1] = _backgroundColour;
|
||||||
pixel_pointer[5] = ((_character_value >> 2)&1) ? cell_colour : _backgroundColour;
|
}
|
||||||
pixel_pointer[6] = ((_character_value >> 1)&1) ? cell_colour : _backgroundColour;
|
else
|
||||||
pixel_pointer[7] = ((_character_value >> 0)&1) ? cell_colour : _backgroundColour;
|
{
|
||||||
|
colours[0] = _backgroundColour;
|
||||||
|
colours[1] = cell_colour;
|
||||||
|
}
|
||||||
|
pixel_pointer[0] = colours[(_character_value >> 7)&1];
|
||||||
|
pixel_pointer[1] = colours[(_character_value >> 6)&1];
|
||||||
|
pixel_pointer[2] = colours[(_character_value >> 5)&1];
|
||||||
|
pixel_pointer[3] = colours[(_character_value >> 4)&1];
|
||||||
|
pixel_pointer[4] = colours[(_character_value >> 3)&1];
|
||||||
|
pixel_pointer[5] = colours[(_character_value >> 2)&1];
|
||||||
|
pixel_pointer[6] = colours[(_character_value >> 1)&1];
|
||||||
|
pixel_pointer[7] = colours[(_character_value >> 0)&1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -316,20 +331,19 @@ void MOS6560::update_audio()
|
|||||||
|
|
||||||
#pragma mark - Audio
|
#pragma mark - Audio
|
||||||
|
|
||||||
MOS6560Speaker::MOS6560Speaker() :
|
MOS6560::Speaker::Speaker() :
|
||||||
_volume(0),
|
_volume(0),
|
||||||
_control_registers{0, 0, 0, 0},
|
_control_registers{0, 0, 0, 0},
|
||||||
_shift_registers{0, 0, 0, 0},
|
_shift_registers{0, 0, 0, 0},
|
||||||
_counters{2, 1, 0, 0} // create a slight phase offset for the three channels
|
_counters{2, 1, 0, 0} // create a slight phase offset for the three channels
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void MOS6560Speaker::set_volume(uint8_t volume)
|
void MOS6560::Speaker::set_volume(uint8_t volume)
|
||||||
{
|
{
|
||||||
_volume = volume;
|
_volume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MOS6560Speaker::set_control(int channel, uint8_t value)
|
void MOS6560::Speaker::set_control(int channel, uint8_t value)
|
||||||
{
|
{
|
||||||
_control_registers[channel] = value;
|
_control_registers[channel] = value;
|
||||||
}
|
}
|
||||||
@ -402,11 +416,11 @@ static uint8_t noise_pattern[] = {
|
|||||||
0xf0, 0xe1, 0xe0, 0x78, 0x70, 0x38, 0x3c, 0x3e, 0x1e, 0x3c, 0x1e, 0x1c, 0x70, 0x3c, 0x38, 0x3f,
|
0xf0, 0xe1, 0xe0, 0x78, 0x70, 0x38, 0x3c, 0x3e, 0x1e, 0x3c, 0x1e, 0x1c, 0x70, 0x3c, 0x38, 0x3f,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define shift(r) _shift_registers[r] = (uint8_t)((_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7));
|
#define shift(r) _shift_registers[r] = (_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7);
|
||||||
#define increment(r) _shift_registers[r] = (_shift_registers[r]+1)%8191;
|
#define increment(r) _shift_registers[r] = (_shift_registers[r]+1)%8191;
|
||||||
#define update(r, m, up) _counters[r]++; if((_counters[r] >> m) == 0x7f) { up(r); _counters[r] = _control_registers[r]&0x7f; }
|
#define update(r, m, up) _counters[r]++; if((_counters[r] >> m) == 0x7f) { up(r); _counters[r] = _control_registers[r]&0x7f; }
|
||||||
|
|
||||||
void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target)
|
void MOS6560::Speaker::get_samples(unsigned int number_of_samples, int16_t *target)
|
||||||
{
|
{
|
||||||
for(unsigned int c = 0; c < number_of_samples; c++)
|
for(unsigned int c = 0; c < number_of_samples; c++)
|
||||||
{
|
{
|
||||||
@ -424,7 +438,7 @@ void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MOS6560Speaker::skip_samples(unsigned int number_of_samples)
|
void MOS6560::Speaker::skip_samples(unsigned int number_of_samples)
|
||||||
{
|
{
|
||||||
for(unsigned int c = 0; c < number_of_samples; c++)
|
for(unsigned int c = 0; c < number_of_samples; c++)
|
||||||
{
|
{
|
||||||
|
@ -14,40 +14,64 @@
|
|||||||
|
|
||||||
namespace MOS {
|
namespace MOS {
|
||||||
|
|
||||||
class MOS6560Speaker: public ::Outputs::Filter<MOS6560Speaker> {
|
/*!
|
||||||
public:
|
The 6560 is a video and audio output chip; it therefore vends both a @c CRT and a @c Speaker.
|
||||||
MOS6560Speaker();
|
|
||||||
|
|
||||||
void set_volume(uint8_t volume);
|
To run the 6560 for a cycle, the caller should call @c get_address, make the requested bus access
|
||||||
void set_control(int channel, uint8_t value);
|
and call @c set_graphics_value with the result.
|
||||||
|
|
||||||
void get_samples(unsigned int number_of_samples, int16_t *target);
|
|
||||||
void skip_samples(unsigned int number_of_samples);
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned int _counters[4];
|
|
||||||
uint8_t _shift_registers[4];
|
|
||||||
uint8_t _control_registers[4];
|
|
||||||
uint8_t _volume;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@c set_register and @c get_register provide register access.
|
||||||
|
*/
|
||||||
class MOS6560 {
|
class MOS6560 {
|
||||||
public:
|
public:
|
||||||
MOS6560();
|
MOS6560();
|
||||||
Outputs::CRT::CRT *get_crt() { return _crt.get(); }
|
Outputs::CRT::CRT *get_crt() { return _crt.get(); }
|
||||||
Outputs::Speaker *get_speaker() { return &_speaker; }
|
Outputs::Speaker *get_speaker() { return &_speaker; }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Impliedly runs the 6560 for a single cycle, returning the next address that it puts on the bus.
|
||||||
|
*/
|
||||||
uint16_t get_address();
|
uint16_t get_address();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
An owning machine should determine the state of the data bus as a result of the access implied
|
||||||
|
by @c get_address and supply it to set_graphics_value.
|
||||||
|
*/
|
||||||
void set_graphics_value(uint8_t value, uint8_t colour_value);
|
void set_graphics_value(uint8_t value, uint8_t colour_value);
|
||||||
|
|
||||||
void synchronise() { update_audio(); }
|
/*!
|
||||||
|
Causes the 6560 to flush as much pending CRT and speaker communications as possible.
|
||||||
|
*/
|
||||||
|
inline void synchronise() { update_audio(); }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Writes to a 6560 register.
|
||||||
|
*/
|
||||||
void set_register(int address, uint8_t value);
|
void set_register(int address, uint8_t value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reads from a 6560 register.
|
||||||
|
*/
|
||||||
uint8_t get_register(int address);
|
uint8_t get_register(int address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Outputs::CRT::CRT> _crt;
|
std::unique_ptr<Outputs::CRT::CRT> _crt;
|
||||||
MOS6560Speaker _speaker;
|
class Speaker: public ::Outputs::Filter<Speaker> {
|
||||||
|
public:
|
||||||
|
Speaker();
|
||||||
|
|
||||||
|
void set_volume(uint8_t volume);
|
||||||
|
void set_control(int channel, uint8_t value);
|
||||||
|
|
||||||
|
void get_samples(unsigned int number_of_samples, int16_t *target);
|
||||||
|
void skip_samples(unsigned int number_of_samples);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int _counters[4];
|
||||||
|
unsigned int _shift_registers[4];
|
||||||
|
uint8_t _control_registers[4];
|
||||||
|
uint8_t _volume;
|
||||||
|
} _speaker;
|
||||||
|
|
||||||
bool _interlaced, _tall_characters;
|
bool _interlaced, _tall_characters;
|
||||||
uint8_t _first_column_location, _first_row_location;
|
uint8_t _first_column_location, _first_row_location;
|
||||||
@ -57,6 +81,7 @@ class MOS6560 {
|
|||||||
bool _invertedCells;
|
bool _invertedCells;
|
||||||
|
|
||||||
int _horizontal_counter, _vertical_counter;
|
int _horizontal_counter, _vertical_counter;
|
||||||
|
bool _did_output_graphics;
|
||||||
|
|
||||||
int _column_counter, _row_counter;
|
int _column_counter, _row_counter;
|
||||||
uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter;
|
uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user