mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Started trying to float out bus control to cartridges.
This commit is contained in:
parent
a04a58e01f
commit
14a76af0d3
@ -16,6 +16,7 @@
|
||||
#include "PIA.hpp"
|
||||
#include "Speaker.hpp"
|
||||
#include "TIA.hpp"
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
#include "Atari2600Inputs.h"
|
||||
@ -48,9 +49,9 @@ class Machine:
|
||||
// to satisfy CRTMachine::Machine
|
||||
virtual void setup_output(float aspect_ratio);
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return tia_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return speaker_; }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return cartridge_->tia_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return cartridge_->speaker_; }
|
||||
virtual void run_for_cycles(int number_of_cycles) { cartridge_->run_for_cycles(number_of_cycles); }
|
||||
|
||||
// to satisfy Outputs::CRT::Delegate
|
||||
virtual void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs);
|
||||
@ -70,27 +71,8 @@ class Machine:
|
||||
// Activision stack records
|
||||
uint8_t last_opcode_;
|
||||
|
||||
// the RIOT and TIA
|
||||
PIA mos6532_;
|
||||
std::unique_ptr<TIA> tia_;
|
||||
|
||||
// joystick state
|
||||
uint8_t tia_input_value_[2];
|
||||
|
||||
// outputs
|
||||
std::shared_ptr<Speaker> speaker_;
|
||||
|
||||
// speaker backlog accumlation counter
|
||||
unsigned int cycles_since_speaker_update_;
|
||||
inline void update_audio();
|
||||
|
||||
// video backlog accumulation counter
|
||||
unsigned int cycles_since_video_update_;
|
||||
inline void update_video();
|
||||
|
||||
// RIOT backlog accumulation counter
|
||||
unsigned int cycles_since_6532_update_;
|
||||
inline void update_6532();
|
||||
// the cartridge
|
||||
std::unique_ptr<CartridgeBase> cartridge_;
|
||||
|
||||
// output frame rate tracker
|
||||
struct FrameRecord
|
||||
|
202
Machines/Atari2600/Cartridge.hpp
Normal file
202
Machines/Atari2600/Cartridge.hpp
Normal file
@ -0,0 +1,202 @@
|
||||
//
|
||||
// Cartridge.h
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 17/03/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Atari2600_Cartridge_hpp
|
||||
#define Atari2600_Cartridge_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
class CartridgeBase {
|
||||
public:
|
||||
virtual void run_for_cycles(int number_of_cycles) = 0;
|
||||
|
||||
// the RIOT, TIA and speaker
|
||||
PIA mos6532_;
|
||||
std::shared_ptr<TIA> tia_;
|
||||
std::shared_ptr<Speaker> speaker_;
|
||||
|
||||
// joystick state
|
||||
uint8_t tia_input_value_[2];
|
||||
|
||||
protected:
|
||||
// speaker backlog accumlation counter
|
||||
unsigned int cycles_since_speaker_update_;
|
||||
inline void update_audio() {
|
||||
unsigned int audio_cycles = cycles_since_speaker_update_ / 114;
|
||||
cycles_since_speaker_update_ %= 114;
|
||||
speaker_->run_for_cycles(audio_cycles);
|
||||
}
|
||||
|
||||
// video backlog accumulation counter
|
||||
unsigned int cycles_since_video_update_;
|
||||
inline void update_video() {
|
||||
tia_->run_for_cycles((int)cycles_since_video_update_);
|
||||
cycles_since_video_update_ = 0;
|
||||
}
|
||||
|
||||
// RIOT backlog accumulation counter
|
||||
unsigned int cycles_since_6532_update_;
|
||||
inline void update_6532() {
|
||||
mos6532_.run_for_cycles(cycles_since_6532_update_);
|
||||
cycles_since_6532_update_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> class Cartridge:
|
||||
public CPU6502::Processor<Cartridge<T>>,
|
||||
public CartridgeBase {
|
||||
|
||||
public:
|
||||
void run_for_cycles(int number_of_cycles) {}
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
uint8_t returnValue = 0xff;
|
||||
unsigned int cycles_run_for = 3;
|
||||
|
||||
// this occurs as a feedback loop — the 2600 requests ready, then performs the cycles_run_for
|
||||
// leap to the end of ready only once ready is signalled — because on a 6502 ready doesn't take
|
||||
// effect until the next read; therefore it isn't safe to assume that signalling ready immediately
|
||||
// skips to the end of the line.
|
||||
if(operation == CPU6502::BusOperation::Ready)
|
||||
cycles_run_for = (unsigned int)tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_);
|
||||
|
||||
cycles_since_speaker_update_ += cycles_run_for;
|
||||
cycles_since_video_update_ += cycles_run_for;
|
||||
cycles_since_6532_update_ += (cycles_run_for / 3);
|
||||
|
||||
if(operation != CPU6502::BusOperation::Ready) {
|
||||
uint16_t masked_address = address & 0x1fff;
|
||||
|
||||
// give the cartridge a chance to respond to the bus access
|
||||
static_cast<T *>(this)->perform_bus_operation(operation, address, value);
|
||||
|
||||
// check for a RIOT RAM access
|
||||
if((address&0x1280) == 0x80) {
|
||||
if(isReadOperation(operation)) {
|
||||
returnValue &= mos6532_.get_ram(address);
|
||||
} else {
|
||||
mos6532_.set_ram(address, *value);
|
||||
}
|
||||
}
|
||||
|
||||
// check for a TIA access
|
||||
if(!(address&0x1080)) {
|
||||
if(isReadOperation(operation)) {
|
||||
const uint16_t decodedAddress = address & 0xf;
|
||||
switch(decodedAddress) {
|
||||
case 0x00: // missile 0 / player collisions
|
||||
case 0x01: // missile 1 / player collisions
|
||||
case 0x02: // player 0 / playfield / ball collisions
|
||||
case 0x03: // player 1 / playfield / ball collisions
|
||||
case 0x04: // missile 0 / playfield / ball collisions
|
||||
case 0x05: // missile 1 / playfield / ball collisions
|
||||
case 0x06: // ball / playfield collisions
|
||||
case 0x07: // player / player, missile / missile collisions
|
||||
returnValue &= tia_->get_collision_flags(decodedAddress);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
// TODO: pot ports
|
||||
returnValue &= 0;
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
returnValue &= tia_input_value_[decodedAddress - 0x0c];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
const uint16_t decodedAddress = address & 0x3f;
|
||||
switch(decodedAddress) {
|
||||
case 0x00: update_video(); tia_->set_sync(*value & 0x02); break;
|
||||
case 0x01: update_video(); tia_->set_blank(*value & 0x02); break;
|
||||
|
||||
case 0x02: set_ready_line(true); break;
|
||||
case 0x03: update_video(); tia_->reset_horizontal_counter(); break;
|
||||
// TODO: audio will now be out of synchronisation — fix
|
||||
|
||||
case 0x04:
|
||||
case 0x05: update_video(); tia_->set_player_number_and_size(decodedAddress - 0x04, *value); break;
|
||||
case 0x06:
|
||||
case 0x07: update_video(); tia_->set_player_missile_colour(decodedAddress - 0x06, *value); break;
|
||||
case 0x08: update_video(); tia_->set_playfield_ball_colour(*value); break;
|
||||
case 0x09: update_video(); tia_->set_background_colour(*value); break;
|
||||
case 0x0a: update_video(); tia_->set_playfield_control_and_ball_size(*value); break;
|
||||
case 0x0b:
|
||||
case 0x0c: update_video(); tia_->set_player_reflected(decodedAddress - 0x0b, !((*value)&8)); break;
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x0f: update_video(); tia_->set_playfield(decodedAddress - 0x0d, *value); break;
|
||||
case 0x10:
|
||||
case 0x11: update_video(); tia_->set_player_position(decodedAddress - 0x10); break;
|
||||
case 0x12:
|
||||
case 0x13: update_video(); tia_->set_missile_position(decodedAddress - 0x12); break;
|
||||
case 0x14: update_video(); tia_->set_ball_position(); break;
|
||||
case 0x1b:
|
||||
case 0x1c: update_video(); tia_->set_player_graphic(decodedAddress - 0x1b, *value); break;
|
||||
case 0x1d:
|
||||
case 0x1e: update_video(); tia_->set_missile_enable(decodedAddress - 0x1d, (*value)&2); break;
|
||||
case 0x1f: update_video(); tia_->set_ball_enable((*value)&2); break;
|
||||
case 0x20:
|
||||
case 0x21: update_video(); tia_->set_player_motion(decodedAddress - 0x20, *value); break;
|
||||
case 0x22:
|
||||
case 0x23: update_video(); tia_->set_missile_motion(decodedAddress - 0x22, *value); break;
|
||||
case 0x24: update_video(); tia_->set_ball_motion(*value); break;
|
||||
case 0x25:
|
||||
case 0x26: tia_->set_player_delay(decodedAddress - 0x25, (*value)&1); break;
|
||||
case 0x27: tia_->set_ball_delay((*value)&1); break;
|
||||
case 0x28:
|
||||
case 0x29: update_video(); tia_->set_missile_position_to_player(decodedAddress - 0x28, (*value)&2); break;
|
||||
case 0x2a: update_video(); tia_->move(); break;
|
||||
case 0x2b: update_video(); tia_->clear_motion(); break;
|
||||
case 0x2c: update_video(); tia_->clear_collision_flags(); break;
|
||||
|
||||
case 0x15:
|
||||
case 0x16: update_audio(); speaker_->set_control(decodedAddress - 0x15, *value); break;
|
||||
case 0x17:
|
||||
case 0x18: update_audio(); speaker_->set_divider(decodedAddress - 0x17, *value); break;
|
||||
case 0x19:
|
||||
case 0x1a: update_audio(); speaker_->set_volume(decodedAddress - 0x19, *value); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for a PIA access
|
||||
if((address&0x1280) == 0x280) {
|
||||
update_6532();
|
||||
if(isReadOperation(operation)) {
|
||||
returnValue &= mos6532_.get_register(address);
|
||||
} else {
|
||||
mos6532_.set_register(address, *value);
|
||||
}
|
||||
}
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value &= returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) set_ready_line(false);
|
||||
|
||||
return cycles_run_for / 3;
|
||||
}
|
||||
|
||||
void synchronise() {
|
||||
update_audio();
|
||||
update_video();
|
||||
speaker_->flush();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* Atari2600_Cartridge_hpp */
|
18
Machines/Atari2600/CartridgeUnpaged.hpp
Normal file
18
Machines/Atari2600/CartridgeUnpaged.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// CartridgeUnpaged.h
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 17/03/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Atari2600_CartridgeUnpaged_hpp
|
||||
#define Atari2600_CartridgeUnpaged_hpp
|
||||
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeUnpaged_hpp */
|
@ -928,6 +928,8 @@
|
||||
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = "<group>"; };
|
||||
4BD69F921D98760000243FE1 /* AcornADF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AcornADF.cpp; sourceTree = "<group>"; };
|
||||
4BD69F931D98760000243FE1 /* AcornADF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AcornADF.hpp; sourceTree = "<group>"; };
|
||||
4BE069991E7C942C00DD379F /* Cartridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
||||
4BE0699A1E7C9C5A00DD379F /* CartridgeUnpaged.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CartridgeUnpaged.hpp; sourceTree = "<group>"; };
|
||||
4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = "<group>"; };
|
||||
4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; };
|
||||
4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = "<group>"; };
|
||||
@ -1110,6 +1112,8 @@
|
||||
4BEA52671DF34909007E74F2 /* PIA.hpp */,
|
||||
4BEA52651DF3472B007E74F2 /* Speaker.hpp */,
|
||||
4BE7C9171E3D397100A5496D /* TIA.hpp */,
|
||||
4BE069991E7C942C00DD379F /* Cartridge.hpp */,
|
||||
4BE0699A1E7C9C5A00DD379F /* CartridgeUnpaged.hpp */,
|
||||
);
|
||||
path = Atari2600;
|
||||
sourceTree = "<group>";
|
||||
|
@ -646,8 +646,8 @@ template <class T> class Processor {
|
||||
scheduleProgramProgramCounter++;
|
||||
|
||||
#define read_op(val, addr) nextBusOperation = BusOperation::ReadOpcode; busAddress = addr; busValue = &val
|
||||
#define read_mem(val, addr) nextBusOperation = BusOperation::Read; busAddress = addr; busValue = &val
|
||||
#define throwaway_read(addr) nextBusOperation = BusOperation::Read; busAddress = addr; busValue = &throwaway_target
|
||||
#define read_mem(val, addr) nextBusOperation = BusOperation::Read; busAddress = addr; busValue = &val; val = 0xff
|
||||
#define throwaway_read(addr) nextBusOperation = BusOperation::Read; busAddress = addr; busValue = &throwaway_target; throwaway_target = 0xff
|
||||
#define write_mem(val, addr) nextBusOperation = BusOperation::Write; busAddress = addr; busValue = &val
|
||||
|
||||
switch(cycle) {
|
||||
|
Loading…
Reference in New Issue
Block a user