mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-04 18:29:40 +00:00
Attempt to wire in a CRTC.
This commit is contained in:
parent
2af6259963
commit
80b2ccd418
@ -17,10 +17,13 @@
|
|||||||
#include "../../InstructionSets/x86/Instruction.hpp"
|
#include "../../InstructionSets/x86/Instruction.hpp"
|
||||||
#include "../../InstructionSets/x86/Perform.hpp"
|
#include "../../InstructionSets/x86/Perform.hpp"
|
||||||
|
|
||||||
#include "../../Components/AudioToggle/AudioToggle.hpp"
|
#include "../../Components/6845/CRTC6845.hpp"
|
||||||
#include "../../Components/8255/i8255.hpp"
|
#include "../../Components/8255/i8255.hpp"
|
||||||
|
#include "../../Components/AudioToggle/AudioToggle.hpp"
|
||||||
|
|
||||||
#include "../../Numeric/RegisterSizes.hpp"
|
#include "../../Numeric/RegisterSizes.hpp"
|
||||||
|
|
||||||
|
#include "../../Outputs/CRT/CRT.hpp"
|
||||||
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
|
|
||||||
#include "../AudioProducer.hpp"
|
#include "../AudioProducer.hpp"
|
||||||
@ -32,6 +35,70 @@
|
|||||||
|
|
||||||
namespace PCCompatible {
|
namespace PCCompatible {
|
||||||
|
|
||||||
|
class MDA {
|
||||||
|
public:
|
||||||
|
MDA() :
|
||||||
|
crtc_(Motorola::CRTC::Personality::HD6845S, outputter_),
|
||||||
|
crt_(873, 9, 382, 3, Outputs::Display::InputDataType::Luminance1)
|
||||||
|
{
|
||||||
|
crt_.set_visible_area(Outputs::Display::Rect(0.1072f, 0.1f, 0.842105263157895f, 0.842105263157895f));
|
||||||
|
crt_.set_display_type(Outputs::Display::DisplayType::CompositeMonochrome);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_for(Cycles cycles) {
|
||||||
|
// I _think_ the MDA's CRTC is clocked at 14/9ths the PIT clock.
|
||||||
|
// Do that conversion here.
|
||||||
|
full_clock_ += 14 * cycles.as<int>();
|
||||||
|
crtc_.run_for(Cycles(full_clock_ / 9));
|
||||||
|
full_clock_ %= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int address>
|
||||||
|
void write(uint8_t value) {
|
||||||
|
if constexpr (address & 0x8) {
|
||||||
|
printf("TODO: write MDA control %02x\n", value);
|
||||||
|
} else {
|
||||||
|
if constexpr (address & 0x1) {
|
||||||
|
crtc_.set_register(value);
|
||||||
|
} else {
|
||||||
|
crtc_.select_register(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int address>
|
||||||
|
uint8_t read() {
|
||||||
|
if constexpr (address & 0x8) {
|
||||||
|
printf("TODO: read MDA control\n");
|
||||||
|
return 0xff;
|
||||||
|
} else {
|
||||||
|
return crtc_.get_register();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Call-ins for ScanProducer.
|
||||||
|
|
||||||
|
void set_scan_target(Outputs::Display::ScanTarget *scan_target) {
|
||||||
|
crt_.set_scan_target(scan_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
Outputs::Display::ScanStatus get_scaled_scan_status() const {
|
||||||
|
return crt_.get_scaled_scan_status() / 4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CRTCOutputter {
|
||||||
|
void perform_bus_cycle_phase1(const Motorola::CRTC::BusState &) {
|
||||||
|
printf("");
|
||||||
|
}
|
||||||
|
void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {}
|
||||||
|
} outputter_;
|
||||||
|
Motorola::CRTC::CRTC6845<CRTCOutputter> crtc_;
|
||||||
|
Outputs::CRT::CRT crt_;
|
||||||
|
|
||||||
|
int full_clock_;
|
||||||
|
};
|
||||||
|
|
||||||
struct PCSpeaker {
|
struct PCSpeaker {
|
||||||
PCSpeaker() :
|
PCSpeaker() :
|
||||||
toggle(queue),
|
toggle(queue),
|
||||||
@ -425,7 +492,8 @@ struct Memory {
|
|||||||
|
|
||||||
class IO {
|
class IO {
|
||||||
public:
|
public:
|
||||||
IO(PIT &pit, DMA &dma, PPI &ppi, PIC &pic) : pit_(pit), dma_(dma), ppi_(ppi), pic_(pic) {}
|
IO(PIT &pit, DMA &dma, PPI &ppi, PIC &pic, MDA &mda) :
|
||||||
|
pit_(pit), dma_(dma), ppi_(ppi), pic_(pic), mda_(mda) {}
|
||||||
|
|
||||||
template <typename IntT> void out(uint16_t port, IntT value) {
|
template <typename IntT> void out(uint16_t port, IntT value) {
|
||||||
switch(port) {
|
switch(port) {
|
||||||
@ -476,10 +544,38 @@ class IO {
|
|||||||
printf("TODO: DMA page write of %02x at %04x\n", value, port);
|
printf("TODO: DMA page write of %02x at %04x\n", value, port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03b0: case 0x03b1: case 0x03b2: case 0x03b3:
|
case 0x03b0:
|
||||||
case 0x03b4: case 0x03b5: case 0x03b6: case 0x03b7:
|
case 0x03b2:
|
||||||
case 0x03b8: case 0x03b9: case 0x03ba: case 0x03bb:
|
case 0x03b4:
|
||||||
case 0x03bc: case 0x03bd: case 0x03be: case 0x03bf:
|
case 0x03b6:
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
|
mda_.write<0>(value);
|
||||||
|
mda_.write<1>(value >> 8);
|
||||||
|
} else {
|
||||||
|
mda_.write<0>(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03b1:
|
||||||
|
case 0x03b3:
|
||||||
|
case 0x03b5:
|
||||||
|
case 0x03b7:
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
|
mda_.write<1>(value);
|
||||||
|
mda_.write<0>(value >> 8);
|
||||||
|
} else {
|
||||||
|
mda_.write<1>(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03b8:
|
||||||
|
case 0x03b9:
|
||||||
|
case 0x03ba:
|
||||||
|
case 0x03bb:
|
||||||
|
case 0x03bc:
|
||||||
|
case 0x03bd:
|
||||||
|
case 0x03be:
|
||||||
|
case 0x03bf:
|
||||||
printf("TODO: MDA write of %02x at %04x\n", value, port);
|
printf("TODO: MDA write of %02x at %04x\n", value, port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -532,6 +628,7 @@ class IO {
|
|||||||
DMA &dma_;
|
DMA &dma_;
|
||||||
PPI &ppi_;
|
PPI &ppi_;
|
||||||
PIC &pic_;
|
PIC &pic_;
|
||||||
|
MDA &mda_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FlowController {
|
class FlowController {
|
||||||
@ -586,7 +683,7 @@ class ConcreteMachine:
|
|||||||
ppi_handler_(speaker_),
|
ppi_handler_(speaker_),
|
||||||
pit_(pit_observer_),
|
pit_(pit_observer_),
|
||||||
ppi_(ppi_handler_),
|
ppi_(ppi_handler_),
|
||||||
context(pit_, dma_, ppi_, pic_)
|
context(pit_, dma_, ppi_, pic_, mda_)
|
||||||
{
|
{
|
||||||
// Use clock rate as a MIPS count; keeping it as a multiple or divisor of the PIT frequency is easy.
|
// Use clock rate as a MIPS count; keeping it as a multiple or divisor of the PIT frequency is easy.
|
||||||
static constexpr int pit_frequency = 1'193'182;
|
static constexpr int pit_frequency = 1'193'182;
|
||||||
@ -634,6 +731,11 @@ class ConcreteMachine:
|
|||||||
pit_.run_for(1);
|
pit_.run_for(1);
|
||||||
++speaker_.cycles_since_update;
|
++speaker_.cycles_since_update;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Advance CRTC at a more approximate rate.
|
||||||
|
//
|
||||||
|
mda_.run_for(Cycles(3));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Perform one CPU instruction every three PIT cycles.
|
// Perform one CPU instruction every three PIT cycles.
|
||||||
// i.e. CPU instruction rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS.
|
// i.e. CPU instruction rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS.
|
||||||
@ -692,9 +794,11 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ScanProducer.
|
// MARK: - ScanProducer.
|
||||||
void set_scan_target([[maybe_unused]] Outputs::Display::ScanTarget *scan_target) override {}
|
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
|
||||||
|
mda_.set_scan_target(scan_target);
|
||||||
|
}
|
||||||
Outputs::Display::ScanStatus get_scaled_scan_status() const override {
|
Outputs::Display::ScanStatus get_scaled_scan_status() const override {
|
||||||
return Outputs::Display::ScanStatus();
|
return mda_.get_scaled_scan_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - AudioProducer.
|
// MARK: - AudioProducer.
|
||||||
@ -713,6 +817,7 @@ class ConcreteMachine:
|
|||||||
PIC pic_;
|
PIC pic_;
|
||||||
DMA dma_;
|
DMA dma_;
|
||||||
PCSpeaker speaker_;
|
PCSpeaker speaker_;
|
||||||
|
MDA mda_;
|
||||||
|
|
||||||
PITObserver pit_observer_;
|
PITObserver pit_observer_;
|
||||||
i8255PortHandler ppi_handler_;
|
i8255PortHandler ppi_handler_;
|
||||||
@ -721,11 +826,11 @@ class ConcreteMachine:
|
|||||||
PPI ppi_;
|
PPI ppi_;
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
Context(PIT &pit, DMA &dma, PPI &ppi, PIC &pic) :
|
Context(PIT &pit, DMA &dma, PPI &ppi, PIC &pic, MDA &mda) :
|
||||||
segments(registers),
|
segments(registers),
|
||||||
memory(registers, segments),
|
memory(registers, segments),
|
||||||
flow_controller(registers, segments),
|
flow_controller(registers, segments),
|
||||||
io(pit, dma, ppi, pic)
|
io(pit, dma, ppi, pic, mda)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user