mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 16:31:42 +00:00
commit
2acb853021
@ -42,7 +42,7 @@ struct NullStatusHandler {
|
|||||||
template <Model model, typename MemoryT, typename StatusObserverT = NullStatusHandler>
|
template <Model model, typename MemoryT, typename StatusObserverT = NullStatusHandler>
|
||||||
struct Executor {
|
struct Executor {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
Executor(StatusObserverT &observer, Args &&...args) : status_observer_(observer), bus(std::forward<Args>(args)...) {}
|
Executor(StatusObserverT &observer, Args &&...args) : bus(std::forward<Args>(args)...), status_observer_(observer) {}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
Executor(Args &&...args) : bus(std::forward<Args>(args)...) {}
|
Executor(Args &&...args) : bus(std::forward<Args>(args)...) {}
|
||||||
@ -327,7 +327,7 @@ struct Executor {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool did_read;
|
bool did_read;
|
||||||
uint32_t value;
|
uint32_t value = 0;
|
||||||
|
|
||||||
if constexpr (flags.transfer_byte()) {
|
if constexpr (flags.transfer_byte()) {
|
||||||
uint8_t target;
|
uint8_t target;
|
||||||
@ -480,7 +480,7 @@ struct Executor {
|
|||||||
// undo the previous load.
|
// undo the previous load.
|
||||||
struct {
|
struct {
|
||||||
uint32_t *target = nullptr;
|
uint32_t *target = nullptr;
|
||||||
uint32_t value;
|
uint32_t value = 0;
|
||||||
} last_replacement;
|
} last_replacement;
|
||||||
|
|
||||||
for(uint32_t c = 0; c < total; c++) {
|
for(uint32_t c = 0; c < total; c++) {
|
||||||
|
@ -272,6 +272,7 @@ struct Registers {
|
|||||||
case Condition::GT: return !le();
|
case Condition::GT: return !le();
|
||||||
case Condition::LE: return le();
|
case Condition::LE: return le();
|
||||||
|
|
||||||
|
default:
|
||||||
case Condition::AL: return true;
|
case Condition::AL: return true;
|
||||||
case Condition::NV: return false;
|
case Condition::NV: return false;
|
||||||
}
|
}
|
||||||
@ -351,6 +352,7 @@ struct Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(mode_) {
|
switch(mode_) {
|
||||||
|
default:
|
||||||
case Mode::User: return active_[offset];
|
case Mode::User: return active_[offset];
|
||||||
|
|
||||||
case Mode::Supervisor:
|
case Mode::Supervisor:
|
||||||
|
@ -34,15 +34,13 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
Log::Logger<Log::Source::Archimedes> logger;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Archimedes {
|
namespace Archimedes {
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::Archimedes> logger;
|
||||||
|
}
|
||||||
|
|
||||||
template <InstructionSet::ARM::Model model, typename Executor>
|
template <InstructionSet::ARM::Model model, typename Executor>
|
||||||
struct HackyDebugger {
|
struct HackyDebugger {
|
||||||
void notify(uint32_t address, uint32_t instruction, Executor &executor) {
|
void notify(uint32_t address, uint32_t instruction, Executor &executor) {
|
||||||
@ -452,7 +450,7 @@ class ConcreteMachine:
|
|||||||
int video_divider_ = 1;
|
int video_divider_ = 1;
|
||||||
|
|
||||||
void tick_cpu() {
|
void tick_cpu() {
|
||||||
uint32_t instruction;
|
uint32_t instruction = 0;
|
||||||
if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) {
|
if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) {
|
||||||
// logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc);
|
// logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc);
|
||||||
executor_.prefetch_abort();
|
executor_.prefetch_abort();
|
||||||
|
@ -71,13 +71,10 @@ struct MemoryController {
|
|||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
bool write(uint32_t address, IntT source, InstructionSet::ARM::Mode, bool trans) {
|
bool write(uint32_t address, IntT source, InstructionSet::ARM::Mode, bool trans) {
|
||||||
// User mode may only _write_ to logically-mapped RAM (subject to further testing below).
|
|
||||||
if(trans && address >= 0x200'0000) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(write_zones_[(address >> 21) & 31]) {
|
switch(write_zones_[(address >> 21) & 31]) {
|
||||||
case Zone::DMAAndMEMC: {
|
case Zone::DMAAndMEMC: {
|
||||||
|
if(trans) return false;
|
||||||
|
|
||||||
const auto buffer_address = [](uint32_t source) -> uint32_t {
|
const auto buffer_address = [](uint32_t source) -> uint32_t {
|
||||||
return (source & 0x1'fffc) << 2;
|
return (source & 0x1'fffc) << 2;
|
||||||
};
|
};
|
||||||
@ -110,6 +107,25 @@ struct MemoryController {
|
|||||||
high_rom_access_time_ = ROMAccessTime((address >> 6) & 3);
|
high_rom_access_time_ = ROMAccessTime((address >> 6) & 3);
|
||||||
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);
|
||||||
|
switch(page_size_) {
|
||||||
|
default:
|
||||||
|
case PageSize::kb4:
|
||||||
|
page_address_shift_ = 12;
|
||||||
|
page_adddress_mask_ = 0x0fff;
|
||||||
|
break;
|
||||||
|
case PageSize::kb8:
|
||||||
|
page_address_shift_ = 13;
|
||||||
|
page_adddress_mask_ = 0x1fff;
|
||||||
|
break;
|
||||||
|
case PageSize::kb16:
|
||||||
|
page_address_shift_ = 14;
|
||||||
|
page_adddress_mask_ = 0x3fff;
|
||||||
|
break;
|
||||||
|
case PageSize::kb32:
|
||||||
|
page_address_shift_ = 15;
|
||||||
|
page_adddress_mask_ = 0x7fff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
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_);
|
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_);
|
||||||
map_dirty_ = true;
|
map_dirty_ = true;
|
||||||
@ -126,19 +142,23 @@ struct MemoryController {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Zone::IOControllers:
|
case Zone::IOControllers:
|
||||||
|
if(trans) return false;
|
||||||
ioc_.template write<IntT>(address, source);
|
ioc_.template write<IntT>(address, source);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::VideoController:
|
case Zone::VideoController:
|
||||||
|
if(trans) return false;
|
||||||
// TODO: handle byte writes correctly.
|
// TODO: handle byte writes correctly.
|
||||||
ioc_.video().write(source);
|
ioc_.video().write(source);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::PhysicallyMappedRAM:
|
case Zone::PhysicallyMappedRAM:
|
||||||
|
if(trans) return false;
|
||||||
physical_ram<IntT>(address) = source;
|
physical_ram<IntT>(address) = source;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::AddressTranslator:
|
case Zone::AddressTranslator:
|
||||||
|
if(trans) return false;
|
||||||
// printf("Translator write at %08x; replaces %08x\n", address, pages_[address & 0x7f]);
|
// printf("Translator write at %08x; replaces %08x\n", address, pages_[address & 0x7f]);
|
||||||
pages_[address & 0x7f] = address;
|
pages_[address & 0x7f] = address;
|
||||||
map_dirty_ = true;
|
map_dirty_ = true;
|
||||||
@ -154,13 +174,9 @@ struct MemoryController {
|
|||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
bool read(uint32_t address, IntT &source, InstructionSet::ARM::Mode, bool trans) {
|
bool read(uint32_t address, IntT &source, InstructionSet::ARM::Mode, bool trans) {
|
||||||
// User mode may only read logically-maped RAM and ROM.
|
|
||||||
if(trans && address >= 0x200'0000 && address < 0x380'0000) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (read_zones_[(address >> 21) & 31]) {
|
switch (read_zones_[(address >> 21) & 31]) {
|
||||||
case Zone::PhysicallyMappedRAM:
|
case Zone::PhysicallyMappedRAM:
|
||||||
|
if(trans) return false;
|
||||||
source = physical_ram<IntT>(address);
|
source = physical_ram<IntT>(address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -184,6 +200,7 @@ struct MemoryController {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Zone::IOControllers:
|
case Zone::IOControllers:
|
||||||
|
if(trans) return false;
|
||||||
ioc_.template read<IntT>(address, source);
|
ioc_.template read<IntT>(address, source);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -298,6 +315,8 @@ struct MemoryController {
|
|||||||
kb16 = 0b10,
|
kb16 = 0b10,
|
||||||
kb32 = 0b11,
|
kb32 = 0b11,
|
||||||
} page_size_ = PageSize::kb4;
|
} page_size_ = PageSize::kb4;
|
||||||
|
int page_address_shift_ = 12;
|
||||||
|
uint32_t page_adddress_mask_ = 0xffff;
|
||||||
|
|
||||||
// Address translator.
|
// Address translator.
|
||||||
//
|
//
|
||||||
@ -339,33 +358,14 @@ struct MemoryController {
|
|||||||
}
|
}
|
||||||
address = aligned<IntT>(address);
|
address = aligned<IntT>(address);
|
||||||
address &= 0x1ff'ffff;
|
address &= 0x1ff'ffff;
|
||||||
size_t page;
|
const size_t page = address >> page_address_shift_;
|
||||||
|
|
||||||
// TODO: eliminate switch here.
|
|
||||||
switch(page_size_) {
|
|
||||||
default:
|
|
||||||
case PageSize::kb4:
|
|
||||||
page = address >> 12;
|
|
||||||
address &= 0x0fff;
|
|
||||||
break;
|
|
||||||
case PageSize::kb8:
|
|
||||||
page = address >> 13;
|
|
||||||
address &= 0x1fff;
|
|
||||||
break;
|
|
||||||
case PageSize::kb16:
|
|
||||||
page = address >> 14;
|
|
||||||
address &= 0x3fff;
|
|
||||||
break;
|
|
||||||
case PageSize::kb32:
|
|
||||||
page = address >> 15;
|
|
||||||
address &= 0x7fff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &map = mapping<is_read>(trans, os_mode_);
|
const auto &map = mapping<is_read>(trans, os_mode_);
|
||||||
if(!map[page]) {
|
if(!map[page]) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address &= page_adddress_mask_;
|
||||||
return reinterpret_cast<IntT *>(&map[page][address]);
|
return reinterpret_cast<IntT *>(&map[page][address]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
enableASanStackUseAfterReturn = "YES"
|
enableASanStackUseAfterReturn = "YES"
|
||||||
|
@ -31,14 +31,21 @@ PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegment &segment) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegmentEventSource &original) {
|
PCMSegmentEventSource::PCMSegmentEventSource(const PCMSegmentEventSource &original) {
|
||||||
|
*this = original;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCMSegmentEventSource &PCMSegmentEventSource::operator =(const PCMSegmentEventSource &original) {
|
||||||
// share underlying data with the original
|
// share underlying data with the original
|
||||||
segment_ = original.segment_;
|
segment_ = original.segment_;
|
||||||
|
|
||||||
// load up the clock rate and set initial conditions
|
// load up the clock rate and set initial conditions
|
||||||
next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;
|
next_event_.length.clock_rate = segment_->length_of_a_bit.clock_rate;
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PCMSegmentEventSource::reset() {
|
void PCMSegmentEventSource::reset() {
|
||||||
// start with the first bit to be considered the zeroth, and assume that it'll be
|
// start with the first bit to be considered the zeroth, and assume that it'll be
|
||||||
// flux transitions for the foreseeable
|
// flux transitions for the foreseeable
|
||||||
|
@ -163,6 +163,7 @@ class PCMSegmentEventSource {
|
|||||||
but a unique pointer into it.
|
but a unique pointer into it.
|
||||||
*/
|
*/
|
||||||
PCMSegmentEventSource(const PCMSegmentEventSource &);
|
PCMSegmentEventSource(const PCMSegmentEventSource &);
|
||||||
|
PCMSegmentEventSource &operator =(const PCMSegmentEventSource &);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns the next event that will occur in this event stream.
|
@returns the next event that will occur in this event stream.
|
||||||
|
Loading…
Reference in New Issue
Block a user