mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 01:32:55 +00:00
Make bit masks easily testable; expand logging.
This commit is contained in:
parent
7aeea535a1
commit
0e4615564d
@ -57,6 +57,16 @@ constexpr std::array<Zone, 0x20> zones(bool is_read) {
|
|||||||
return zones;
|
return zones;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int start, int end> struct BitMask {
|
||||||
|
static_assert(start >= end);
|
||||||
|
static constexpr uint32_t value = ((1 << (start + 1)) - 1) - ((1 << end) - 1);
|
||||||
|
};
|
||||||
|
static_assert(BitMask<0, 0>::value == 1);
|
||||||
|
static_assert(BitMask<1, 1>::value == 2);
|
||||||
|
static_assert(BitMask<15, 15>::value == 32768);
|
||||||
|
static_assert(BitMask<15, 0>::value == 0xffff);
|
||||||
|
static_assert(BitMask<15, 14>::value == 49152);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Archimedes {
|
namespace Archimedes {
|
||||||
@ -312,21 +322,20 @@ struct Interrupts {
|
|||||||
|
|
||||||
bool write(uint32_t address, uint8_t value) {
|
bool write(uint32_t address, uint8_t value) {
|
||||||
const auto target = address & AddressMask;
|
const auto target = address & AddressMask;
|
||||||
logger.error().append("IO controller write of %02x at %08x", value, address);
|
|
||||||
switch(target) {
|
switch(target) {
|
||||||
default:
|
default:
|
||||||
logger.error().append("Unrecognised IOC write of %02x at %08x", value, address);
|
logger.error().append("Unrecognised IOC write of %02x at %08x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x3200000 & AddressMask:
|
case 0x320'0000 & AddressMask:
|
||||||
logger.error().append("TODO: IOC control write %02x", value);
|
logger.error().append("TODO: IOC control write %02x", value);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x3200004 & AddressMask:
|
case 0x320'0004 & AddressMask:
|
||||||
logger.error().append("TODO: IOC serial transmit");
|
logger.error().append("TODO: IOC serial transmit %02x", value);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x3200014 & AddressMask:
|
case 0x320'0014 & AddressMask:
|
||||||
// b2: clear IF.
|
// b2: clear IF.
|
||||||
// b3: clear IR.
|
// b3: clear IR.
|
||||||
// b4: clear POR.
|
// b4: clear POR.
|
||||||
@ -336,42 +345,82 @@ struct Interrupts {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Interrupts.
|
// Interrupts.
|
||||||
case 0x3200018 & AddressMask: irq_a_.mask = value; return true;
|
case 0x320'0018 & AddressMask: irq_a_.mask = value; return true;
|
||||||
case 0x3200028 & AddressMask: irq_b_.mask = value; return true;
|
case 0x320'0028 & AddressMask: irq_b_.mask = value; return true;
|
||||||
case 0x3200038 & AddressMask: fiq_.mask = value; return true;
|
case 0x320'0038 & AddressMask: fiq_.mask = value; return true;
|
||||||
|
|
||||||
// Counters.
|
// Counters.
|
||||||
case 0x3200040 & AddressMask:
|
case 0x320'0040 & AddressMask:
|
||||||
case 0x3200050 & AddressMask:
|
case 0x320'0050 & AddressMask:
|
||||||
case 0x3200060 & AddressMask:
|
case 0x320'0060 & AddressMask:
|
||||||
case 0x3200070 & AddressMask:
|
case 0x320'0070 & AddressMask:
|
||||||
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
||||||
(counters_[(target >> 4) - 0x4].reload & 0xff00) | value
|
(counters_[(target >> 4) - 0x4].reload & 0xff00) | value
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x3200044 & AddressMask:
|
case 0x320'0044 & AddressMask:
|
||||||
case 0x3200054 & AddressMask:
|
case 0x320'0054 & AddressMask:
|
||||||
case 0x3200064 & AddressMask:
|
case 0x320'0064 & AddressMask:
|
||||||
case 0x3200074 & AddressMask:
|
case 0x320'0074 & AddressMask:
|
||||||
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
||||||
(counters_[(target >> 4) - 0x4].reload & 0x00ff) | (value << 8)
|
(counters_[(target >> 4) - 0x4].reload & 0x00ff) | (value << 8)
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x3200048 & AddressMask:
|
case 0x320'0048 & AddressMask:
|
||||||
case 0x3200058 & AddressMask:
|
case 0x320'0058 & AddressMask:
|
||||||
case 0x3200068 & AddressMask:
|
case 0x320'0068 & AddressMask:
|
||||||
case 0x3200078 & AddressMask:
|
case 0x320'0078 & AddressMask:
|
||||||
counters_[(target >> 4) - 0x4].value = counters_[(target >> 4) - 0x4].reload;
|
counters_[(target >> 4) - 0x4].value = counters_[(target >> 4) - 0x4].reload;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x320004c & AddressMask:
|
case 0x320'004c & AddressMask:
|
||||||
case 0x320005c & AddressMask:
|
case 0x320'005c & AddressMask:
|
||||||
case 0x320006c & AddressMask:
|
case 0x320'006c & AddressMask:
|
||||||
case 0x320007c & AddressMask:
|
case 0x320'007c & AddressMask:
|
||||||
counters_[(target >> 4) - 0x4].output = counters_[(target >> 4) - 0x4].value;
|
counters_[(target >> 4) - 0x4].output = counters_[(target >> 4) - 0x4].value;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case 0x327'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: exteded external podule space");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x331'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: 1772 / disk write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x335'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: LS374 / printer data write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x335'0018 & AddressMask:
|
||||||
|
logger.error().append("TODO: latch B write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x335'0040 & AddressMask:
|
||||||
|
logger.error().append("TODO: latch A write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x335'0048 & AddressMask:
|
||||||
|
logger.error().append("TODO: latch C write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x336'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: podule interrupt request");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x336'0004 & AddressMask:
|
||||||
|
logger.error().append("TODO: podule interrupt mask");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x33a'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: 6854 / econet write");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 0x33b'0000 & AddressMask:
|
||||||
|
logger.error().append("TODO: 6551 / serial line write");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -424,10 +473,15 @@ struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
bool write(uint32_t address, IntT source, InstructionSet::ARM::Mode mode, bool) {
|
uint32_t aligned(uint32_t address) {
|
||||||
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
||||||
address &= static_cast<uint32_t>(~3);
|
return address & static_cast<uint32_t>(~3);
|
||||||
}
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntT>
|
||||||
|
bool write(uint32_t address, IntT source, InstructionSet::ARM::Mode mode, bool) {
|
||||||
if(mode == InstructionSet::ARM::Mode::User && address < 0x2000000) {
|
if(mode == InstructionSet::ARM::Mode::User && address < 0x2000000) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -452,7 +506,7 @@ struct Memory {
|
|||||||
low_rom_access_time_ = ROMAccessTime((address >> 4) & 3);
|
low_rom_access_time_ = ROMAccessTime((address >> 4) & 3);
|
||||||
page_size_ = PageSize((address >> 2) & 3);
|
page_size_ = PageSize((address >> 2) & 3);
|
||||||
|
|
||||||
logger.info().append("MEMC Control: %08x -> OS:%d sound:%d video:%d high:%d low:%d size:%d", address, os_mode_, sound_dma_enable_, video_dma_enable_, high_rom_access_time_, low_rom_access_time_, page_size_);
|
logger.info().append("MEMC Control: %08x -> OS:%d sound:%d video:%d refresh:%d high:%d low:%d size:%d", address, os_mode_, sound_dma_enable_, video_dma_enable_, dynamic_ram_refresh_, high_rom_access_time_, low_rom_access_time_, page_size_);
|
||||||
update_mapping();
|
update_mapping();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -462,6 +516,7 @@ struct Memory {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::LogicallyMappedRAM: {
|
case Zone::LogicallyMappedRAM: {
|
||||||
|
update_mapping();
|
||||||
const auto item = logical_ram<IntT, false>(address, mode);
|
const auto item = logical_ram<IntT, false>(address, mode);
|
||||||
if(!item) {
|
if(!item) {
|
||||||
return false;
|
return false;
|
||||||
@ -485,9 +540,9 @@ struct Memory {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Zone::AddressTranslator:
|
case Zone::AddressTranslator:
|
||||||
// printf("Translator write at %08x\n", address);
|
printf("Translator write at %08x\n", address);
|
||||||
pages_[address & 0x7f] = address;
|
pages_[address & 0x7f] = address;
|
||||||
update_mapping();
|
// update_mapping();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -580,12 +635,14 @@ struct Memory {
|
|||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
IntT &physical_ram(uint32_t address) {
|
IntT &physical_ram(uint32_t address) {
|
||||||
const auto access_address = address & (ram_.size() - 1);
|
address = aligned<IntT>(address);
|
||||||
return *reinterpret_cast<IntT *>(&ram_[access_address]);
|
address &= (ram_.size() - 1);
|
||||||
|
return *reinterpret_cast<IntT *>(&ram_[address]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
IntT &high_rom(uint32_t address) {
|
IntT &high_rom(uint32_t address) {
|
||||||
|
address = aligned<IntT>(address);
|
||||||
return *reinterpret_cast<IntT *>(&rom_[address & (rom_.size() - 1)]);
|
return *reinterpret_cast<IntT *>(&rom_[address & (rom_.size() - 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,6 +697,7 @@ struct Memory {
|
|||||||
|
|
||||||
template <typename IntT, bool is_read>
|
template <typename IntT, bool is_read>
|
||||||
IntT *logical_ram(uint32_t address, InstructionSet::ARM::Mode mode) {
|
IntT *logical_ram(uint32_t address, InstructionSet::ARM::Mode mode) {
|
||||||
|
address = aligned<IntT>(address);
|
||||||
address &= 0x1ff'ffff;
|
address &= 0x1ff'ffff;
|
||||||
size_t page;
|
size_t page;
|
||||||
|
|
||||||
@ -716,10 +774,6 @@ struct Memory {
|
|||||||
// Clear all logical mappings.
|
// Clear all logical mappings.
|
||||||
std::fill(mapping_.begin(), mapping_.end(), MappedPage{});
|
std::fill(mapping_.begin(), mapping_.end(), MappedPage{});
|
||||||
|
|
||||||
const auto bits = [](int start, int end) -> uint32_t {
|
|
||||||
return ((1 << (start + 1)) - 1) - ((1 << end) - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// For each physical page, project it into logical space
|
// For each physical page, project it into logical space
|
||||||
// and store it.
|
// and store it.
|
||||||
for(const auto page: pages_) {
|
for(const auto page: pages_) {
|
||||||
@ -730,57 +784,57 @@ struct Memory {
|
|||||||
// 4kb:
|
// 4kb:
|
||||||
// A[6:0] -> PPN[6:0]
|
// A[6:0] -> PPN[6:0]
|
||||||
// A[11:10] -> LPN[12:11]; A[22:12] -> LPN[10:0] i.e. 8192 logical pages
|
// A[11:10] -> LPN[12:11]; A[22:12] -> LPN[10:0] i.e. 8192 logical pages
|
||||||
physical = page & bits(6, 0);
|
physical = page & BitMask<6, 0>::value;
|
||||||
|
|
||||||
physical <<= 12;
|
physical <<= 12;
|
||||||
|
|
||||||
logical = (page & bits(11, 10)) << 1;
|
logical = (page & BitMask<11, 10>::value) << 1;
|
||||||
logical |= (page & bits(22, 12)) >> 12;
|
logical |= (page & BitMask<22, 12>::value) >> 12;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PageSize::kb8:
|
case PageSize::kb8:
|
||||||
// 8kb:
|
// 8kb:
|
||||||
// A[0] -> PPN[6]; A[6:1] -> PPN[5:0]
|
// A[0] -> PPN[6]; A[6:1] -> PPN[5:0]
|
||||||
// A[11:10] -> LPN[11:10]; A[22:13] -> LPN[9:0] i.e. 4096 logical pages
|
// A[11:10] -> LPN[11:10]; A[22:13] -> LPN[9:0] i.e. 4096 logical pages
|
||||||
physical = (page & bits(0, 0)) << 6;
|
physical = (page & BitMask<0, 0>::value) << 6;
|
||||||
physical |= (page & bits(6, 1)) >> 1;
|
physical |= (page & BitMask<6, 1>::value) >> 1;
|
||||||
|
|
||||||
physical <<= 13;
|
physical <<= 13;
|
||||||
|
|
||||||
logical = page & bits(11, 10);
|
logical = page & BitMask<11, 10>::value;
|
||||||
logical |= (page & bits(22, 13)) >> 13;
|
logical |= (page & BitMask<22, 13>::value) >> 13;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PageSize::kb16:
|
case PageSize::kb16:
|
||||||
// 16kb:
|
// 16kb:
|
||||||
// A[1:0] -> PPN[6:5]; A[6:2] -> PPN[4:0]
|
// A[1:0] -> PPN[6:5]; A[6:2] -> PPN[4:0]
|
||||||
// A[11:10] -> LPN[10:9]; A[22:14] -> LPN[8:0] i.e. 2048 logical pages
|
// A[11:10] -> LPN[10:9]; A[22:14] -> LPN[8:0] i.e. 2048 logical pages
|
||||||
physical = (page & bits(1, 0)) << 5;
|
physical = (page & BitMask<1, 0>::value) << 5;
|
||||||
physical |= (page & bits(6, 2)) >> 2;
|
physical |= (page & BitMask<6, 2>::value) >> 2;
|
||||||
|
|
||||||
physical <<= 14;
|
physical <<= 14;
|
||||||
|
|
||||||
logical = (page & bits(11, 10)) >> 1;
|
logical = (page & BitMask<11, 10>::value) >> 1;
|
||||||
logical |= (page & bits(22, 14)) >> 14;
|
logical |= (page & BitMask<22, 14>::value) >> 14;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PageSize::kb32:
|
case PageSize::kb32:
|
||||||
// 32kb:
|
// 32kb:
|
||||||
// A[1] -> PPN[6]; A[2] -> PPN[5]; A[0] -> PPN[4]; A[6:3] -> PPN[3:0]
|
// A[1] -> PPN[6]; A[2] -> PPN[5]; A[0] -> PPN[4]; A[6:3] -> PPN[3:0]
|
||||||
// A[11:10] -> LPN[9:8]; A[22:15] -> LPN[7:0] i.e. 1024 logical pages
|
// A[11:10] -> LPN[9:8]; A[22:15] -> LPN[7:0] i.e. 1024 logical pages
|
||||||
physical = (page & bits(1, 1)) << 5;
|
physical = (page & BitMask<1, 1>::value) << 5;
|
||||||
physical |= (page & bits(2, 2)) << 3;
|
physical |= (page & BitMask<2, 2>::value) << 3;
|
||||||
physical |= (page & bits(0, 0)) << 4;
|
physical |= (page & BitMask<0, 0>::value) << 4;
|
||||||
physical |= (page & bits(6, 3)) >> 3;
|
physical |= (page & BitMask<6, 3>::value) >> 3;
|
||||||
|
|
||||||
physical <<= 15;
|
physical <<= 15;
|
||||||
|
|
||||||
logical = (page & bits(11, 10)) >> 2;
|
logical = (page & BitMask<11, 10>::value) >> 2;
|
||||||
logical |= (page & bits(22, 15)) >> 15;
|
logical |= (page & BitMask<22, 15>::value) >> 15;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("%08x => logical %d -> physical %d\n", page, logical, (physical >> 15));
|
printf("%08x => logical %d -> physical %d\n", page, logical, (physical >> 15));
|
||||||
|
|
||||||
// TODO: consider clashes.
|
// TODO: consider clashes.
|
||||||
// TODO: what if there's less than 4mb present?
|
// TODO: what if there's less than 4mb present?
|
||||||
@ -864,7 +918,7 @@ class ConcreteMachine:
|
|||||||
// printf("");
|
// printf("");
|
||||||
// }
|
// }
|
||||||
// log |= (executor_.pc() > 0x02000000 && executor_.pc() < 0x02000078);
|
// log |= (executor_.pc() > 0x02000000 && executor_.pc() < 0x02000078);
|
||||||
// log |= executor_.pc() == 0x03801980;
|
log |= executor_.pc() == 0x03810398;
|
||||||
// log |= (executor_.pc() > 0x03801000);
|
// log |= (executor_.pc() > 0x03801000);
|
||||||
// log &= executor_.pc() != 0x03801a0c;
|
// log &= executor_.pc() != 0x03801a0c;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user