mirror of
https://github.com/TomHarte/CLK.git
synced 2025-11-01 11:16:16 +00:00
Switch the BBC Micro to 6502Mk2.
This commit is contained in:
@@ -120,7 +120,6 @@ public:
|
||||
case 6: layout_.vertical.displayed = value; break;
|
||||
case 7: layout_.vertical.start_sync = value; break;
|
||||
case 8:
|
||||
printf("Interlace mode: %d", value & 3);
|
||||
switch(value & 3) {
|
||||
default: layout_.interlace_mode_ = InterlaceMode::Off; break;
|
||||
case 0b01: layout_.interlace_mode_ = InterlaceMode::Sync; break;
|
||||
|
||||
@@ -763,18 +763,11 @@ public:
|
||||
if(!target.loading_command.empty()) {
|
||||
type_string(target.loading_command);
|
||||
}
|
||||
|
||||
// Prime the display and then reset.
|
||||
// run_for(Cycles(100'000'000));
|
||||
// m6502_.set_power_on(true);
|
||||
}
|
||||
|
||||
// MARK: - 6502 bus.
|
||||
Cycles perform_bus_operation(
|
||||
const CPU::MOS6502::BusOperation operation,
|
||||
const uint16_t address,
|
||||
uint8_t *const value
|
||||
) {
|
||||
template <CPU::MOS6502Mk2::BusOperation operation, typename AddressT>
|
||||
Cycles perform(const AddressT address, CPU::MOS6502Mk2::data_t<operation> value) {
|
||||
// Returns @c true if @c address is a device on the 1Mhz bus; @c false otherwise.
|
||||
static constexpr auto is_1mhz = [](const uint16_t address) {
|
||||
// Fast exit if outside the IO space.
|
||||
@@ -842,84 +835,84 @@ public:
|
||||
//
|
||||
if(address >= 0xfc00 && address < 0xff00) {
|
||||
if(address >= 0xfe40 && address < 0xfe60) {
|
||||
if(is_read(operation)) {
|
||||
*value = system_via_.read(address);
|
||||
if constexpr (is_read(operation)) {
|
||||
value = system_via_.read(address);
|
||||
} else {
|
||||
system_via_.write(address, *value);
|
||||
system_via_.write(address, value);
|
||||
}
|
||||
} else if(address >= 0xfe60 && address < 0xfe80) {
|
||||
if(is_read(operation)) {
|
||||
*value = user_via_.read(address);
|
||||
if constexpr (is_read(operation)) {
|
||||
value = user_via_.read(address);
|
||||
} else {
|
||||
user_via_.write(address, *value);
|
||||
user_via_.write(address, value);
|
||||
}
|
||||
} else if(address == 0xfe30) {
|
||||
if(is_read(operation)) {
|
||||
*value = 0xfe;
|
||||
if constexpr (is_read(operation)) {
|
||||
value = 0xfe;
|
||||
} else {
|
||||
page_sideways(*value & 0xf);
|
||||
page_sideways(value & 0xf);
|
||||
}
|
||||
} else if(address >= 0xfe00 && address < 0xfe08) {
|
||||
if(is_read(operation)) {
|
||||
if constexpr (is_read(operation)) {
|
||||
if(address & 1) {
|
||||
*value = crtc_.get_register();
|
||||
value = crtc_.get_register();
|
||||
} else {
|
||||
*value = crtc_.get_status();
|
||||
value = crtc_.get_status();
|
||||
}
|
||||
} else {
|
||||
if(address & 1) {
|
||||
crtc_.set_register(*value);
|
||||
crtc_.set_register(value);
|
||||
} else {
|
||||
crtc_.select_register(*value);
|
||||
crtc_.select_register(value);
|
||||
}
|
||||
}
|
||||
} else if(address >= 0xfe20 && address < 0xfe30) {
|
||||
if(is_read(operation)) {
|
||||
*value = 0xfe;
|
||||
if constexpr (is_read(operation)) {
|
||||
value = 0xfe;
|
||||
} else {
|
||||
switch(address) {
|
||||
case 0xfe20:
|
||||
crtc_bus_handler_.set_control(*value);
|
||||
crtc_2mhz_ = *value & 0x10;
|
||||
crtc_bus_handler_.set_control(value);
|
||||
crtc_2mhz_ = value & 0x10;
|
||||
break;
|
||||
case 0xfe21:
|
||||
crtc_bus_handler_.set_palette(*value);
|
||||
crtc_bus_handler_.set_palette(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(address == 0xfee0) {
|
||||
if(is_read(operation)) {
|
||||
if constexpr (is_read(operation)) {
|
||||
Logger::info().append("Read tube status: 0");
|
||||
*value = 0;
|
||||
value = 0;
|
||||
} else {
|
||||
Logger::info().append("Wrote tube: %02x", *value);
|
||||
Logger::info().append("Wrote tube: %02x", value);
|
||||
}
|
||||
} else if(address >= 0xfe08 && address < 0xfe10) {
|
||||
if(is_read(operation)) {
|
||||
if constexpr (is_read(operation)) {
|
||||
// Logger::info().append("ACIA read");
|
||||
*value = acia_.read(address);
|
||||
value = acia_.read(address);
|
||||
} else {
|
||||
// Logger::info().append("ACIA write: %02x", *value);
|
||||
acia_.write(address, *value);
|
||||
acia_.write(address, value);
|
||||
}
|
||||
} else if(address >= 0xfec0 && address < 0xfee0) {
|
||||
if(is_read(operation)) {
|
||||
*value = adc_.read(address);
|
||||
if constexpr (is_read(operation)) {
|
||||
value = adc_.read(address);
|
||||
} else {
|
||||
adc_.write(address, *value);
|
||||
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);
|
||||
if constexpr (!is_read(operation)) {
|
||||
wd1770_.set_control_register(value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(is_read(operation)) {
|
||||
*value = wd1770_.read(address);
|
||||
if constexpr (is_read(operation)) {
|
||||
value = wd1770_.read(address);
|
||||
} else {
|
||||
wd1770_.write(address, *value);
|
||||
wd1770_.write(address, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -927,7 +920,7 @@ public:
|
||||
else {
|
||||
Logger::error()
|
||||
.append("Unhandled IO %s at %04x", is_read(operation) ? "read" : "write", address)
|
||||
.append_if(!is_read(operation), ": %02x", *value);
|
||||
.append_if(!is_read(operation), ": %02x", value);
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
@@ -935,16 +928,16 @@ public:
|
||||
//
|
||||
// ROM or RAM access.
|
||||
//
|
||||
if(is_read(operation)) {
|
||||
if constexpr (is_read(operation)) {
|
||||
// TODO: probably don't do this with this condition? See how it compiles. If it's a CMOV somehow, no problem.
|
||||
if((address >> 14) == 2 && !sideways_read_mask_) {
|
||||
*value = 0xff;
|
||||
value = 0xff;
|
||||
} else {
|
||||
*value = memory_[address >> 14][address];
|
||||
value = memory_[address >> 14][address];
|
||||
}
|
||||
} else {
|
||||
if(memory_write_masks_[address >> 14]) {
|
||||
memory_[address >> 14][address] = *value;
|
||||
memory_[address >> 14][address] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,7 +998,7 @@ private:
|
||||
break;
|
||||
|
||||
case Key::Break:
|
||||
m6502_.set_reset_line(is_pressed);
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::Reset>(is_pressed);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1016,12 +1009,12 @@ private:
|
||||
bool was_caps_ = false;
|
||||
|
||||
void clear_all_keys() final {
|
||||
m6502_.set_reset_line(false);
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::Reset>(false);
|
||||
system_via_port_handler_.clear_all_keys();
|
||||
}
|
||||
|
||||
HalfCycles get_typer_delay(const std::string &text) const final {
|
||||
if(!m6502_.get_is_resetting()) {
|
||||
if(!m6502_.is_resetting()) {
|
||||
return Cycles(0);
|
||||
}
|
||||
|
||||
@@ -1109,7 +1102,13 @@ private:
|
||||
}
|
||||
|
||||
// MARK: - Components.
|
||||
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, ConcreteMachine, false> m6502_;
|
||||
|
||||
struct M6502Traits {
|
||||
static constexpr auto uses_ready_line = false;
|
||||
static constexpr auto pause_precision = CPU::MOS6502Mk2::PausePrecision::BetweenInstructions;
|
||||
using BusHandlerT = ConcreteMachine;
|
||||
};
|
||||
CPU::MOS6502Mk2::Processor<CPU::MOS6502Mk2::Model::M6502, M6502Traits> m6502_;
|
||||
|
||||
UserVIAPortHandler user_via_port_handler_;
|
||||
SystemVIAPortHandler system_via_port_handler_;
|
||||
@@ -1117,7 +1116,7 @@ private:
|
||||
SystemVIA system_via_;
|
||||
|
||||
void update_irq_line() {
|
||||
m6502_.set_irq_line(
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(
|
||||
user_via_.get_interrupt_line() ||
|
||||
system_via_.get_interrupt_line()
|
||||
);
|
||||
@@ -1136,7 +1135,9 @@ private:
|
||||
// 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());
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::NMI>(
|
||||
wd1770_.get_interrupt_request_line() || wd1770_.get_data_request_line()
|
||||
);
|
||||
}
|
||||
|
||||
// MARK: - Joysticks
|
||||
@@ -1150,44 +1151,10 @@ private:
|
||||
|
||||
using namespace BBCMicro;
|
||||
|
||||
namespace {
|
||||
|
||||
struct Handler {
|
||||
uint8_t memory_[65536];
|
||||
|
||||
template <CPU::MOS6502Mk2::BusOperation operation, typename AddressT>
|
||||
Cycles perform(const AddressT address, CPU::MOS6502Mk2::data_t<operation> data) {
|
||||
if constexpr (!is_dataless(operation)) {
|
||||
if constexpr (is_read(operation)) {
|
||||
data = memory_[address];
|
||||
} else {
|
||||
memory_[address] = data;
|
||||
}
|
||||
}
|
||||
return Cycles(1);
|
||||
}
|
||||
};
|
||||
|
||||
struct Traits {
|
||||
static constexpr auto uses_ready_line = false;
|
||||
static constexpr auto pause_precision = CPU::MOS6502Mk2::PausePrecision::AnyCycle;
|
||||
using BusHandlerT = Handler;
|
||||
};
|
||||
|
||||
void test_it() {
|
||||
Handler handler;
|
||||
CPU::MOS6502Mk2::Processor<CPU::MOS6502Mk2::Model::M6502, Traits> processor(handler);
|
||||
processor.run_for(Cycles(1000));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Machine> Machine::BBCMicro(
|
||||
const Analyser::Static::Target *target,
|
||||
const ROMMachine::ROMFetcher &rom_fetcher
|
||||
) {
|
||||
test_it();
|
||||
|
||||
using Target = Analyser::Static::Acorn::BBCMicroTarget;
|
||||
const Target *const acorn_target = dynamic_cast<const Target *>(target);
|
||||
if(acorn_target->has_1770dfs || acorn_target->has_adfs) {
|
||||
|
||||
Reference in New Issue
Block a user