1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-29 16:55:59 +00:00

Capture DMA high bytes, add actor for accesses.

This commit is contained in:
Thomas Harte 2023-11-30 12:47:50 -05:00
parent edc36bf3f4
commit 5f6bbec741
3 changed files with 113 additions and 35 deletions

View File

@ -13,7 +13,7 @@
namespace PCCompatible {
class DMA {
class i8237 {
public:
void flip_flop_reset() {
next_access_low = true;
@ -78,6 +78,41 @@ class DMA {
} channels_[4];
};
class DMAPages {
public:
template <int index>
void set_page(uint8_t value) {
pages_[page_for_index(index)] = value;
}
template <int index>
uint8_t page() {
return pages_[page_for_index(index)];
}
uint8_t channel_page(int channel) {
return pages_[channel];
}
private:
uint8_t pages_[8];
constexpr int page_for_index(int index) {
switch(index) {
case 7: return 0;
case 3: return 1;
case 1: return 2;
case 2: return 3;
default:
case 0: return 4;
case 4: return 5;
case 5: return 6;
case 6: return 7;
}
}
};
}
#endif /* DMA_hpp */

View File

@ -8,10 +8,10 @@
#include "PCCompatible.hpp"
#include "DMA.hpp"
#include "KeyboardMapper.hpp"
#include "PIC.hpp"
#include "PIT.hpp"
#include "DMA.hpp"
#include "../../InstructionSets/x86/Decoder.hpp"
#include "../../InstructionSets/x86/Flags.hpp"
@ -48,6 +48,22 @@ namespace PCCompatible {
//bool log = false;
//std::string previous;
struct Memory;
class DMA {
public:
i8237 i8237;
DMAPages pages;
// Memory is set posthoc to resolve a startup time.
void set_memory(Memory *memory) {
memory_ = memory;
}
private:
Memory *memory_;
};
class FloppyController {
public:
FloppyController(PIC &pic, DMA &dma) : pic_(pic), dma_(dma) {
@ -106,9 +122,22 @@ class FloppyController {
printf("TODO: implement FDC command %d\n", uint8_t(decoder_.command()));
break;
case Command::ReadData:
case Command::ReadData: {
printf("FDC: Read %d:%d at %d/%d\n", decoder_.target().drive, decoder_.target().head, decoder_.geometry().cylinder, decoder_.geometry().head);
break;
// Search for a matching sector.
const auto target = decoder_.geometry();
for(auto &pair: drives_[decoder_.target().drive].cached_track) {
if(
(pair.second.address.track == target.cylinder) &&
(pair.second.address.sector == target.sector) &&
(pair.second.address.side == target.head) &&
(pair.second.size == target.size)
) {
printf("");
}
}
} break;
case Command::Seek:
printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target());
@ -274,7 +303,7 @@ class FloppyController {
}
} drives_[4];
std::string drive_name(int c) const {
static std::string drive_name(int c) {
char name[3] = "A";
name[0] += c;
return std::string("Drive ") + name;
@ -588,7 +617,7 @@ class PITObserver {
// channel 1 is used for DRAM refresh (presumably connected to DMA?);
// channel 2 is gated by a PPI output and feeds into the speaker.
};
using PIT = i8237<false, PITObserver>;
using PIT = i8253<false, PITObserver>;
class i8255PortHandler : public Intel::i8255::PortHandler {
// Likely to be helpful: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
@ -924,14 +953,14 @@ class IO {
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
break;
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 0x0000: dma_.i8237.write<0>(value); break;
case 0x0001: dma_.i8237.write<1>(value); break;
case 0x0002: dma_.i8237.write<2>(value); break;
case 0x0003: dma_.i8237.write<3>(value); break;
case 0x0004: dma_.i8237.write<4>(value); break;
case 0x0005: dma_.i8237.write<5>(value); break;
case 0x0006: dma_.i8237.write<6>(value); break;
case 0x0007: dma_.i8237.write<7>(value); break;
case 0x0008: case 0x0009:
case 0x000a: case 0x000b:
@ -939,8 +968,8 @@ class IO {
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 0x000d: dma_.i8237.master_reset(); break;
case 0x000e: dma_.i8237.mask_reset(); break;
case 0x0020: pic_.write<0>(value); break;
case 0x0021: pic_.write<1>(value); break;
@ -954,20 +983,22 @@ class IO {
case 0x0064: case 0x0065: case 0x0066: case 0x0067:
case 0x0068: case 0x0069: case 0x006a: case 0x006b:
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
ppi_.write(port, value);
ppi_.write(port, uint8_t(value));
break;
case 0x0080: case 0x0081: case 0x0082: case 0x0083:
case 0x0084: case 0x0085: case 0x0086: case 0x0087:
case 0x0088: case 0x0089: case 0x008a: case 0x008b:
case 0x008c: case 0x008d: case 0x008e: case 0x008f:
printf("TODO: DMA page write of %02x at %04x\n", value, port);
break;
case 0x0080: dma_.pages.set_page<0>(uint8_t(value)); break;
case 0x0081: dma_.pages.set_page<1>(uint8_t(value)); break;
case 0x0082: dma_.pages.set_page<2>(uint8_t(value)); break;
case 0x0083: dma_.pages.set_page<3>(uint8_t(value)); break;
case 0x0084: dma_.pages.set_page<4>(uint8_t(value)); break;
case 0x0085: dma_.pages.set_page<5>(uint8_t(value)); break;
case 0x0086: dma_.pages.set_page<6>(uint8_t(value)); break;
case 0x0087: dma_.pages.set_page<7>(uint8_t(value)); break;
case 0x03b0: case 0x03b2: case 0x03b4: case 0x03b6:
if constexpr (std::is_same_v<IntT, uint16_t>) {
mda_.write<0>(value);
mda_.write<1>(value >> 8);
mda_.write<0>(uint8_t(value));
mda_.write<1>(uint8_t(value >> 8));
} else {
mda_.write<0>(value);
}
@ -1027,14 +1058,14 @@ 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 0x0000: return dma_.i8237.read<0>();
case 0x0001: return dma_.i8237.read<1>();
case 0x0002: return dma_.i8237.read<2>();
case 0x0003: return dma_.i8237.read<3>();
case 0x0004: return dma_.i8237.read<4>();
case 0x0005: return dma_.i8237.read<5>();
case 0x0006: return dma_.i8237.read<6>();
case 0x0007: return dma_.i8237.read<7>();
case 0x0008: case 0x0009:
case 0x000a: case 0x000b:
@ -1055,6 +1086,15 @@ class IO {
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
return ppi_.read(port);
case 0x0080: return dma_.pages.page<0>();
case 0x0081: return dma_.pages.page<1>();
case 0x0082: return dma_.pages.page<2>();
case 0x0083: return dma_.pages.page<3>();
case 0x0084: return dma_.pages.page<4>();
case 0x0085: return dma_.pages.page<5>();
case 0x0086: return dma_.pages.page<6>();
case 0x0087: return dma_.pages.page<7>();
case 0x0201: break; // Ignore game port.
case 0x0278: case 0x0279: case 0x027a:
@ -1148,6 +1188,9 @@ class ConcreteMachine:
ppi_(ppi_handler_),
context(pit_, dma_, ppi_, pic_, mda_, fdc_)
{
// Set up DMA source/target.
dma_.set_memory(&context.memory);
// 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));

View File

@ -12,9 +12,9 @@
namespace PCCompatible {
template <bool is_8254, typename PITObserver>
class i8237 {
class i8253 {
public:
i8237(PITObserver &observer) : observer_(observer) {}
i8253(PITObserver &observer) : observer_(observer) {}
template <int channel> uint8_t read() {
return channels_[channel].read();