mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-29 16:55:59 +00:00
Start looking at address translation.
This commit is contained in:
parent
0d666f9935
commit
ed92e98ca2
@ -78,16 +78,55 @@ struct Memory {
|
|||||||
case Zone::DMAAndMEMC:
|
case Zone::DMAAndMEMC:
|
||||||
// if(mode != InstructionSet::ARM::Mode::Supervisor) return false;
|
// if(mode != InstructionSet::ARM::Mode::Supervisor) return false;
|
||||||
if((address & 0b1110'0000'0000'0000'0000) == 0b1110'0000'0000'0000'0000) {
|
if((address & 0b1110'0000'0000'0000'0000) == 0b1110'0000'0000'0000'0000) {
|
||||||
logger.error().append("TODO: MEMC Control: %08x", source);
|
// "The parameters are encoded into the processor address lines".
|
||||||
|
os_mode_ = address & (1 << 12);
|
||||||
|
sound_dma_enable_ = address & (1 << 11);
|
||||||
|
video_dma_enable_ = address & (1 << 10);
|
||||||
|
switch((address >> 8) & 3) {
|
||||||
|
default:
|
||||||
|
dynamic_ram_refresh_ = DynamicRAMRefresh::None;
|
||||||
break;
|
break;
|
||||||
} else {
|
case 0b01:
|
||||||
logger.error().append("TODO: DMA/MEMC %08x to %08x", source, address);
|
case 0b11:
|
||||||
|
dynamic_ram_refresh_ = DynamicRAMRefresh((address >> 8) & 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
high_rom_access_time_ = ROMAccessTime((address >> 6) & 3);
|
||||||
|
low_rom_access_time_ = ROMAccessTime((address >> 4) & 3);
|
||||||
|
page_size_ = PageSize((address >> 2) & 3);
|
||||||
|
|
||||||
|
logger.info().append("MEMC Control: OS:%d sound:%d video:%d ", os_mode_, sound_dma_enable_, video_dma_enable_);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
logger.error().append("TODO: DMA/MEMC %08x to %08x", source, address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Zone::LogicallyMappedRAM: {
|
||||||
|
const auto item = logical_ram<IntT, false>(address, mode);
|
||||||
|
if(!item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*item = source;
|
||||||
|
return true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Zone::IOControllers:
|
||||||
|
logger.error().append("TODO: Write to IO controllers of %08x to %08x", source, address);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Zone::VideoController:
|
||||||
|
logger.error().append("TODO: Write to video controller of %08x to %08x", source, address);
|
||||||
|
break;
|
||||||
|
|
||||||
case Zone::PhysicallyMappedRAM:
|
case Zone::PhysicallyMappedRAM:
|
||||||
// if(mode != InstructionSet::ARM::Mode::Supervisor) return false;
|
// if(mode != InstructionSet::ARM::Mode::Supervisor) return false;
|
||||||
physical_ram<IntT>(address) = source;
|
physical_ram<IntT>(address) = source;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Zone::AddressTranslator:
|
||||||
|
logger.error().append("TODO: Write address translator of %08x to %08x", source, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -100,7 +139,6 @@ struct Memory {
|
|||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
bool read(uint32_t address, IntT &source, InstructionSet::ARM::Mode mode, bool trans) {
|
bool read(uint32_t address, IntT &source, InstructionSet::ARM::Mode mode, bool trans) {
|
||||||
(void)mode;
|
|
||||||
(void)trans;
|
(void)trans;
|
||||||
|
|
||||||
switch (read_zones_[(address >> 21) & 31]) {
|
switch (read_zones_[(address >> 21) & 31]) {
|
||||||
@ -109,17 +147,46 @@ struct Memory {
|
|||||||
source = physical_ram<IntT>(address);
|
source = physical_ram<IntT>(address);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Zone::LogicallyMappedRAM:
|
case Zone::LogicallyMappedRAM: {
|
||||||
if(!has_moved_rom_) {
|
if(!has_moved_rom_) { // TODO: maintain this state in the zones table.
|
||||||
source = high_rom<IntT>(address);
|
source = high_rom<IntT>(address);
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
logger.error().append("TODO: Logical RAM read from %08x", address);
|
|
||||||
|
const auto item = logical_ram<IntT, true>(address, mode);
|
||||||
|
if(!item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
source = *item;
|
||||||
|
return true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Zone::LowROM:
|
||||||
|
logger.error().append("TODO: Low ROM read from %08x", address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::HighROM:
|
case Zone::HighROM:
|
||||||
has_moved_rom_ = true;
|
has_moved_rom_ = true;
|
||||||
source = high_rom<IntT>(address);
|
source = high_rom<IntT>(address);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Zone::IOControllers:
|
||||||
|
switch(address & 0x7f) {
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
case 0x10: // IRQ status A
|
||||||
|
source = 0x80;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x20: // IRQ status B
|
||||||
|
source = 0x00;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x30: // FIQ status
|
||||||
|
source = 0x80;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
logger.error().append("TODO: IO controller read from %08x", address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -128,7 +195,6 @@ struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source = 0;
|
source = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +215,61 @@ struct Memory {
|
|||||||
|
|
||||||
static constexpr std::array<Zone, 0x20> read_zones_ = zones(true);
|
static constexpr std::array<Zone, 0x20> read_zones_ = zones(true);
|
||||||
static constexpr std::array<Zone, 0x20> write_zones_ = zones(false);
|
static constexpr std::array<Zone, 0x20> write_zones_ = zones(false);
|
||||||
|
|
||||||
|
// Control register values.
|
||||||
|
bool os_mode_ = false;
|
||||||
|
bool sound_dma_enable_ = false;
|
||||||
|
bool video_dma_enable_ = false; // "Unaffected" by reset, so here picked arbitrarily.
|
||||||
|
|
||||||
|
enum class DynamicRAMRefresh {
|
||||||
|
None = 0b00,
|
||||||
|
DuringFlyback = 0b01,
|
||||||
|
Continuous = 0b11,
|
||||||
|
} dynamic_ram_refresh_ = DynamicRAMRefresh::None; // State at reset is undefined; constrain to a valid enum value.
|
||||||
|
|
||||||
|
enum class ROMAccessTime {
|
||||||
|
ns450 = 0b00,
|
||||||
|
ns325 = 0b01,
|
||||||
|
ns200 = 0b10,
|
||||||
|
ns200with60nsNibble = 0b11,
|
||||||
|
} high_rom_access_time_ = ROMAccessTime::ns450, low_rom_access_time_ = ROMAccessTime::ns450;
|
||||||
|
|
||||||
|
enum class PageSize {
|
||||||
|
kb4 = 0b00,
|
||||||
|
kb8 = 0b01,
|
||||||
|
kb16 = 0b10,
|
||||||
|
kb32 = 0b11,
|
||||||
|
} page_size_ = PageSize::kb4;
|
||||||
|
|
||||||
|
// Address translator.
|
||||||
|
//
|
||||||
|
// MEMC contains one entry per a physical page number, indicating where it goes logically.
|
||||||
|
// Any logical access is tested against all 128 mappings. So that's backwards compared to
|
||||||
|
// the ideal for an emulator, which would map from logical to physical, even if a lot more
|
||||||
|
// compact — there are always 128 physical pages; there are up to 8192 logical pages.
|
||||||
|
//
|
||||||
|
// So captured here are both the physical -> logical map as representative of the real
|
||||||
|
// hardware, and the reverse logical -> physical map, which is built (and rebuilt, and rebuilt)
|
||||||
|
// from the other.
|
||||||
|
|
||||||
|
// Physical to logical mapping.
|
||||||
|
uint32_t pages_[128]{};
|
||||||
|
|
||||||
|
// Logical to physical mapping.
|
||||||
|
struct MappedPage {
|
||||||
|
uint8_t *target = nullptr;
|
||||||
|
uint8_t protection_level = 0;
|
||||||
|
};
|
||||||
|
MappedPage mapping_[8192];
|
||||||
|
|
||||||
|
template <typename IntT, bool is_read>
|
||||||
|
IntT *logical_ram(uint32_t address, InstructionSet::ARM::Mode) {
|
||||||
|
logger.error().append("TODO: Logical RAM mapping at %08x", address);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_mapping() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConcreteMachine:
|
class ConcreteMachine:
|
||||||
@ -195,6 +316,7 @@ class ConcreteMachine:
|
|||||||
executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false);
|
executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false);
|
||||||
// TODO: what if abort? How about pipeline prefetch?
|
// TODO: what if abort? How about pipeline prefetch?
|
||||||
|
|
||||||
|
logger.info().append("%08x: %08x", executor_.pc(), instruction);
|
||||||
InstructionSet::ARM::execute<arm_model>(instruction, executor_);
|
InstructionSet::ARM::execute<arm_model>(instruction, executor_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user