mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-11-04 00:16:26 +00:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ee6ac3b4a9 | ||
| 
						 | 
					c8130f9d6f | ||
| 
						 | 
					8abd837c8b | ||
| 
						 | 
					02ad080bb8 | ||
| 
						 | 
					5887e3e580 | ||
| 
						 | 
					1994b2dc9f | ||
| 
						 | 
					0017bd6d0f | ||
| 
						 | 
					15f30995b1 | ||
| 
						 | 
					37ca0e4f81 | ||
| 
						 | 
					e400aa200c | ||
| 
						 | 
					e168298aa0 | 
@@ -9,6 +9,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Analyser/Static/StaticAnalyser.hpp"
 | 
					#include "Analyser/Static/StaticAnalyser.hpp"
 | 
				
			||||||
 | 
					#include "Reflection/Enum.hpp"
 | 
				
			||||||
#include "Reflection/Struct.hpp"
 | 
					#include "Reflection/Struct.hpp"
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,6 +45,9 @@ struct BBCMicroTarget: public ::Analyser::Static::Target, public Reflection::Str
 | 
				
			|||||||
	bool has_adfs = false;
 | 
						bool has_adfs = false;
 | 
				
			||||||
	bool has_sideways_ram = true;
 | 
						bool has_sideways_ram = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ReflectableEnum(TubeProcessor, None, MOS6502);
 | 
				
			||||||
 | 
						TubeProcessor tube_processor = TubeProcessor::None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BBCMicroTarget() : Analyser::Static::Target(Machine::BBCMicro) {}
 | 
						BBCMicroTarget() : Analyser::Static::Target(Machine::BBCMicro) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@@ -52,6 +56,8 @@ private:
 | 
				
			|||||||
		DeclareField(has_1770dfs);
 | 
							DeclareField(has_1770dfs);
 | 
				
			||||||
		DeclareField(has_adfs);
 | 
							DeclareField(has_adfs);
 | 
				
			||||||
		DeclareField(has_sideways_ram);
 | 
							DeclareField(has_sideways_ram);
 | 
				
			||||||
 | 
							AnnounceEnum(TubeProcessor);
 | 
				
			||||||
 | 
							DeclareField(tube_processor);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,15 @@ struct Video {
 | 
				
			|||||||
		sound_(sound),
 | 
							sound_(sound),
 | 
				
			||||||
		ram_(ram),
 | 
							ram_(ram),
 | 
				
			||||||
		crt_(Outputs::Display::InputDataType::Red4Green4Blue4) {
 | 
							crt_(Outputs::Display::InputDataType::Red4Green4Blue4) {
 | 
				
			||||||
 | 
							const auto cycles_per_line = static_cast<int>(24'000'000 / (312 * 50));
 | 
				
			||||||
 | 
							crt_.set_new_timing(
 | 
				
			||||||
 | 
								cycles_per_line,
 | 
				
			||||||
 | 
								312,								/* Height of display. */
 | 
				
			||||||
 | 
								Outputs::CRT::PAL::ColourSpace,
 | 
				
			||||||
 | 
								Outputs::CRT::PAL::ColourCycleNumerator,
 | 
				
			||||||
 | 
								Outputs::CRT::PAL::ColourCycleDenominator,
 | 
				
			||||||
 | 
								Outputs::CRT::PAL::VerticalSyncLength,
 | 
				
			||||||
 | 
								Outputs::CRT::PAL::AlternatesPhase);
 | 
				
			||||||
		set_clock_divider(3);
 | 
							set_clock_divider(3);
 | 
				
			||||||
		crt_.set_fixed_framing(Outputs::Display::Rect(0.041f, 0.04f, 0.95f, 0.95f));
 | 
							crt_.set_fixed_framing(Outputs::Display::Rect(0.041f, 0.04f, 0.95f, 0.95f));
 | 
				
			||||||
		crt_.set_display_type(Outputs::Display::DisplayType::RGB);
 | 
							crt_.set_display_type(Outputs::Display::DisplayType::RGB);
 | 
				
			||||||
@@ -210,7 +219,7 @@ struct Video {
 | 
				
			|||||||
			case Phase::StartInterlacedSync:	tick_horizontal<Phase::StartInterlacedSync>();		break;
 | 
								case Phase::StartInterlacedSync:	tick_horizontal<Phase::StartInterlacedSync>();		break;
 | 
				
			||||||
			case Phase::EndInterlacedSync:		tick_horizontal<Phase::EndInterlacedSync>();		break;
 | 
								case Phase::EndInterlacedSync:		tick_horizontal<Phase::EndInterlacedSync>();		break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		++time_in_phase_;
 | 
							time_in_phase_ += clock_divider_;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// @returns @c true if a vertical retrace interrupt has been signalled since the last call to @c interrupt(); @c false otherwise.
 | 
						/// @returns @c true if a vertical retrace interrupt has been signalled since the last call to @c interrupt(); @c false otherwise.
 | 
				
			||||||
@@ -476,15 +485,6 @@ private:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		clock_divider_ = divider;
 | 
							clock_divider_ = divider;
 | 
				
			||||||
		const auto cycles_per_line = static_cast<int>(24'000'000 / (divider * 312 * 50));
 | 
					 | 
				
			||||||
		crt_.set_new_timing(
 | 
					 | 
				
			||||||
			cycles_per_line,
 | 
					 | 
				
			||||||
			312,								/* Height of display. */
 | 
					 | 
				
			||||||
			Outputs::CRT::PAL::ColourSpace,
 | 
					 | 
				
			||||||
			Outputs::CRT::PAL::ColourCycleNumerator,
 | 
					 | 
				
			||||||
			Outputs::CRT::PAL::ColourCycleDenominator,
 | 
					 | 
				
			||||||
			Outputs::CRT::PAL::VerticalSyncLength,
 | 
					 | 
				
			||||||
			Outputs::CRT::PAL::AlternatesPhase);
 | 
					 | 
				
			||||||
		clock_rate_observer_.update_clock_rates();
 | 
							clock_rate_observer_.update_clock_rates();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,9 +14,11 @@
 | 
				
			|||||||
#include "Machines/Utility/MemoryFuzzer.hpp"
 | 
					#include "Machines/Utility/MemoryFuzzer.hpp"
 | 
				
			||||||
#include "Machines/Utility/Typer.hpp"
 | 
					#include "Machines/Utility/Typer.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Processors/6502/6502.hpp"
 | 
					 | 
				
			||||||
#include "Processors/6502Mk2/6502Mk2.hpp"
 | 
					#include "Processors/6502Mk2/6502Mk2.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Machines/Acorn/Tube/ULA.hpp"
 | 
				
			||||||
 | 
					#include "Machines/Acorn/Tube/Tube6502.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Components/6522/6522.hpp"
 | 
					#include "Components/6522/6522.hpp"
 | 
				
			||||||
#include "Components/6845/CRTC6845.hpp"
 | 
					#include "Components/6845/CRTC6845.hpp"
 | 
				
			||||||
#include "Components/6850/6850.hpp"
 | 
					#include "Components/6850/6850.hpp"
 | 
				
			||||||
@@ -46,6 +48,7 @@ namespace BBCMicro {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
using Logger = Log::Logger<Log::Source::BBCMicro>;
 | 
					using Logger = Log::Logger<Log::Source::BBCMicro>;
 | 
				
			||||||
 | 
					using TubeProcessor = Analyser::Static::Acorn::BBCMicroTarget::TubeProcessor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*!
 | 
					/*!
 | 
				
			||||||
	Provides an analogue joystick with a single fire button.
 | 
						Provides an analogue joystick with a single fire button.
 | 
				
			||||||
@@ -671,7 +674,7 @@ using CRTC = Motorola::CRTC::CRTC6845<
 | 
				
			|||||||
	Motorola::CRTC::CursorType::Native>;
 | 
						Motorola::CRTC::CursorType::Native>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <bool has_1770>
 | 
					template <TubeProcessor tube_processor, bool has_1770>
 | 
				
			||||||
class ConcreteMachine:
 | 
					class ConcreteMachine:
 | 
				
			||||||
	public Activity::Source,
 | 
						public Activity::Source,
 | 
				
			||||||
	public Configurable::Device,
 | 
						public Configurable::Device,
 | 
				
			||||||
@@ -700,7 +703,8 @@ public:
 | 
				
			|||||||
		crtc_bus_handler_(ram_.data(), system_via_),
 | 
							crtc_bus_handler_(ram_.data(), system_via_),
 | 
				
			||||||
		crtc_(crtc_bus_handler_),
 | 
							crtc_(crtc_bus_handler_),
 | 
				
			||||||
		acia_(HalfCycles(2'000'000)), // TODO: look up real ACIA clock rate.
 | 
							acia_(HalfCycles(2'000'000)), // TODO: look up real ACIA clock rate.
 | 
				
			||||||
		adc_(HalfCycles(2'000'000))
 | 
							adc_(HalfCycles(2'000'000)),
 | 
				
			||||||
 | 
							tube_ula_(*this, tube6502_)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		set_clock_rate(2'000'000);
 | 
							set_clock_rate(2'000'000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -724,6 +728,13 @@ public:
 | 
				
			|||||||
			request = request && Request(Name::BBCMicroADFS130);
 | 
								request = request && Request(Name::BBCMicroADFS130);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch(tube_processor) {
 | 
				
			||||||
 | 
								default: break;
 | 
				
			||||||
 | 
								case TubeProcessor::MOS6502:
 | 
				
			||||||
 | 
									request = request && Request(Name::BBCMicroTube110);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto roms = rom_fetcher(request);
 | 
							auto roms = rom_fetcher(request);
 | 
				
			||||||
		if(!request.validate(roms)) {
 | 
							if(!request.validate(roms)) {
 | 
				
			||||||
			throw ROMMachine::Error::MissingROMs;
 | 
								throw ROMMachine::Error::MissingROMs;
 | 
				
			||||||
@@ -744,6 +755,14 @@ public:
 | 
				
			|||||||
			install_sideways(fs_slot--, roms.find(Name::BBCMicroADFS130)->second, false);
 | 
								install_sideways(fs_slot--, roms.find(Name::BBCMicroADFS130)->second, false);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Throw the tube ROM to its target.
 | 
				
			||||||
 | 
							switch(tube_processor) {
 | 
				
			||||||
 | 
								default: break;
 | 
				
			||||||
 | 
								case TubeProcessor::MOS6502:
 | 
				
			||||||
 | 
									tube6502_.set_rom(roms.find(Name::BBCMicroTube110)->second);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Install the ADT ROM if available, but don't error if it's missing. It's very optional.
 | 
							// Install the ADT ROM if available, but don't error if it's missing. It's very optional.
 | 
				
			||||||
		if(target.has_1770dfs || target.has_adfs) {
 | 
							if(target.has_1770dfs || target.has_adfs) {
 | 
				
			||||||
			const auto adt_rom = rom_fetcher(Request(Name::BBCMicroAdvancedDiscToolkit140));
 | 
								const auto adt_rom = rom_fetcher(Request(Name::BBCMicroAdvancedDiscToolkit140));
 | 
				
			||||||
@@ -831,11 +850,14 @@ public:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		adc_.run_for(duration);
 | 
							adc_.run_for(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if constexpr (has_1770) {
 | 
							if constexpr (has_1770) {
 | 
				
			||||||
			// The WD1770 is nominally clocked at 8Mhz.
 | 
								// The WD1770 is nominally clocked at 8Mhz.
 | 
				
			||||||
			wd1770_.run_for(duration * 4);
 | 
								wd1770_.run_for(duration * 4);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if constexpr (tube_processor == TubeProcessor::MOS6502) {
 | 
				
			||||||
 | 
								tube6502_.run_for(duration);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//
 | 
							//
 | 
				
			||||||
		// Questionably-clocked devices.
 | 
							// Questionably-clocked devices.
 | 
				
			||||||
@@ -893,12 +915,19 @@ public:
 | 
				
			|||||||
						break;
 | 
											break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if(address == 0xfee0) {
 | 
								} else if(address >= 0xfee0 && address < 0xfee8) {
 | 
				
			||||||
 | 
									if(tube_processor == TubeProcessor::None) {
 | 
				
			||||||
					if constexpr (is_read(operation)) {
 | 
										if constexpr (is_read(operation)) {
 | 
				
			||||||
					Logger::info().append("Read tube status: 0");
 | 
											value = address == 0xfee0 ? 0xfe : 0xff;
 | 
				
			||||||
					value = 0;
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					Logger::info().append("Wrote tube: %02x", value);
 | 
										if constexpr (is_read(operation)) {
 | 
				
			||||||
 | 
											Logger::info().append("Read tube status %04x: %02x", +address, tube_ula_.status());
 | 
				
			||||||
 | 
											value = tube_ula_.status();
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											Logger::info().append("Wrote tube %04x: %02x", +address, value);
 | 
				
			||||||
 | 
											tube_ula_.set_status(value);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if(address >= 0xfe08 && address < 0xfe10) {
 | 
								} else if(address >= 0xfe08 && address < 0xfe10) {
 | 
				
			||||||
				if constexpr (is_read(operation)) {
 | 
									if constexpr (is_read(operation)) {
 | 
				
			||||||
@@ -943,6 +972,7 @@ public:
 | 
				
			|||||||
			return duration;
 | 
								return duration;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//
 | 
							//
 | 
				
			||||||
		// ROM or RAM access.
 | 
							// ROM or RAM access.
 | 
				
			||||||
		//
 | 
							//
 | 
				
			||||||
@@ -1136,7 +1166,11 @@ private:
 | 
				
			|||||||
	void update_irq_line() {
 | 
						void update_irq_line() {
 | 
				
			||||||
		m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(
 | 
							m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(
 | 
				
			||||||
			user_via_.get_interrupt_line() ||
 | 
								user_via_.get_interrupt_line() ||
 | 
				
			||||||
			system_via_.get_interrupt_line()
 | 
								system_via_.get_interrupt_line() ||
 | 
				
			||||||
 | 
								(
 | 
				
			||||||
 | 
									tube_processor != TubeProcessor::None &&
 | 
				
			||||||
 | 
									tube_ula_.has_host_irq()
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1175,21 +1209,44 @@ private:
 | 
				
			|||||||
		const auto options = dynamic_cast<Options *>(str.get());
 | 
							const auto options = dynamic_cast<Options *>(str.get());
 | 
				
			||||||
		crtc_bus_handler_.set_dynamic_framing(options->dynamic_crop);
 | 
							crtc_bus_handler_.set_dynamic_framing(options->dynamic_crop);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// MARK: - Tube.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: use templated coprocessor type, if any, optionally to include this storage.
 | 
				
			||||||
 | 
						Acorn::Tube::Tube6502 tube6502_;
 | 
				
			||||||
 | 
						Acorn::Tube::ULA<ConcreteMachine, Acorn::Tube::Tube6502> tube_ula_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void set_tube_irq() {
 | 
				
			||||||
 | 
							update_irq_line();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace BBCMicro;
 | 
					using namespace BBCMicro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					using Target = Analyser::Static::Acorn::BBCMicroTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <Target::TubeProcessor processor>
 | 
				
			||||||
 | 
					std::unique_ptr<Machine> machine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) {
 | 
				
			||||||
 | 
						if(target.has_1770dfs || target.has_adfs) {
 | 
				
			||||||
 | 
							return std::make_unique<BBCMicro::ConcreteMachine<processor, true>>(target, rom_fetcher);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return std::make_unique<BBCMicro::ConcreteMachine<processor, false>>(target, rom_fetcher);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::unique_ptr<Machine> Machine::BBCMicro(
 | 
					std::unique_ptr<Machine> Machine::BBCMicro(
 | 
				
			||||||
	const Analyser::Static::Target *target,
 | 
						const Analyser::Static::Target *target,
 | 
				
			||||||
	const ROMMachine::ROMFetcher &rom_fetcher
 | 
						const ROMMachine::ROMFetcher &rom_fetcher
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
	using Target = Analyser::Static::Acorn::BBCMicroTarget;
 | 
					 | 
				
			||||||
	const Target *const acorn_target = dynamic_cast<const Target *>(target);
 | 
						const Target *const acorn_target = dynamic_cast<const Target *>(target);
 | 
				
			||||||
	if(acorn_target->has_1770dfs || acorn_target->has_adfs) {
 | 
						switch(acorn_target->tube_processor) {
 | 
				
			||||||
		return std::make_unique<BBCMicro::ConcreteMachine<true>>(*acorn_target, rom_fetcher);
 | 
							case TubeProcessor::None:		/* return machine<TubeProcessor::None>(*acorn_target, rom_fetcher); */
 | 
				
			||||||
	} else {
 | 
							case TubeProcessor::MOS6502:	return machine<TubeProcessor::MOS6502>(*acorn_target, rom_fetcher);
 | 
				
			||||||
		return std::make_unique<BBCMicro::ConcreteMachine<false>>(*acorn_target, rom_fetcher);
 | 
							default:	return nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								Machines/Acorn/Tube/FIFO.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Machines/Acorn/Tube/FIFO.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Header.hpp
 | 
				
			||||||
 | 
					//  Clock Signal
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Thomas Harte on 30/10/2025.
 | 
				
			||||||
 | 
					//  Copyright © 2025 Thomas Harte. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Acorn::Tube {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <size_t length, typename ULAT>
 | 
				
			||||||
 | 
					struct FIFO {
 | 
				
			||||||
 | 
						FIFO(ULAT &ula, const uint8_t mask = 0x00) : ula_(ula), mask_(mask) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t status() const {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
								((read_ != write_) ? 0x80 : 0x00) |
 | 
				
			||||||
 | 
								((size_t(write_ - read_) < length) ? 0x40 : 0x00);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void write(const uint8_t value) {
 | 
				
			||||||
 | 
							if(write_ - read_ == length) return;
 | 
				
			||||||
 | 
							if(write_ == read_) {
 | 
				
			||||||
 | 
								ula_.fifo_has_data(mask_);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							buffer_[write_++] = value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t read() {
 | 
				
			||||||
 | 
							const uint8_t result = buffer_[read_ % length];
 | 
				
			||||||
 | 
							if(write_ != read_) ++read_;
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						ULAT &ula_;
 | 
				
			||||||
 | 
						uint8_t mask_;
 | 
				
			||||||
 | 
						std::array<uint8_t, length> buffer_;
 | 
				
			||||||
 | 
						uint32_t read_ = 0;
 | 
				
			||||||
 | 
						uint32_t write_ = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										68
									
								
								Machines/Acorn/Tube/Tube6502.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Machines/Acorn/Tube/Tube6502.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Tube6502.hpp
 | 
				
			||||||
 | 
					//  Clock Signal
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Thomas Harte on 03/11/2025.
 | 
				
			||||||
 | 
					//  Copyright © 2025 Thomas Harte. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Processors/6502Mk2/6502Mk2.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Acorn::Tube {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Tube6502 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Tube6502() : m6502_(*this) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// By convention, these are cycles relative to the host's 2Mhz bus.
 | 
				
			||||||
 | 
						// Multiply by 3/2 to turn that into the tube 6502's usual 3Mhz bus.
 | 
				
			||||||
 | 
						void run_for(const Cycles cycles) {
 | 
				
			||||||
 | 
							cycles_modulo_ += cycles * 3;
 | 
				
			||||||
 | 
							m6502_.run_for(cycles_modulo_.divide(Cycles(2)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <CPU::MOS6502Mk2::BusOperation operation, typename AddressT>
 | 
				
			||||||
 | 
						Cycles perform(const AddressT address, CPU::MOS6502Mk2::data_t<operation> value) {
 | 
				
			||||||
 | 
							if(address >= 0xfef8 && address < 0xff00) {
 | 
				
			||||||
 | 
					//			printf("TODO: second processor FIFO access @ %04x\n", +address);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if constexpr (is_read(operation)) {
 | 
				
			||||||
 | 
								value = ram_[address];
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ram_[address] = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return Cycles(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_rom(const std::vector<uint8_t> &source) {
 | 
				
			||||||
 | 
							// TODO: verify the ROM is 2kb.
 | 
				
			||||||
 | 
							// TODO: determine whethe rthis really is ROM, or is ROM that should have copied itself to RAM, or is something else.
 | 
				
			||||||
 | 
							std::copy(source.begin(), source.end(), &ram_[65536 - 2048]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_tube_irq() {
 | 
				
			||||||
 | 
							m6502_.set<CPU::MOS6502Mk2::Line::IRQ>(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_tube_nmi() {
 | 
				
			||||||
 | 
							m6502_.set<CPU::MOS6502Mk2::Line::NMI>(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						uint8_t ram_[65536];
 | 
				
			||||||
 | 
						Cycles cycles_modulo_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct M6502Traits {
 | 
				
			||||||
 | 
							static constexpr auto uses_ready_line = false;
 | 
				
			||||||
 | 
							static constexpr auto pause_precision = CPU::MOS6502Mk2::PausePrecision::AnyCycle;
 | 
				
			||||||
 | 
							using BusHandlerT = Tube6502;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						CPU::MOS6502Mk2::Processor<CPU::MOS6502Mk2::Model::M6502, M6502Traits> m6502_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										84
									
								
								Machines/Acorn/Tube/ULA.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								Machines/Acorn/Tube/ULA.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					//  ULA.hpp
 | 
				
			||||||
 | 
					//  Clock Signal
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  Created by Thomas Harte on 03/11/2025.
 | 
				
			||||||
 | 
					//  Copyright © 2025 Thomas Harte. All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FIFO.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Acorn::Tube {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
						The non-FIFO section of the tube ULA.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					template <typename HostT, typename ParasiteT>
 | 
				
			||||||
 | 
					struct ULA {
 | 
				
			||||||
 | 
						ULA(HostT &host, ParasiteT ¶site) :
 | 
				
			||||||
 | 
							host_(host),
 | 
				
			||||||
 | 
							parasite_(parasite),
 | 
				
			||||||
 | 
							to_parasite1_(*this, 0x02),
 | 
				
			||||||
 | 
							to_parasite2_(*this),
 | 
				
			||||||
 | 
							to_parasite3_(*this, 0x08),
 | 
				
			||||||
 | 
							to_parasite4_(*this, 0x04),
 | 
				
			||||||
 | 
							to_host1_(*this),
 | 
				
			||||||
 | 
							to_host2_(*this),
 | 
				
			||||||
 | 
							to_host3_(*this),
 | 
				
			||||||
 | 
							to_host4_(*this, 0x01)
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t status() const {
 | 
				
			||||||
 | 
							return flags_;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set_status(const uint8_t value) {
 | 
				
			||||||
 | 
							const uint8_t bits = value & 0x3f;
 | 
				
			||||||
 | 
							if(value & 0x80) {
 | 
				
			||||||
 | 
								flags_ |= bits;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								flags_ &= ~bits;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void fifo_has_data(const uint8_t mask) {
 | 
				
			||||||
 | 
							if(!(flags_ & mask)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch(mask) {
 | 
				
			||||||
 | 
								default: __builtin_unreachable();
 | 
				
			||||||
 | 
								case 0x01:
 | 
				
			||||||
 | 
									host_.set_tube_irq();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
								case 0x02:
 | 
				
			||||||
 | 
								case 0x04:
 | 
				
			||||||
 | 
									parasite_.set_tube_irq();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
								case 0x08:
 | 
				
			||||||
 | 
									parasite_.set_tube_nmi();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_host_irq() const {
 | 
				
			||||||
 | 
							return (flags_ & 0x01) && (to_host1_.status() & 0x80);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						HostT &host_;
 | 
				
			||||||
 | 
						ParasiteT ¶site_;
 | 
				
			||||||
 | 
						uint8_t flags_ = 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FIFO<1, ULA> to_parasite1_;
 | 
				
			||||||
 | 
						FIFO<1, ULA> to_parasite2_;
 | 
				
			||||||
 | 
						FIFO<2, ULA> to_parasite3_;
 | 
				
			||||||
 | 
						FIFO<1, ULA> to_parasite4_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FIFO<24, ULA> to_host1_;
 | 
				
			||||||
 | 
						FIFO<1, ULA> to_host2_;
 | 
				
			||||||
 | 
						FIFO<2, ULA> to_host3_;
 | 
				
			||||||
 | 
						FIFO<1, ULA> to_host4_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -453,6 +453,14 @@ const std::vector<Description> &Description::all_roms() {
 | 
				
			|||||||
			16_kb,
 | 
								16_kb,
 | 
				
			||||||
			0x8314fed0u
 | 
								0x8314fed0u
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								BBCMicroTube110,
 | 
				
			||||||
 | 
								"BBCMicro",
 | 
				
			||||||
 | 
								"the Tube 1.10 Boot ROM",
 | 
				
			||||||
 | 
								"TUBE110.rom",
 | 
				
			||||||
 | 
								2_kb,
 | 
				
			||||||
 | 
								0x9ec2dbd0u
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// ColecoVision.
 | 
						// ColecoVision.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,6 +85,7 @@ enum Name {
 | 
				
			|||||||
	BBCMicroDFS226,
 | 
						BBCMicroDFS226,
 | 
				
			||||||
	BBCMicroADFS130,
 | 
						BBCMicroADFS130,
 | 
				
			||||||
	BBCMicroAdvancedDiscToolkit140,
 | 
						BBCMicroAdvancedDiscToolkit140,
 | 
				
			||||||
 | 
						BBCMicroTube110,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ColecoVision.
 | 
						// ColecoVision.
 | 
				
			||||||
	ColecoVisionBIOS,
 | 
						ColecoVisionBIOS,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1561,6 +1561,8 @@
 | 
				
			|||||||
		4B3FCC3F201EC24200960631 /* MultiMachine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiMachine.cpp; sourceTree = "<group>"; };
 | 
							4B3FCC3F201EC24200960631 /* MultiMachine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiMachine.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPM.cpp; path = Parsers/CPM.cpp; sourceTree = "<group>"; };
 | 
							4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPM.cpp; path = Parsers/CPM.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B3FE75D1F3CF68B00448EE4 /* CPM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CPM.hpp; path = Parsers/CPM.hpp; sourceTree = "<group>"; };
 | 
							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>"; };
 | 
				
			||||||
		4B43983829620FB1006B0BFC /* 9918.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = 9918.cpp; 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>"; };
 | 
							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>"; };
 | 
							4B43983E29628538006B0BFC /* Fetch.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Fetch.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
@@ -1612,6 +1614,7 @@
 | 
				
			|||||||
		4B49F0A823346F7A0045E6A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/MacintoshOptions.xib"; sourceTree = SOURCE_ROOT; };
 | 
							4B49F0A823346F7A0045E6A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/MacintoshOptions.xib"; sourceTree = SOURCE_ROOT; };
 | 
				
			||||||
		4B4A75BC2EB2C55100EA398F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/CompositeDynamicCropOptions.xib; sourceTree = "<group>"; };
 | 
							4B4A75BC2EB2C55100EA398F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/CompositeDynamicCropOptions.xib; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4A75BF2EB399D700EA398F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/DynamicCropOptions.xib; sourceTree = "<group>"; };
 | 
							4B4A75BF2EB399D700EA398F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/DynamicCropOptions.xib; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							4B4A75C22EB43F1C00EA398F /* FIFO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FIFO.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4A762E1DB1A3FA007AAE2E /* AY38910.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AY38910.cpp; sourceTree = "<group>"; };
 | 
							4B4A762E1DB1A3FA007AAE2E /* AY38910.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AY38910.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4A762F1DB1A3FA007AAE2E /* AY38910.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AY38910.hpp; sourceTree = "<group>"; };
 | 
							4B4A762F1DB1A3FA007AAE2E /* AY38910.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AY38910.hpp; sourceTree = "<group>"; };
 | 
				
			||||||
		4B4B1A3A200198C900A0F866 /* KonamiSCC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KonamiSCC.cpp; sourceTree = "<group>"; };
 | 
							4B4B1A3A200198C900A0F866 /* KonamiSCC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KonamiSCC.cpp; sourceTree = "<group>"; };
 | 
				
			||||||
@@ -2547,10 +2550,10 @@
 | 
				
			|||||||
			isa = PBXFrameworksBuildPhase;
 | 
								isa = PBXFrameworksBuildPhase;
 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
								buildActionMask = 2147483647;
 | 
				
			||||||
			files = (
 | 
								files = (
 | 
				
			||||||
 | 
									4B0150262D71286B00F270C7 /* SDL2.framework in Frameworks */,
 | 
				
			||||||
				4B055AF21FAE9C1C0060FFFF /* OpenGL.framework in Frameworks */,
 | 
									4B055AF21FAE9C1C0060FFFF /* OpenGL.framework in Frameworks */,
 | 
				
			||||||
				4BB8617224E22F5A00A00E03 /* Accelerate.framework in Frameworks */,
 | 
									4BB8617224E22F5A00A00E03 /* Accelerate.framework in Frameworks */,
 | 
				
			||||||
				4B055ABD1FAE86530060FFFF /* libz.tbd in Frameworks */,
 | 
									4B055ABD1FAE86530060FFFF /* libz.tbd in Frameworks */,
 | 
				
			||||||
				4B0150262D71286B00F270C7 /* SDL2.framework in Frameworks */,
 | 
					 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
@@ -3354,6 +3357,16 @@
 | 
				
			|||||||
			path = uPD7002;
 | 
								path = uPD7002;
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							4B4A75C32EB43F1C00EA398F /* Tube */ = {
 | 
				
			||||||
 | 
								isa = PBXGroup;
 | 
				
			||||||
 | 
								children = (
 | 
				
			||||||
 | 
									4B4A75C22EB43F1C00EA398F /* FIFO.hpp */,
 | 
				
			||||||
 | 
									4B4195F42EB8F061001C966D /* ULA.hpp */,
 | 
				
			||||||
 | 
									4B4195F52EB92630001C966D /* Tube6502.hpp */,
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								path = Tube;
 | 
				
			||||||
 | 
								sourceTree = "<group>";
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		4B4A762D1DB1A35C007AAE2E /* AY38910 */ = {
 | 
							4B4A762D1DB1A35C007AAE2E /* AY38910 */ = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
@@ -4673,6 +4686,7 @@
 | 
				
			|||||||
		4BB505682B962DDF0031C43C /* Acorn */ = {
 | 
							4BB505682B962DDF0031C43C /* Acorn */ = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
 | 
									4B4A75C32EB43F1C00EA398F /* Tube */,
 | 
				
			||||||
				4BB505692B962DDF0031C43C /* Archimedes */,
 | 
									4BB505692B962DDF0031C43C /* Archimedes */,
 | 
				
			||||||
				4B710C8C2E77A3B20056BDF4 /* BBCMicro */,
 | 
									4B710C8C2E77A3B20056BDF4 /* BBCMicro */,
 | 
				
			||||||
				4BB5056A2B962DDF0031C43C /* Electron */,
 | 
									4BB5056A2B962DDF0031C43C /* Electron */,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,9 +57,13 @@
 | 
				
			|||||||
            isEnabled = "NO">
 | 
					            isEnabled = "NO">
 | 
				
			||||||
         </CommandLineArgument>
 | 
					         </CommandLineArgument>
 | 
				
			||||||
         <CommandLineArgument
 | 
					         <CommandLineArgument
 | 
				
			||||||
            argument = "--new=archimedes"
 | 
					            argument = ""/Users/thomasharte/Library/Mobile\ Documents/com\~apple\~CloudDocs/Soft/Archimedes/Lemmings.adf""
 | 
				
			||||||
            isEnabled = "YES">
 | 
					            isEnabled = "YES">
 | 
				
			||||||
         </CommandLineArgument>
 | 
					         </CommandLineArgument>
 | 
				
			||||||
 | 
					         <CommandLineArgument
 | 
				
			||||||
 | 
					            argument = "--new=archimedes"
 | 
				
			||||||
 | 
					            isEnabled = "NO">
 | 
				
			||||||
 | 
					         </CommandLineArgument>
 | 
				
			||||||
         <CommandLineArgument
 | 
					         <CommandLineArgument
 | 
				
			||||||
            argument = "/Users/thomasharte/Downloads/Program/Program.prg"
 | 
					            argument = "/Users/thomasharte/Downloads/Program/Program.prg"
 | 
				
			||||||
            isEnabled = "NO">
 | 
					            isEnabled = "NO">
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user