1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-29 12:50:28 +00:00

Add enough of the DMA subsystem to trip over in PPI world.

This commit is contained in:
Thomas Harte 2023-11-19 22:55:29 -05:00
parent 119c83eb18
commit 55f466f2fa

View File

@ -13,6 +13,8 @@
#include "../../InstructionSets/x86/Instruction.hpp" #include "../../InstructionSets/x86/Instruction.hpp"
#include "../../InstructionSets/x86/Perform.hpp" #include "../../InstructionSets/x86/Perform.hpp"
#include "../../Numeric/RegisterSizes.hpp"
#include "../ScanProducer.hpp" #include "../ScanProducer.hpp"
#include "../TimedMachine.hpp" #include "../TimedMachine.hpp"
@ -20,6 +22,71 @@
namespace PCCompatible { namespace PCCompatible {
class DMA {
public:
void flip_flop_reset() {
next_access_low = true;
}
void mask_reset() {
// TODO: set all mask bits off.
}
void master_reset() {
flip_flop_reset();
// TODO: clear status, set all mask bits on.
}
template <int address>
void write(uint8_t value) {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low ^= true;
if(next_access_low) {
if constexpr (is_count) {
channels_[channel].count.halves.high = value;
} else {
channels_[channel].address.halves.high = value;
}
} else {
if constexpr (is_count) {
channels_[channel].count.halves.low = value;
} else {
channels_[channel].address.halves.low = value;
}
}
}
template <int address>
uint8_t read() {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low ^= true;
if(next_access_low) {
if constexpr (is_count) {
return channels_[channel].count.halves.high;
} else {
return channels_[channel].address.halves.high;
}
} else {
if constexpr (is_count) {
return channels_[channel].count.halves.low;
} else {
return channels_[channel].address.halves.low;
}
}
}
private:
bool next_access_low = true;
struct Channel {
CPU::RegisterPair16 address, count;
} channels_[4];
};
template <bool is_8254> template <bool is_8254>
class PIT { class PIT {
public: public:
@ -46,7 +113,6 @@ class PIT {
printf("Set mode on %d\n", channel_id); printf("Set mode on %d\n", channel_id);
Channel &channel = channels_[channel_id]; Channel &channel = channels_[channel_id];
channel.next_write_high = false;
switch((value >> 4) & 3) { switch((value >> 4) & 3) {
default: default:
channel.latch_value(); channel.latch_value();
@ -57,7 +123,7 @@ class PIT {
case 3: channel.latch_mode = LatchMode::LowHigh; break; case 3: channel.latch_mode = LatchMode::LowHigh; break;
} }
channel.is_bcd = value & 1; channel.is_bcd = value & 1;
channel.next_write_high = false; channel.next_access_high = false;
const auto operating_mode = (value >> 1) & 7; const auto operating_mode = (value >> 1) & 7;
switch(operating_mode) { switch(operating_mode) {
@ -127,7 +193,7 @@ class PIT {
uint16_t latch = 0; uint16_t latch = 0;
bool output = false; bool output = false;
bool next_write_high = false; bool next_access_high = false;
void latch_value() { void latch_value() {
latch = counter; latch = counter;
@ -169,17 +235,16 @@ class PIT {
reload = (reload & 0xff00) | value; reload = (reload & 0xff00) | value;
break; break;
case LatchMode::HighOnly: case LatchMode::HighOnly:
reload = (reload & 0x00ff) | (value << 8); reload = uint16_t((reload & 0x00ff) | (value << 8));
break; break;
case LatchMode::LowHigh: case LatchMode::LowHigh:
if(!next_write_high) { next_access_high ^= true;
if(next_access_high) {
reload = (reload & 0xff00) | value; reload = (reload & 0xff00) | value;
next_write_high = true;
return; return;
} }
reload = (reload & 0x00ff) | (value << 8); reload = uint16_t((reload & 0x00ff) | (value << 8));
next_write_high = false;
break; break;
} }
@ -199,8 +264,8 @@ class PIT {
case LatchMode::HighOnly: return uint8_t(latch >> 8); case LatchMode::HighOnly: return uint8_t(latch >> 8);
default: default:
case LatchMode::LowHigh: case LatchMode::LowHigh:
next_write_high ^= true; next_access_high ^= true;
return next_write_high ? uint8_t(latch) : uint8_t(latch >> 8); return next_access_high ? uint8_t(latch) : uint8_t(latch >> 8);
break; break;
} }
} }
@ -464,7 +529,7 @@ struct Memory {
class IO { class IO {
public: public:
IO(PIT<false> &pit) : pit_(pit) {} IO(PIT<false> &pit, DMA &dma) : pit_(pit), dma_(dma) {}
template <typename IntT> void out([[maybe_unused]] uint16_t port, [[maybe_unused]] IntT value) { template <typename IntT> void out([[maybe_unused]] uint16_t port, [[maybe_unused]] IntT value) {
switch(port) { switch(port) {
@ -481,13 +546,23 @@ class IO {
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked"); printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
break; break;
case 0x0000: case 0x0001: case 0x0002: case 0x0003: case 0x0000: dma_.write<0>(value); break;
case 0x0004: case 0x0005: case 0x0006: case 0x0007: case 0x0001: dma_.write<1>(value); break;
case 0x0002: dma_.write<2>(value); break;
case 0x0003: dma_.write<3>(value); break;
case 0x0004: dma_.write<4>(value); break;
case 0x0005: dma_.write<5>(value); break;
case 0x0006: dma_.write<6>(value); break;
case 0x0007: dma_.write<7>(value); break;
case 0x0008: case 0x0009: case 0x000a: case 0x000b: case 0x0008: case 0x0009: case 0x000a: case 0x000b:
case 0x000c: case 0x000d: case 0x000e: case 0x000f: case 0x000c: case 0x000f:
printf("TODO: DMA write of %02x at %04x\n", value, port); printf("TODO: DMA write of %02x at %04x\n", value, port);
break; break;
case 0x000d: dma_.master_reset(); break;
case 0x000e: dma_.mask_reset(); break;
case 0x0060: case 0x0061: case 0x0062: case 0x0063: case 0x0060: case 0x0061: case 0x0062: case 0x0063:
case 0x0064: case 0x0065: case 0x0066: case 0x0067: case 0x0064: case 0x0065: case 0x0066: case 0x0067:
case 0x0068: case 0x0069: case 0x006a: case 0x006b: case 0x0068: case 0x0069: case 0x006a: case 0x006b:
@ -529,6 +604,15 @@ class IO {
printf("Unhandled in: %04x\n", port); printf("Unhandled in: %04x\n", port);
break; break;
case 0x0000: return dma_.read<0>();
case 0x0001: return dma_.read<1>();
case 0x0002: return dma_.read<2>();
case 0x0003: return dma_.read<3>();
case 0x0004: return dma_.read<4>();
case 0x0005: return dma_.read<5>();
case 0x0006: return dma_.read<6>();
case 0x0007: return dma_.read<7>();
case 0x0040: return pit_.read<0>(); case 0x0040: return pit_.read<0>();
case 0x0041: return pit_.read<1>(); case 0x0041: return pit_.read<1>();
case 0x0042: return pit_.read<2>(); case 0x0042: return pit_.read<2>();
@ -545,6 +629,7 @@ class IO {
private: private:
PIT<false> &pit_; PIT<false> &pit_;
DMA &dma_;
}; };
class FlowController { class FlowController {
@ -596,7 +681,7 @@ class ConcreteMachine:
ConcreteMachine( ConcreteMachine(
[[maybe_unused]] const Analyser::Static::Target &target, [[maybe_unused]] const Analyser::Static::Target &target,
const ROMMachine::ROMFetcher &rom_fetcher const ROMMachine::ROMFetcher &rom_fetcher
) : context(pit_) { ) : context(pit_, dma_) {
// 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;
set_clock_rate(double(pit_frequency) * double(PitMultiplier) / double(PitDivisor)); // i.e. almost 0.4 MIPS for an XT. set_clock_rate(double(pit_frequency) * double(PitMultiplier) / double(PitDivisor)); // i.e. almost 0.4 MIPS for an XT.
@ -655,13 +740,14 @@ class ConcreteMachine:
private: private:
PIT<false> pit_; PIT<false> pit_;
DMA dma_;
struct Context { struct Context {
Context(PIT<false> &pit) : Context(PIT<false> &pit, DMA &dma) :
segments(registers), segments(registers),
memory(registers, segments), memory(registers, segments),
flow_controller(registers, segments), flow_controller(registers, segments),
io(pit) io(pit, dma)
{ {
reset(); reset();
} }