mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Made a very basic attempt to emulate tape output.
This commit is contained in:
parent
1819e7b9cc
commit
96c946b8af
@ -117,12 +117,12 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
if(isReadOperation(operation))
|
if(isReadOperation(operation))
|
||||||
{
|
{
|
||||||
*value = _tape.get_data_register();
|
*value = _tape.get_data_register();
|
||||||
_tape.clear_interrupts(Interrupt::TransmitDataEmpty);
|
_tape.clear_interrupts(Interrupt::ReceiveDataFull);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_tape.set_data_register(*value);
|
_tape.set_data_register(*value);
|
||||||
_tape.clear_interrupts(Interrupt::ReceiveDataFull);
|
_tape.clear_interrupts(Interrupt::TransmitDataEmpty);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
@ -606,7 +606,7 @@ void Speaker::set_is_enabled(bool is_enabled)
|
|||||||
Tape
|
Tape
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Tape::Tape() : _is_running(false), _data_register(0), _delegate(nullptr) {}
|
Tape::Tape() : _is_running(false), _data_register(0), _delegate(nullptr), _output_bits_remaining(0), _last_posted_interrupt_status(0), _interrupt_status(0) {}
|
||||||
|
|
||||||
void Tape::set_tape(std::shared_ptr<Storage::Tape> tape)
|
void Tape::set_tape(std::shared_ptr<Storage::Tape> tape)
|
||||||
{
|
{
|
||||||
@ -627,33 +627,36 @@ inline void Tape::get_next_tape_pulse()
|
|||||||
inline void Tape::push_tape_bit(uint16_t bit)
|
inline void Tape::push_tape_bit(uint16_t bit)
|
||||||
{
|
{
|
||||||
_data_register = (uint16_t)((_data_register >> 1) | (bit << 10));
|
_data_register = (uint16_t)((_data_register >> 1) | (bit << 10));
|
||||||
|
|
||||||
uint8_t old_interrupt_status = _interrupt_status;
|
|
||||||
|
|
||||||
if(_bits_since_start)
|
if(_bits_since_start)
|
||||||
{
|
{
|
||||||
_bits_since_start--;
|
_bits_since_start--;
|
||||||
|
|
||||||
if(_bits_since_start == 7)
|
if(_bits_since_start == 7)
|
||||||
{
|
{
|
||||||
_interrupt_status &= ~Interrupt::TransmitDataEmpty;
|
_interrupt_status &= ~Interrupt::ReceiveDataFull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
evaluate_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Tape::evaluate_interrupts()
|
||||||
|
{
|
||||||
|
if((_data_register&0x3) == 0x1)
|
||||||
{
|
{
|
||||||
if((_data_register&0x3) == 0x1)
|
_interrupt_status |= Interrupt::ReceiveDataFull;
|
||||||
{
|
_bits_since_start = 9;
|
||||||
_interrupt_status |= Interrupt::TransmitDataEmpty;
|
|
||||||
_bits_since_start = 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_data_register == 0x3ff)
|
|
||||||
_interrupt_status |= Interrupt::HighToneDetect;
|
|
||||||
else
|
|
||||||
_interrupt_status &= ~Interrupt::HighToneDetect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(old_interrupt_status != _interrupt_status && _delegate) _delegate->tape_did_change_interrupt_status(this);
|
if(_data_register == 0x3ff)
|
||||||
|
_interrupt_status |= Interrupt::HighToneDetect;
|
||||||
|
else
|
||||||
|
_interrupt_status &= ~Interrupt::HighToneDetect;
|
||||||
|
|
||||||
|
if(_last_posted_interrupt_status != _interrupt_status)
|
||||||
|
{
|
||||||
|
_last_posted_interrupt_status = _interrupt_status;
|
||||||
|
if(_delegate) _delegate->tape_did_change_interrupt_status(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Tape::clear_interrupts(uint8_t interrupts)
|
inline void Tape::clear_interrupts(uint8_t interrupts)
|
||||||
@ -665,43 +668,84 @@ inline void Tape::clear_interrupts(uint8_t interrupts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Tape::set_is_in_input_mode(bool is_in_input_mode)
|
||||||
|
{
|
||||||
|
_is_in_input_mode = is_in_input_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Tape::set_counter(uint8_t value)
|
||||||
|
{
|
||||||
|
_pulse_stepper = std::shared_ptr<SignalProcessing::Stepper>(new SignalProcessing::Stepper(1200, 2000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Tape::set_data_register(uint8_t value)
|
||||||
|
{
|
||||||
|
_data_register = (uint16_t)((value << 2) | 1);
|
||||||
|
_output_bits_remaining = 9;
|
||||||
|
}
|
||||||
|
|
||||||
inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
||||||
{
|
{
|
||||||
if(_is_running && _is_enabled && _tape != nullptr)
|
if(_is_enabled)
|
||||||
{
|
{
|
||||||
while(number_of_cycles--)
|
if(_is_in_input_mode)
|
||||||
{
|
{
|
||||||
_time_into_pulse += (unsigned int)_pulse_stepper->step();
|
if(_is_running && _tape != nullptr)
|
||||||
if(_time_into_pulse == _current_pulse.length.length)
|
|
||||||
{
|
{
|
||||||
get_next_tape_pulse();
|
while(number_of_cycles--)
|
||||||
|
|
||||||
_crossings[0] = _crossings[1];
|
|
||||||
_crossings[1] = _crossings[2];
|
|
||||||
_crossings[2] = _crossings[3];
|
|
||||||
|
|
||||||
_crossings[3] = Tape::Unrecognised;
|
|
||||||
if(_current_pulse.type != Storage::Tape::Pulse::Zero)
|
|
||||||
{
|
{
|
||||||
float pulse_length = (float)_current_pulse.length.length / (float)_current_pulse.length.clock_rate;
|
_time_into_pulse += (unsigned int)_pulse_stepper->step();
|
||||||
if(pulse_length > 0.4 / 2400.0 && pulse_length < 0.6 / 2400.0) _crossings[3] = Tape::Short;
|
if(_time_into_pulse == _current_pulse.length.length)
|
||||||
if(pulse_length > 0.4 / 1200.0 && pulse_length < 0.6 / 1200.0) _crossings[3] = Tape::Long;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_crossings[0] == Tape::Long && _crossings[1] == Tape::Long)
|
|
||||||
{
|
|
||||||
push_tape_bit(0);
|
|
||||||
_crossings[1] = Tape::Unrecognised;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(_crossings[0] == Tape::Short && _crossings[1] == Tape::Short && _crossings[2] == Tape::Short && _crossings[3] == Tape::Short)
|
|
||||||
{
|
{
|
||||||
push_tape_bit(1);
|
get_next_tape_pulse();
|
||||||
|
|
||||||
|
_crossings[0] = _crossings[1];
|
||||||
|
_crossings[1] = _crossings[2];
|
||||||
|
_crossings[2] = _crossings[3];
|
||||||
|
|
||||||
_crossings[3] = Tape::Unrecognised;
|
_crossings[3] = Tape::Unrecognised;
|
||||||
|
if(_current_pulse.type != Storage::Tape::Pulse::Zero)
|
||||||
|
{
|
||||||
|
float pulse_length = (float)_current_pulse.length.length / (float)_current_pulse.length.clock_rate;
|
||||||
|
if(pulse_length > 0.4 / 2400.0 && pulse_length < 0.6 / 2400.0) _crossings[3] = Tape::Short;
|
||||||
|
if(pulse_length > 0.4 / 1200.0 && pulse_length < 0.6 / 1200.0) _crossings[3] = Tape::Long;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_crossings[0] == Tape::Long && _crossings[1] == Tape::Long)
|
||||||
|
{
|
||||||
|
push_tape_bit(0);
|
||||||
|
_crossings[1] = Tape::Unrecognised;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_crossings[0] == Tape::Short && _crossings[1] == Tape::Short && _crossings[2] == Tape::Short && _crossings[3] == Tape::Short)
|
||||||
|
{
|
||||||
|
push_tape_bit(1);
|
||||||
|
_crossings[3] = Tape::Unrecognised;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(number_of_cycles--)
|
||||||
|
{
|
||||||
|
if(_pulse_stepper->step())
|
||||||
|
{
|
||||||
|
_output_bits_remaining--;
|
||||||
|
if(!_output_bits_remaining)
|
||||||
|
{
|
||||||
|
_output_bits_remaining = 9;
|
||||||
|
_interrupt_status |= Interrupt::TransmitDataEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate_interrupts();
|
||||||
|
|
||||||
|
_data_register = (_data_register >> 1) | 0x200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@ enum ROMSlot: uint8_t {
|
|||||||
enum Interrupt: uint8_t {
|
enum Interrupt: uint8_t {
|
||||||
DisplayEnd = 0x04,
|
DisplayEnd = 0x04,
|
||||||
RealTimeClock = 0x08,
|
RealTimeClock = 0x08,
|
||||||
TransmitDataEmpty = 0x10,
|
ReceiveDataFull = 0x10,
|
||||||
ReceiveDataFull = 0x20,
|
TransmitDataEmpty = 0x20,
|
||||||
HighToneDetect = 0x40
|
HighToneDetect = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ class Tape {
|
|||||||
void set_tape(std::shared_ptr<Storage::Tape> tape);
|
void set_tape(std::shared_ptr<Storage::Tape> tape);
|
||||||
|
|
||||||
inline uint8_t get_data_register() { return (uint8_t)(_data_register >> 2); }
|
inline uint8_t get_data_register() { return (uint8_t)(_data_register >> 2); }
|
||||||
inline void set_data_register(uint8_t value) {}
|
inline void set_data_register(uint8_t value);
|
||||||
inline void set_counter(uint8_t value) {}
|
inline void set_counter(uint8_t value);
|
||||||
|
|
||||||
inline uint8_t get_interrupt_status() { return _interrupt_status; }
|
inline uint8_t get_interrupt_status() { return _interrupt_status; }
|
||||||
inline void clear_interrupts(uint8_t interrupts);
|
inline void clear_interrupts(uint8_t interrupts);
|
||||||
@ -80,7 +80,7 @@ class Tape {
|
|||||||
|
|
||||||
inline void set_is_running(bool is_running) { _is_running = is_running; }
|
inline void set_is_running(bool is_running) { _is_running = is_running; }
|
||||||
inline void set_is_enabled(bool is_enabled) { _is_enabled = is_enabled; }
|
inline void set_is_enabled(bool is_enabled) { _is_enabled = is_enabled; }
|
||||||
inline void set_is_in_input_mode(bool is_in_input_mode) {}
|
inline void set_is_in_input_mode(bool is_in_input_mode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void push_tape_bit(uint16_t bit);
|
inline void push_tape_bit(uint16_t bit);
|
||||||
@ -94,11 +94,13 @@ class Tape {
|
|||||||
|
|
||||||
bool _is_running;
|
bool _is_running;
|
||||||
bool _is_enabled;
|
bool _is_enabled;
|
||||||
|
bool _is_in_input_mode;
|
||||||
|
|
||||||
int _bits_since_start;
|
inline void evaluate_interrupts();
|
||||||
|
int _bits_since_start, _output_bits_remaining;
|
||||||
uint16_t _data_register;
|
uint16_t _data_register;
|
||||||
|
|
||||||
uint8_t _interrupt_status;
|
uint8_t _interrupt_status, _last_posted_interrupt_status;
|
||||||
Delegate *_delegate;
|
Delegate *_delegate;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
Loading…
Reference in New Issue
Block a user