1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 03:32:01 +00:00

Started trying to float out bus control to cartridges.

This commit is contained in:
Thomas Harte 2017-03-17 20:28:07 -04:00
parent a04a58e01f
commit 14a76af0d3
5 changed files with 232 additions and 26 deletions

View File

@ -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

View 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 */

View 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 */

View File

@ -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>";

View File

@ -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) {