mirror of
https://github.com/TomHarte/CLK.git
synced 2025-09-25 08:25:09 +00:00
@@ -38,12 +38,15 @@ private:
|
||||
|
||||
struct BBCMicroTarget: public ::Analyser::Static::Target, public Reflection::StructImpl<BBCMicroTarget> {
|
||||
std::string loading_command;
|
||||
bool has_1770dfs = false;
|
||||
|
||||
BBCMicroTarget() : Analyser::Static::Target(Machine::BBCMicro) {}
|
||||
|
||||
private:
|
||||
friend Reflection::StructImpl<BBCMicroTarget>;
|
||||
void declare_fields() {}
|
||||
void declare_fields() {
|
||||
DeclareField(has_1770dfs);
|
||||
}
|
||||
};
|
||||
|
||||
struct ArchimedesTarget: public ::Analyser::Static::Target, public Reflection::StructImpl<ArchimedesTarget> {
|
||||
|
@@ -114,6 +114,7 @@ uint8_t WD1770::read(const int address) {
|
||||
update_status([] (Status &status) {
|
||||
status.data_request = false;
|
||||
});
|
||||
// Logger::info().append("Returned data %02x; [drq:%d]", data_, status_.data_request);
|
||||
return data_;
|
||||
}
|
||||
}
|
||||
@@ -486,8 +487,12 @@ void WD1770::posit_event(const int new_event_type) {
|
||||
WAIT_FOR_EVENT(Event::Token);
|
||||
if(get_latest_token().type != Token::Byte) goto type2_read_byte;
|
||||
data_ = get_latest_token().byte_value;
|
||||
// Logger::info().append("Posting %02x", data_);
|
||||
update_status([] (Status &status) {
|
||||
status.lost_data |= status.data_request;
|
||||
// if(status.lost_data) {
|
||||
// Logger::info().append("Lost data");
|
||||
// }
|
||||
status.data_request = true;
|
||||
});
|
||||
distance_into_section_++;
|
||||
|
@@ -20,6 +20,9 @@
|
||||
#include "Components/6850/6850.hpp"
|
||||
#include "Components/uPD7002/uPD7002.hpp"
|
||||
|
||||
// TODO: factor this more appropriately.
|
||||
#include "Machines/Acorn/Electron/Plus3.hpp"
|
||||
|
||||
#include "Analyser/Static/Acorn/Target.hpp"
|
||||
#include "Outputs/Log.hpp"
|
||||
|
||||
@@ -457,14 +460,17 @@ using CRTC = Motorola::CRTC::CRTC6845<
|
||||
Motorola::CRTC::CursorType::None>;
|
||||
}
|
||||
|
||||
template <bool has_1770>
|
||||
class ConcreteMachine:
|
||||
public Machine,
|
||||
public MachineTypes::AudioProducer,
|
||||
public MachineTypes::MappedKeyboardMachine,
|
||||
public MachineTypes::MediaTarget,
|
||||
public MachineTypes::ScanProducer,
|
||||
public MachineTypes::TimedMachine,
|
||||
public MOS::MOS6522::IRQDelegatePortHandler::Delegate,
|
||||
public NEC::uPD7002::Delegate
|
||||
public NEC::uPD7002::Delegate,
|
||||
public WD::WD1770::Delegate
|
||||
{
|
||||
public:
|
||||
ConcreteMachine(
|
||||
@@ -488,7 +494,12 @@ public:
|
||||
// Grab ROMs.
|
||||
using Request = ::ROM::Request;
|
||||
using Name = ::ROM::Name;
|
||||
const auto request = Request(Name::AcornBASICII) && Request(Name::BBCMicroMOS12);
|
||||
|
||||
auto request = Request(Name::AcornBASICII) && Request(Name::BBCMicroMOS12);
|
||||
if(target.has_1770dfs) {
|
||||
request = request && Request(Name::AcornDFS226);
|
||||
}
|
||||
|
||||
auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
@@ -498,6 +509,9 @@ public:
|
||||
std::copy(os_data.begin(), os_data.end(), os_.begin());
|
||||
|
||||
install_sideways(15, roms.find(Name::AcornBASICII)->second, false);
|
||||
if(target.has_1770dfs) {
|
||||
install_sideways(14, roms.find(Name::AcornDFS226)->second, false);
|
||||
}
|
||||
|
||||
// Setup fixed parts of memory map.
|
||||
page(0, &ram_[0], true);
|
||||
@@ -506,7 +520,11 @@ public:
|
||||
page(3, os_.data(), false);
|
||||
Memory::Fuzz(ram_);
|
||||
|
||||
(void)target;
|
||||
if constexpr (has_1770) {
|
||||
wd1770_.set_delegate(this);
|
||||
}
|
||||
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
// MARK: - 6502 bus.
|
||||
@@ -538,7 +556,7 @@ public:
|
||||
};
|
||||
|
||||
// Determine whether this access hits the 1Mhz bus; if so then apply appropriate penalty, and update phase.
|
||||
const auto duration = is_1mhz(address) ? Cycles(2 + (phase_&1)) : Cycles(1);
|
||||
const auto duration = Cycles(is_1mhz(address) ? 2 + (phase_&1) : 1);
|
||||
phase_ += duration.as<int>();
|
||||
|
||||
|
||||
@@ -565,6 +583,11 @@ public:
|
||||
adc_.run_for(duration);
|
||||
|
||||
|
||||
if constexpr (has_1770) {
|
||||
// The WD1770 is nominally clocked at 8Mhz.
|
||||
wd1770_.run_for(duration * 4);
|
||||
}
|
||||
|
||||
//
|
||||
// Questionably-clocked devices.
|
||||
//
|
||||
@@ -642,6 +665,21 @@ public:
|
||||
} else {
|
||||
adc_.write(address, *value);
|
||||
}
|
||||
} else if(has_1770 && address >= 0xfe80 && address < 0xfe88) {
|
||||
switch(address) {
|
||||
case 0xfe80:
|
||||
if(!is_read(operation)) {
|
||||
wd1770_.set_control_register(*value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(is_read(operation)) {
|
||||
*value = wd1770_.read(address);
|
||||
} else {
|
||||
wd1770_.write(address, *value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger::error()
|
||||
@@ -720,6 +758,15 @@ private:
|
||||
update_irq_line();
|
||||
}
|
||||
|
||||
// MARK: - MediaTarget.
|
||||
bool insert_media(const Analyser::Static::Media &media) override {
|
||||
if(!media.disks.empty() && has_1770) {
|
||||
wd1770_.set_disk(media.disks.front(), 0);
|
||||
}
|
||||
|
||||
return !media.disks.empty();
|
||||
}
|
||||
|
||||
// MARK: - Clock phase.
|
||||
int phase_ = 0;
|
||||
|
||||
@@ -778,6 +825,12 @@ private:
|
||||
Motorola::ACIA::ACIA acia_;
|
||||
|
||||
NEC::uPD7002 adc_;
|
||||
|
||||
// MARK: - WD1770.
|
||||
Electron::Plus3 wd1770_;
|
||||
void wd1770_did_change_output(WD::WD1770 &) override {
|
||||
m6502_.set_nmi_line(wd1770_.get_interrupt_request_line() || wd1770_.get_data_request_line());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -790,5 +843,9 @@ std::unique_ptr<Machine> Machine::BBCMicro(
|
||||
) {
|
||||
using Target = Analyser::Static::Acorn::BBCMicroTarget;
|
||||
const Target *const acorn_target = dynamic_cast<const Target *>(target);
|
||||
return std::make_unique<BBCMicro::ConcreteMachine>(*acorn_target, rom_fetcher);
|
||||
if(acorn_target->has_1770dfs) {
|
||||
return std::make_unique<BBCMicro::ConcreteMachine<true>>(*acorn_target, rom_fetcher);
|
||||
} else {
|
||||
return std::make_unique<BBCMicro::ConcreteMachine<false>>(*acorn_target, rom_fetcher);
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ void Plus3::set_control_register(uint8_t control) {
|
||||
// bit 1 => enable or disable drive 2
|
||||
// bit 2 => side select
|
||||
// bit 3 => single density select
|
||||
// bit 5 => reset?
|
||||
|
||||
uint8_t changes = control ^ last_control_;
|
||||
last_control_ = control;
|
||||
|
@@ -429,6 +429,14 @@ const std::vector<Description> &Description::all_roms() {
|
||||
16_kb,
|
||||
0x3c14fc70u
|
||||
},
|
||||
{
|
||||
AcornDFS226,
|
||||
"BBCMicro",
|
||||
"the Acorn 1770 DFS 2.26 ROM",
|
||||
"dfs-2.26.rom",
|
||||
16_kb,
|
||||
0x5ae33e94u
|
||||
},
|
||||
|
||||
//
|
||||
// ColecoVision.
|
||||
|
@@ -82,6 +82,7 @@ enum Name {
|
||||
|
||||
// BBC Micro.
|
||||
BBCMicroMOS12,
|
||||
AcornDFS226,
|
||||
|
||||
// ColecoVision.
|
||||
ColecoVisionBIOS,
|
||||
|
@@ -165,10 +165,9 @@
|
||||
if(self) {
|
||||
auto target = std::make_unique<Analyser::Static::Acorn::BBCMicroTarget>();
|
||||
// TODO.
|
||||
(void)dfs;
|
||||
(void)adfs;
|
||||
(void)sidewaysRAM;
|
||||
// target->has_dfs = dfs;
|
||||
target->has_1770dfs = dfs;
|
||||
// target->has_pres_adfs = adfs;
|
||||
// target->has_ap6_rom = ap6;
|
||||
// target->has_sideways_ram = sidewaysRAM;
|
||||
|
@@ -194,13 +194,10 @@ void Processor<personality, T, uses_ready_line>::run_for(const Cycles cycles) {
|
||||
case OperationRSTPickVector: next_address_.full = 0xfffc; continue;
|
||||
case CycleReadVectorLow: read_mem(pc_.halves.low, next_address_.full); break;
|
||||
case CycleReadVectorHigh: read_mem(pc_.halves.high, next_address_.full+1); break;
|
||||
case OperationSetIRQFlags:
|
||||
case OperationSetInterruptFlags:
|
||||
flags_.inverse_interrupt = 0;
|
||||
if(is_65c02(personality)) flags_.decimal = 0;
|
||||
continue;
|
||||
case OperationSetNMIRSTFlags:
|
||||
if(is_65c02(personality)) flags_.decimal = 0;
|
||||
continue;
|
||||
|
||||
case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break;
|
||||
case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break;
|
||||
|
@@ -77,7 +77,7 @@ using namespace CPU::MOS6502;
|
||||
|
||||
ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
const InstructionList operations_6502[] = {
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetIRQFlags, CycleReadVectorLow, CycleReadVectorHigh),
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetInterruptFlags, CycleReadVectorLow, CycleReadVectorHigh),
|
||||
/* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA),
|
||||
/* 0x02 JAM */ JAM, /* 0x03 ASO x, ind */ IndexedIndirectReadModifyWrite(OperationASO),
|
||||
/* 0x04 NOP zpg */ ZeroNop(), /* 0x05 ORA zpg */ ZeroRead(OperationORA),
|
||||
@@ -228,7 +228,7 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
CycleNoWritePush,
|
||||
OperationRSTPickVector,
|
||||
CycleNoWritePush,
|
||||
OperationSetNMIRSTFlags,
|
||||
OperationSetInterruptFlags,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh
|
||||
),
|
||||
@@ -242,7 +242,7 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
OperationBRKPickVector,
|
||||
OperationSetOperandFromFlags,
|
||||
CyclePushOperand,
|
||||
OperationSetIRQFlags,
|
||||
OperationSetInterruptFlags,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh
|
||||
),
|
||||
@@ -256,7 +256,7 @@ ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
OperationNMIPickVector,
|
||||
OperationSetOperandFromFlags,
|
||||
CyclePushOperand,
|
||||
OperationSetNMIRSTFlags,
|
||||
OperationSetInterruptFlags,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh
|
||||
),
|
||||
|
@@ -35,8 +35,7 @@ class ProcessorStorage {
|
||||
CyclePushY, // pushes Y to the stack
|
||||
CyclePushOperand, // pushes operand_ to the stack
|
||||
|
||||
OperationSetIRQFlags, // 6502: sets I; 65C02: sets I and resets D
|
||||
OperationSetNMIRSTFlags, // 6502: no-op. 65C02: resets D
|
||||
OperationSetInterruptFlags, // 6502: sets I; 65C02: sets I and resets D
|
||||
|
||||
OperationBRKPickVector, // 65C02: sets next_address_ to the BRK vector location; 6502: as 65C02 if no NMI is pending; otherwise sets next_address_ to the NMI address and resets the internal NMI-pending flag
|
||||
OperationNMIPickVector, // sets next_address_ to the NMI vector
|
||||
|
Reference in New Issue
Block a user