1
0
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:
Thomas Harte 2024-12-12 22:07:51 -05:00
parent ed766c74e6
commit 58b464bdfc
4 changed files with 149 additions and 10 deletions
Machines/Commodore/Plus4
OSBindings/Mac/Clock Signal.xcodeproj

@ -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 */,