From 8669265b6247c43f7734310ac30dbd30409cc0ce Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Tue, 25 Apr 2023 12:33:21 +0200 Subject: [PATCH] [#314] Implement ZX-spectrum bus --- application/build.gradle | 2 + .../src/main/files/config/ZxSpectrum48K.toml | 49 ++++-- .../virtualcomputer/ContextPoolImpl.java | 2 +- .../virtualcomputer/VirtualComputer.java | 3 +- .../plugins/compiler/ram/MemoryStub.java | 8 +- .../plugins/compiler/rasp/MemoryStub.java | 8 +- .../plugins/cpu/rasp/MemoryStub.java | 8 +- .../plugins/cpu/ssem/TimingEstimator.java | 10 +- .../plugins/cpu/zilogZ80/CpuImpl.java | 2 + .../plugins/cpu/zilogZ80/api/ContextZ80.java | 2 + plugins/device/cassette-player/build.gradle | 2 +- .../device/cassette_player/DeviceImpl.java | 2 +- .../cassette_player/PlaybackListenerImpl.java | 8 +- .../cassette_player/loaders/TapLoader.java | 2 +- plugins/device/zxspectrum-bus/build.gradle | 57 +++++++ .../device/zxspectrum/bus/DeviceImpl.java | 138 ++++++++++++++++ .../zxspectrum/bus/ZxSpectrumBusImpl.java | 155 ++++++++++++++++++ .../zxspectrum/bus/api/ZxSpectrumBus.java | 89 ++++++++++ .../version.properties | 20 +++ plugins/device/zxspectrum-ula/build.gradle | 1 + .../device/zxspectrum/ula/DeviceImpl.java | 36 +--- .../plugins/device/zxspectrum/ula/ULA.java | 33 ++-- .../device/zxspectrum/ula/api/LineInPort.java | 42 ----- .../zxspectrum/ula/gui/DisplayCanvas.java | 5 +- .../memory/bytemem/MemoryContextImpl.java | 9 +- .../plugins/memory/ram/MemoryContextImpl.java | 8 +- .../memory/rasp/MemoryContextImpl.java | 11 +- .../memory/ssem/MemoryContextImpl.java | 9 +- settings.gradle | 1 + 29 files changed, 595 insertions(+), 127 deletions(-) create mode 100644 plugins/device/zxspectrum-bus/build.gradle create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java create mode 100644 plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties delete mode 100644 plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java diff --git a/application/build.gradle b/application/build.gradle index c3d209d05..dc114de65 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -75,6 +75,7 @@ dependencies { providedRuntime project(":plugins:device:vt100-terminal") providedRuntime project(":plugins:device:simh-pseudo") providedRuntime project(":plugins:device:ssem-display") + providedRuntime project(":plugins:device:zxspectrum-bus") providedRuntime project(":plugins:device:zxspectrum-ula") providedRuntime project(":plugins:device:cassette-player") @@ -218,6 +219,7 @@ distributions { from(output(":plugins:device:vt100-terminal")) from(output(":plugins:device:simh-pseudo")) from(output(":plugins:device:ssem-display")) + from(output(":plugins:device:zxspectrum-bus")) from(output(":plugins:device:zxspectrum-ula")) from(output(":plugins:device:cassette-player")) } diff --git a/application/src/main/files/config/ZxSpectrum48K.toml b/application/src/main/files/config/ZxSpectrum48K.toml index 113a159ee..fa65fe0b4 100644 --- a/application/src/main/files/config/ZxSpectrum48K.toml +++ b/application/src/main/files/config/ZxSpectrum48K.toml @@ -1,7 +1,7 @@ name = "ZX Spectrum 48K" [MEMORY] - schemaPoint = "220,60" + schemaPoint = "80,180" path = "byte-mem.jar" name = "byte-mem" id = "1e13a25d-fb23-4061-853a-5fe996b03281" @@ -10,9 +10,11 @@ name = "ZX Spectrum 48K" [MEMORY.settings] #memorySize = 49152 banksCount = 0 - ROMfrom0 = 0 + imageName0 = "/home/vbmacher/tmp/emuStudio/examples/zxspectrum-48k/48.rom" # TODO: change! + imageBank1 = 0 + imageBank0 = 0 commonBoundary = 0 - ROMto0 = 16383 + imageAddress0 = 0 # memorySize = 65536 # ROM areas are stored as pairs ROMfromN and ROMtoN, where N is 0-based counter. There can be multiple rom areas. @@ -36,15 +38,14 @@ name = "ZX Spectrum 48K" type = "COMPILER" [CPU] - schemaPoint = "220,180" + schemaPoint = "260,300" path = "z80-cpu.jar" - settings = {} name = "z80-cpu" id = "b86d4bc2-632c-46e3-bba1-c088c9177983" type = "CPU" [CPU.settings] - frequency_khz = 3500 + frequency_khz = 3500 # Uncomment the following for specific settings (and remove settings = {} above) # [CPU.settings] @@ -52,13 +53,29 @@ name = "ZX Spectrum 48K" # printCodeUseCache = true # printCodeFileName = "syserr" # Or custom path to a file [[DEVICE]] - schemaPoint = "380,180" + schemaPoint = "420,60" path = "zxspectrum-ula.jar" settings = {} name = "zxspectrum-ula" id = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" type = "DEVICE" +[[DEVICE]] + schemaPoint = "420,180" + path = "cassette-player.jar" + settings = {} + name = "cassette-player" + id = "581cc598-3beb-4a67-b1e3-b4ec1731a9a7" + type = "DEVICE" + +[[DEVICE]] + schemaPoint = "260,180" + path = "zxspectrum-bus.jar" + settings = {} + name = "zxspectrum-bus" + id = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + type = "DEVICE" + [[connections]] bidirectional = true from = "9233e0c2-b53c-41e7-9eca-bbb264fcd9da" @@ -68,18 +85,24 @@ name = "ZX Spectrum 48K" [[connections]] bidirectional = true from = "1e13a25d-fb23-4061-853a-5fe996b03281" - to = "b86d4bc2-632c-46e3-bba1-c088c9177983" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" points = [] [[connections]] bidirectional = true - from = "b86d4bc2-632c-46e3-bba1-c088c9177983" - to = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" + from = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + points = ["260,60"] + +[[connections]] + bidirectional = true + from = "581cc598-3beb-4a67-b1e3-b4ec1731a9a7" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" points = [] [[connections]] bidirectional = true - from = "1e13a25d-fb23-4061-853a-5fe996b03281" - to = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" - points = ["360,60"] + from = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + to = "b86d4bc2-632c-46e3-bba1-c088c9177983" + points = [] diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java b/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java index 3eb4513b3..1aab99e5e 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java @@ -267,7 +267,7 @@ private void verifyPluginContext(Class contextInterface) thro throw new InvalidContextException("Given class is not an interface"); } if (!contextInterface.isAnnotationPresent(PluginContext.class)) { - throw new InvalidContextException("The interface is not annotated with 'PluginContext' annotation"); + throw new InvalidContextException("The interface is not annotated with 'PluginContext' annotation: " + contextInterface); } } } diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java index 97efb74ef..edaf09121 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java @@ -151,8 +151,7 @@ private static Plugin createPluginInstance(long pluginID, Class constructor = mainClass.getDeclaredConstructor(PLUGIN_CONSTRUCTOR_PARAMS); return (Plugin) constructor.newInstance(pluginID, applicationApi, pluginSettings); diff --git a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java index 474a4b84b..36bfdee69 100644 --- a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java +++ b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java @@ -31,9 +31,10 @@ public class MemoryStub extends AbstractMemoryContext implements private final RamInstruction[] memory = new RamInstruction[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -73,6 +74,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java index 60d2f5534..9b53dbde0 100644 --- a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java +++ b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java @@ -29,9 +29,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Integer[] memory = new Integer[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -66,6 +67,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java index 26a7d0aee..afd9a9b56 100644 --- a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java +++ b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java @@ -29,9 +29,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Integer[] memory = new Integer[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -71,6 +72,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java index c9f276ca2..5ef53e1bc 100644 --- a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java +++ b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java @@ -20,7 +20,9 @@ import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotation; import net.emustudio.emulib.plugins.memory.annotations.Annotations; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.emulib.runtime.helpers.NumberUtils; import java.util.Arrays; @@ -62,7 +64,8 @@ public class TimingEstimator { 0x3F, 0xFF, 0xE0, 0x50 }; - private final MemoryContext memoryContext = new AbstractMemoryContext<>(new Annotations()) { + private final MemoryContext memoryContext = new AbstractMemoryContext<>() { + private final Annotations annotations = new Annotations(); @Override public Byte read(int position) { @@ -98,6 +101,11 @@ public void clear() { public int getSize() { return memory.length; } + + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } }; public long estimateWaitNanos(int instructionsPerSecond) { diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java index 02ac2403c..ec012e572 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java @@ -29,6 +29,7 @@ import net.emustudio.emulib.runtime.settings.PluginSettings; import net.emustudio.plugins.cpu.intel8080.api.Context8080; import net.emustudio.plugins.cpu.intel8080.api.FrequencyUpdater; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; import net.emustudio.plugins.cpu.zilogZ80.gui.StatusPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,7 @@ public CpuImpl(long pluginID, ApplicationApi applicationApi, PluginSettings sett super(pluginID, applicationApi, settings); try { applicationApi.getContextPool().register(pluginID, context, Context8080.class); + applicationApi.getContextPool().register(pluginID, context, ContextZ80.class); } catch (InvalidContextException | ContextAlreadyRegisteredException e) { LOGGER.error("Could not register Z80 CPU context", e); applicationApi.getDialogs().showError( diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java index 066c8ff8e..24fe594e2 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java @@ -18,9 +18,11 @@ */ package net.emustudio.plugins.cpu.zilogZ80.api; +import net.emustudio.emulib.plugins.annotations.PluginContext; import net.emustudio.plugins.cpu.intel8080.api.Context8080; @SuppressWarnings("unused") +@PluginContext public interface ContextZ80 extends Context8080 { /** diff --git a/plugins/device/cassette-player/build.gradle b/plugins/device/cassette-player/build.gradle index dacd46629..18f3889ca 100644 --- a/plugins/device/cassette-player/build.gradle +++ b/plugins/device/cassette-player/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation libs.emuLib implementation libs.slf4JApi implementation libs.jcipAnnotations -// cpuLib project(":plugins:cpu:8080-cpu") + deviceLib project(":plugins:device:zxspectrum-bus") testImplementation libs.junit testImplementation libs.slf4JSimple diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java index d0f652694..41aaf1ec4 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java @@ -54,7 +54,7 @@ public void initialize() throws PluginInitializationException { // a cassette player needs a device to which it will write at its own pace DeviceContext lineIn = applicationApi.getContextPool().getDeviceContext(pluginID, DeviceContext.class); if (lineIn.getDataType() != Byte.class) { - throw new PluginInitializationException("Could not find Byte device"); + throw new PluginInitializationException("Could not find line-in device"); } this.cassetteListener = new PlaybackListenerImpl(lineIn); this.controller = new CassetteController(cassetteListener); diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java index 8e36f5f77..ffee671c2 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java @@ -26,12 +26,14 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +//Machine Pilot pulse Length Sync1 Sync2 Bit 0 Bit 1 +//ZX Spectrum 2168 (1) 667 735 855 1710 public class PlaybackListenerImpl implements Loader.PlaybackListener { - private final DeviceContext lineIn; + private final DeviceContext bus; private final AtomicReference gui = new AtomicReference<>(); - public PlaybackListenerImpl(DeviceContext lineIn) { - this.lineIn = Objects.requireNonNull(lineIn); + public PlaybackListenerImpl(DeviceContext bus) { + this.bus = Objects.requireNonNull(bus); } public void setGui(CassettePlayerGui gui) { diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java index 71d4ba0c7..4e02dc3bf 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java @@ -79,7 +79,7 @@ private void interpret(byte[] content, PlaybackListener listener) { if (flagByte == 255) { listener.onData(data); } else { - LOGGER.warn("TAP: Unknwon flag: " + flagByte); + LOGGER.warn("TAP: unknown flag: " + flagByte); } } buffer.get(); // checksum diff --git a/plugins/device/zxspectrum-bus/build.gradle b/plugins/device/zxspectrum-bus/build.gradle new file mode 100644 index 000000000..fff9a4635 --- /dev/null +++ b/plugins/device/zxspectrum-bus/build.gradle @@ -0,0 +1,57 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.apache.tools.ant.filters.ReplaceTokens + +plugins { + id 'java' + id 'com.adarshr.test-logger' version '3.1.0' +} + +dependencies { + implementation libs.emuLib + implementation libs.slf4JApi + implementation libs.jcipAnnotations + cpuLib project(":plugins:cpu:z80-cpu") + cpuLib project(":plugins:cpu:8080-cpu") + + testImplementation libs.junit + testImplementation libs.slf4JSimple + testImplementation libs.easyMock +} + +jar { + archiveVersion = '' + manifest { + attributes manifestAttributes('') + } +} + +processResources { + filesMatching("**/*.properties") { + filter ReplaceTokens, tokens: [ + "project.version": project.version, + "today.year" : new Date().format("yyyy") + ] + } +} + +compileJava.options.encoding = 'UTF-8' +compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java new file mode 100644 index 000000000..ea84a7ca6 --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java @@ -0,0 +1,138 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus; + +import net.emustudio.emulib.plugins.PluginInitializationException; +import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; +import net.emustudio.emulib.plugins.annotations.PluginRoot; +import net.emustudio.emulib.plugins.device.AbstractDevice; +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.runtime.ApplicationApi; +import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; +import net.emustudio.emulib.runtime.ContextPool; +import net.emustudio.emulib.runtime.InvalidContextException; +import net.emustudio.emulib.runtime.settings.PluginSettings; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; + +/** + * ZX Spectrum Bus + *

+ * - controls access to memory + * - provides access to cycle counter (TimeEventProcessor) + * - provides memory and I/O contention + *

+ * Example usage: + * a cassette player plays a tape = puts data on the bus in given time intervals. Z80 CPU reads the data from the bus + * when convenient. + */ +@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K Bus") +public class DeviceImpl extends AbstractDevice { + private final static Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); + private final ZxSpectrumBusImpl bus = new ZxSpectrumBusImpl(); + + public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { + super(pluginID, applicationApi, settings); + + try { + ContextPool contextPool = applicationApi.getContextPool(); + contextPool.register(pluginID, bus, ZxSpectrumBus.class); + contextPool.register(pluginID, bus, MemoryContext.class); + contextPool.register(pluginID, bus, DeviceContext.class); + } catch (InvalidContextException | ContextAlreadyRegisteredException e) { + LOGGER.error("Could not register zx-spectrum bus context", e); + applicationApi.getDialogs().showError( + "Could not register zx-spectrum bus. Please see log file for more details", getTitle() + ); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initialize() throws PluginInitializationException { + MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { + throw new PluginInitializationException("Could not find Byte-cell memory"); + } + ContextZ80 cpu = applicationApi.getContextPool().getCPUContext(pluginID, ContextZ80.class); + this.bus.initialize(cpu, memory); + } + + @Override + public void showGUI(JFrame parent) { + + } + + @Override + public boolean isGuiSupported() { + return false; + } + + @Override + public void destroy() { + + } + + @Override + public void showSettings(JFrame jFrame) { + + } + + @Override + public boolean isShowSettingsSupported() { + return false; + } + + @Override + public boolean isAutomationSupported() { + return true; + } + + @Override + public String getVersion() { + return getResourceBundle().map(b -> b.getString("version")).orElse("(unknown)"); + } + + @Override + public String getCopyright() { + return getResourceBundle().map(b -> b.getString("copyright")).orElse("(unknown)"); + } + + @Override + public String getDescription() { + return "ZX Spectrum48K Bus"; + } + + private Optional getResourceBundle() { + try { + return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.bus.version")); + } catch (MissingResourceException e) { + return Optional.empty(); + } + } +} diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java new file mode 100644 index 000000000..4ddc96a7d --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java @@ -0,0 +1,155 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus; + +import net.emustudio.emulib.plugins.annotations.PluginContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; +import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; +import net.emustudio.plugins.cpu.intel8080.api.Context8080; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; +import net.jcip.annotations.NotThreadSafe; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Also a memory proxy + */ +@NotThreadSafe +public class ZxSpectrumBusImpl extends AbstractMemoryContext implements ZxSpectrumBus { + private ContextZ80 cpu; + private MemoryContext memory; + private volatile byte busData; // data on the bus + + private final Map deferredAttachments = new HashMap<>(); + + + public void initialize(ContextZ80 cpu, MemoryContext memory) { + this.cpu = Objects.requireNonNull(cpu); + this.memory = Objects.requireNonNull(memory); + + for (Map.Entry attachment : deferredAttachments.entrySet()) { + // TODO: contended device proxy if needed + if (!cpu.attachDevice(attachment.getKey(), attachment.getValue())) { + throw new RuntimeException("Could not attach device " + attachment.getValue().getName() + " to CPU"); + } + } + } + + @Override + public void attachDevice(int port, Context8080.CpuPortDevice device) { + if (cpu == null) { + deferredAttachments.put(port, device); + } else { + // TODO: contended device proxy if needed + if (!cpu.attachDevice(port, device)) { + throw new RuntimeException("Could not attach device " + device.getName() + " to CPU"); + } + } + } + + @Override + public void signalNonMaskableInterrupt() { + cpu.signalNonMaskableInterrupt(); + } + + @Override + public void signalInterrupt(byte[] data) { + cpu.signalInterrupt(data); + } + + @Override + public Optional getTimedEventsProcessor() { + return cpu.getTimedEventsProcessor(); + } + + @Override + public byte readMemoryNotContended(int location) { + return memory.read(location); + } + + @Override + public void writeMemoryNotContended(int location, byte data) { + memory.write(location, data); + } + + @Override + public Byte readData() { + return busData; + } + + @Override + public void writeData(Byte data) { + this.busData = data; + } + + @Override + public Byte read(int location) { + // TODO: contention + return memory.read(location); + } + + @Override + public Byte[] read(int location, int count) { + // TODO: contention + return memory.read(location, count); + } + + @Override + public void write(int location, Byte data) { + // TODO: contention + memory.write(location, data); + } + + @Override + public void write(int location, Byte[] data, int count) { + // TODO: contention + memory.write(location, data, count); + } + + @Override + public Class getCellTypeClass() { + return Byte.class; + } + + @Override + public Class getDataType() { + return Byte.class; + } + + @Override + public void clear() { + memory.clear(); + } + + @Override + public int getSize() { + return memory.getSize(); + } + + @Override + public MemoryContextAnnotations annotations() { + return memory.annotations(); + } +} diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java new file mode 100644 index 000000000..1b63267c0 --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java @@ -0,0 +1,89 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus.api; + +import net.emustudio.emulib.plugins.annotations.PluginContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.plugins.cpu.intel8080.api.Context8080; + +import java.util.Optional; + +/** + * ZX Spectrum bus. + *

+ * It's a proxy between CPU, memory and devices. Mostly due to contention, but also for CPU cycles synchronization + * (devices are usually not connected to CPU directly). + */ +@PluginContext +public interface ZxSpectrumBus extends DeviceContext, MemoryContext { + + /** + * Attach a device on the bus. + *

+ * Under the hood, it will be attached to the CPU on given port. If the port adheres to contention, + * device access will be contended. + * + * @param port CPU port where the device should be attached + * @param device the device + */ + void attachDevice(int port, Context8080.CpuPortDevice device); + + /** + * Signals a NMI to the CPU + */ + void signalNonMaskableInterrupt(); + + /** + * Signals an interrupt to the CPU + * + * @param data interrupt data + */ + void signalInterrupt(byte[] data); + + /** + * For synchronizing with Z80 T-state cycles. + * + * @return CPU timed events processor if any + */ + Optional getTimedEventsProcessor(); + + /** + * Read data from memory, a non-contended variant. + *

+ * Under the hood it uses existing byte-memory. The reason for this method is the default readMemory() applies + * contention on specific location. + * + * @param location memory location + * @return data read by memory + */ + byte readMemoryNotContended(int location); + + /** + * Write data from memory, a non-contended variant. + *

+ * Under the hood it uses existing byte-memory. The reason for this method is the default writeMemory() applies + * contention on specific memory location. + * + * @param location memory location + * @param data data to write + */ + void writeMemoryNotContended(int location, byte data); +} diff --git a/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties b/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties new file mode 100644 index 000000000..8061ed30f --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties @@ -0,0 +1,20 @@ +# +# This file is part of emuStudio. +# +# Copyright (C) 2006-2023 Peter Jakubčo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +version=@project.version@ +copyright=\u00A9 Copyright 2006-@today.year@, Peter Jakubčo diff --git a/plugins/device/zxspectrum-ula/build.gradle b/plugins/device/zxspectrum-ula/build.gradle index 2e07bf53e..7a5a3b601 100644 --- a/plugins/device/zxspectrum-ula/build.gradle +++ b/plugins/device/zxspectrum-ula/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation libs.slf4JApi implementation libs.jcipAnnotations cpuLib project(":plugins:cpu:8080-cpu") + deviceLib project(":plugins:device:zxspectrum-bus") testImplementation libs.junit testImplementation libs.slf4JSimple diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java index be9001985..c902111f5 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java @@ -22,20 +22,12 @@ import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; import net.emustudio.emulib.plugins.annotations.PluginRoot; import net.emustudio.emulib.plugins.device.AbstractDevice; -import net.emustudio.emulib.plugins.device.DeviceContext; -import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; -import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; -import net.emustudio.emulib.runtime.ContextPool; -import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.interaction.GuiUtils; import net.emustudio.emulib.runtime.settings.PluginSettings; -import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.device.zxspectrum.ula.api.LineInPort; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; import net.emustudio.plugins.device.zxspectrum.ula.gui.TerminalWindow; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.swing.*; import java.util.MissingResourceException; @@ -44,7 +36,6 @@ @PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K ULA") public class DeviceImpl extends AbstractDevice { - private final static Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); private final boolean guiSupported; private final Keyboard keyboard = new Keyboard(); @@ -57,32 +48,14 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s super(pluginID, applicationApi, settings); this.guiSupported = !settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); - - try { - ContextPool contextPool = applicationApi.getContextPool(); - contextPool.register(pluginID, new LineInPort(), DeviceContext.class); - } catch (InvalidContextException | ContextAlreadyRegisteredException e) { - LOGGER.error("Could not register memory context", e); - applicationApi.getDialogs().showError( - "Could not register memory. Please see log file for more details", getTitle() - ); - } } - @SuppressWarnings("unchecked") @Override public void initialize() throws PluginInitializationException { - MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - Class cellTypeClass = memory.getCellTypeClass(); - if (cellTypeClass != Byte.class) { - throw new PluginInitializationException("Could not find Byte-cell memory"); - } - Context8080 cpu = applicationApi.getContextPool().getCPUContext(pluginID, Context8080.class); - - this.ula = new ULA(memory, cpu); + ZxSpectrumBus bus = applicationApi.getContextPool().getDeviceContext(pluginID, ZxSpectrumBus.class); + this.ula = new ULA(bus); keyboard.addOnKeyListener(ula); - - cpu.attachDevice(0xFE, ula); + bus.attachDevice(0xFE, ula); } @Override @@ -148,7 +121,6 @@ public boolean isAutomationSupported() { return true; } - private Optional getResourceBundle() { try { return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.ula.version")); diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java index 349fb5502..7c92e6b7b 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java @@ -18,12 +18,14 @@ */ package net.emustudio.plugins.device.zxspectrum.ula; -import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; import net.emustudio.plugins.cpu.intel8080.api.Context8080; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; import java.awt.event.KeyEvent; import java.util.Arrays; +import java.util.NoSuchElementException; import java.util.Objects; /** @@ -71,8 +73,7 @@ public class ULA implements Context8080.CpuPortDevice, Keyboard.OnKeyListener { public final byte[][] attributeMemory = new byte[SCREEN_WIDTH][ATTRIBUTE_HEIGHT]; private final static int[] lineStartOffsets = computeLineStartOffsets(); - private final MemoryContext memory; - private final Context8080 cpu; + private final ZxSpectrumBus bus; private int borderColor; private boolean microphoneAndEar; @@ -85,41 +86,41 @@ private static int[] computeLineStartOffsets() { return result; } - public ULA(MemoryContext memory, Context8080 cpu) { - this.memory = Objects.requireNonNull(memory); - this.cpu = Objects.requireNonNull(cpu); + public ULA(ZxSpectrumBus bus) { + this.bus = Objects.requireNonNull(bus); Arrays.fill(keymap, (byte) 0xBF); } - // little hack.. - public Context8080 getCpu() { - return cpu; - } - public void readScreen() { for (int x = 0; x < SCREEN_WIDTH; x++) { for (int y = 0; y < SCREEN_HEIGHT; y++) { - videoMemory[x][y] = memory.read(0x4000 + lineStartOffsets[y] + x); + videoMemory[x][y] = bus.readMemoryNotContended(0x4000 + lineStartOffsets[y] + x); if (y < ATTRIBUTE_HEIGHT) { int off = ((y >>> 3) << 8) | (((y & 0x07) << 5) | x); int attributeAddress = 0x5800 + off; - attributeMemory[x][y] = memory.read(attributeAddress); + attributeMemory[x][y] = bus.readMemoryNotContended(attributeAddress); } } } } public void triggerInterrupt() { - cpu.signalInterrupt(RST_7); + bus.signalInterrupt(RST_7); + } + + public TimedEventsProcessor getTimedEventsProcessor() { + return bus + .getTimedEventsProcessor() + .orElseThrow(() -> new NoSuchElementException("The CPU does not provide TimedEventProcessor")); } public void readLine(int y) { for (int x = 0; x < SCREEN_WIDTH; x++) { - videoMemory[x][y] = memory.read(0x4000 + lineStartOffsets[y] + x); + videoMemory[x][y] = bus.readMemoryNotContended(0x4000 + lineStartOffsets[y] + x); if (y < ATTRIBUTE_HEIGHT) { int off = ((y >>> 3) << 8) | (((y & 0x07) << 5) | x); int attributeAddress = 0x5800 + off; - attributeMemory[x][y] = memory.read(attributeAddress); + attributeMemory[x][y] = bus.readMemoryNotContended(attributeAddress); } } } diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java deleted file mode 100644 index c7beed31a..000000000 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of emuStudio. - * - * Copyright (C) 2006-2023 Peter Jakubčo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.emustudio.plugins.device.zxspectrum.ula.api; - -import net.emustudio.emulib.plugins.annotations.PluginContext; -import net.emustudio.emulib.plugins.device.DeviceContext; - -// cassette receiver -@PluginContext(id = "line-in port") -public class LineInPort implements DeviceContext { - - @Override - public Byte readData() { - return null; - } - - @Override - public void writeData(Byte data) { - System.out.println("Received: " + Integer.toHexString(data & 0xFF)); - } - - @Override - public Class getDataType() { - return Byte.class; - } -} diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java index 1418f51ba..1e728974d 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java @@ -25,7 +25,6 @@ import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -88,9 +87,7 @@ public class DisplayCanvas extends Canvas implements AutoCloseable { public DisplayCanvas(ULA ula) { this.ula = Objects.requireNonNull(ula); - this.ted = ula.getCpu() - .getTimedEventsProcessor() - .orElseThrow(() -> new NoSuchElementException("The CPU does not provide TimedEventProcessor")); + this.ted = ula.getTimedEventsProcessor(); this.screenImage.setAccelerationPriority(1.0f); this.screenImageData = ((DataBufferInt) this.screenImage.getRaster().getDataBuffer()).getData(); } diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java index ddfed6105..78e3e20fc 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java @@ -25,19 +25,21 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; @PluginContext(id = "Byte Memory") public class MemoryContextImpl extends AbstractMemoryContext implements ByteMemoryContext { final static int DEFAULT_MEM_SIZE = 65536; private final RangeTree romRanges = new RangeTree(); + private final MemoryContextAnnotations annotations; private Byte[][] mem = new Byte[1][0]; private int banksCount; private int bankSelect = 0; private int bankCommon = 0; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } void init(int size, int banks, int bankCommon) { @@ -141,6 +143,11 @@ public int getSize() { return mem[0].length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setReadWrite(AddressRange range) { if (range.getStartAddress() > range.getStopAddress()) { diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java index 9bda7f9f3..af3c3f369 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java @@ -35,9 +35,10 @@ public class MemoryContextImpl extends AbstractMemoryContext imp private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + private final MemoryContextAnnotations annotations; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -56,6 +57,11 @@ public int getSize() { return rwl.lockRead(memory::size); } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public RamInstruction read(int address) { return rwl.lockRead(() -> memory.get(address)); diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java index 171a0c842..b615e3bc7 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java @@ -29,19 +29,17 @@ import java.io.*; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; -import java.util.function.Supplier; public class MemoryContextImpl extends AbstractMemoryContext implements RaspMemoryContext { private final Map memory = new HashMap<>(); private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + private final MemoryContextAnnotations annotations; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -60,6 +58,11 @@ public int getSize() { return rwl.lockRead(() -> memory.keySet().stream().max(Comparator.naturalOrder()).orElse(0)); } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public Integer read(int address) { return rwl.lockRead(() -> memory.getOrDefault(address, 0)); diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java index 5e6c842be..4406e4f39 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java @@ -22,15 +22,17 @@ import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import java.util.Arrays; +import java.util.Objects; public class MemoryContextImpl extends AbstractMemoryContext { public static final int NUMBER_OF_CELLS = 32 * 4; // byte type is atomic in JVM memory model private final Byte[] memory = new Byte[NUMBER_OF_CELLS]; + private final MemoryContextAnnotations annotations; public MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); Arrays.fill(memory, (byte) 0); } @@ -72,4 +74,9 @@ public Class getCellTypeClass() { public int getSize() { return memory.length; } + + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } } diff --git a/settings.gradle b/settings.gradle index b4cba9e94..ec5c26c10 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,6 +49,7 @@ include ':plugins:device:adm3A-terminal' include ':plugins:device:vt100-terminal' include ':plugins:device:simh-pseudo' include ':plugins:device:ssem-display' +include ':plugins:device:zxspectrum-bus' include ':plugins:device:zxspectrum-ula' include ':plugins:device:cassette-player'