mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 03:32:01 +00:00
Capture DMA high bytes, add actor for accesses.
This commit is contained in:
parent
edc36bf3f4
commit
5f6bbec741
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace PCCompatible {
|
namespace PCCompatible {
|
||||||
|
|
||||||
class DMA {
|
class i8237 {
|
||||||
public:
|
public:
|
||||||
void flip_flop_reset() {
|
void flip_flop_reset() {
|
||||||
next_access_low = true;
|
next_access_low = true;
|
||||||
@ -78,6 +78,41 @@ class DMA {
|
|||||||
} channels_[4];
|
} 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 */
|
#endif /* DMA_hpp */
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
#include "PCCompatible.hpp"
|
#include "PCCompatible.hpp"
|
||||||
|
|
||||||
#include "DMA.hpp"
|
|
||||||
#include "KeyboardMapper.hpp"
|
#include "KeyboardMapper.hpp"
|
||||||
#include "PIC.hpp"
|
#include "PIC.hpp"
|
||||||
#include "PIT.hpp"
|
#include "PIT.hpp"
|
||||||
|
#include "DMA.hpp"
|
||||||
|
|
||||||
#include "../../InstructionSets/x86/Decoder.hpp"
|
#include "../../InstructionSets/x86/Decoder.hpp"
|
||||||
#include "../../InstructionSets/x86/Flags.hpp"
|
#include "../../InstructionSets/x86/Flags.hpp"
|
||||||
@ -48,6 +48,22 @@ namespace PCCompatible {
|
|||||||
//bool log = false;
|
//bool log = false;
|
||||||
//std::string previous;
|
//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 {
|
class FloppyController {
|
||||||
public:
|
public:
|
||||||
FloppyController(PIC &pic, DMA &dma) : pic_(pic), dma_(dma) {
|
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()));
|
printf("TODO: implement FDC command %d\n", uint8_t(decoder_.command()));
|
||||||
break;
|
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);
|
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:
|
case Command::Seek:
|
||||||
printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target());
|
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];
|
} drives_[4];
|
||||||
|
|
||||||
std::string drive_name(int c) const {
|
static std::string drive_name(int c) {
|
||||||
char name[3] = "A";
|
char name[3] = "A";
|
||||||
name[0] += c;
|
name[0] += c;
|
||||||
return std::string("Drive ") + name;
|
return std::string("Drive ") + name;
|
||||||
@ -588,7 +617,7 @@ class PITObserver {
|
|||||||
// channel 1 is used for DRAM refresh (presumably connected to DMA?);
|
// channel 1 is used for DRAM refresh (presumably connected to DMA?);
|
||||||
// channel 2 is gated by a PPI output and feeds into the speaker.
|
// 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 {
|
class i8255PortHandler : public Intel::i8255::PortHandler {
|
||||||
// Likely to be helpful: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
|
// 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");
|
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0000: dma_.write<0>(value); break;
|
case 0x0000: dma_.i8237.write<0>(value); break;
|
||||||
case 0x0001: dma_.write<1>(value); break;
|
case 0x0001: dma_.i8237.write<1>(value); break;
|
||||||
case 0x0002: dma_.write<2>(value); break;
|
case 0x0002: dma_.i8237.write<2>(value); break;
|
||||||
case 0x0003: dma_.write<3>(value); break;
|
case 0x0003: dma_.i8237.write<3>(value); break;
|
||||||
case 0x0004: dma_.write<4>(value); break;
|
case 0x0004: dma_.i8237.write<4>(value); break;
|
||||||
case 0x0005: dma_.write<5>(value); break;
|
case 0x0005: dma_.i8237.write<5>(value); break;
|
||||||
case 0x0006: dma_.write<6>(value); break;
|
case 0x0006: dma_.i8237.write<6>(value); break;
|
||||||
case 0x0007: dma_.write<7>(value); break;
|
case 0x0007: dma_.i8237.write<7>(value); break;
|
||||||
|
|
||||||
case 0x0008: case 0x0009:
|
case 0x0008: case 0x0009:
|
||||||
case 0x000a: case 0x000b:
|
case 0x000a: case 0x000b:
|
||||||
@ -939,8 +968,8 @@ class IO {
|
|||||||
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 0x000d: dma_.i8237.master_reset(); break;
|
||||||
case 0x000e: dma_.mask_reset(); break;
|
case 0x000e: dma_.i8237.mask_reset(); break;
|
||||||
|
|
||||||
case 0x0020: pic_.write<0>(value); break;
|
case 0x0020: pic_.write<0>(value); break;
|
||||||
case 0x0021: pic_.write<1>(value); break;
|
case 0x0021: pic_.write<1>(value); break;
|
||||||
@ -954,20 +983,22 @@ class IO {
|
|||||||
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:
|
||||||
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
|
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
|
||||||
ppi_.write(port, value);
|
ppi_.write(port, uint8_t(value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0080: case 0x0081: case 0x0082: case 0x0083:
|
case 0x0080: dma_.pages.set_page<0>(uint8_t(value)); break;
|
||||||
case 0x0084: case 0x0085: case 0x0086: case 0x0087:
|
case 0x0081: dma_.pages.set_page<1>(uint8_t(value)); break;
|
||||||
case 0x0088: case 0x0089: case 0x008a: case 0x008b:
|
case 0x0082: dma_.pages.set_page<2>(uint8_t(value)); break;
|
||||||
case 0x008c: case 0x008d: case 0x008e: case 0x008f:
|
case 0x0083: dma_.pages.set_page<3>(uint8_t(value)); break;
|
||||||
printf("TODO: DMA page write of %02x at %04x\n", value, port);
|
case 0x0084: dma_.pages.set_page<4>(uint8_t(value)); break;
|
||||||
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:
|
case 0x03b0: case 0x03b2: case 0x03b4: case 0x03b6:
|
||||||
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
mda_.write<0>(value);
|
mda_.write<0>(uint8_t(value));
|
||||||
mda_.write<1>(value >> 8);
|
mda_.write<1>(uint8_t(value >> 8));
|
||||||
} else {
|
} else {
|
||||||
mda_.write<0>(value);
|
mda_.write<0>(value);
|
||||||
}
|
}
|
||||||
@ -1027,14 +1058,14 @@ class IO {
|
|||||||
printf("Unhandled in: %04x\n", port);
|
printf("Unhandled in: %04x\n", port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0000: return dma_.read<0>();
|
case 0x0000: return dma_.i8237.read<0>();
|
||||||
case 0x0001: return dma_.read<1>();
|
case 0x0001: return dma_.i8237.read<1>();
|
||||||
case 0x0002: return dma_.read<2>();
|
case 0x0002: return dma_.i8237.read<2>();
|
||||||
case 0x0003: return dma_.read<3>();
|
case 0x0003: return dma_.i8237.read<3>();
|
||||||
case 0x0004: return dma_.read<4>();
|
case 0x0004: return dma_.i8237.read<4>();
|
||||||
case 0x0005: return dma_.read<5>();
|
case 0x0005: return dma_.i8237.read<5>();
|
||||||
case 0x0006: return dma_.read<6>();
|
case 0x0006: return dma_.i8237.read<6>();
|
||||||
case 0x0007: return dma_.read<7>();
|
case 0x0007: return dma_.i8237.read<7>();
|
||||||
|
|
||||||
case 0x0008: case 0x0009:
|
case 0x0008: case 0x0009:
|
||||||
case 0x000a: case 0x000b:
|
case 0x000a: case 0x000b:
|
||||||
@ -1055,6 +1086,15 @@ class IO {
|
|||||||
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
|
case 0x006c: case 0x006d: case 0x006e: case 0x006f:
|
||||||
return ppi_.read(port);
|
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 0x0201: break; // Ignore game port.
|
||||||
|
|
||||||
case 0x0278: case 0x0279: case 0x027a:
|
case 0x0278: case 0x0279: case 0x027a:
|
||||||
@ -1148,6 +1188,9 @@ class ConcreteMachine:
|
|||||||
ppi_(ppi_handler_),
|
ppi_(ppi_handler_),
|
||||||
context(pit_, dma_, ppi_, pic_, mda_, fdc_)
|
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.
|
// 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));
|
set_clock_rate(double(pit_frequency));
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
namespace PCCompatible {
|
namespace PCCompatible {
|
||||||
|
|
||||||
template <bool is_8254, typename PITObserver>
|
template <bool is_8254, typename PITObserver>
|
||||||
class i8237 {
|
class i8253 {
|
||||||
public:
|
public:
|
||||||
i8237(PITObserver &observer) : observer_(observer) {}
|
i8253(PITObserver &observer) : observer_(observer) {}
|
||||||
|
|
||||||
template <int channel> uint8_t read() {
|
template <int channel> uint8_t read() {
|
||||||
return channels_[channel].read();
|
return channels_[channel].read();
|
||||||
|
Loading…
Reference in New Issue
Block a user