mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-21 05:29:13 +00:00
Reduce repetitive dynamic work in 6522 usages.
This commit is contained in:
parent
b67bb50f4a
commit
f8e4023307
@ -33,15 +33,18 @@ enum Line {
|
||||
class PortHandler {
|
||||
public:
|
||||
/// Requests the current input value of the named port from the port handler.
|
||||
uint8_t get_port_input(Port) {
|
||||
template<Port port>
|
||||
uint8_t get_port_input() const {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/// Sets the current output value of the named oprt and provides @c direction_mask, indicating which pins are marked as output.
|
||||
void set_port_output(Port, [[maybe_unused]] uint8_t value, [[maybe_unused]] uint8_t direction_mask) {}
|
||||
template<Port port>
|
||||
void set_port_output([[maybe_unused]] uint8_t value, [[maybe_unused]] uint8_t direction_mask) {}
|
||||
|
||||
/// Sets the current logical output level for the named line on the specified port.
|
||||
void set_control_line_output(Port, Line, [[maybe_unused]] bool value) {}
|
||||
template<Port port, Line line>
|
||||
void set_control_line_output([[maybe_unused]] bool value) {}
|
||||
|
||||
/// Sets the current logical value of the interrupt line.
|
||||
void set_interrupt_status([[maybe_unused]] bool status) {}
|
||||
@ -101,7 +104,8 @@ public:
|
||||
BusHandlerT &bus_handler();
|
||||
|
||||
/// Sets the input value of the named line and port.
|
||||
void set_control_line_input(Port, Line, bool value);
|
||||
template<Port, Line>
|
||||
void set_control_line_input(bool value);
|
||||
|
||||
/// Runs for a specified number of half cycles.
|
||||
void run_for(const HalfCycles);
|
||||
@ -126,12 +130,13 @@ private:
|
||||
|
||||
void access(int address);
|
||||
|
||||
uint8_t get_port_input(Port port, uint8_t output_mask, uint8_t output, uint8_t timer_mask);
|
||||
template <Port> uint8_t get_port_input(uint8_t output_mask, uint8_t output, uint8_t timer_mask);
|
||||
template <Port port, int shift> void update_pcr(const uint8_t);
|
||||
inline void reevaluate_interrupts();
|
||||
|
||||
/// Sets the current intended output value for the port and line;
|
||||
/// if this affects the visible output, it will be passed to the handler.
|
||||
void set_control_line_output(Port port, Line line, LineState value);
|
||||
template <Port, Line> void set_control_line_output(LineState);
|
||||
void evaluate_cb2_output();
|
||||
void evaluate_port_b_output();
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ template <typename T> void MOS6522<T>::access(const int address) {
|
||||
case 0x0:
|
||||
// In both handshake and pulse modes, CB2 goes low on any read or write of Port B.
|
||||
if(handshake_modes_[1] != HandshakeMode::None) {
|
||||
set_control_line_output(Port::B, Line::Two, LineState::Off);
|
||||
set_control_line_output<Port::B, Line::Two>(LineState::Off);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -27,7 +27,7 @@ template <typename T> void MOS6522<T>::access(const int address) {
|
||||
case 0x1:
|
||||
// In both handshake and pulse modes, CA2 goes low on any read or write of Port A.
|
||||
if(handshake_modes_[0] != HandshakeMode::None) {
|
||||
set_control_line_output(Port::A, Line::Two, LineState::Off);
|
||||
set_control_line_output<Port::A, Line::Two>(LineState::Off);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -55,10 +55,10 @@ template <typename T> void MOS6522<T>::write(int address, const uint8_t value) {
|
||||
registers_.output[0] = value;
|
||||
|
||||
bus_handler_.run_for(time_since_bus_handler_call_.flush<HalfCycles>());
|
||||
bus_handler_.set_port_output(Port::A, value, registers_.data_direction[0]);
|
||||
bus_handler_.template set_port_output<Port::A>(value, registers_.data_direction[0]);
|
||||
|
||||
if(handshake_modes_[1] != HandshakeMode::None) {
|
||||
set_control_line_output(Port::A, Line::Two, LineState::Off);
|
||||
set_control_line_output<Port::A, Line::Two>(LineState::Off);
|
||||
}
|
||||
|
||||
registers_.interrupt_flags &= ~(
|
||||
@ -136,40 +136,8 @@ template <typename T> void MOS6522<T>::write(int address, const uint8_t value) {
|
||||
// const auto old_peripheral_control = registers_.peripheral_control;
|
||||
registers_.peripheral_control = value;
|
||||
|
||||
int shift = 0;
|
||||
for(int port = 0; port < 2; ++port) {
|
||||
handshake_modes_[port] = HandshakeMode::None;
|
||||
switch((value >> shift) & 0x0e) {
|
||||
default: break;
|
||||
|
||||
case 0x00: // Negative interrupt input; set Cx2 interrupt on negative Cx2 transition, clear on access to Port x register.
|
||||
case 0x02: // Independent negative interrupt input; set Cx2 interrupt on negative transition, don't clear automatically.
|
||||
case 0x04: // Positive interrupt input; set Cx2 interrupt on positive Cx2 transition, clear on access to Port x register.
|
||||
case 0x06: // Independent positive interrupt input; set Cx2 interrupt on positive transition, don't clear automatically.
|
||||
set_control_line_output(Port(port), Line::Two, LineState::Input);
|
||||
break;
|
||||
|
||||
case 0x08: // Handshake: set Cx2 to low on any read or write of Port x; set to high on an active transition of Cx1.
|
||||
handshake_modes_[port] = HandshakeMode::Handshake;
|
||||
set_control_line_output(Port(port), Line::Two, LineState::Off); // At a guess.
|
||||
break;
|
||||
|
||||
case 0x0a: // Pulse output: Cx2 is low for one cycle following a read or write of Port x.
|
||||
handshake_modes_[port] = HandshakeMode::Pulse;
|
||||
set_control_line_output(Port(port), Line::Two, LineState::On);
|
||||
break;
|
||||
|
||||
case 0x0c: // Manual output: Cx2 low.
|
||||
set_control_line_output(Port(port), Line::Two, LineState::Off);
|
||||
break;
|
||||
|
||||
case 0x0e: // Manual output: Cx2 high.
|
||||
set_control_line_output(Port(port), Line::Two, LineState::On);
|
||||
break;
|
||||
}
|
||||
|
||||
shift += 4;
|
||||
}
|
||||
update_pcr<Port::A, 0>(value);
|
||||
update_pcr<Port::B, 4>(value);
|
||||
} break;
|
||||
|
||||
// Interrupt control
|
||||
@ -187,6 +155,40 @@ template <typename T> void MOS6522<T>::write(int address, const uint8_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <Port port, int shift>
|
||||
void MOS6522<T>::update_pcr(const uint8_t value) {
|
||||
handshake_modes_[port] = HandshakeMode::None;
|
||||
switch((value >> shift) & 0x0e) {
|
||||
default: break;
|
||||
|
||||
case 0x00: // Negative interrupt input; set Cx2 interrupt on negative Cx2 transition, clear on access to Port x register.
|
||||
case 0x02: // Independent negative interrupt input; set Cx2 interrupt on negative transition, don't clear automatically.
|
||||
case 0x04: // Positive interrupt input; set Cx2 interrupt on positive Cx2 transition, clear on access to Port x register.
|
||||
case 0x06: // Independent positive interrupt input; set Cx2 interrupt on positive transition, don't clear automatically.
|
||||
set_control_line_output<port, Line::Two>(LineState::Input);
|
||||
break;
|
||||
|
||||
case 0x08: // Handshake: set Cx2 to low on any read or write of Port x; set to high on an active transition of Cx1.
|
||||
handshake_modes_[port] = HandshakeMode::Handshake;
|
||||
set_control_line_output<port, Line::Two>(LineState::Off); // At a guess.
|
||||
break;
|
||||
|
||||
case 0x0a: // Pulse output: Cx2 is low for one cycle following a read or write of Port x.
|
||||
handshake_modes_[port] = HandshakeMode::Pulse;
|
||||
set_control_line_output<port, Line::Two>(LineState::On);
|
||||
break;
|
||||
|
||||
case 0x0c: // Manual output: Cx2 low.
|
||||
set_control_line_output<port, Line::Two>(LineState::Off);
|
||||
break;
|
||||
|
||||
case 0x0e: // Manual output: Cx2 high.
|
||||
set_control_line_output<port, Line::Two>(LineState::On);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> uint8_t MOS6522<T>::read(int address) {
|
||||
address &= 0xf;
|
||||
access(address);
|
||||
@ -194,12 +196,12 @@ template <typename T> uint8_t MOS6522<T>::read(int address) {
|
||||
case 0x0: // Read Port B ('IRB').
|
||||
registers_.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | InterruptFlag::CB2ActiveEdge);
|
||||
reevaluate_interrupts();
|
||||
return get_port_input(Port::B, registers_.data_direction[1], registers_.output[1], registers_.auxiliary_control & 0x80);
|
||||
return get_port_input<Port::B>(registers_.data_direction[1], registers_.output[1], registers_.auxiliary_control & 0x80);
|
||||
case 0xf:
|
||||
case 0x1: // Read Port A ('IRA').
|
||||
registers_.interrupt_flags &= ~(InterruptFlag::CA1ActiveEdge | InterruptFlag::CA2ActiveEdge);
|
||||
reevaluate_interrupts();
|
||||
return get_port_input(Port::A, registers_.data_direction[0], registers_.output[0], 0);
|
||||
return get_port_input<Port::A>(registers_.data_direction[0], registers_.output[0], 0);
|
||||
|
||||
case 0x2: return registers_.data_direction[1]; // Port B direction ('DDRB').
|
||||
case 0x3: return registers_.data_direction[0]; // Port A direction ('DDRA').
|
||||
@ -236,14 +238,15 @@ template <typename T> uint8_t MOS6522<T>::read(int address) {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
template <typename T> uint8_t MOS6522<T>::get_port_input(
|
||||
const Port port,
|
||||
template <typename T>
|
||||
template <Port port>
|
||||
uint8_t MOS6522<T>::get_port_input(
|
||||
const uint8_t output_mask,
|
||||
uint8_t output,
|
||||
const uint8_t timer_mask
|
||||
) {
|
||||
bus_handler_.run_for(time_since_bus_handler_call_.flush<HalfCycles>());
|
||||
const uint8_t input = bus_handler_.get_port_input(port);
|
||||
const uint8_t input = bus_handler_.template get_port_input<port>();
|
||||
output = (output & ~timer_mask) | (registers_.timer_port_b_output & timer_mask);
|
||||
return (input & ~output_mask) | (output & output_mask);
|
||||
}
|
||||
@ -263,13 +266,15 @@ template <typename T> void MOS6522<T>::reevaluate_interrupts() {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void MOS6522<T>::set_control_line_input(const Port port, const Line line, const bool value) {
|
||||
template <typename T>
|
||||
template <Port port, Line line>
|
||||
void MOS6522<T>::set_control_line_input(const bool value) {
|
||||
switch(line) {
|
||||
case Line::One:
|
||||
if(value != control_inputs_[port].lines[line]) {
|
||||
// In handshake mode, any transition on C[A/B]1 sets output high on C[A/B]2.
|
||||
if(handshake_modes_[port] == HandshakeMode::Handshake) {
|
||||
set_control_line_output(port, Line::Two, LineState::On);
|
||||
set_control_line_output<port, Line::Two>(LineState::On);
|
||||
}
|
||||
|
||||
// Set the proper transition interrupt bit if enabled.
|
||||
@ -332,10 +337,10 @@ template <typename T> void MOS6522<T>::do_phase2() {
|
||||
|
||||
// In pulse modes, CA2 and CB2 go high again on the next clock edge.
|
||||
if(handshake_modes_[1] == HandshakeMode::Pulse) {
|
||||
set_control_line_output(Port::B, Line::Two, LineState::On);
|
||||
set_control_line_output<Port::B, Line::Two>(LineState::On);
|
||||
}
|
||||
if(handshake_modes_[0] == HandshakeMode::Pulse) {
|
||||
set_control_line_output(Port::A, Line::Two, LineState::On);
|
||||
set_control_line_output<Port::A, Line::Two>(LineState::On);
|
||||
}
|
||||
|
||||
// If the shift register is shifting according to the input clock, do a shift.
|
||||
@ -388,8 +393,7 @@ template <typename T> void MOS6522<T>::do_phase1() {
|
||||
template <typename T> void MOS6522<T>::evaluate_port_b_output() {
|
||||
// Apply current timer-linked PB7 output if any atop the stated output.
|
||||
const uint8_t timer_control_bit = registers_.auxiliary_control & 0x80;
|
||||
bus_handler_.set_port_output(
|
||||
Port::B,
|
||||
bus_handler_.template set_port_output<Port::B>(
|
||||
(registers_.output[1] & (0xff ^ timer_control_bit)) | timer_control_bit,
|
||||
registers_.data_direction[1] | timer_control_bit);
|
||||
}
|
||||
@ -448,19 +452,20 @@ template <typename T> void MOS6522<T>::evaluate_cb2_output() {
|
||||
// Shift register is enabled, one way or the other; but announce only output.
|
||||
if(is_shifting_out()) {
|
||||
// Output mode; set the level according to the current top of the shift register.
|
||||
bus_handler_.set_control_line_output(Port::B, Line::Two, !!(registers_.shift & 0x80));
|
||||
bus_handler_.template set_control_line_output<Port::B, Line::Two>(registers_.shift & 0x80);
|
||||
} else {
|
||||
// Input mode.
|
||||
bus_handler_.set_control_line_output(Port::B, Line::Two, true);
|
||||
bus_handler_.template set_control_line_output<Port::B, Line::Two>(true);
|
||||
}
|
||||
} else {
|
||||
// Shift register is disabled.
|
||||
bus_handler_.set_control_line_output(Port::B, Line::Two, control_outputs_[1].lines[1] != LineState::Off);
|
||||
bus_handler_.template set_control_line_output<Port::B, Line::Two>(control_outputs_[1].lines[1] != LineState::Off);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MOS6522<T>::set_control_line_output(const Port port, const Line line, const LineState value) {
|
||||
template <Port port, Line line>
|
||||
void MOS6522<T>::set_control_line_output(const LineState value) {
|
||||
if(port == Port::B && line == Line::Two) {
|
||||
control_outputs_[port].lines[line] = value;
|
||||
evaluate_cb2_output();
|
||||
@ -474,7 +479,7 @@ void MOS6522<T>::set_control_line_output(const Port port, const Line line, const
|
||||
|
||||
if(value != LineState::Input) {
|
||||
bus_handler_.run_for(time_since_bus_handler_call_.flush<HalfCycles>());
|
||||
bus_handler_.set_control_line_output(port, line, value != LineState::Off);
|
||||
bus_handler_.template set_control_line_output<port, line>(value != LineState::Off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,8 @@ private:
|
||||
card.did_change_interrupt_flags();
|
||||
}
|
||||
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
void set_port_output(const uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
using ControlLines = GI::AY38910::ControlLines;
|
||||
ay.set_control_lines(
|
||||
@ -116,7 +117,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t get_port_input(MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
uint8_t get_port_input() const {
|
||||
if(!port) {
|
||||
return ay.get_data_output();
|
||||
}
|
||||
|
@ -579,7 +579,7 @@ private:
|
||||
time_since_video_update_ -= time_until_video_event_;
|
||||
time_until_video_event_ = video_.next_sequence_point();
|
||||
|
||||
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !video_.vsync());
|
||||
via_.template set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::One>(!video_.vsync());
|
||||
}
|
||||
|
||||
via_clock_ += via_cycles_outstanding;
|
||||
@ -592,8 +592,8 @@ private:
|
||||
if(keyboard_clock_ >= KEYBOARD_CLOCK_RATE) {
|
||||
const auto keyboard_ticks = keyboard_clock_.divide(KEYBOARD_CLOCK_RATE);
|
||||
keyboard_.run_for(keyboard_ticks);
|
||||
via_.set_control_line_input(MOS::MOS6522::Port::B, MOS::MOS6522::Line::Two, keyboard_.get_data());
|
||||
via_.set_control_line_input(MOS::MOS6522::Port::B, MOS::MOS6522::Line::One, keyboard_.get_clock());
|
||||
via_.template set_control_line_input<MOS::MOS6522::Port::B, MOS::MOS6522::Line::Two>(keyboard_.get_data());
|
||||
via_.template set_control_line_input<MOS::MOS6522::Port::B, MOS::MOS6522::Line::One>(keyboard_.get_clock());
|
||||
}
|
||||
|
||||
// Feed mouse inputs within at most 1250 cycles of each other.
|
||||
@ -616,8 +616,8 @@ private:
|
||||
while(ticks--) {
|
||||
clock_.update();
|
||||
// TODO: leave a delay between toggling the input rather than using this coupled hack.
|
||||
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two, true);
|
||||
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two, false);
|
||||
via_.template set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two>(true);
|
||||
via_.template set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two>(false);
|
||||
}
|
||||
|
||||
// Update the SCSI if currently active.
|
||||
@ -645,7 +645,7 @@ private:
|
||||
using Port = MOS::MOS6522::Port;
|
||||
using Line = MOS::MOS6522::Line;
|
||||
|
||||
void set_port_output(Port port, uint8_t value, uint8_t) {
|
||||
template <Port port> void set_port_output(const uint8_t value, uint8_t) {
|
||||
/*
|
||||
Peripheral lines: keyboard data, interrupt configuration.
|
||||
(See p176 [/215])
|
||||
@ -691,7 +691,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t get_port_input(Port port) {
|
||||
template <Port port> uint8_t get_port_input() const {
|
||||
switch(port) {
|
||||
case Port::A:
|
||||
// printf("6522 r A\n");
|
||||
@ -711,7 +711,7 @@ private:
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void set_control_line_output(Port port, Line line, bool value) {
|
||||
template <Port port, Line line> void set_control_line_output(const bool value) {
|
||||
/*
|
||||
Keyboard wiring (I believe):
|
||||
CB2 = data (input/output)
|
||||
|
@ -162,12 +162,14 @@ void MachineBase::drive_via_did_set_data_density(void *, const int density) {
|
||||
|
||||
// MARK: - SerialPortVIA
|
||||
|
||||
uint8_t SerialPortVIA::get_port_input(MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
uint8_t SerialPortVIA::get_port_input() const {
|
||||
if(port) return port_b_;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void SerialPortVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
void SerialPortVIA::set_port_output(const uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
attention_acknowledge_level_ = !(value&0x10);
|
||||
data_level_output_ = (value&0x02);
|
||||
@ -178,8 +180,8 @@ void SerialPortVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint
|
||||
}
|
||||
|
||||
void SerialPortVIA::set_serial_line_state(
|
||||
::Commodore::Serial::Line line,
|
||||
bool value,
|
||||
const Commodore::Serial::Line line,
|
||||
const bool value,
|
||||
MOS::MOS6522::MOS6522<SerialPortVIA> &via
|
||||
) {
|
||||
switch(line) {
|
||||
@ -189,7 +191,7 @@ void SerialPortVIA::set_serial_line_state(
|
||||
case ::Commodore::Serial::Line::Attention:
|
||||
attention_level_input_ = !value;
|
||||
port_b_ = (port_b_ & ~0x80) | (value ? 0x00 : 0x80);
|
||||
via.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !value);
|
||||
via.set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::One>(!value);
|
||||
update_data_line();
|
||||
break;
|
||||
}
|
||||
@ -212,11 +214,12 @@ void DriveVIA::set_delegate(Delegate *delegate) {
|
||||
}
|
||||
|
||||
// write protect tab uncovered
|
||||
uint8_t DriveVIA::get_port_input(MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
uint8_t DriveVIA::get_port_input() const {
|
||||
return port ? port_b_ : port_a_;
|
||||
}
|
||||
|
||||
void DriveVIA::set_sync_detected(bool sync_detected) {
|
||||
void DriveVIA::set_sync_detected(const bool sync_detected) {
|
||||
port_b_ = (port_b_ & 0x7f) | (sync_detected ? 0x00 : 0x80);
|
||||
}
|
||||
|
||||
@ -232,13 +235,15 @@ bool DriveVIA::get_motor_enabled() {
|
||||
return drive_motor_;
|
||||
}
|
||||
|
||||
void DriveVIA::set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) {
|
||||
template <MOS::MOS6522::Port port, MOS::MOS6522::Line line>
|
||||
void DriveVIA::set_control_line_output(const bool value) {
|
||||
if(port == MOS::MOS6522::Port::A && line == MOS::MOS6522::Line::Two) {
|
||||
should_set_overflow_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
void DriveVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
template <MOS::MOS6522::Port port>
|
||||
void DriveVIA::set_port_output(const uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
if(previous_port_b_output_ != value) {
|
||||
// Record drive motor state.
|
||||
@ -275,6 +280,7 @@ void DriveVIA::set_activity_observer(Activity::Observer *observer) {
|
||||
// MARK: - SerialPort
|
||||
|
||||
void SerialPort::set_input(Serial::Line line, Serial::LineLevel level) {
|
||||
// TODO: add dynamic.
|
||||
serial_port_via_->set_serial_line_state(line, bool(level), *via_);
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,13 @@ namespace Commodore::C1540 {
|
||||
*/
|
||||
class SerialPortVIA: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
public:
|
||||
uint8_t get_port_input(MOS::MOS6522::Port);
|
||||
template <MOS::MOS6522::Port>
|
||||
uint8_t get_port_input() const;
|
||||
|
||||
void set_port_output(MOS::MOS6522::Port, uint8_t value, uint8_t mask);
|
||||
void set_serial_line_state(::Commodore::Serial::Line, bool, MOS::MOS6522::MOS6522<SerialPortVIA> &);
|
||||
template <MOS::MOS6522::Port>
|
||||
void set_port_output(uint8_t value, uint8_t mask);
|
||||
|
||||
void set_serial_line_state(Commodore::Serial::Line, bool, MOS::MOS6522::MOS6522<SerialPortVIA> &);
|
||||
|
||||
void set_serial_port(Commodore::Serial::Port &);
|
||||
|
||||
@ -56,6 +59,13 @@ private:
|
||||
void update_data_line();
|
||||
};
|
||||
|
||||
//inline void set_serial_line_state(Commodore::Serial::Line line bool value, MOS::MOS6522::MOS6522<SerialPortVIA> &via) {
|
||||
// switch(line){
|
||||
// case Commodore::Serial::Line::One:
|
||||
// via.set_serial_line_state<Commodore::Serial::Line::One>(value, via);
|
||||
// }
|
||||
//}
|
||||
|
||||
/*!
|
||||
An implementation of the drive VIA in a Commodore 1540: the VIA that is used to interface with the disk.
|
||||
|
||||
@ -81,16 +91,19 @@ public:
|
||||
};
|
||||
void set_delegate(Delegate *);
|
||||
|
||||
uint8_t get_port_input(MOS::MOS6522::Port);
|
||||
template <MOS::MOS6522::Port>
|
||||
uint8_t get_port_input() const;
|
||||
|
||||
void set_sync_detected(bool);
|
||||
void set_data_input(uint8_t);
|
||||
bool get_should_set_overflow();
|
||||
bool get_motor_enabled();
|
||||
|
||||
void set_control_line_output(MOS::MOS6522::Port, MOS::MOS6522::Line, bool value);
|
||||
template <MOS::MOS6522::Port, MOS::MOS6522::Line>
|
||||
void set_control_line_output(bool value);
|
||||
|
||||
void set_port_output(MOS::MOS6522::Port, uint8_t value, uint8_t direction_mask);
|
||||
template <MOS::MOS6522::Port>
|
||||
void set_port_output(uint8_t value, uint8_t direction_mask);
|
||||
|
||||
void set_activity_observer(Activity::Observer *);
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
/*!
|
||||
Called by the bus to signal a change in any input line level. Subclasses should implement this.
|
||||
*/
|
||||
virtual void set_input(Line line, LineLevel value) = 0;
|
||||
virtual void set_input(Line, LineLevel) = 0;
|
||||
|
||||
/*!
|
||||
Sets the supplied serial bus as that to which line levels will be communicated.
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
UserPortVIA() : port_a_(0xbf) {}
|
||||
|
||||
/// Reports the current input to the 6522 port @c port.
|
||||
uint8_t get_port_input(const MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port> uint8_t get_port_input() const {
|
||||
// Port A provides information about the presence or absence of a tape, and parts of
|
||||
// the joystick and serial port state, both of which have been statefully collected
|
||||
// into port_a_.
|
||||
@ -79,7 +79,7 @@ public:
|
||||
}
|
||||
|
||||
/// Receives announcements of control line output change from the 6522.
|
||||
void set_control_line_output(const MOS::MOS6522::Port port, const MOS::MOS6522::Line line, const bool value) {
|
||||
template <MOS::MOS6522::Port port, MOS::MOS6522::Line line> void set_control_line_output(const bool value) {
|
||||
// The CA2 output is used to control the tape motor.
|
||||
if(port == MOS::MOS6522::Port::A && line == MOS::MOS6522::Line::Two) {
|
||||
tape_->set_motor_control(!value);
|
||||
@ -87,7 +87,7 @@ public:
|
||||
}
|
||||
|
||||
/// Receives announcements of changes in the serial bus connected to the serial port and propagates them into Port A.
|
||||
void set_serial_line_state(const ::Commodore::Serial::Line line, const bool value) {
|
||||
void set_serial_line_state(Commodore::Serial::Line line, const bool value) {
|
||||
switch(line) {
|
||||
default: break;
|
||||
case ::Commodore::Serial::Line::Data: port_a_ = (port_a_ & ~0x02) | (value ? 0x02 : 0x00); break;
|
||||
@ -103,7 +103,7 @@ public:
|
||||
}
|
||||
|
||||
/// Receives announcements from the 6522 of user-port output, which might affect what's currently being presented onto the serial bus.
|
||||
void set_port_output(const MOS::MOS6522::Port port, const uint8_t value, uint8_t) {
|
||||
template <MOS::MOS6522::Port port> void set_port_output(const uint8_t value, uint8_t) {
|
||||
// Line 7 of port A is inverted and output as serial ATN.
|
||||
if(!port) {
|
||||
serial_port_->set_output(Serial::Line::Attention, Serial::LineLevel(!(value&0x80)));
|
||||
@ -150,7 +150,7 @@ public:
|
||||
}
|
||||
|
||||
/// Called by the 6522 to get input. Reads the keyboard on Port A, returns a small amount of joystick state on Port B.
|
||||
uint8_t get_port_input(const MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port> uint8_t get_port_input() const {
|
||||
if(!port) {
|
||||
uint8_t result = 0xff;
|
||||
for(int c = 0; c < 8; c++) {
|
||||
@ -164,12 +164,12 @@ public:
|
||||
}
|
||||
|
||||
/// Called by the 6522 to set output. The value of Port B selects which part of the keyboard to read.
|
||||
void set_port_output(const MOS::MOS6522::Port port, const uint8_t value, const uint8_t mask) {
|
||||
template <MOS::MOS6522::Port port> void set_port_output(const uint8_t value, const uint8_t mask) {
|
||||
if(port) activation_mask_ = (value & mask) | (~mask);
|
||||
}
|
||||
|
||||
/// Called by the 6522 to set control line output. Which affects the serial port.
|
||||
void set_control_line_output(const MOS::MOS6522::Port port, const MOS::MOS6522::Line line, const bool value) {
|
||||
template <MOS::MOS6522::Port port, MOS::MOS6522::Line line> void set_control_line_output(const bool value) {
|
||||
if(line == MOS::MOS6522::Line::Two) {
|
||||
// CB2 is inverted to become serial data; CA2 is inverted to become serial clock
|
||||
if(port == MOS::MOS6522::Port::A)
|
||||
@ -469,7 +469,7 @@ public:
|
||||
} else {
|
||||
switch(key) {
|
||||
case KeyRestore:
|
||||
user_port_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !is_pressed);
|
||||
user_port_via_.set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::One>(!is_pressed);
|
||||
break;
|
||||
#define ShiftedMap(source, target) \
|
||||
case source: \
|
||||
@ -694,7 +694,7 @@ public:
|
||||
}
|
||||
|
||||
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *const tape) final {
|
||||
keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->input());
|
||||
keyboard_via_.set_control_line_input<MOS::MOS6522::Port::A, MOS::MOS6522::Line::One>(!tape->input());
|
||||
}
|
||||
|
||||
KeyboardMapper *get_keyboard_mapper() final {
|
||||
|
@ -193,7 +193,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
Reponds to the 6522's control line output change signal; on an Oric A2 is connected to
|
||||
the AY's BDIR, and B2 is connected to the AY's A2.
|
||||
*/
|
||||
void set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) {
|
||||
template <MOS::MOS6522::Port port, MOS::MOS6522::Line line> void set_control_line_output(const bool value) {
|
||||
if(line) {
|
||||
if(port) ay_bdir_ = value; else ay_bc1_ = value;
|
||||
update_ay();
|
||||
@ -205,7 +205,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
Reponds to changes in the 6522's port output. On an Oric port B sets the tape motor control
|
||||
and the keyboard's active row. Port A is connected to the AY's data bus.
|
||||
*/
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
template <MOS::MOS6522::Port port> void set_port_output(uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
keyboard_.set_active_row(value);
|
||||
tape_player_.set_motor_control(value & 0x40);
|
||||
@ -219,7 +219,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
/*!
|
||||
Provides input data for the 6522. Port B reads the keyboard, and port A reads from the AY.
|
||||
*/
|
||||
uint8_t get_port_input(MOS::MOS6522::Port port) {
|
||||
template <MOS::MOS6522::Port port> uint8_t get_port_input() const {
|
||||
if(port) {
|
||||
uint8_t column = ay8910_.get_port_output(false) ^ 0xff;
|
||||
return keyboard_.query_column(column) ? 0x08 : 0x00;
|
||||
@ -630,8 +630,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
|
||||
|
||||
void set_via_port_b_input() {
|
||||
// set CB1
|
||||
via_.set_control_line_input(
|
||||
MOS::MOS6522::Port::B, MOS::MOS6522::Line::One,
|
||||
via_.set_control_line_input<MOS::MOS6522::Port::B, MOS::MOS6522::Line::One>(
|
||||
tape_player_.motor_control() ?
|
||||
!tape_player_.input() :
|
||||
!video_->vsync()
|
||||
@ -811,7 +810,8 @@ using namespace Oric;
|
||||
|
||||
namespace {
|
||||
|
||||
template <CPU::MOS6502Esque::Type processor> std::unique_ptr<Machine> machine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) {
|
||||
template <CPU::MOS6502Esque::Type processor>
|
||||
std::unique_ptr<Machine> machine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) {
|
||||
switch(target.disk_interface) {
|
||||
default: return std::make_unique<ConcreteMachine<DiskInterface::None, processor>>(target, rom_fetcher);
|
||||
case DiskInterface::Microdisc: return std::make_unique<ConcreteMachine<DiskInterface::Microdisc, processor>>(target, rom_fetcher);
|
||||
|
Loading…
x
Reference in New Issue
Block a user