mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 16:31:31 +00:00
Merge pull request #39 from TomHarte/1540
Starts work on the serial bus and preparatory work for a 1540 emulation
This commit is contained in:
commit
cf83258eaf
@ -10,6 +10,7 @@
|
||||
#define _522_hpp
|
||||
|
||||
#include <cstdint>
|
||||
#include <typeinfo>
|
||||
#include <cstdio>
|
||||
|
||||
namespace MOS {
|
||||
@ -52,14 +53,14 @@ template <class T> class MOS6522 {
|
||||
inline void set_register(int address, uint8_t value)
|
||||
{
|
||||
address &= 0xf;
|
||||
// printf("6522 %p: %d <- %02x\n", this, address, value);
|
||||
// printf("6522 [%s]: %0x <- %02x\n", typeid(*this).name(), address, value);
|
||||
switch(address)
|
||||
{
|
||||
case 0x0:
|
||||
_registers.output[1] = value;
|
||||
static_cast<T *>(this)->set_port_output(Port::B, value, _registers.data_direction[1]); // TODO: handshake
|
||||
|
||||
_registers.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | InterruptFlag::CB2ActiveEdge);
|
||||
_registers.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | ((_registers.peripheral_control&0x20) ? 0 : InterruptFlag::CB2ActiveEdge));
|
||||
reevaluate_interrupts();
|
||||
break;
|
||||
case 0xf:
|
||||
@ -67,7 +68,7 @@ template <class T> class MOS6522 {
|
||||
_registers.output[0] = value;
|
||||
static_cast<T *>(this)->set_port_output(Port::A, value, _registers.data_direction[0]); // TODO: handshake
|
||||
|
||||
_registers.interrupt_flags &= ~(InterruptFlag::CA1ActiveEdge | InterruptFlag::CA2ActiveEdge);
|
||||
_registers.interrupt_flags &= ~(InterruptFlag::CA1ActiveEdge | ((_registers.peripheral_control&0x02) ? 0 : InterruptFlag::CB2ActiveEdge));
|
||||
reevaluate_interrupts();
|
||||
break;
|
||||
// // No handshake, so write directly
|
||||
@ -114,17 +115,25 @@ template <class T> class MOS6522 {
|
||||
case 0xc:
|
||||
// printf("Peripheral control %02x\n", value);
|
||||
_registers.peripheral_control = value;
|
||||
switch(value & 0x0e)
|
||||
|
||||
// TODO: simplify below; trying to avoid improper logging of unimplemented warnings in input mode
|
||||
if(value & 0x08)
|
||||
{
|
||||
default: printf("Unimplemented control line mode %d\n", (value >> 1)&7); break;
|
||||
case 0x0c: static_cast<T *>(this)->set_control_line_output(Port::A, Line::Two, false); break;
|
||||
case 0x0e: static_cast<T *>(this)->set_control_line_output(Port::A, Line::Two, true); break;
|
||||
switch(value & 0x0e)
|
||||
{
|
||||
default: printf("Unimplemented control line mode %d\n", (value >> 1)&7); break;
|
||||
case 0x0c: static_cast<T *>(this)->set_control_line_output(Port::A, Line::Two, false); break;
|
||||
case 0x0e: static_cast<T *>(this)->set_control_line_output(Port::A, Line::Two, true); break;
|
||||
}
|
||||
}
|
||||
switch(value & 0xe0)
|
||||
if(value & 0x80)
|
||||
{
|
||||
default: printf("Unimplemented control line mode %d\n", (value >> 5)&7); break;
|
||||
case 0xc0: static_cast<T *>(this)->set_control_line_output(Port::B, Line::Two, false); break;
|
||||
case 0xe0: static_cast<T *>(this)->set_control_line_output(Port::B, Line::Two, true); break;
|
||||
switch(value & 0xe0)
|
||||
{
|
||||
default: printf("Unimplemented control line mode %d\n", (value >> 5)&7); break;
|
||||
case 0xc0: static_cast<T *>(this)->set_control_line_output(Port::B, Line::Two, false); break;
|
||||
case 0xe0: static_cast<T *>(this)->set_control_line_output(Port::B, Line::Two, true); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -207,7 +216,16 @@ template <class T> class MOS6522 {
|
||||
break;
|
||||
|
||||
case Line::Two:
|
||||
// TODO
|
||||
// TODO: output modes, but probably elsewhere?
|
||||
if( value != _control_inputs[port].line_two && // i.e. value has changed ...
|
||||
!(_registers.peripheral_control & (port ? 0x80 : 0x08)) && // ... and line is input ...
|
||||
value == !!(_registers.peripheral_control & (port ? 0x40 : 0x04)) // ... and it's either high or low, as required
|
||||
)
|
||||
{
|
||||
_registers.interrupt_flags |= port ? InterruptFlag::CB2ActiveEdge : InterruptFlag::CA2ActiveEdge;
|
||||
reevaluate_interrupts();
|
||||
}
|
||||
_control_inputs[port].line_two = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -284,9 +302,8 @@ template <class T> class MOS6522 {
|
||||
// Expected to be overridden
|
||||
uint8_t get_port_input(Port port) { return 0xff; }
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask) {}
|
||||
bool get_control_line(Port port, Line line) { return true; }
|
||||
void set_control_line_output(Port port, Line line, bool value) {}
|
||||
void set_interrupt_status(bool status) {}
|
||||
void set_interrupt_status(bool status) {}
|
||||
|
||||
// Input/output multiplexer
|
||||
uint8_t get_port_input(Port port, uint8_t output_mask, uint8_t output)
|
||||
|
100
Machines/Commodore/1540/C1540.cpp
Normal file
100
Machines/Commodore/1540/C1540.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
//
|
||||
// Commodore1540.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "C1540.hpp"
|
||||
#include <string.h>
|
||||
|
||||
using namespace Commodore::C1540;
|
||||
|
||||
Machine::Machine()
|
||||
{
|
||||
// create a serial port and a VIA to run it
|
||||
_serialPortVIA.reset(new SerialPortVIA);
|
||||
_serialPort.reset(new SerialPort);
|
||||
|
||||
// attach the serial port to its VIA and vice versa
|
||||
_serialPort->set_serial_port_via(_serialPortVIA);
|
||||
_serialPortVIA->set_serial_port(_serialPort);
|
||||
|
||||
// set this instance as the delegate to receive interrupt requests from both VIAs
|
||||
_serialPortVIA->set_delegate(this);
|
||||
_driveVIA.set_delegate(this);
|
||||
}
|
||||
|
||||
void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus)
|
||||
{
|
||||
Commodore::Serial::AttachPortAndBus(_serialPort, serial_bus);
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
// if(operation == CPU6502::BusOperation::ReadOpcode && (address >= 0xF556 && address <= 0xF56D)) printf("%04x\n", address);
|
||||
// if(operation == CPU6502::BusOperation::ReadOpcode && (address == 0xE887)) printf("A: %02x\n", get_value_of_register(CPU6502::Register::A));
|
||||
|
||||
/* static bool log = false;
|
||||
|
||||
if(operation == CPU6502::BusOperation::ReadOpcode)
|
||||
{
|
||||
log = (address >= 0xE85B && address <= 0xE907) || (address >= 0xE9C9 && address <= 0xEA2D);
|
||||
if(log) printf("\n%04x: ", address);
|
||||
}
|
||||
if(log) printf("[%c %04x] ", isReadOperation(operation) ? 'r' : 'w', address);*/
|
||||
|
||||
/*
|
||||
Memory map (given that I'm unsure yet on any potential mirroring):
|
||||
|
||||
0x0000–0x07ff RAM
|
||||
0x1800–0x180f the serial-port VIA
|
||||
0x1c00–0x1c0f the drive VIA
|
||||
0xc000–0xffff ROM
|
||||
*/
|
||||
if(address < 0x800)
|
||||
{
|
||||
if(isReadOperation(operation))
|
||||
*value = _ram[address];
|
||||
else
|
||||
_ram[address] = *value;
|
||||
}
|
||||
else if(address >= 0xc000)
|
||||
{
|
||||
if(isReadOperation(operation))
|
||||
*value = _rom[address & 0x3fff];
|
||||
}
|
||||
else if(address >= 0x1800 && address <= 0x180f)
|
||||
{
|
||||
if(isReadOperation(operation))
|
||||
*value = _serialPortVIA->get_register(address);
|
||||
else
|
||||
_serialPortVIA->set_register(address, *value);
|
||||
}
|
||||
else if(address >= 0x1c00 && address <= 0x1c0f)
|
||||
{
|
||||
if(isReadOperation(operation))
|
||||
*value = _driveVIA.get_register(address);
|
||||
else
|
||||
_driveVIA.set_register(address, *value);
|
||||
}
|
||||
|
||||
_serialPortVIA->run_for_half_cycles(2);
|
||||
_driveVIA.run_for_half_cycles(2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Machine::set_rom(const uint8_t *rom)
|
||||
{
|
||||
memcpy(_rom, rom, sizeof(_rom));
|
||||
}
|
||||
|
||||
#pragma mark - 6522 delegate
|
||||
|
||||
void Machine::mos6522_did_change_interrupt_status(void *mos6522)
|
||||
{
|
||||
// both VIAs are connected to the IRQ line
|
||||
set_irq_line(_serialPortVIA->get_interrupt_line() || _driveVIA.get_interrupt_line());
|
||||
}
|
194
Machines/Commodore/1540/C1540.hpp
Normal file
194
Machines/Commodore/1540/C1540.hpp
Normal file
@ -0,0 +1,194 @@
|
||||
//
|
||||
// Commodore1540.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Commodore1540_hpp
|
||||
#define Commodore1540_hpp
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
#include "../SerialBus.hpp"
|
||||
|
||||
namespace Commodore {
|
||||
namespace C1540 {
|
||||
|
||||
/*!
|
||||
An implementation of the serial-port VIA in a Commodore 1540 — the VIA that facilitates all
|
||||
IEC bus communications.
|
||||
|
||||
It is wired up such that Port B contains:
|
||||
Bit 0: data input; 1 if the line is low, 0 if it is high;
|
||||
Bit 1: data output; 1 if the line should be low, 0 if it should be high;
|
||||
Bit 2: clock input; 1 if the line is low, 0 if it is high;
|
||||
Bit 3: clock output; 1 if the line is low, 0 if it is high;
|
||||
Bit 4: attention acknowledge output; exclusive ORd with the attention input and ORd onto the data output;
|
||||
Bits 5/6: device select input; the 1540 will act as device 8 + [value of bits]
|
||||
Bit 7: attention input; 1 if the line is low, 0 if it is high
|
||||
|
||||
The attention input is also connected to CA1, similarly inverted — the CA1 wire will be high when the bus is low and vice versa.
|
||||
*/
|
||||
class SerialPortVIA: public MOS::MOS6522<SerialPortVIA>, public MOS::MOS6522IRQDelegate {
|
||||
public:
|
||||
using MOS6522IRQDelegate::set_interrupt_status;
|
||||
|
||||
SerialPortVIA() : _portB(0x00), _attention_acknowledge_level(false), _attention_level_input(true), _data_level_output(false) {}
|
||||
|
||||
uint8_t get_port_input(Port port) {
|
||||
if(port) {
|
||||
return _portB;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
An implementation of the drive VIA in a Commodore 1540 — the VIA that is used to interface with the disk.
|
||||
|
||||
It is wired up such that Port B contains:
|
||||
Bits 0/1: head step direction (TODO)
|
||||
Bit 2: motor control (TODO)
|
||||
Bit 3: LED control (TODO)
|
||||
Bit 4: write protect photocell status (TODO)
|
||||
Bits 5/6: write density (TODO)
|
||||
Bit 7: 0 if sync marks are currently being detected, 1 otherwise;
|
||||
|
||||
... and Port A contains the byte most recently read from the disk or the byte next to write to the disk, depending on data direction.
|
||||
|
||||
It is implied that CA2 might be used to set processor overflow, CA1 a strobe for data input, and one of the CBs being definitive on
|
||||
whether the disk head is being told to read or write, but it's unclear and I've yet to investigate. So, TODO.
|
||||
*/
|
||||
class DriveVIA: public MOS::MOS6522<DriveVIA>, public MOS::MOS6522IRQDelegate {
|
||||
public:
|
||||
using MOS6522IRQDelegate::set_interrupt_status;
|
||||
|
||||
uint8_t get_port_input(Port port) {
|
||||
if(port)
|
||||
{
|
||||
return 0xff; // imply not sync, write protect tab uncovered
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask) {
|
||||
if(port)
|
||||
{
|
||||
// if(value&4)
|
||||
// {
|
||||
// printf("Head step: %d\n", value&3);
|
||||
// printf("Motor: %s\n", value&4 ? "On" : "Off");
|
||||
// printf("LED: %s\n", value&8 ? "On" : "Off");
|
||||
// printf("Density: %d\n", (value >> 5)&3);
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
An implementation of the C1540's serial port; this connects incoming line levels to the serial-port VIA.
|
||||
*/
|
||||
class SerialPort : public ::Commodore::Serial::Port {
|
||||
public:
|
||||
void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) {
|
||||
std::shared_ptr<SerialPortVIA> serialPortVIA = _serialPortVIA.lock();
|
||||
if(serialPortVIA) serialPortVIA->set_serial_line_state(line, (bool)level);
|
||||
}
|
||||
|
||||
void set_serial_port_via(std::shared_ptr<SerialPortVIA> serialPortVIA) {
|
||||
_serialPortVIA = serialPortVIA;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<SerialPortVIA> _serialPortVIA;
|
||||
};
|
||||
|
||||
/*!
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public MOS::MOS6522IRQDelegate::Delegate {
|
||||
|
||||
public:
|
||||
Machine();
|
||||
|
||||
/*!
|
||||
Sets the ROM image to use for this drive; it is assumed that the buffer provided will be at least 16 kb in size.
|
||||
*/
|
||||
void set_rom(const uint8_t *rom);
|
||||
|
||||
/*!
|
||||
Sets the serial bus to which this drive should attach itself.
|
||||
*/
|
||||
void set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
||||
private:
|
||||
uint8_t _ram[0x800];
|
||||
uint8_t _rom[0x4000];
|
||||
|
||||
std::shared_ptr<SerialPortVIA> _serialPortVIA;
|
||||
std::shared_ptr<SerialPort> _serialPort;
|
||||
DriveVIA _driveVIA;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Commodore1540_hpp */
|
93
Machines/Commodore/SerialBus.cpp
Normal file
93
Machines/Commodore/SerialBus.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// SerialPort.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "SerialBus.hpp"
|
||||
|
||||
using namespace Commodore::Serial;
|
||||
|
||||
const char *::Commodore::Serial::StringForLine(Line line)
|
||||
{
|
||||
switch(line)
|
||||
{
|
||||
case ServiceRequest: return "Service request";
|
||||
case Attention: return "Attention";
|
||||
case Clock: return "Clock";
|
||||
case Data: return "Data";
|
||||
case Reset: return "Reset";
|
||||
}
|
||||
}
|
||||
|
||||
void ::Commodore::Serial::AttachPortAndBus(std::shared_ptr<Port> port, std::shared_ptr<Bus> bus)
|
||||
{
|
||||
port->set_serial_bus(bus);
|
||||
bus->add_port(port);
|
||||
}
|
||||
|
||||
void Bus::add_port(std::shared_ptr<Port> port)
|
||||
{
|
||||
_ports.push_back(port);
|
||||
for(int line = (int)ServiceRequest; line <= (int)Reset; line++)
|
||||
{
|
||||
// the addition of a new device may change the line output...
|
||||
set_line_output_did_change((Line)line);
|
||||
|
||||
// ... but the new device will need to be told the current state regardless
|
||||
port->set_input((Line)line, _line_levels[line]);
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::set_line_output_did_change(Line line)
|
||||
{
|
||||
// i.e. I believe these lines to be open collector
|
||||
LineLevel new_line_level = High;
|
||||
for(std::weak_ptr<Port> port : _ports)
|
||||
{
|
||||
std::shared_ptr<Port> locked_port = port.lock();
|
||||
if(locked_port)
|
||||
{
|
||||
new_line_level = (LineLevel)((bool)new_line_level & (bool)locked_port->get_output(line));
|
||||
}
|
||||
}
|
||||
|
||||
// post an update only if one occurred
|
||||
if(new_line_level != _line_levels[line])
|
||||
{
|
||||
_line_levels[line] = new_line_level;
|
||||
|
||||
for(std::weak_ptr<Port> port : _ports)
|
||||
{
|
||||
std::shared_ptr<Port> locked_port = port.lock();
|
||||
if(locked_port)
|
||||
{
|
||||
locked_port->set_input(line, new_line_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - The debug port
|
||||
|
||||
void DebugPort::set_input(Line line, LineLevel value)
|
||||
{
|
||||
_input_levels[line] = value;
|
||||
|
||||
printf("[Bus] %s is %s\n", StringForLine(line), value ? "high" : "low");
|
||||
if(!_incoming_count)
|
||||
{
|
||||
_incoming_count = (!_input_levels[Line::Clock] && !_input_levels[Line::Data]) ? 8 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(line == Line::Clock && value)
|
||||
{
|
||||
_incoming_byte = (_incoming_byte >> 1) | (_input_levels[Line::Data] ? 0x80 : 0x00);
|
||||
}
|
||||
_incoming_count--;
|
||||
if(_incoming_count == 0) printf("[Bus] Observed %02x\n", _incoming_byte);
|
||||
}
|
||||
}
|
131
Machines/Commodore/SerialBus.hpp
Normal file
131
Machines/Commodore/SerialBus.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// SerialPort.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef SerialBus_hpp
|
||||
#define SerialBus_hpp
|
||||
|
||||
#import <vector>
|
||||
|
||||
namespace Commodore {
|
||||
namespace Serial {
|
||||
|
||||
enum Line {
|
||||
ServiceRequest = 0,
|
||||
Attention,
|
||||
Clock,
|
||||
Data,
|
||||
Reset
|
||||
};
|
||||
|
||||
enum LineLevel: bool {
|
||||
High = true,
|
||||
Low = false
|
||||
};
|
||||
|
||||
class Port;
|
||||
class Bus;
|
||||
|
||||
/*!
|
||||
Returns a C string giving a human-readable name for the supplied line.
|
||||
*/
|
||||
const char *StringForLine(Line line);
|
||||
|
||||
/*!
|
||||
Calls both of the necessary methods to (i) set @c bus as the target for @c port outputs; and
|
||||
(ii) add @c port as one of the targets to which @c bus propagates line changes.
|
||||
*/
|
||||
void AttachPortAndBus(std::shared_ptr<Port> port, std::shared_ptr<Bus> bus);
|
||||
|
||||
/*!
|
||||
A serial bus is responsible for retaining a weakly-held collection of attached ports and for deciding the
|
||||
current bus levels based upon the net result of each port's output, and for communicating changes in bus
|
||||
levels to every port.
|
||||
*/
|
||||
class Bus {
|
||||
public:
|
||||
Bus() : _line_levels{High, High, High, High, High} {}
|
||||
|
||||
/*!
|
||||
Adds the supplied port to the bus.
|
||||
*/
|
||||
void add_port(std::shared_ptr<Port> port);
|
||||
|
||||
/*!
|
||||
Communicates to the bus that one of its attached port has changed its output level for the given line.
|
||||
The bus will therefore recalculate bus state and propagate as necessary.
|
||||
*/
|
||||
void set_line_output_did_change(Line line);
|
||||
|
||||
private:
|
||||
LineLevel _line_levels[5];
|
||||
std::vector<std::weak_ptr<Port>> _ports;
|
||||
};
|
||||
|
||||
/*!
|
||||
A serial port is an endpoint on a serial bus; this class provides a direct setter for current line outputs and
|
||||
expects to be subclassed in order for specific port-housing devices to deal with input.
|
||||
*/
|
||||
class Port {
|
||||
public:
|
||||
Port() : _line_levels{High, High, High, High, High} {}
|
||||
|
||||
/*!
|
||||
Sets the current level of an output line on this serial port.
|
||||
*/
|
||||
void set_output(Line line, LineLevel level) {
|
||||
if(_line_levels[line] != level)
|
||||
{
|
||||
_line_levels[line] = level;
|
||||
std::shared_ptr<Bus> bus = _serial_bus.lock();
|
||||
if(bus) bus->set_line_output_did_change(line);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the previously set level of an output line.
|
||||
*/
|
||||
LineLevel get_output(Line line) {
|
||||
return _line_levels[line];
|
||||
}
|
||||
|
||||
/*!
|
||||
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;
|
||||
|
||||
/*!
|
||||
Sets the supplied serial bus as that to which line levels will be communicated.
|
||||
*/
|
||||
inline void set_serial_bus(std::shared_ptr<Bus> serial_bus) {
|
||||
_serial_bus = serial_bus;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<Bus> _serial_bus;
|
||||
LineLevel _line_levels[5];
|
||||
};
|
||||
|
||||
/*!
|
||||
A debugging port, which makes some attempt to log bus activity. Incomplete. TODO: complete.
|
||||
*/
|
||||
class DebugPort: public Port {
|
||||
public:
|
||||
void set_input(Line line, LineLevel value);
|
||||
|
||||
DebugPort() : _incoming_count(0) {}
|
||||
|
||||
private:
|
||||
uint8_t _incoming_byte;
|
||||
int _incoming_count;
|
||||
LineLevel _input_levels[5];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SerialPort_hpp */
|
@ -10,23 +10,31 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Vic20;
|
||||
using namespace Commodore::Vic20;
|
||||
|
||||
Machine::Machine() :
|
||||
_rom(nullptr)
|
||||
{
|
||||
// create 6522s, serial port and bus
|
||||
_userPortVIA.reset(new UserPortVIA);
|
||||
_keyboardVIA.reset(new KeyboardVIA);
|
||||
_serialPort.reset(new SerialPort);
|
||||
_serialBus.reset(new ::Commodore::Serial::Bus);
|
||||
|
||||
// wire up the serial bus and serial port
|
||||
Commodore::Serial::AttachPortAndBus(_serialPort, _serialBus);
|
||||
|
||||
// wire up 6522s and serial port
|
||||
_userPortVIA->set_serial_port(_serialPort);
|
||||
_keyboardVIA->set_serial_port(_serialPort);
|
||||
_serialPort->set_vias(_userPortVIA, _keyboardVIA);
|
||||
_serialPort->set_user_port_via(_userPortVIA);
|
||||
|
||||
// wire up the 6522s, tape and machine
|
||||
_userPortVIA->set_delegate(this);
|
||||
_keyboardVIA->set_delegate(this);
|
||||
_tape.set_delegate(this);
|
||||
|
||||
// establish the memory maps
|
||||
memset(_videoMemoryMap, 0, sizeof(_videoMemoryMap));
|
||||
memset(_processorReadMemoryMap, 0, sizeof(_processorReadMemoryMap));
|
||||
memset(_processorWriteMemoryMap, 0, sizeof(_processorWriteMemoryMap));
|
||||
@ -45,6 +53,13 @@ Machine::Machine() :
|
||||
write_to_map(_processorWriteMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory));
|
||||
write_to_map(_processorWriteMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory));
|
||||
write_to_map(_processorWriteMemoryMap, _colorMemory, 0x9400, sizeof(_colorMemory));
|
||||
|
||||
// TEMPORARY: attach a [diskless] 1540
|
||||
// set_disc();
|
||||
|
||||
// _debugPort.reset(new ::Commodore::Serial::DebugPort);
|
||||
// _debugPort->set_serial_bus(_serialBus);
|
||||
// _serialBus->add_port(_debugPort);
|
||||
}
|
||||
|
||||
void Machine::write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length)
|
||||
@ -59,7 +74,6 @@ void Machine::write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Machine::~Machine()
|
||||
{
|
||||
delete[] _rom;
|
||||
@ -67,6 +81,13 @@ Machine::~Machine()
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
// static int logCount = 0;
|
||||
// if(operation == CPU6502::BusOperation::ReadOpcode && address == 0xee17) logCount = 500;
|
||||
// if(operation == CPU6502::BusOperation::ReadOpcode && logCount) {
|
||||
// logCount--;
|
||||
// printf("%04x\n", address);
|
||||
// }
|
||||
|
||||
// run the phase-1 part of this cycle, in which the VIC accesses memory
|
||||
uint16_t video_address = _mos6560->get_address();
|
||||
uint8_t video_value = _videoMemoryMap[video_address >> 10] ? _videoMemoryMap[video_address >> 10][video_address & 0x3ff] : 0xff; // TODO
|
||||
@ -85,7 +106,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
*value = result;
|
||||
|
||||
// test for PC at F92F
|
||||
if(_use_fast_tape_hack && address == 0xf92f && operation == CPU6502::BusOperation::ReadOpcode)
|
||||
if(_use_fast_tape_hack && _tape.has_tape() && address == 0xf92f && operation == CPU6502::BusOperation::ReadOpcode)
|
||||
{
|
||||
// advance time on the tape and the VIAs until an interrupt is signalled
|
||||
while(!_userPortVIA->get_interrupt_line() && !_keyboardVIA->get_interrupt_line())
|
||||
@ -112,6 +133,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
_keyboardVIA->run_for_half_cycles(2);
|
||||
if(_typer) _typer->update(1);
|
||||
_tape.run_for_cycles(1);
|
||||
if(_c1540) _c1540->run_for_cycles(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -141,9 +163,16 @@ void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data)
|
||||
size_t max_length = 0x2000;
|
||||
switch(slot)
|
||||
{
|
||||
case ROMSlotKernel: target = _kernelROM; break;
|
||||
case ROMSlotCharacters: target = _characterROM; max_length = 0x1000; break;
|
||||
case ROMSlotBASIC: target = _basicROM; break;
|
||||
case Kernel: target = _kernelROM; break;
|
||||
case Characters: target = _characterROM; max_length = 0x1000; break;
|
||||
case BASIC: target = _basicROM; break;
|
||||
case Drive:
|
||||
if(_c1540)
|
||||
{
|
||||
_c1540->set_rom(data);
|
||||
_c1540->run_for_cycles(2000000); // pretend it booted a couple of seconds ago
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(target)
|
||||
@ -315,34 +344,13 @@ void Tape::process_input_pulse(Storage::Tape::Pulse pulse)
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Serial Port
|
||||
#pragma mark - Disc
|
||||
|
||||
void SerialPort::set_clock_output(bool value)
|
||||
void Machine::set_disc()
|
||||
{
|
||||
printf("Serial port clock output %s\n", value ? "on" : "off");
|
||||
}
|
||||
// construct the 1540
|
||||
_c1540.reset(new ::Commodore::C1540::Machine);
|
||||
|
||||
void SerialPort::set_data_output(bool value)
|
||||
{
|
||||
printf("Serial port data output %s\n", value ? "on" : "off");
|
||||
}
|
||||
|
||||
void SerialPort::set_attention_output(bool value)
|
||||
{
|
||||
printf("Serial port attention output %s\n", value ? "on" : "off");
|
||||
}
|
||||
|
||||
void SerialPort::set_clock_input(bool value)
|
||||
{
|
||||
printf("Serial port clock input %s\n", value ? "on" : "off");
|
||||
}
|
||||
|
||||
void SerialPort::set_data_input(bool value)
|
||||
{
|
||||
printf("Serial port data input %s\n", value ? "on" : "off");
|
||||
}
|
||||
|
||||
void SerialPort::set_attention_input(bool value)
|
||||
{
|
||||
printf("Serial port attention input %s\n", value ? "on" : "off");
|
||||
// attach it to the serial bus
|
||||
_c1540->set_serial_bus(_serialBus);
|
||||
}
|
@ -9,23 +9,26 @@
|
||||
#ifndef Vic20_hpp
|
||||
#define Vic20_hpp
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
#include "../../Components/6560/6560.hpp"
|
||||
#include "../../Components/6522/6522.hpp"
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Storage/Tape/Tape.hpp"
|
||||
#include "../../../Components/6560/6560.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
#include "../1540/C1540.hpp"
|
||||
#include "../SerialBus.hpp"
|
||||
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../Typer.hpp"
|
||||
#include "../../CRTMachine.hpp"
|
||||
#include "../../Typer.hpp"
|
||||
|
||||
namespace Commodore {
|
||||
namespace Vic20 {
|
||||
|
||||
enum ROMSlot {
|
||||
ROMSlotKernel,
|
||||
ROMSlotBASIC,
|
||||
ROMSlotCharacters,
|
||||
Kernel,
|
||||
BASIC,
|
||||
Characters,
|
||||
Drive
|
||||
};
|
||||
|
||||
|
||||
#define key(line, mask) (((mask) << 3) | (line))
|
||||
|
||||
enum Key: uint16_t {
|
||||
@ -57,29 +60,6 @@ enum JoystickInput {
|
||||
Fire = 0x20
|
||||
};
|
||||
|
||||
class UserPortVIA;
|
||||
class KeyboardVIA;
|
||||
|
||||
class SerialPort {
|
||||
public:
|
||||
void set_clock_output(bool value);
|
||||
void set_data_output(bool value);
|
||||
void set_attention_output(bool value);
|
||||
|
||||
void set_clock_input(bool value);
|
||||
void set_data_input(bool value);
|
||||
void set_attention_input(bool value);
|
||||
|
||||
void set_vias(std::shared_ptr<UserPortVIA> userPortVIA, std::shared_ptr<KeyboardVIA> keyboardVIA) {
|
||||
_userPortVIA = userPortVIA;
|
||||
_keyboardVIA = keyboardVIA;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<UserPortVIA> _userPortVIA;
|
||||
std::weak_ptr<KeyboardVIA> _keyboardVIA;
|
||||
};
|
||||
|
||||
class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDelegate {
|
||||
public:
|
||||
uint8_t get_port_input(Port port) {
|
||||
@ -95,6 +75,15 @@ class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDeleg
|
||||
// }
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -103,9 +92,11 @@ class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDeleg
|
||||
}
|
||||
|
||||
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<SerialPort> serialPort = _serialPort.lock();
|
||||
if(serialPort) serialPort->set_attention_output(!(value&0x80));
|
||||
std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock();
|
||||
if(serialPort)
|
||||
serialPort->set_output(::Commodore::Serial::Line::Attention, (::Commodore::Serial::LineLevel)!(value&0x80));
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,13 +104,13 @@ class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDeleg
|
||||
|
||||
UserPortVIA() : _portA(0xbf) {}
|
||||
|
||||
void set_serial_port(std::shared_ptr<SerialPort> serialPort) {
|
||||
void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) {
|
||||
_serialPort = serialPort;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _portA;
|
||||
std::weak_ptr<SerialPort> _serialPort;
|
||||
std::weak_ptr<::Commodore::Serial::Port> _serialPort;
|
||||
};
|
||||
|
||||
class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDelegate {
|
||||
@ -161,12 +152,13 @@ class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDeleg
|
||||
|
||||
void set_control_line_output(Port port, Line line, bool value) {
|
||||
if(line == Line::Two) {
|
||||
std::shared_ptr<SerialPort> serialPort = _serialPort.lock();
|
||||
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_clock_output(value);
|
||||
serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!value);
|
||||
} else {
|
||||
serialPort->set_data_output(value);
|
||||
serialPort->set_output(::Commodore::Serial::Line::Data, (::Commodore::Serial::LineLevel)!value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,7 +173,7 @@ class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDeleg
|
||||
|
||||
using MOS6522IRQDelegate::set_interrupt_status;
|
||||
|
||||
void set_serial_port(std::shared_ptr<SerialPort> serialPort) {
|
||||
void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) {
|
||||
_serialPort = serialPort;
|
||||
}
|
||||
|
||||
@ -189,7 +181,22 @@ class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDeleg
|
||||
uint8_t _portB;
|
||||
uint8_t _columns[8];
|
||||
uint8_t _activation_mask;
|
||||
std::weak_ptr<SerialPort> _serialPort;
|
||||
std::weak_ptr<::Commodore::Serial::Port> _serialPort;
|
||||
};
|
||||
|
||||
class SerialPort : public ::Commodore::Serial::Port {
|
||||
public:
|
||||
void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) {
|
||||
std::shared_ptr<UserPortVIA> userPortVIA = _userPortVIA.lock();
|
||||
if(userPortVIA) userPortVIA->set_serial_line_state(line, (bool)level);
|
||||
}
|
||||
|
||||
void set_user_port_via(std::shared_ptr<UserPortVIA> userPortVIA) {
|
||||
_userPortVIA = userPortVIA;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<UserPortVIA> _userPortVIA;
|
||||
};
|
||||
|
||||
class Tape: public Storage::TapePlayer {
|
||||
@ -230,6 +237,7 @@ class Machine:
|
||||
void set_rom(ROMSlot slot, size_t length, const uint8_t *data);
|
||||
void add_prg(size_t length, const uint8_t *data);
|
||||
void set_tape(std::shared_ptr<Storage::Tape> tape);
|
||||
void set_disc();
|
||||
|
||||
void set_key_state(Key key, bool isPressed) { _keyboardVIA->set_key_state(key, isPressed); }
|
||||
void clear_all_keys() { _keyboardVIA->clear_all_keys(); }
|
||||
@ -286,12 +294,18 @@ class Machine:
|
||||
std::shared_ptr<UserPortVIA> _userPortVIA;
|
||||
std::shared_ptr<KeyboardVIA> _keyboardVIA;
|
||||
std::shared_ptr<SerialPort> _serialPort;
|
||||
std::shared_ptr<::Commodore::Serial::Bus> _serialBus;
|
||||
// std::shared_ptr<::Commodore::Serial::DebugPort> _debugPort;
|
||||
|
||||
// Tape
|
||||
Tape _tape;
|
||||
bool _use_fast_tape_hack;
|
||||
|
||||
// Disc
|
||||
std::shared_ptr<::Commodore::C1540::Machine> _c1540;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Vic20_hpp */
|
@ -24,7 +24,7 @@ void Typer::update(int duration)
|
||||
}
|
||||
|
||||
_counter += duration;
|
||||
while(_counter > _frequency)
|
||||
while(_string && _counter > _frequency)
|
||||
{
|
||||
_counter -= _frequency;
|
||||
type_next_character();
|
||||
|
@ -14,7 +14,6 @@
|
||||
4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */; };
|
||||
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; };
|
||||
4B1E85751D170228001EF87D /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85731D170228001EF87D /* Typer.cpp */; };
|
||||
4B1E857F1D17644D001EF87D /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */; };
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85801D176468001EF87D /* 6532Tests.swift */; };
|
||||
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2409531C45AB05004DA684 /* Speaker.cpp */; };
|
||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
|
||||
@ -25,6 +24,14 @@
|
||||
4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; };
|
||||
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; };
|
||||
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; };
|
||||
4B3BA0C31D318AEC005DD7A7 /* C1540Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */; };
|
||||
4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */; };
|
||||
4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */; };
|
||||
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */; };
|
||||
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */; };
|
||||
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8261D2C2470003C5BF8 /* C1540.cpp */; };
|
||||
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; };
|
||||
4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE561C3B7D360093A61B /* Atari2600Document.swift */; };
|
||||
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE571C3B7D360093A61B /* ElectronDocument.swift */; };
|
||||
4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */; };
|
||||
@ -34,11 +41,9 @@
|
||||
4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; };
|
||||
4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; };
|
||||
4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; };
|
||||
4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; };
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
|
||||
4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; };
|
||||
4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; };
|
||||
4BB298F01B587D8400A49093 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BB297E31B587D8300A49093 /* TestMachine.mm */; };
|
||||
4BB298F11B587D8400A49093 /* start in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E51B587D8300A49093 /* start */; };
|
||||
4BB298F21B587D8400A49093 /* adca in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E61B587D8300A49093 /* adca */; };
|
||||
4BB298F31B587D8400A49093 /* adcax in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E71B587D8300A49093 /* adcax */; };
|
||||
@ -317,7 +322,6 @@
|
||||
4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B74D1CD194CC00F86E85 /* Shader.cpp */; };
|
||||
4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B7501CD1956900F86E85 /* OutputShader.cpp */; };
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC751B11D157E61006C31D9 /* 6522Tests.swift */; };
|
||||
4BC751B61D157EB3006C31D9 /* MOS6522Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BC751B51D157EB3006C31D9 /* MOS6522Bridge.mm */; };
|
||||
4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; };
|
||||
4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; };
|
||||
4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */; };
|
||||
@ -359,8 +363,6 @@
|
||||
4B1E85731D170228001EF87D /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Typer.cpp; sourceTree = "<group>"; };
|
||||
4B1E85741D170228001EF87D /* Typer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Typer.hpp; sourceTree = "<group>"; };
|
||||
4B1E857B1D174DEC001EF87D /* 6532.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6532.hpp; sourceTree = "<group>"; };
|
||||
4B1E857D1D17644D001EF87D /* MOS6532Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6532Bridge.h; sourceTree = "<group>"; };
|
||||
4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6532Bridge.mm; sourceTree = "<group>"; };
|
||||
4B1E85801D176468001EF87D /* 6532Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6532Tests.swift; sourceTree = "<group>"; };
|
||||
4B2409531C45AB05004DA684 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = ../../Outputs/Speaker.cpp; sourceTree = "<group>"; };
|
||||
4B2409541C45AB05004DA684 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = ../../Outputs/Speaker.hpp; sourceTree = "<group>"; };
|
||||
@ -384,6 +386,22 @@
|
||||
4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = "<group>"; };
|
||||
4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = "<group>"; };
|
||||
4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = "<group>"; };
|
||||
4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = C1540Tests.swift; sourceTree = "<group>"; };
|
||||
4B3BA0C51D318B44005DD7A7 /* C1540Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C1540Bridge.h; sourceTree = "<group>"; };
|
||||
4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = C1540Bridge.mm; sourceTree = "<group>"; };
|
||||
4B3BA0C71D318B44005DD7A7 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6522Bridge.h; sourceTree = "<group>"; };
|
||||
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6522Bridge.mm; sourceTree = "<group>"; };
|
||||
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6532Bridge.h; sourceTree = "<group>"; };
|
||||
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6532Bridge.mm; sourceTree = "<group>"; };
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
|
||||
4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vic20.cpp; sourceTree = "<group>"; };
|
||||
4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vic20.hpp; sourceTree = "<group>"; };
|
||||
4B4DC8261D2C2470003C5BF8 /* C1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C1540.cpp; sourceTree = "<group>"; };
|
||||
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
|
||||
4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialBus.cpp; sourceTree = "<group>"; };
|
||||
4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialBus.hpp; sourceTree = "<group>"; };
|
||||
4B55CE561C3B7D360093A61B /* Atari2600Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atari2600Document.swift; sourceTree = "<group>"; };
|
||||
4B55CE571C3B7D360093A61B /* ElectronDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElectronDocument.swift; sourceTree = "<group>"; };
|
||||
4B55CE5B1C3B7D6F0093A61B /* CSOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSOpenGLView.h; sourceTree = "<group>"; };
|
||||
@ -396,14 +414,9 @@
|
||||
4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
4B73C7191D036BD90074D992 /* Vic20Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20Document.swift; sourceTree = "<group>"; };
|
||||
4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; };
|
||||
4B886FF01D03B517004291C3 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vic20.cpp; path = "Vic-20/Vic20.cpp"; sourceTree = "<group>"; };
|
||||
4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = "<group>"; };
|
||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
|
||||
4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = "<group>"; };
|
||||
4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = "<group>"; };
|
||||
4BB297E21B587D8300A49093 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
|
||||
4BB297E31B587D8300A49093 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
|
||||
4BB297E51B587D8300A49093 /* start */ = {isa = PBXFileReference; lastKnownFileType = file; path = " start"; sourceTree = "<group>"; };
|
||||
4BB297E61B587D8300A49093 /* adca */ = {isa = PBXFileReference; lastKnownFileType = file; path = adca; sourceTree = "<group>"; };
|
||||
4BB297E71B587D8300A49093 /* adcax */ = {isa = PBXFileReference; lastKnownFileType = file; path = adcax; sourceTree = "<group>"; };
|
||||
@ -699,8 +712,6 @@
|
||||
4BC3B7501CD1956900F86E85 /* OutputShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputShader.cpp; sourceTree = "<group>"; };
|
||||
4BC3B7511CD1956900F86E85 /* OutputShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OutputShader.hpp; sourceTree = "<group>"; };
|
||||
4BC751B11D157E61006C31D9 /* 6522Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6522Tests.swift; sourceTree = "<group>"; };
|
||||
4BC751B41D157EB3006C31D9 /* MOS6522Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6522Bridge.h; sourceTree = "<group>"; };
|
||||
4BC751B51D157EB3006C31D9 /* MOS6522Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6522Bridge.mm; sourceTree = "<group>"; };
|
||||
4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIRFilter.cpp; sourceTree = "<group>"; };
|
||||
4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = "<group>"; };
|
||||
4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
|
||||
@ -859,6 +870,51 @@
|
||||
name = Outputs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B3BA0C41D318B44005DD7A7 /* Bridges */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B3BA0C51D318B44005DD7A7 /* C1540Bridge.h */,
|
||||
4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */,
|
||||
4B3BA0C71D318B44005DD7A7 /* Clock SignalTests-Bridging-Header.h */,
|
||||
4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */,
|
||||
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */,
|
||||
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */,
|
||||
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */,
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine.h */,
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */,
|
||||
);
|
||||
path = Bridges;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B4DC81D1D2C2425003C5BF8 /* Commodore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4DC8251D2C2470003C5BF8 /* 1540 */,
|
||||
4B4DC81E1D2C2425003C5BF8 /* Vic-20 */,
|
||||
4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */,
|
||||
4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */,
|
||||
);
|
||||
path = Commodore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B4DC81E1D2C2425003C5BF8 /* Vic-20 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */,
|
||||
4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */,
|
||||
);
|
||||
path = "Vic-20";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B4DC8251D2C2470003C5BF8 /* 1540 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4DC8261D2C2470003C5BF8 /* C1540.cpp */,
|
||||
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */,
|
||||
);
|
||||
path = 1540;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B55CE551C3B7D360093A61B /* Documents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -913,15 +969,6 @@
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B886FF61D03B632004291C3 /* Vic-20 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B886FF01D03B517004291C3 /* Vic20.cpp */,
|
||||
4B886FF11D03B517004291C3 /* Vic20.hpp */,
|
||||
);
|
||||
name = "Vic-20";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1243,22 +1290,17 @@
|
||||
4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */,
|
||||
4BC751B41D157EB3006C31D9 /* MOS6522Bridge.h */,
|
||||
4B1E857D1D17644D001EF87D /* MOS6532Bridge.h */,
|
||||
4BB297E21B587D8300A49093 /* TestMachine.h */,
|
||||
4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */,
|
||||
4BC751B51D157EB3006C31D9 /* MOS6522Bridge.mm */,
|
||||
4BB297E31B587D8300A49093 /* TestMachine.mm */,
|
||||
4BB73EB81B587A5100552FC2 /* Info.plist */,
|
||||
4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */,
|
||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */,
|
||||
4BC751B11D157E61006C31D9 /* 6522Tests.swift */,
|
||||
4B1E85801D176468001EF87D /* 6532Tests.swift */,
|
||||
4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */,
|
||||
4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */,
|
||||
4B1414611B58888700E04248 /* KlausDormannTests.swift */,
|
||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */,
|
||||
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */,
|
||||
4B3BA0C41D318B44005DD7A7 /* Bridges */,
|
||||
4B1414631B588A1100E04248 /* Test Binaries */,
|
||||
4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */,
|
||||
);
|
||||
path = "Clock SignalTests";
|
||||
sourceTree = "<group>";
|
||||
@ -1275,10 +1317,10 @@
|
||||
4BB73EDC1B587CA500552FC2 /* Machines */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4DC81D1D2C2425003C5BF8 /* Commodore */,
|
||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
|
||||
4B2E2D961C3A06EC00138695 /* Atari2600 */,
|
||||
4B2E2D9E1C3A070900138695 /* Electron */,
|
||||
4B886FF61D03B632004291C3 /* Vic-20 */,
|
||||
4B1E85731D170228001EF87D /* Typer.cpp */,
|
||||
4B1E85741D170228001EF87D /* Typer.hpp */,
|
||||
);
|
||||
@ -1780,7 +1822,7 @@
|
||||
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */,
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */,
|
||||
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */,
|
||||
4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */,
|
||||
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
|
||||
4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */,
|
||||
4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */,
|
||||
4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */,
|
||||
@ -1791,8 +1833,10 @@
|
||||
4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */,
|
||||
4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */,
|
||||
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */,
|
||||
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,
|
||||
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
|
||||
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
|
||||
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */,
|
||||
4B1E85751D170228001EF87D /* Typer.cpp in Sources */,
|
||||
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,
|
||||
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */,
|
||||
@ -1813,17 +1857,19 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4BC751B61D157EB3006C31D9 /* MOS6522Bridge.mm in Sources */,
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */,
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */,
|
||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */,
|
||||
4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */,
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine.mm in Sources */,
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */,
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */,
|
||||
4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */,
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */,
|
||||
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */,
|
||||
4B3BA0C31D318AEC005DD7A7 /* C1540Tests.swift in Sources */,
|
||||
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */,
|
||||
4BB298F01B587D8400A49093 /* TestMachine.mm in Sources */,
|
||||
4B1E857F1D17644D001EF87D /* MOS6532Bridge.mm in Sources */,
|
||||
4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -2014,7 +2060,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
|
||||
};
|
||||
@ -2030,7 +2076,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
|
||||
};
|
||||
name = Release;
|
||||
|
@ -31,6 +31,10 @@ class Vic20Document: MachineDocument {
|
||||
vic20.setBASICROM(basic)
|
||||
vic20.setCharactersROM(characters)
|
||||
}
|
||||
|
||||
if let drive = dataForResource("1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
|
||||
vic20.setDriveROM(drive)
|
||||
}
|
||||
}
|
||||
|
||||
override class func autosavesInPlace() -> Bool {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#import "CSAtari2600.h"
|
||||
|
||||
#import "Atari2600.hpp"
|
||||
#include "Atari2600.hpp"
|
||||
#import "CSMachine+Subclassing.h"
|
||||
|
||||
@interface CSAtari2600 ()
|
||||
|
@ -15,6 +15,7 @@
|
||||
- (void)setKernelROM:(nonnull NSData *)rom;
|
||||
- (void)setBASICROM:(nonnull NSData *)rom;
|
||||
- (void)setCharactersROM:(nonnull NSData *)rom;
|
||||
- (void)setDriveROM:(nonnull NSData *)rom;
|
||||
|
||||
- (void)setPRG:(nonnull NSData *)prg;
|
||||
- (BOOL)openTAPAtURL:(nonnull NSURL *)URL;
|
||||
|
@ -11,8 +11,10 @@
|
||||
#include "Vic20.hpp"
|
||||
#include "CommodoreTAP.hpp"
|
||||
|
||||
using namespace Commodore::Vic20;
|
||||
|
||||
@implementation CSVic20 {
|
||||
Vic20::Machine _vic20;
|
||||
Machine _vic20;
|
||||
BOOL _joystickMode;
|
||||
}
|
||||
|
||||
@ -20,22 +22,26 @@
|
||||
return &_vic20;
|
||||
}
|
||||
|
||||
- (void)setROM:(nonnull NSData *)rom slot:(Vic20::ROMSlot)slot {
|
||||
- (void)setROM:(nonnull NSData *)rom slot:(ROMSlot)slot {
|
||||
@synchronized(self) {
|
||||
_vic20.set_rom(slot, rom.length, (const uint8_t *)rom.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setKernelROM:(nonnull NSData *)rom {
|
||||
[self setROM:rom slot:Vic20::ROMSlotKernel];
|
||||
[self setROM:rom slot:Kernel];
|
||||
}
|
||||
|
||||
- (void)setBASICROM:(nonnull NSData *)rom {
|
||||
[self setROM:rom slot:Vic20::ROMSlotBASIC];
|
||||
[self setROM:rom slot:BASIC];
|
||||
}
|
||||
|
||||
- (void)setCharactersROM:(nonnull NSData *)rom {
|
||||
[self setROM:rom slot:Vic20::ROMSlotCharacters];
|
||||
[self setROM:rom slot:Characters];
|
||||
}
|
||||
|
||||
- (void)setDriveROM:(nonnull NSData *)rom {
|
||||
[self setROM:rom slot:Drive];
|
||||
}
|
||||
|
||||
- (BOOL)openTAPAtURL:(NSURL *)URL {
|
||||
@ -59,50 +65,50 @@
|
||||
|
||||
- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed {
|
||||
static NSDictionary<NSNumber *, NSNumber *> *vicKeysByKeys = @{
|
||||
@(VK_ANSI_1): @(Vic20::Key::Key1), @(VK_ANSI_2): @(Vic20::Key::Key2),
|
||||
@(VK_ANSI_3): @(Vic20::Key::Key3), @(VK_ANSI_4): @(Vic20::Key::Key4),
|
||||
@(VK_ANSI_5): @(Vic20::Key::Key5), @(VK_ANSI_6): @(Vic20::Key::Key6),
|
||||
@(VK_ANSI_7): @(Vic20::Key::Key7), @(VK_ANSI_8): @(Vic20::Key::Key8),
|
||||
@(VK_ANSI_9): @(Vic20::Key::Key9), @(VK_ANSI_0): @(Vic20::Key::Key0),
|
||||
@(VK_ANSI_1): @(Key::Key1), @(VK_ANSI_2): @(Key::Key2),
|
||||
@(VK_ANSI_3): @(Key::Key3), @(VK_ANSI_4): @(Key::Key4),
|
||||
@(VK_ANSI_5): @(Key::Key5), @(VK_ANSI_6): @(Key::Key6),
|
||||
@(VK_ANSI_7): @(Key::Key7), @(VK_ANSI_8): @(Key::Key8),
|
||||
@(VK_ANSI_9): @(Key::Key9), @(VK_ANSI_0): @(Key::Key0),
|
||||
|
||||
@(VK_ANSI_Q): @(Vic20::Key::KeyQ), @(VK_ANSI_W): @(Vic20::Key::KeyW),
|
||||
@(VK_ANSI_E): @(Vic20::Key::KeyE), @(VK_ANSI_R): @(Vic20::Key::KeyR),
|
||||
@(VK_ANSI_T): @(Vic20::Key::KeyT), @(VK_ANSI_Y): @(Vic20::Key::KeyY),
|
||||
@(VK_ANSI_U): @(Vic20::Key::KeyU), @(VK_ANSI_I): @(Vic20::Key::KeyI),
|
||||
@(VK_ANSI_O): @(Vic20::Key::KeyO), @(VK_ANSI_P): @(Vic20::Key::KeyP),
|
||||
@(VK_ANSI_A): @(Vic20::Key::KeyA), @(VK_ANSI_S): @(Vic20::Key::KeyS),
|
||||
@(VK_ANSI_D): @(Vic20::Key::KeyD), @(VK_ANSI_F): @(Vic20::Key::KeyF),
|
||||
@(VK_ANSI_G): @(Vic20::Key::KeyG), @(VK_ANSI_H): @(Vic20::Key::KeyH),
|
||||
@(VK_ANSI_J): @(Vic20::Key::KeyJ), @(VK_ANSI_K): @(Vic20::Key::KeyK),
|
||||
@(VK_ANSI_L): @(Vic20::Key::KeyL), @(VK_ANSI_Z): @(Vic20::Key::KeyZ),
|
||||
@(VK_ANSI_X): @(Vic20::Key::KeyX), @(VK_ANSI_C): @(Vic20::Key::KeyC),
|
||||
@(VK_ANSI_V): @(Vic20::Key::KeyV), @(VK_ANSI_B): @(Vic20::Key::KeyB),
|
||||
@(VK_ANSI_N): @(Vic20::Key::KeyN), @(VK_ANSI_M): @(Vic20::Key::KeyM),
|
||||
@(VK_ANSI_Q): @(Key::KeyQ), @(VK_ANSI_W): @(Key::KeyW),
|
||||
@(VK_ANSI_E): @(Key::KeyE), @(VK_ANSI_R): @(Key::KeyR),
|
||||
@(VK_ANSI_T): @(Key::KeyT), @(VK_ANSI_Y): @(Key::KeyY),
|
||||
@(VK_ANSI_U): @(Key::KeyU), @(VK_ANSI_I): @(Key::KeyI),
|
||||
@(VK_ANSI_O): @(Key::KeyO), @(VK_ANSI_P): @(Key::KeyP),
|
||||
@(VK_ANSI_A): @(Key::KeyA), @(VK_ANSI_S): @(Key::KeyS),
|
||||
@(VK_ANSI_D): @(Key::KeyD), @(VK_ANSI_F): @(Key::KeyF),
|
||||
@(VK_ANSI_G): @(Key::KeyG), @(VK_ANSI_H): @(Key::KeyH),
|
||||
@(VK_ANSI_J): @(Key::KeyJ), @(VK_ANSI_K): @(Key::KeyK),
|
||||
@(VK_ANSI_L): @(Key::KeyL), @(VK_ANSI_Z): @(Key::KeyZ),
|
||||
@(VK_ANSI_X): @(Key::KeyX), @(VK_ANSI_C): @(Key::KeyC),
|
||||
@(VK_ANSI_V): @(Key::KeyV), @(VK_ANSI_B): @(Key::KeyB),
|
||||
@(VK_ANSI_N): @(Key::KeyN), @(VK_ANSI_M): @(Key::KeyM),
|
||||
|
||||
@(VK_Space): @(Vic20::Key::KeySpace),
|
||||
@(VK_Return): @(Vic20::Key::KeyReturn),
|
||||
@(VK_Delete): @(Vic20::Key::KeyDelete),
|
||||
@(VK_ANSI_Comma): @(Vic20::Key::KeyComma),
|
||||
@(VK_ANSI_Period): @(Vic20::Key::KeyFullStop),
|
||||
@(VK_ANSI_Minus): @(Vic20::Key::KeyDash),
|
||||
@(VK_ANSI_Equal): @(Vic20::Key::KeyEquals),
|
||||
@(VK_ANSI_Semicolon): @(Vic20::Key::KeyColon),
|
||||
@(VK_ANSI_Quote): @(Vic20::Key::KeySemicolon),
|
||||
@(VK_ANSI_Slash): @(Vic20::Key::KeySlash),
|
||||
@(VK_Option): @(Vic20::Key::KeyCBM),
|
||||
@(VK_Control): @(Vic20::Key::KeyControl),
|
||||
@(VK_Space): @(Key::KeySpace),
|
||||
@(VK_Return): @(Key::KeyReturn),
|
||||
@(VK_Delete): @(Key::KeyDelete),
|
||||
@(VK_ANSI_Comma): @(Key::KeyComma),
|
||||
@(VK_ANSI_Period): @(Key::KeyFullStop),
|
||||
@(VK_ANSI_Minus): @(Key::KeyDash),
|
||||
@(VK_ANSI_Equal): @(Key::KeyEquals),
|
||||
@(VK_ANSI_Semicolon): @(Key::KeyColon),
|
||||
@(VK_ANSI_Quote): @(Key::KeySemicolon),
|
||||
@(VK_ANSI_Slash): @(Key::KeySlash),
|
||||
@(VK_Option): @(Key::KeyCBM),
|
||||
@(VK_Control): @(Key::KeyControl),
|
||||
|
||||
@(VK_F1): @(Vic20::Key::KeyF1), @(VK_F3): @(Vic20::Key::KeyF3),
|
||||
@(VK_F5): @(Vic20::Key::KeyF5), @(VK_F7): @(Vic20::Key::KeyF7),
|
||||
@(VK_F1): @(Key::KeyF1), @(VK_F3): @(Key::KeyF3),
|
||||
@(VK_F5): @(Key::KeyF5), @(VK_F7): @(Key::KeyF7),
|
||||
|
||||
@(VK_ANSI_Grave): @(Vic20::Key::KeyLeft),
|
||||
@(VK_Tab): @(Vic20::Key::KeyRunStop),
|
||||
@(VK_ANSI_LeftBracket): @(Vic20::Key::KeyAt),
|
||||
@(VK_ANSI_RightBracket): @(Vic20::Key::KeyAsterisk),
|
||||
@(VK_ANSI_Backslash): @(Vic20::Key::KeyUp),
|
||||
@(VK_ANSI_Grave): @(Key::KeyLeft),
|
||||
@(VK_Tab): @(Key::KeyRunStop),
|
||||
@(VK_ANSI_LeftBracket): @(Key::KeyAt),
|
||||
@(VK_ANSI_RightBracket): @(Key::KeyAsterisk),
|
||||
@(VK_ANSI_Backslash): @(Key::KeyUp),
|
||||
|
||||
@(VK_RightArrow): @(Vic20::Key::KeyRight),
|
||||
@(VK_DownArrow): @(Vic20::Key::KeyDown),
|
||||
@(VK_RightArrow): @(Key::KeyRight),
|
||||
@(VK_DownArrow): @(Key::KeyDown),
|
||||
};
|
||||
|
||||
// Not yet mapped:
|
||||
@ -120,11 +126,11 @@
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case VK_UpArrow: _vic20.set_joystick_state(Vic20::JoystickInput::Up, isPressed); break;
|
||||
case VK_DownArrow: _vic20.set_joystick_state(Vic20::JoystickInput::Down, isPressed); break;
|
||||
case VK_LeftArrow: _vic20.set_joystick_state(Vic20::JoystickInput::Left, isPressed); break;
|
||||
case VK_RightArrow: _vic20.set_joystick_state(Vic20::JoystickInput::Right, isPressed); break;
|
||||
case VK_ANSI_A: _vic20.set_joystick_state(Vic20::JoystickInput::Fire, isPressed); break;
|
||||
case VK_UpArrow: _vic20.set_joystick_state(JoystickInput::Up, isPressed); break;
|
||||
case VK_DownArrow: _vic20.set_joystick_state(JoystickInput::Down, isPressed); break;
|
||||
case VK_LeftArrow: _vic20.set_joystick_state(JoystickInput::Left, isPressed); break;
|
||||
case VK_RightArrow: _vic20.set_joystick_state(JoystickInput::Right, isPressed); break;
|
||||
case VK_ANSI_A: _vic20.set_joystick_state(JoystickInput::Fire, isPressed); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -135,16 +141,18 @@
|
||||
NSNumber *targetKey = vicKeysByKeys[@(key)];
|
||||
if(targetKey)
|
||||
{
|
||||
_vic20.set_key_state((Vic20::Key)targetKey.integerValue, isPressed);
|
||||
_vic20.set_key_state((Key)targetKey.integerValue, isPressed);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Unmapped: %02x", key);
|
||||
}
|
||||
} break;
|
||||
|
||||
case VK_Shift:
|
||||
// Yuck
|
||||
_vic20.set_key_state(Vic20::Key::KeyLShift, isPressed);
|
||||
_vic20.set_key_state(Vic20::Key::KeyRShift, isPressed);
|
||||
_vic20.set_key_state(Key::KeyLShift, isPressed);
|
||||
_vic20.set_key_state(Key::KeyRShift, isPressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
20
OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.h
Normal file
20
OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// C1540Bridge.h
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface C1540Bridge : NSObject
|
||||
|
||||
@property (nonatomic) BOOL attentionLine;
|
||||
@property (nonatomic) BOOL dataLine;
|
||||
@property (nonatomic) BOOL clockLine;
|
||||
|
||||
- (void)runForCycles:(NSUInteger)numberOfCycles;
|
||||
- (void)setROM:(NSData *)ROM;
|
||||
|
||||
@end
|
83
OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm
Normal file
83
OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// C1540Bridge.m
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import "C1540Bridge.h"
|
||||
#include "C1540.hpp"
|
||||
|
||||
class VanillaSerialPort: public Commodore::Serial::Port {
|
||||
public:
|
||||
void set_input(Commodore::Serial::Line line, Commodore::Serial::LineLevel value)
|
||||
{
|
||||
_input_line_levels[(int)line] = value;
|
||||
}
|
||||
|
||||
Commodore::Serial::LineLevel _input_line_levels[5];
|
||||
};
|
||||
|
||||
@implementation C1540Bridge
|
||||
{
|
||||
Commodore::C1540::Machine _c1540;
|
||||
std::shared_ptr<Commodore::Serial::Bus> _serialBus;
|
||||
std::shared_ptr<VanillaSerialPort> _serialPort;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if(self)
|
||||
{
|
||||
_serialBus.reset(new ::Commodore::Serial::Bus);
|
||||
_serialPort.reset(new VanillaSerialPort);
|
||||
|
||||
_c1540.set_serial_bus(_serialBus);
|
||||
Commodore::Serial::AttachPortAndBus(_serialPort, _serialBus);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setROM:(NSData *)ROM
|
||||
{
|
||||
_c1540.set_rom((uint8_t *)ROM.bytes);
|
||||
}
|
||||
|
||||
- (void)runForCycles:(NSUInteger)numberOfCycles
|
||||
{
|
||||
_c1540.run_for_cycles((int)numberOfCycles);
|
||||
}
|
||||
|
||||
- (void)setAttentionLine:(BOOL)attentionLine
|
||||
{
|
||||
_serialPort->set_output(Commodore::Serial::Line::Attention, attentionLine ? Commodore::Serial::LineLevel::High : Commodore::Serial::LineLevel::Low);
|
||||
}
|
||||
|
||||
- (BOOL)attentionLine
|
||||
{
|
||||
return _serialPort->_input_line_levels[Commodore::Serial::Line::Attention];
|
||||
}
|
||||
|
||||
- (void)setDataLine:(BOOL)dataLine
|
||||
{
|
||||
_serialPort->set_output(Commodore::Serial::Line::Data, dataLine ? Commodore::Serial::LineLevel::High : Commodore::Serial::LineLevel::Low);
|
||||
}
|
||||
|
||||
- (BOOL)dataLine
|
||||
{
|
||||
return _serialPort->_input_line_levels[Commodore::Serial::Line::Data];
|
||||
}
|
||||
|
||||
- (void)setClockLine:(BOOL)clockLine
|
||||
{
|
||||
_serialPort->set_output(Commodore::Serial::Line::Clock, clockLine ? Commodore::Serial::LineLevel::High : Commodore::Serial::LineLevel::Low);
|
||||
}
|
||||
|
||||
- (BOOL)clockLine
|
||||
{
|
||||
return _serialPort->_input_line_levels[Commodore::Serial::Line::Clock];
|
||||
}
|
||||
|
||||
@end
|
@ -5,3 +5,4 @@
|
||||
#import "TestMachine.h"
|
||||
#import "MOS6522Bridge.h"
|
||||
#import "MOS6532Bridge.h"
|
||||
#import "C1540Bridge.h"
|
79
OSBindings/Mac/Clock SignalTests/C1540Tests.swift
Normal file
79
OSBindings/Mac/Clock SignalTests/C1540Tests.swift
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// C1540Tests.swift
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class C1540Tests: XCTestCase {
|
||||
|
||||
private func with1540(action: (C1540Bridge) -> ()) {
|
||||
let bridge = C1540Bridge()
|
||||
|
||||
if let path = NSBundle.mainBundle().pathForResource("1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
|
||||
let data = NSData(contentsOfFile: path)
|
||||
bridge.setROM(data)
|
||||
}
|
||||
|
||||
action(bridge)
|
||||
}
|
||||
|
||||
private func transmit(c1540: C1540Bridge, value: Int) {
|
||||
var shiftedValue = value
|
||||
|
||||
c1540.dataLine = true
|
||||
c1540.runForCycles(256)
|
||||
XCTAssert(c1540.dataLine == false, "Listener should have taken data line low for start of transmission")
|
||||
|
||||
c1540.clockLine = true
|
||||
c1540.runForCycles(256) // this isn't time limited on real hardware
|
||||
XCTAssert(c1540.dataLine == true, "Listener should have let data line go high again")
|
||||
|
||||
// set up for byte transfer
|
||||
c1540.clockLine = false
|
||||
c1540.dataLine = true
|
||||
c1540.runForCycles(40)
|
||||
|
||||
// transmit bits
|
||||
for _ in 0..<8 {
|
||||
// load data line
|
||||
c1540.dataLine = (shiftedValue & 1) == 1
|
||||
shiftedValue >>= 1
|
||||
|
||||
// toggle clock
|
||||
c1540.clockLine = true
|
||||
c1540.runForCycles(40)
|
||||
c1540.clockLine = false
|
||||
c1540.runForCycles(40)
|
||||
}
|
||||
|
||||
// check for acknowledgment
|
||||
c1540.dataLine = true
|
||||
c1540.runForCycles(1000)
|
||||
XCTAssert(c1540.dataLine == false, "Listener should have acknowledged byte")
|
||||
}
|
||||
|
||||
// MARK: EOI
|
||||
|
||||
func testTransmission() {
|
||||
with1540 {
|
||||
// allow some booting time
|
||||
$0.runForCycles(2000000)
|
||||
|
||||
// I want to be talker, so hold attention and clock low with data high
|
||||
$0.clockLine = false
|
||||
$0.attentionLine = false
|
||||
$0.dataLine = true
|
||||
|
||||
// proceed 1 ms and check that the 1540 pulled the data line low
|
||||
$0.runForCycles(1000)
|
||||
XCTAssert($0.dataLine == false, "Listener should have taken data line low")
|
||||
|
||||
// transmit LISTEN #8
|
||||
self.transmit($0, value: 0x28)
|
||||
}
|
||||
}
|
||||
}
|
@ -666,6 +666,7 @@ template <class T> class Processor {
|
||||
break;
|
||||
|
||||
case OperationDecodeOperation:
|
||||
// printf("d %02x\n", _operation);
|
||||
decode_operation(_operation);
|
||||
break;
|
||||
|
||||
|
5
ROMImages/Commodore1540/readme.txt
Normal file
5
ROMImages/Commodore1540/readme.txt
Normal file
@ -0,0 +1,5 @@
|
||||
ROM files would ordinarily go here; the copyright status of these is uncertain so they have not been included in this repository.
|
||||
|
||||
Expected files:
|
||||
|
||||
1540.rom; a 16kb image of the 1540's ROM area.
|
Loading…
Reference in New Issue
Block a user