mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 16:31:42 +00:00
Add enough of the DMA subsystem to trip over in PPI world.
This commit is contained in:
parent
119c83eb18
commit
55f466f2fa
@ -13,6 +13,8 @@
|
||||
#include "../../InstructionSets/x86/Instruction.hpp"
|
||||
#include "../../InstructionSets/x86/Perform.hpp"
|
||||
|
||||
#include "../../Numeric/RegisterSizes.hpp"
|
||||
|
||||
#include "../ScanProducer.hpp"
|
||||
#include "../TimedMachine.hpp"
|
||||
|
||||
@ -20,6 +22,71 @@
|
||||
|
||||
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>
|
||||
class PIT {
|
||||
public:
|
||||
@ -46,7 +113,6 @@ class PIT {
|
||||
printf("Set mode on %d\n", channel_id);
|
||||
|
||||
Channel &channel = channels_[channel_id];
|
||||
channel.next_write_high = false;
|
||||
switch((value >> 4) & 3) {
|
||||
default:
|
||||
channel.latch_value();
|
||||
@ -57,7 +123,7 @@ class PIT {
|
||||
case 3: channel.latch_mode = LatchMode::LowHigh; break;
|
||||
}
|
||||
channel.is_bcd = value & 1;
|
||||
channel.next_write_high = false;
|
||||
channel.next_access_high = false;
|
||||
|
||||
const auto operating_mode = (value >> 1) & 7;
|
||||
switch(operating_mode) {
|
||||
@ -127,7 +193,7 @@ class PIT {
|
||||
uint16_t latch = 0;
|
||||
bool output = false;
|
||||
|
||||
bool next_write_high = false;
|
||||
bool next_access_high = false;
|
||||
|
||||
void latch_value() {
|
||||
latch = counter;
|
||||
@ -169,17 +235,16 @@ class PIT {
|
||||
reload = (reload & 0xff00) | value;
|
||||
break;
|
||||
case LatchMode::HighOnly:
|
||||
reload = (reload & 0x00ff) | (value << 8);
|
||||
reload = uint16_t((reload & 0x00ff) | (value << 8));
|
||||
break;
|
||||
case LatchMode::LowHigh:
|
||||
if(!next_write_high) {
|
||||
next_access_high ^= true;
|
||||
if(next_access_high) {
|
||||
reload = (reload & 0xff00) | value;
|
||||
next_write_high = true;
|
||||
return;
|
||||
}
|
||||
|
||||
reload = (reload & 0x00ff) | (value << 8);
|
||||
next_write_high = false;
|
||||
reload = uint16_t((reload & 0x00ff) | (value << 8));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -199,8 +264,8 @@ class PIT {
|
||||
case LatchMode::HighOnly: return uint8_t(latch >> 8);
|
||||
default:
|
||||
case LatchMode::LowHigh:
|
||||
next_write_high ^= true;
|
||||
return next_write_high ? uint8_t(latch) : uint8_t(latch >> 8);
|
||||
next_access_high ^= true;
|
||||
return next_access_high ? uint8_t(latch) : uint8_t(latch >> 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -464,7 +529,7 @@ struct Memory {
|
||||
|
||||
class IO {
|
||||
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) {
|
||||
switch(port) {
|
||||
@ -481,13 +546,23 @@ class IO {
|
||||
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
|
||||
break;
|
||||
|
||||
case 0x0000: case 0x0001: case 0x0002: case 0x0003:
|
||||
case 0x0004: case 0x0005: case 0x0006: case 0x0007:
|
||||
case 0x0000: dma_.write<0>(value); break;
|
||||
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 0x000c: case 0x000d: case 0x000e: case 0x000f:
|
||||
case 0x000c: case 0x000f:
|
||||
printf("TODO: DMA write of %02x at %04x\n", value, port);
|
||||
break;
|
||||
|
||||
case 0x000d: dma_.master_reset(); break;
|
||||
case 0x000e: dma_.mask_reset(); break;
|
||||
|
||||
case 0x0060: case 0x0061: case 0x0062: case 0x0063:
|
||||
case 0x0064: case 0x0065: case 0x0066: case 0x0067:
|
||||
case 0x0068: case 0x0069: case 0x006a: case 0x006b:
|
||||
@ -529,6 +604,15 @@ class IO {
|
||||
printf("Unhandled in: %04x\n", port);
|
||||
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 0x0041: return pit_.read<1>();
|
||||
case 0x0042: return pit_.read<2>();
|
||||
@ -545,6 +629,7 @@ class IO {
|
||||
|
||||
private:
|
||||
PIT<false> &pit_;
|
||||
DMA &dma_;
|
||||
};
|
||||
|
||||
class FlowController {
|
||||
@ -596,7 +681,7 @@ class ConcreteMachine:
|
||||
ConcreteMachine(
|
||||
[[maybe_unused]] const Analyser::Static::Target &target,
|
||||
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.
|
||||
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.
|
||||
@ -655,13 +740,14 @@ class ConcreteMachine:
|
||||
|
||||
private:
|
||||
PIT<false> pit_;
|
||||
DMA dma_;
|
||||
|
||||
struct Context {
|
||||
Context(PIT<false> &pit) :
|
||||
Context(PIT<false> &pit, DMA &dma) :
|
||||
segments(registers),
|
||||
memory(registers, segments),
|
||||
flow_controller(registers, segments),
|
||||
io(pit)
|
||||
io(pit, dma)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user