2016-07-05 17:28:27 +00:00
//
// 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
2016-07-05 20:39:18 +00:00
# include "../../../Processors/6502/CPU6502.hpp"
# include "../../../Components/6522/6522.hpp"
2016-07-05 21:27:02 +00:00
# include "../SerialBus.hpp"
2016-07-05 20:39:18 +00:00
namespace Commodore {
namespace C1540 {
2016-07-05 21:27:02 +00:00
class SerialPortVIA : public MOS : : MOS6522 < SerialPortVIA > , public MOS : : MOS6522IRQDelegate {
public :
using MOS6522IRQDelegate : : set_interrupt_status ;
2016-07-05 23:12:43 +00:00
2016-07-08 23:00:39 +00:00
SerialPortVIA ( ) : _portB ( 0x00 ) , _attention_acknowledge_level ( false ) , _attention_level_input ( true ) , _data_level_output ( false ) { }
2016-07-05 23:12:43 +00:00
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 ) {
2016-07-07 11:16:36 +00:00
printf ( " 1540 output: %02x \n " , value ) ;
2016-07-08 02:13:18 +00:00
// "ATNA (Attention Acknowledge) is an output from PB4 which is sensed on the serial data line after being exclusively "ored" by the attention line and inverted"
_attention_acknowledge_level = ! ( value & 0x10 ) ;
2016-07-08 23:00:39 +00:00
_data_level_output = ( value & 0x02 ) ;
2016-07-08 02:13:18 +00:00
2016-07-08 23:00:39 +00:00
serialPort - > set_output ( : : Commodore : : Serial : : Line : : Clock , ( : : Commodore : : Serial : : LineLevel ) ! ( value & 0x08 ) ) ;
update_data_line ( ) ;
2016-07-05 23:12:43 +00:00
}
2016-07-06 11:46:21 +00:00
// printf("1540 serial port VIA port B: %02x\n", value);
2016-07-05 23:12:43 +00:00
}
2016-07-06 11:46:21 +00:00
// else
// printf("1540 serial port VIA port A: %02x\n", value);
2016-07-05 23:12:43 +00:00
}
void set_serial_line_state ( : : Commodore : : Serial : : Line line , bool value ) {
2016-07-06 11:46:21 +00:00
// printf("1540 Serial port line %d: %s\n", line, value ? "on" : "off");
2016-07-05 23:12:43 +00:00
switch ( line ) {
default : break ;
2016-07-07 11:16:36 +00:00
case : : Commodore : : Serial : : Line : : Data : _portB = ( _portB & ~ 0x01 ) | ( value ? 0x00 : 0x01 ) ; break ;
case : : Commodore : : Serial : : Line : : Clock : _portB = ( _portB & ~ 0x04 ) | ( value ? 0x00 : 0x04 ) ; break ;
2016-07-05 23:19:46 +00:00
case : : Commodore : : Serial : : Line : : Attention :
2016-07-08 02:13:18 +00:00
// "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"
2016-07-08 23:00:39 +00:00
_attention_level_input = ! value ;
2016-07-07 11:16:36 +00:00
_portB = ( _portB & ~ 0x80 ) | ( value ? 0x00 : 0x80 ) ;
set_control_line_input ( Port : : A , Line : : One , ! value ) ;
2016-07-08 23:00:39 +00:00
update_data_line ( ) ;
2016-07-05 23:19:46 +00:00
break ;
2016-07-05 23:12:43 +00:00
}
}
void set_serial_port ( std : : shared_ptr < : : Commodore : : Serial : : Port > serialPort ) {
_serialPort = serialPort ;
}
private :
uint8_t _portB ;
std : : weak_ptr < : : Commodore : : Serial : : Port > _serialPort ;
2016-07-08 23:00:39 +00:00
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 ) {
serialPort - > set_output ( : : Commodore : : Serial : : Line : : Data ,
( : : Commodore : : Serial : : LineLevel ) ! ( _data_level_output
| | ( _attention_level_input = = _attention_acknowledge_level ) )
) ;
//
}
}
2016-07-05 21:27:02 +00:00
} ;
2016-07-07 00:22:46 +00:00
class DriveVIA : public MOS : : MOS6522 < DriveVIA > , public MOS : : MOS6522IRQDelegate {
2016-07-06 02:22:09 +00:00
public :
using MOS6522IRQDelegate : : set_interrupt_status ;
2016-07-07 02:17:32 +00:00
uint8_t get_port_input ( Port port ) {
2016-07-08 02:13:18 +00:00
if ( port )
{
return 0x7f ; // imply not sync, write protect tab uncovered
}
2016-07-07 02:17:32 +00:00
return 0xff ;
}
2016-07-06 02:22:09 +00:00
} ;
2016-07-05 21:27:02 +00:00
class SerialPort : public : : Commodore : : Serial : : Port {
public :
2016-07-07 10:44:13 +00:00
void set_input ( : : Commodore : : Serial : : Line line , : : Commodore : : Serial : : LineLevel level ) {
2016-07-05 23:12:43 +00:00
std : : shared_ptr < SerialPortVIA > serialPortVIA = _serialPortVIA . lock ( ) ;
2016-07-07 10:44:13 +00:00
if ( serialPortVIA ) serialPortVIA - > set_serial_line_state ( line , ( bool ) level ) ;
2016-07-05 21:27:02 +00:00
}
void set_serial_port_via ( std : : shared_ptr < SerialPortVIA > serialPortVIA ) {
_serialPortVIA = serialPortVIA ;
}
private :
std : : weak_ptr < SerialPortVIA > _serialPortVIA ;
} ;
2016-07-05 20:39:18 +00:00
class Machine :
2016-07-05 23:12:43 +00:00
public CPU6502 : : Processor < Machine > ,
public MOS : : MOS6522IRQDelegate : : Delegate {
2016-07-05 20:39:18 +00:00
public :
2016-07-05 21:27:02 +00:00
Machine ( ) ;
2016-07-05 20:39:18 +00:00
unsigned int perform_bus_operation ( CPU6502 : : BusOperation operation , uint16_t address , uint8_t * value ) ;
2016-07-05 20:54:25 +00:00
void set_rom ( const uint8_t * rom ) ;
2016-07-05 21:27:02 +00:00
void set_serial_bus ( std : : shared_ptr < : : Commodore : : Serial : : Bus > serial_bus ) ;
2016-07-05 20:39:18 +00:00
2016-07-05 23:12:43 +00:00
// to satisfy MOS::MOS6522::Delegate
virtual void mos6522_did_change_interrupt_status ( void * mos6522 ) ;
2016-07-05 20:39:18 +00:00
private :
uint8_t _ram [ 0x800 ] ;
uint8_t _rom [ 0x4000 ] ;
2016-07-05 21:27:02 +00:00
std : : shared_ptr < SerialPortVIA > _serialPortVIA ;
std : : shared_ptr < SerialPort > _serialPort ;
2016-07-06 02:22:09 +00:00
DriveVIA _driveVIA ;
2016-07-05 20:39:18 +00:00
} ;
}
}
2016-07-05 17:28:27 +00:00
# endif /* Commodore1540_hpp */