mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 15:39:08 +00:00
Attempt to add interrupts.
This commit is contained in:
parent
ed766c74e6
commit
58b464bdfc
Machines/Commodore/Plus4
OSBindings/Mac/Clock Signal.xcodeproj
68
Machines/Commodore/Plus4/Interrupts.hpp
Normal file
68
Machines/Commodore/Plus4/Interrupts.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// Interrupts.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 12/12/2024.
|
||||
// Copyright © 2024 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
|
||||
namespace Commodore::Plus4 {
|
||||
|
||||
struct Interrupts {
|
||||
public:
|
||||
struct Delegate {
|
||||
virtual void set_irq_line(bool) = 0;
|
||||
};
|
||||
|
||||
Interrupts(Delegate &delegate) : delegate_(delegate) {}
|
||||
|
||||
enum Flag {
|
||||
Timer3 = 0x40,
|
||||
Timer2 = 0x10,
|
||||
Timer1 = 0x08,
|
||||
Raster = 0x02,
|
||||
};
|
||||
|
||||
uint8_t status() const {
|
||||
return status_ | ((status_ & mask_) ? 0x80 : 0x00);
|
||||
}
|
||||
|
||||
uint8_t mask() const {
|
||||
return mask_;
|
||||
}
|
||||
|
||||
void set_status(const uint8_t status) {
|
||||
status_ = status & 0x7f;
|
||||
update_output();
|
||||
}
|
||||
|
||||
void apply(const uint8_t interrupt) {
|
||||
status_ |= interrupt;
|
||||
update_output();
|
||||
}
|
||||
|
||||
void set_mask(const uint8_t mask) {
|
||||
mask_ = mask;
|
||||
update_output();
|
||||
}
|
||||
|
||||
private:
|
||||
void update_output() {
|
||||
const bool set = status_ & mask_;
|
||||
if(set != last_set_) {
|
||||
delegate_.set_irq_line(set);
|
||||
last_set_ = set;
|
||||
}
|
||||
}
|
||||
|
||||
Delegate &delegate_;
|
||||
uint8_t status_;
|
||||
uint8_t mask_;
|
||||
bool last_set_ = false;
|
||||
};
|
||||
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "Plus4.hpp"
|
||||
|
||||
#include "Interrupts.hpp"
|
||||
#include "Pager.hpp"
|
||||
#include "Video.hpp"
|
||||
|
||||
@ -21,6 +22,8 @@ namespace {
|
||||
|
||||
class Timers {
|
||||
public:
|
||||
Timers(Interrupts &interrupts) : interrupts_(interrupts) {}
|
||||
|
||||
template <int offset>
|
||||
void write(const uint8_t value) {
|
||||
const auto load_low = [&](uint16_t &target) {
|
||||
@ -78,16 +81,24 @@ private:
|
||||
|
||||
// Check for interrupt.
|
||||
if(!timers_[timer]) {
|
||||
switch(timer) {
|
||||
case 0: interrupts_.apply(Interrupts::Flag::Timer1); break;
|
||||
case 1: interrupts_.apply(Interrupts::Flag::Timer2); break;
|
||||
case 2: interrupts_.apply(Interrupts::Flag::Timer3); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t timers_[3]{};
|
||||
uint16_t timer0_reload_ = 0xffff;
|
||||
bool paused_[3]{};
|
||||
|
||||
Interrupts &interrupts_;
|
||||
};
|
||||
|
||||
class ConcreteMachine:
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public Interrupts::Delegate,
|
||||
public MachineTypes::TimedMachine,
|
||||
public MachineTypes::ScanProducer,
|
||||
public MachineTypes::MediaTarget,
|
||||
@ -95,7 +106,9 @@ class ConcreteMachine:
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
video_(map_)
|
||||
interrupts_(*this),
|
||||
timers_(interrupts_),
|
||||
video_(map_, interrupts_)
|
||||
{
|
||||
// PAL: 8867240 divided by 5 or 4?
|
||||
// NTSC: 7159090?
|
||||
@ -155,12 +168,24 @@ public:
|
||||
} else {
|
||||
if(isReadOperation(operation)) {
|
||||
switch(address) {
|
||||
case 0xff00: *value = timers_.read<0>(); break;
|
||||
case 0xff01: *value = timers_.read<1>(); break;
|
||||
case 0xff02: *value = timers_.read<2>(); break;
|
||||
case 0xff03: *value = timers_.read<3>(); break;
|
||||
case 0xff04: *value = timers_.read<4>(); break;
|
||||
case 0xff05: *value = timers_.read<5>(); break;
|
||||
case 0xff00: *value = timers_.read<0>(); break;
|
||||
case 0xff01: *value = timers_.read<1 >(); break;
|
||||
case 0xff02: *value = timers_.read<2>(); break;
|
||||
case 0xff03: *value = timers_.read<3>(); break;
|
||||
case 0xff04: *value = timers_.read<4>(); break;
|
||||
case 0xff05: *value = timers_.read<5>(); break;
|
||||
|
||||
case 0xff08:
|
||||
// TODO: keyboard.
|
||||
*value = 0xff;
|
||||
break;
|
||||
|
||||
case 0xff09: *value = interrupts_.status(); break;
|
||||
case 0xff0a: *value = interrupts_.mask(); break;
|
||||
|
||||
case 0xff0b: *value = video_.read<0xff0b>(); break;
|
||||
case 0xff1c: *value = video_.read<0xff1c>(); break;
|
||||
case 0xff1d: *value = video_.read<0xff1d>(); break;
|
||||
|
||||
default:
|
||||
printf("TODO: TED read at %04x\n", address);
|
||||
@ -174,6 +199,19 @@ public:
|
||||
case 0xff04: timers_.write<4>(*value); break;
|
||||
case 0xff05: timers_.write<5>(*value); break;
|
||||
|
||||
case 0xff08:
|
||||
// TODO: keyboard.
|
||||
break;
|
||||
|
||||
case 0xff09:
|
||||
interrupts_.set_status(*value);
|
||||
break;
|
||||
case 0xff0a:
|
||||
interrupts_.set_mask(*value);
|
||||
video_.write<0xff0a>(*value);
|
||||
break;
|
||||
case 0xff0b: video_.write<0xff0b>(*value); break;
|
||||
|
||||
case 0xff06: video_.write<0xff06>(*value); break;
|
||||
case 0xff07: video_.write<0xff07>(*value); break;
|
||||
case 0xff0c: video_.write<0xff0c>(*value); break;
|
||||
@ -198,6 +236,10 @@ public:
|
||||
private:
|
||||
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, ConcreteMachine, true> m6502_;
|
||||
|
||||
void set_irq_line(bool active) override {
|
||||
m6502_.set_irq_line(active);
|
||||
}
|
||||
|
||||
void page_rom() {
|
||||
map_.page<PagerSide::Read, 0x8000, 16384>(basic_.data());
|
||||
map_.page<PagerSide::Read, 0xc000, 16384>(kernel_.data());
|
||||
@ -227,6 +269,7 @@ private:
|
||||
std::vector<uint8_t> kernel_;
|
||||
std::vector<uint8_t> basic_;
|
||||
|
||||
Interrupts interrupts_;
|
||||
Cycles timers_subcycles_;
|
||||
Timers timers_;
|
||||
Video video_;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Interrupts.hpp"
|
||||
#include "Pager.hpp"
|
||||
|
||||
#include "../../../Numeric/UpperBound.hpp"
|
||||
@ -19,14 +20,26 @@ namespace Commodore::Plus4 {
|
||||
|
||||
struct Video {
|
||||
public:
|
||||
Video(const Commodore::Plus4::Pager &pager) :
|
||||
Video(const Commodore::Plus4::Pager &pager, Interrupts &interrupts) :
|
||||
crt_(465, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Luminance8Phase8),
|
||||
pager_(pager)
|
||||
pager_(pager),
|
||||
interrupts_(interrupts)
|
||||
{
|
||||
// TODO: perfect crop.
|
||||
crt_.set_visible_area(Outputs::Display::Rect(0.075f, 0.065f, 0.85f, 0.85f));
|
||||
}
|
||||
|
||||
template <uint16_t address>
|
||||
uint8_t read() const {
|
||||
switch(address) {
|
||||
case 0xff0b: return uint8_t(raster_interrupt_);
|
||||
case 0xff1c: return uint8_t(vertical_counter_ >> 8);
|
||||
case 0xff0d: return uint8_t(vertical_counter_);
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
template <uint16_t address>
|
||||
void write(const uint8_t value) {
|
||||
const auto load_high10 = [&](uint16_t &target) {
|
||||
@ -65,6 +78,13 @@ public:
|
||||
screen_memory_address_ = uint16_t((value & 0xf8) << 8);
|
||||
break;
|
||||
|
||||
case 0xff0a:
|
||||
raster_interrupt_ = (raster_interrupt_ & 0x00ff) | ((value & 1) << 8);
|
||||
break;
|
||||
case 0xff0b:
|
||||
raster_interrupt_ = (raster_interrupt_ & 0xff00) | value;
|
||||
break;
|
||||
|
||||
case 0xff0c: load_high10(cursor_address_); break;
|
||||
case 0xff0d: load_low8(cursor_address_); break;
|
||||
case 0xff1a: load_high10(character_row_address_); break;
|
||||
@ -144,6 +164,9 @@ public:
|
||||
case 257: if(!is_ntsc_) vertical_sync_ = false; break; // PAL vsync end.
|
||||
case 269: if(!is_ntsc_) vertical_blank_ = false; break; // PAL vertical blank end.
|
||||
}
|
||||
if(raster_interrupt_ == vertical_counter_) {
|
||||
interrupts_.apply(Interrupts::Flag::Raster);
|
||||
}
|
||||
|
||||
const auto next = Numeric::upper_bound<
|
||||
0, 3, 288, 290, 296, 304, 307, 315, 328, 336, 344, 358, 376, 384, 390, 400, 416, 424, 432, 440, 451, 465
|
||||
@ -216,7 +239,7 @@ public:
|
||||
break;
|
||||
|
||||
case 376: // Increment vertical line.
|
||||
++vertical_counter_;
|
||||
vertical_counter_ = (vertical_counter_ + 1) & 0x1ff;
|
||||
break;
|
||||
|
||||
case 384: // Burst start, end of screen — clear vertical line, vertical sub and character reload registers.
|
||||
@ -274,6 +297,8 @@ private:
|
||||
uint16_t character_generator_address_ = 0;
|
||||
uint16_t screen_memory_address_ = 0;
|
||||
|
||||
int raster_interrupt_ = 0x1ff;
|
||||
|
||||
// Field position.
|
||||
int horizontal_counter_ = 0;
|
||||
int vertical_counter_ = 0;
|
||||
@ -304,6 +329,7 @@ private:
|
||||
std::array<uint16_t, 5> background_{};
|
||||
|
||||
const Commodore::Plus4::Pager &pager_;
|
||||
Interrupts &interrupts_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1299,6 +1299,7 @@
|
||||
4B03291F2D0923E300C51EB5 /* Video.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Video.hpp; sourceTree = "<group>"; };
|
||||
4B0329202D0A78DC00C51EB5 /* UpperBound.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = UpperBound.hpp; sourceTree = "<group>"; };
|
||||
4B0329212D0A8C4700C51EB5 /* Pager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pager.hpp; sourceTree = "<group>"; };
|
||||
4B0329222D0BD32500C51EB5 /* Interrupts.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Interrupts.hpp; sourceTree = "<group>"; };
|
||||
4B0333AD2094081A0050B93D /* AppleDSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppleDSK.cpp; sourceTree = "<group>"; };
|
||||
4B0333AE2094081A0050B93D /* AppleDSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppleDSK.hpp; sourceTree = "<group>"; };
|
||||
4B046DC31CFE651500E9E45E /* ScanProducer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ScanProducer.hpp; sourceTree = "<group>"; };
|
||||
@ -3395,6 +3396,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B596EB02D037E8800FBF4B1 /* Plus4.cpp */,
|
||||
4B0329222D0BD32500C51EB5 /* Interrupts.hpp */,
|
||||
4B0329212D0A8C4700C51EB5 /* Pager.hpp */,
|
||||
4B596EAF2D037E8800FBF4B1 /* Plus4.hpp */,
|
||||
4B03291F2D0923E300C51EB5 /* Video.hpp */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user