diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp index fc52a4006..e5324ba93 100644 --- a/Machines/Commodore/1540/C1540.cpp +++ b/Machines/Commodore/1540/C1540.cpp @@ -167,3 +167,137 @@ void Machine::drive_via_did_set_data_density(void *driveVIA, int density) { set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone((unsigned int)density)); } + +#pragma mark - SerialPortVIA + +SerialPortVIA::SerialPortVIA() : + _portB(0x00), _attention_acknowledge_level(false), _attention_level_input(true), _data_level_output(false) +{} + +uint8_t SerialPortVIA::get_port_input(Port port) +{ + if(port) return _portB; + return 0xff; +} + +void SerialPortVIA::set_port_output(Port port, uint8_t value, uint8_t mask) +{ + if(port) + { + std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); + if(serialPort) { + _attention_acknowledge_level = !(value&0x10); + _data_level_output = (value&0x02); + + serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!(value&0x08)); + update_data_line(); + } + } +} + +void SerialPortVIA::set_serial_line_state(::Commodore::Serial::Line line, bool value) +{ + switch(line) + { + default: break; + case ::Commodore::Serial::Line::Data: _portB = (_portB & ~0x01) | (value ? 0x00 : 0x01); break; + case ::Commodore::Serial::Line::Clock: _portB = (_portB & ~0x04) | (value ? 0x00 : 0x04); break; + case ::Commodore::Serial::Line::Attention: + _attention_level_input = !value; + _portB = (_portB & ~0x80) | (value ? 0x00 : 0x80); + set_control_line_input(Port::A, Line::One, !value); + update_data_line(); + break; + } +} + +void SerialPortVIA::set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) +{ + _serialPort = serialPort; +} + +void SerialPortVIA::update_data_line() +{ + std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); + if(serialPort) + { + // "ATN (Attention) is an input on pin 3 of P2 and P3 that is sensed at PB7 and CA1 of UC3 after being inverted by UA1" + serialPort->set_output(::Commodore::Serial::Line::Data, + (::Commodore::Serial::LineLevel)(!_data_level_output + && (_attention_level_input != _attention_acknowledge_level))); + } +} + +#pragma mark - DriveVIA + +void DriveVIA::set_delegate(Delegate *delegate) +{ + _delegate = delegate; +} + +// write protect tab uncovered +DriveVIA::DriveVIA() : _port_b(0xff), _port_a(0xff), _delegate(nullptr) {} + +uint8_t DriveVIA::get_port_input(Port port) { + return port ? _port_b : _port_a; +} + +void DriveVIA::set_sync_detected(bool sync_detected) { + _port_b = (_port_b & 0x7f) | (sync_detected ? 0x00 : 0x80); +} + +void DriveVIA::set_data_input(uint8_t value) { + _port_a = value; +} + +bool DriveVIA::get_should_set_overflow() { + return _should_set_overflow; +} + +bool DriveVIA::get_motor_enabled() { + return _drive_motor; +} + +void DriveVIA::set_control_line_output(Port port, Line line, bool value) { + if(port == Port::A && line == Line::Two) { + _should_set_overflow = value; + } +} + +void DriveVIA::set_port_output(Port port, uint8_t value, uint8_t direction_mask) { + if(port) + { + // record drive motor state + _drive_motor = !!(value&4); + + // check for a head step + int step_difference = ((value&3) - (_previous_port_b_output&3))&3; + if(step_difference) + { + if(_delegate) _delegate->drive_via_did_step_head(this, (step_difference == 1) ? 1 : -1); + } + + // check for a change in density + int density_difference = (_previous_port_b_output^value) & (3 << 5); + if(density_difference && _delegate) + { + _delegate->drive_via_did_set_data_density(this, (value >> 5)&3); + } + + // TODO: something with the drive LED +// printf("LED: %s\n", value&8 ? "On" : "Off"); + + _previous_port_b_output = value; + } +} + +#pragma mark - SerialPort + +void SerialPort::set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { + std::shared_ptr serialPortVIA = _serialPortVIA.lock(); + if(serialPortVIA) serialPortVIA->set_serial_line_state(line, (bool)level); +} + +void SerialPort::set_serial_port_via(std::shared_ptr serialPortVIA) { + _serialPortVIA = serialPortVIA; +} diff --git a/Machines/Commodore/1540/C1540.hpp b/Machines/Commodore/1540/C1540.hpp index cddefaeb8..752684071 100644 --- a/Machines/Commodore/1540/C1540.hpp +++ b/Machines/Commodore/1540/C1540.hpp @@ -39,62 +39,21 @@ class SerialPortVIA: public MOS::MOS6522, public MOS::MOS6522IRQD public: using MOS6522IRQDelegate::set_interrupt_status; - SerialPortVIA() : _portB(0x00), _attention_acknowledge_level(false), _attention_level_input(true), _data_level_output(false) {} + SerialPortVIA(); - uint8_t get_port_input(Port port) { - if(port) { - return _portB; - } + uint8_t get_port_input(Port port); - return 0xff; - } + void set_port_output(Port port, uint8_t value, uint8_t mask); + void set_serial_line_state(::Commodore::Serial::Line line, bool value); - void set_port_output(Port port, uint8_t value, uint8_t mask) { - if(port) { - std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); - if(serialPort) { - _attention_acknowledge_level = !(value&0x10); - _data_level_output = (value&0x02); - - serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!(value&0x08)); - update_data_line(); - } - } - } - - void set_serial_line_state(::Commodore::Serial::Line line, bool value) { - switch(line) { - default: break; - case ::Commodore::Serial::Line::Data: _portB = (_portB & ~0x01) | (value ? 0x00 : 0x01); break; - case ::Commodore::Serial::Line::Clock: _portB = (_portB & ~0x04) | (value ? 0x00 : 0x04); break; - case ::Commodore::Serial::Line::Attention: - _attention_level_input = !value; - _portB = (_portB & ~0x80) | (value ? 0x00 : 0x80); - set_control_line_input(Port::A, Line::One, !value); - update_data_line(); - break; - } - } - - void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) { - _serialPort = serialPort; - } + void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort); private: uint8_t _portB; std::weak_ptr<::Commodore::Serial::Port> _serialPort; bool _attention_acknowledge_level, _attention_level_input, _data_level_output; - void update_data_line() - { - std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); - if(serialPort) { - // "ATN (Attention) is an input on pin 3 of P2 and P3 that is sensed at PB7 and CA1 of UC3 after being inverted by UA1" - serialPort->set_output(::Commodore::Serial::Line::Data, - (::Commodore::Serial::LineLevel)(!_data_level_output - && (_attention_level_input != _attention_acknowledge_level))); - } - } + void update_data_line(); }; /*! @@ -120,68 +79,22 @@ class DriveVIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { virtual void drive_via_did_step_head(void *driveVIA, int direction) = 0; virtual void drive_via_did_set_data_density(void *driveVIA, int density) = 0; }; - void set_delegate(Delegate *delegate) - { - _delegate = delegate; - } + void set_delegate(Delegate *delegate); using MOS6522IRQDelegate::set_interrupt_status; - // write protect tab uncovered - DriveVIA() : _port_b(0xff), _port_a(0xff), _delegate(nullptr) {} + DriveVIA(); - uint8_t get_port_input(Port port) { - return port ? _port_b : _port_a; - } + uint8_t get_port_input(Port port); - void set_sync_detected(bool sync_detected) { - _port_b = (_port_b & 0x7f) | (sync_detected ? 0x00 : 0x80); - } + void set_sync_detected(bool sync_detected); + void set_data_input(uint8_t value); + bool get_should_set_overflow(); + bool get_motor_enabled(); - void set_data_input(uint8_t value) { - _port_a = value; - } + void set_control_line_output(Port port, Line line, bool value); - bool get_should_set_overflow() { - return _should_set_overflow; - } - - bool get_motor_enabled() { - return _drive_motor; - } - - void set_control_line_output(Port port, Line line, bool value) { - if(port == Port::A && line == Line::Two) { - _should_set_overflow = value; - } - } - - void set_port_output(Port port, uint8_t value, uint8_t direction_mask) { - if(port) - { - // record drive motor state - _drive_motor = !!(value&4); - - // check for a head step - int step_difference = ((value&3) - (_previous_port_b_output&3))&3; - if(step_difference) - { - if(_delegate) _delegate->drive_via_did_step_head(this, (step_difference == 1) ? 1 : -1); - } - - // check for a change in density - int density_difference = (_previous_port_b_output^value) & (3 << 5); - if(density_difference && _delegate) - { - _delegate->drive_via_did_set_data_density(this, (value >> 5)&3); - } - - // TODO: something with the drive LED -// printf("LED: %s\n", value&8 ? "On" : "Off"); - - _previous_port_b_output = value; - } - } + void set_port_output(Port port, uint8_t value, uint8_t direction_mask); private: uint8_t _port_b, _port_a; @@ -196,14 +109,8 @@ class DriveVIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { */ class SerialPort : public ::Commodore::Serial::Port { public: - void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { - std::shared_ptr serialPortVIA = _serialPortVIA.lock(); - if(serialPortVIA) serialPortVIA->set_serial_line_state(line, (bool)level); - } - - void set_serial_port_via(std::shared_ptr serialPortVIA) { - _serialPortVIA = serialPortVIA; - } + void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level); + void set_serial_port_via(std::shared_ptr serialPortVIA); private: std::weak_ptr _serialPortVIA; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 78a63c13d..e72ff238f 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -474,3 +474,140 @@ bool Machine::typer_set_next_character(::Utility::Typer *typer, char character, return true; } +#pragma mark - UserPortVIA + +uint8_t UserPortVIA::get_port_input(Port port) +{ + if(!port) + { + return _portA; // TODO: bit 6 should be high if there is no tape, low otherwise + } + return 0xff; +} + +void UserPortVIA::set_control_line_output(Port port, Line line, bool value) +{ +// if(port == Port::A && line == Line::Two) { +// printf("Tape motor %s\n", value ? "on" : "off"); +// } +} + +void UserPortVIA::set_serial_line_state(::Commodore::Serial::Line line, bool value) +{ + switch(line) + { + default: break; + case ::Commodore::Serial::Line::Data: _portA = (_portA & ~0x02) | (value ? 0x02 : 0x00); break; + case ::Commodore::Serial::Line::Clock: _portA = (_portA & ~0x01) | (value ? 0x01 : 0x00); break; + } +} + +void UserPortVIA::set_joystick_state(JoystickInput input, bool value) +{ + if(input != JoystickInput::Right) + { + _portA = (_portA & ~input) | (value ? 0 : input); + } +} + +void UserPortVIA::set_port_output(Port port, uint8_t value, uint8_t mask) +{ + // Line 7 of port A is inverted and output as serial ATN + if(!port) + { + std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); + if(serialPort) + serialPort->set_output(::Commodore::Serial::Line::Attention, (::Commodore::Serial::LineLevel)!(value&0x80)); + } +} + +UserPortVIA::UserPortVIA() : _portA(0xbf) {} + +void UserPortVIA::set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) +{ + _serialPort = serialPort; +} + +#pragma mark - KeyboardVIA + +KeyboardVIA::KeyboardVIA() : _portB(0xff) +{ + clear_all_keys(); +} + +void KeyboardVIA::set_key_state(Key key, bool isPressed) +{ + if(isPressed) + _columns[key & 7] &= ~(key >> 3); + else + _columns[key & 7] |= (key >> 3); +} + +void KeyboardVIA::clear_all_keys() +{ + memset(_columns, 0xff, sizeof(_columns)); +} + +uint8_t KeyboardVIA::get_port_input(Port port) +{ + if(!port) + { + uint8_t result = 0xff; + for(int c = 0; c < 8; c++) + { + if(!(_activation_mask&(1 << c))) + result &= _columns[c]; + } + return result; + } + + return _portB; +} + +void KeyboardVIA::set_port_output(Port port, uint8_t value, uint8_t mask) +{ + if(port) + _activation_mask = (value & mask) | (~mask); +} + +void KeyboardVIA::set_control_line_output(Port port, Line line, bool value) +{ + if(line == Line::Two) + { + std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); + if(serialPort) + { + // CB2 is inverted to become serial data; CA2 is inverted to become serial clock + if(port == Port::A) + serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!value); + else + serialPort->set_output(::Commodore::Serial::Line::Data, (::Commodore::Serial::LineLevel)!value); + } + } +} + +void KeyboardVIA::set_joystick_state(JoystickInput input, bool value) +{ + if(input == JoystickInput::Right) + { + _portB = (_portB & ~input) | (value ? 0 : input); + } +} + +void KeyboardVIA::set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) +{ + _serialPort = serialPort; +} + +#pragma mark - SerialPort + +void SerialPort::set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) +{ + std::shared_ptr userPortVIA = _userPortVIA.lock(); + if(userPortVIA) userPortVIA->set_serial_line_state(line, (bool)level); +} + +void SerialPort::set_user_port_via(std::shared_ptr userPortVIA) +{ + _userPortVIA = userPortVIA; +} diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index f652bbdbe..8ee08f753 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -77,51 +77,16 @@ enum JoystickInput { class UserPortVIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { public: - uint8_t get_port_input(Port port) { - if(!port) { - return _portA; // TODO: bit 6 should be high if there is no tape, low otherwise - } - return 0xff; - } - - void set_control_line_output(Port port, Line line, bool value) { -// if(port == Port::A && line == Line::Two) { -// printf("Tape motor %s\n", value ? "on" : "off"); -// } - } - - void set_serial_line_state(::Commodore::Serial::Line line, bool value) { -// printf("VIC Serial port line %d: %s\n", line, value ? "on" : "off"); - switch(line) { - default: break; - case ::Commodore::Serial::Line::Data: _portA = (_portA & ~0x02) | (value ? 0x02 : 0x00); break; - case ::Commodore::Serial::Line::Clock: _portA = (_portA & ~0x01) | (value ? 0x01 : 0x00); break; - } - } - - void set_joystick_state(JoystickInput input, bool value) { - if(input != JoystickInput::Right) - { - _portA = (_portA & ~input) | (value ? 0 : input); - } - } - - void set_port_output(Port port, uint8_t value, uint8_t mask) { - // Line 7 of port A is inverted and output as serial ATN - if(!port) { - std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); - if(serialPort) - serialPort->set_output(::Commodore::Serial::Line::Attention, (::Commodore::Serial::LineLevel)!(value&0x80)); - } - } - + UserPortVIA(); using MOS6522IRQDelegate::set_interrupt_status; - UserPortVIA() : _portA(0xbf) {} + uint8_t get_port_input(Port port); + void set_control_line_output(Port port, Line line, bool value); + void set_serial_line_state(::Commodore::Serial::Line line, bool value); + void set_joystick_state(JoystickInput input, bool value); + void set_port_output(Port port, uint8_t value, uint8_t mask); - void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) { - _serialPort = serialPort; - } + void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort); private: uint8_t _portA; @@ -130,67 +95,21 @@ class UserPortVIA: public MOS::MOS6522, public MOS::MOS6522IRQDeleg class KeyboardVIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { public: - KeyboardVIA() : _portB(0xff) { - clear_all_keys(); - } - - void set_key_state(Key key, bool isPressed) { - if(isPressed) - _columns[key & 7] &= ~(key >> 3); - else - _columns[key & 7] |= (key >> 3); - } - - void clear_all_keys() { - memset(_columns, 0xff, sizeof(_columns)); - } - - // to satisfy MOS::MOS6522 - uint8_t get_port_input(Port port) { - if(!port) { - uint8_t result = 0xff; - for(int c = 0; c < 8; c++) - { - if(!(_activation_mask&(1 << c))) - result &= _columns[c]; - } - return result; - } - - return _portB; - } - - void set_port_output(Port port, uint8_t value, uint8_t mask) { - if(port) - _activation_mask = (value & mask) | (~mask); - } - - void set_control_line_output(Port port, Line line, bool value) { - if(line == Line::Two) { - std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock(); - if(serialPort) { - // CB2 is inverted to become serial data; CA2 is inverted to become serial clock - if(port == Port::A) { - serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!value); - } else { - serialPort->set_output(::Commodore::Serial::Line::Data, (::Commodore::Serial::LineLevel)!value); - } - } - } - } - - void set_joystick_state(JoystickInput input, bool value) { - if(input == JoystickInput::Right) - { - _portB = (_portB & ~input) | (value ? 0 : input); - } - } - + KeyboardVIA(); using MOS6522IRQDelegate::set_interrupt_status; - void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) { - _serialPort = serialPort; - } + void set_key_state(Key key, bool isPressed); + void clear_all_keys(); + + // to satisfy MOS::MOS6522 + uint8_t get_port_input(Port port); + + void set_port_output(Port port, uint8_t value, uint8_t mask); + void set_control_line_output(Port port, Line line, bool value); + + void set_joystick_state(JoystickInput input, bool value); + + void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort); private: uint8_t _portB; @@ -201,14 +120,8 @@ class KeyboardVIA: public MOS::MOS6522, public MOS::MOS6522IRQDeleg class SerialPort : public ::Commodore::Serial::Port { public: - void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { - std::shared_ptr userPortVIA = _userPortVIA.lock(); - if(userPortVIA) userPortVIA->set_serial_line_state(line, (bool)level); - } - - void set_user_port_via(std::shared_ptr userPortVIA) { - _userPortVIA = userPortVIA; - } + void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level); + void set_user_port_via(std::shared_ptr userPortVIA); private: std::weak_ptr _userPortVIA; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 5f0becc8a..4d4390442 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -122,3 +122,57 @@ void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player // set CB1 _via.set_control_line_input(VIA::Port::B, VIA::Line::One, tape_player->get_input()); } + +#pragma mark - The 6522 + +void Machine::VIA::set_control_line_output(Port port, Line line, bool value) +{ + if(line) + { + if(port) _ay_bdir = value; else _ay_bc1 = value; + update_ay(); + } +} + +void Machine::VIA::set_port_output(Port port, uint8_t value, uint8_t direction_mask) { + if(port) + { + keyboard->row = value; + tape->set_motor_control(value & 0x40); + } + else + { + ay8910->set_data_input(value); + } +} + +uint8_t Machine::VIA::get_port_input(Port port) { + if(port) + { + uint8_t column = ay8910->get_port_output(false) ^ 0xff; + return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00; + } + else + { + return ay8910->get_data_output(); + } +} + +void Machine::VIA::synchronise() +{ + ay8910->run_for_cycles(_half_cycles_since_ay_update >> 1); + _half_cycles_since_ay_update &= 1; +} + +void Machine::VIA::run_for_half_cycles(unsigned int number_of_cycles) +{ + _half_cycles_since_ay_update += number_of_cycles; + MOS::MOS6522::run_for_half_cycles(number_of_cycles); +} + +void Machine::VIA::update_ay() +{ + ay8910->run_for_cycles(_half_cycles_since_ay_update >> 1); + _half_cycles_since_ay_update &= 1; + ay8910->set_control_lines( (GI::AY38910::ControlLines)((_ay_bdir ? GI::AY38910::BCDIR : 0) | (_ay_bc1 ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2)); +} diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index d37a9429d..bcd55eebd 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -102,58 +102,19 @@ class Machine: public: using MOS6522IRQDelegate::set_interrupt_status; - void set_control_line_output(Port port, Line line, bool value) - { - if(line) - { - if(port) _ay_bdir = value; else _ay_bc1 = value; - update_ay(); - } - } - - void set_port_output(Port port, uint8_t value, uint8_t direction_mask) { - if(port) - { - keyboard->row = value; - tape->set_motor_control(value & 0x40); - } - else - { - ay8910->set_data_input(value); - } - } - - uint8_t get_port_input(Port port) { - if(port) - { - uint8_t column = ay8910->get_port_output(false) ^ 0xff; - return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00; - } - else - { - return ay8910->get_data_output(); - } - } - - inline void run_for_half_cycles(unsigned int number_of_cycles) - { - _half_cycles_since_ay_update += number_of_cycles; - MOS::MOS6522::run_for_half_cycles(number_of_cycles); - } + void set_control_line_output(Port port, Line line, bool value); + void set_port_output(Port port, uint8_t value, uint8_t direction_mask); + uint8_t get_port_input(Port port); + inline void run_for_half_cycles(unsigned int number_of_cycles); std::shared_ptr ay8910; std::shared_ptr tape; std::shared_ptr keyboard; - inline void synchronise() { ay8910->run_for_cycles(_half_cycles_since_ay_update >> 1); _half_cycles_since_ay_update = 0; } + void synchronise(); private: - void update_ay() - { - ay8910->run_for_cycles(_half_cycles_since_ay_update >> 1); - _half_cycles_since_ay_update = 0; - ay8910->set_control_lines( (GI::AY38910::ControlLines)((_ay_bdir ? GI::AY38910::BCDIR : 0) | (_ay_bc1 ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2)); - } + void update_ay(); bool _ay_bdir, _ay_bc1; unsigned int _half_cycles_since_ay_update; }; diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index d0283ffbe..90b48e160 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -93,3 +93,45 @@ void TapePlayer::process_next_event() process_input_pulse(_current_pulse); get_next_pulse(); } + +#pragma mark - Binary Player + +BinaryTapePlayer::BinaryTapePlayer(unsigned int input_clock_rate) : + TapePlayer(input_clock_rate), _motor_is_running(false) +{} + +void BinaryTapePlayer::set_motor_control(bool enabled) +{ + _motor_is_running = enabled; +} + +void BinaryTapePlayer::set_tape_output(bool set) +{ + // TODO +} + +bool BinaryTapePlayer::get_input() +{ + return _input_level; +} + +void BinaryTapePlayer::run_for_cycles(int number_of_cycles) +{ + if(_motor_is_running) TapePlayer::run_for_cycles(number_of_cycles); +} + +void BinaryTapePlayer::set_delegate(Delegate *delegate) +{ + _delegate = delegate; +} + +void BinaryTapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) +{ + bool new_input_level = pulse.type == Tape::Pulse::Low; + if(_input_level != new_input_level) + { + _input_level = new_input_level; + if(_delegate) _delegate->tape_did_change_input(this); + } +} + diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index fcf2b3d2a..7b1dd7b84 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -94,39 +94,32 @@ class TapePlayer: public TimedEventLoop { Tape::Pulse _current_pulse; }; +/*! + A specific subclass of the tape player for machines that sample such as to report only either a + high or a low current input level. + + Such machines can use @c get_input() to get the current level of the input. + + They can also provide a delegate to be notified upon any change in the input level. +*/ class BinaryTapePlayer: public TapePlayer { public: - BinaryTapePlayer(unsigned int input_clock_rate) : TapePlayer(input_clock_rate), _motor_is_running(false) {} - void set_motor_control(bool enabled) { _motor_is_running = enabled; } - void set_tape_output(bool set) {} // TODO - inline bool get_input() { return _input_level; } + BinaryTapePlayer(unsigned int input_clock_rate); + void set_motor_control(bool enabled); + void set_tape_output(bool set); + bool get_input(); - void run_for_cycles(int number_of_cycles) { - if(_motor_is_running) { - TapePlayer::run_for_cycles(number_of_cycles); - } - } + void run_for_cycles(int number_of_cycles); class Delegate { public: virtual void tape_did_change_input(BinaryTapePlayer *tape_player) = 0; }; - void set_delegate(Delegate *delegate) - { - _delegate = delegate; - } + void set_delegate(Delegate *delegate); private: Delegate *_delegate; - virtual void process_input_pulse(Storage::Tape::Tape::Pulse pulse) - { - bool new_input_level = pulse.type == Tape::Pulse::Low; - if(_input_level != new_input_level) - { - _input_level = new_input_level; - if(_delegate) _delegate->tape_did_change_input(this); - } - } + virtual void process_input_pulse(Storage::Tape::Tape::Pulse pulse); bool _input_level; bool _motor_is_running; };