mirror of
https://github.com/TomHarte/CLK.git
synced 2026-01-23 16:16:16 +00:00
Mostly wire in a Z80 second processor.
This commit is contained in:
@@ -45,7 +45,7 @@ struct BBCMicroTarget: public ::Analyser::Static::Target, public Reflection::Str
|
||||
bool has_adfs = false;
|
||||
bool has_sideways_ram = true;
|
||||
|
||||
ReflectableEnum(TubeProcessor, None, WDC65C02);
|
||||
ReflectableEnum(TubeProcessor, None, WDC65C02, Z80);
|
||||
TubeProcessor tube_processor = TubeProcessor::None;
|
||||
|
||||
BBCMicroTarget() : Analyser::Static::Target(Machine::BBCMicro) {}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "Machines/Acorn/Tube/ULA.hpp"
|
||||
#include "Machines/Acorn/Tube/Tube6502.hpp"
|
||||
#include "Machines/Acorn/Tube/TubeZ80.hpp"
|
||||
|
||||
#include "Components/6522/6522.hpp"
|
||||
#include "Components/6845/CRTC6845.hpp"
|
||||
@@ -704,6 +705,17 @@ struct Tube<HostT, TubeProcessor::WDC65C02> {
|
||||
processor(ula) {}
|
||||
};
|
||||
|
||||
template <typename HostT>
|
||||
struct Tube<HostT, TubeProcessor::Z80> {
|
||||
using TubeULA = Acorn::Tube::ULA<HostT>;
|
||||
TubeULA ula;
|
||||
Acorn::Tube::TubeZ80<TubeULA> processor;
|
||||
|
||||
Tube(HostT &owner) :
|
||||
ula(owner),
|
||||
processor(ula) {}
|
||||
};
|
||||
|
||||
// MARK: - ConcreteMachine.
|
||||
|
||||
template <TubeProcessor tube_processor, bool has_1770>
|
||||
@@ -760,11 +772,8 @@ public:
|
||||
request = request && Request(Name::BBCMicroADFS130);
|
||||
}
|
||||
|
||||
switch(tube_processor) {
|
||||
default: break;
|
||||
case TubeProcessor::WDC65C02:
|
||||
request = request && Request(Name::BBCMicroTube110);
|
||||
break;
|
||||
if constexpr (tube_processor != TubeProcessor::None) {
|
||||
request = request && Request(tube_.processor.ROM);
|
||||
}
|
||||
|
||||
auto roms = rom_fetcher(request);
|
||||
@@ -796,14 +805,7 @@ public:
|
||||
|
||||
// Throw the tube ROM to its target.
|
||||
if constexpr (tube_processor != TubeProcessor::None) {
|
||||
switch(tube_processor) {
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
|
||||
case TubeProcessor::WDC65C02:
|
||||
tube_.processor.set_rom(roms.find(Name::BBCMicroTube110)->second);
|
||||
break;
|
||||
}
|
||||
tube_.processor.set_rom(roms.find(tube_.processor.ROM)->second);
|
||||
}
|
||||
|
||||
// Install the ADT ROM if available, but don't error if it's missing. It's very optional.
|
||||
@@ -1294,6 +1296,7 @@ std::unique_ptr<Machine> Machine::BBCMicro(
|
||||
switch(acorn_target->tube_processor) {
|
||||
case TubeProcessor::None: return machine<TubeProcessor::None>(*acorn_target, rom_fetcher);
|
||||
case TubeProcessor::WDC65C02: return machine<TubeProcessor::WDC65C02>(*acorn_target, rom_fetcher);
|
||||
case TubeProcessor::Z80: return machine<TubeProcessor::Z80>(*acorn_target, rom_fetcher);
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Processors/6502Mk2/6502Mk2.hpp"
|
||||
#include "Machines/Utility/ROMCatalogue.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -18,9 +19,14 @@ namespace Acorn::Tube {
|
||||
// of sense to me; it is copied into RAM (by whom?) and then copied in again upon every reset
|
||||
// (again: by whom?).
|
||||
|
||||
// TODO: based on the service manual I believe correct behaviour is to page the ROM upon reset, and keep
|
||||
// it paged until a tube register is hit. It'll copy itself into the underlying RAM in the meantime.
|
||||
|
||||
template <typename ULAT>
|
||||
struct Tube6502 {
|
||||
public:
|
||||
static constexpr auto ROM = ROM::Name::BBCMicroTube110;
|
||||
|
||||
Tube6502(ULAT &ula) : m6502_(*this), ula_(ula) {}
|
||||
|
||||
// By convention, these are cycles relative to the host's 2Mhz bus.
|
||||
|
||||
90
Machines/Acorn/Tube/TubeZ80.hpp
Normal file
90
Machines/Acorn/Tube/TubeZ80.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// TubeZ80.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 04/11/2025.
|
||||
// Copyright © 2025 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Processors/Z80/Z80.hpp"
|
||||
#include "Machines/Utility/ROMCatalogue.hpp"
|
||||
|
||||
namespace Acorn::Tube {
|
||||
|
||||
template <typename ULAT>
|
||||
struct TubeZ80: public CPU::Z80::BusHandler {
|
||||
public:
|
||||
// TODO.
|
||||
static constexpr auto ROM = ROM::Name::BBCMicroTube110;
|
||||
void set_rom(const std::vector<uint8_t> &) {}
|
||||
|
||||
TubeZ80(ULAT &ula) : z80_(*this), ula_(ula) {}
|
||||
|
||||
void run_for(const Cycles cycles) {
|
||||
// Map from 2Mhz to 6Mhz.
|
||||
z80_.run_for(cycles * 3);
|
||||
}
|
||||
|
||||
void set_irq() { z80_.set_interrupt_line(true); }
|
||||
void set_nmi() { z80_.set_non_maskable_interrupt_line(true); }
|
||||
void set_reset(const bool reset) {
|
||||
z80_.set_reset_line(reset);
|
||||
rom_visible_ |= reset;
|
||||
}
|
||||
|
||||
HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
||||
if(!cycle.is_terminal()) {
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
const uint16_t address = *cycle.address;
|
||||
rom_visible_ &= address < 0x8000;
|
||||
|
||||
switch(cycle.operation) {
|
||||
case CPU::Z80::PartialMachineCycle::ReadOpcode:
|
||||
if(address == 0x66) {
|
||||
rom_visible_ = true;
|
||||
}
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
if(rom_visible_ && address <= sizeof(rom_)) {
|
||||
*cycle.value = rom_[address];
|
||||
return HalfCycles(2);
|
||||
} else {
|
||||
*cycle.value = ram_[address];
|
||||
}
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Write:
|
||||
ram_[address] = cycle.value;
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Interrupt:
|
||||
*cycle.value = 0xff;
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Input:
|
||||
*cycle.value = ula_.read_parasite(address);
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Output:
|
||||
ula_.write_parasite(address, *cycle.value);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::Z80::Processor<TubeZ80, false, false> z80_;
|
||||
bool rom_visible_ = true;
|
||||
|
||||
uint8_t rom_[4096];
|
||||
uint8_t ram_[65536];
|
||||
ULAT &ula_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1563,6 +1563,7 @@
|
||||
4B3FE75D1F3CF68B00448EE4 /* CPM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CPM.hpp; path = Parsers/CPM.hpp; sourceTree = "<group>"; };
|
||||
4B4195F42EB8F061001C966D /* ULA.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ULA.hpp; sourceTree = "<group>"; };
|
||||
4B4195F52EB92630001C966D /* Tube6502.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Tube6502.hpp; sourceTree = "<group>"; };
|
||||
4B4195F62EBAB06C001C966D /* TubeZ80.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TubeZ80.hpp; sourceTree = "<group>"; };
|
||||
4B43983829620FB1006B0BFC /* 9918.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = 9918.cpp; sourceTree = "<group>"; };
|
||||
4B43983C29621024006B0BFC /* ClockConverter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ClockConverter.hpp; sourceTree = "<group>"; };
|
||||
4B43983E29628538006B0BFC /* Fetch.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Fetch.hpp; sourceTree = "<group>"; };
|
||||
@@ -3361,8 +3362,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4A75C22EB43F1C00EA398F /* FIFO.hpp */,
|
||||
4B4195F42EB8F061001C966D /* ULA.hpp */,
|
||||
4B4195F52EB92630001C966D /* Tube6502.hpp */,
|
||||
4B4195F62EBAB06C001C966D /* TubeZ80.hpp */,
|
||||
4B4195F42EB8F061001C966D /* ULA.hpp */,
|
||||
);
|
||||
path = Tube;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef NS_ENUM(NSInteger, CSMachineArchimedesModel) {
|
||||
typedef NS_ENUM(NSInteger, CSMachineBBCMicroSecondProcessor) {
|
||||
CSMachineBBCMicroSecondProcessorNone,
|
||||
CSMachineBBCMicroSecondProcessor65C02,
|
||||
CSMachineBBCMicroSecondProcessorZ80,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSMachineCommodoreTEDModel) {
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
switch(secondProcessor) {
|
||||
case CSMachineBBCMicroSecondProcessorNone: target->tube_processor = Target::TubeProcessor::None; break;
|
||||
case CSMachineBBCMicroSecondProcessor65C02: target->tube_processor = Target::TubeProcessor::WDC65C02; break;
|
||||
case CSMachineBBCMicroSecondProcessorZ80: target->tube_processor = Target::TubeProcessor::Z80; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
|
||||
@@ -459,11 +459,12 @@ Gw
|
||||
<rect key="frame" x="141" y="168" width="81" height="25"/>
|
||||
<popUpButtonCell key="cell" type="push" title="None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Rpc-1u-8X2" id="vk3-Qo-uxV">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<font key="font" metaFont="message"/>
|
||||
<menu key="menu" id="Qyy-YZ-beq">
|
||||
<items>
|
||||
<menuItem title="None" state="on" id="Rpc-1u-8X2"/>
|
||||
<menuItem title="65C02" tag="6502" id="k5e-d2-O0X"/>
|
||||
<menuItem title="Z80" tag="80" id="oWF-1C-PLs"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
|
||||
@@ -352,6 +352,7 @@ class MachinePicker: NSObject, NSTableViewDataSource, NSTableViewDelegate {
|
||||
var secondProcessor: CSMachineBBCMicroSecondProcessor = .processorNone
|
||||
switch bbcSecondProcessorButton.selectedTag() {
|
||||
case 6502: secondProcessor = .processor65C02
|
||||
case 80: secondProcessor = .processorZ80
|
||||
case 0: fallthrough
|
||||
default: secondProcessor = .processorNone
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user