Skip to content

Commit

Permalink
Merge pull request #356 from emustudio/feature-314
Browse files Browse the repository at this point in the history
[#314] Add BS + DELETE to keyboard mapping
  • Loading branch information
vbmacher authored Jan 2, 2024
2 parents 2f7342c + 11a54d3 commit 4e1e462
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
@NotThreadSafe
public class ZxSpectrumBusImpl extends AbstractMemoryContext<Byte> implements ZxSpectrumBus, CPUContext.PassedCyclesListener {
private static final long LINE_TSTATES = 224;
private static final long FRAME_TSTATES = 69888;

// from 14335 to 14463, then 96 tstates pause to reach "end of line", then repeat.
private final static Map<Long, Integer> CONTENTION_MAP = new HashMap<>();
Expand Down Expand Up @@ -129,6 +130,7 @@ public void initialize(ContextZ80 cpu, MemoryContext<Byte> memory) {
for (CPUContext.PassedCyclesListener listener : deferredListeners) {
cpu.addPassedCyclesListener(listener);
}
cpu.addPassedCyclesListener(this);

deferredAttachments.clear();
deferredListeners.clear();
Expand Down Expand Up @@ -248,6 +250,7 @@ private void contendedMemory(int location) {
if (location >= 0x4000 && location <= 0x7FFF) {
Integer cycles = CONTENTION_MAP.get(contentionCycles);
if (cycles != null) {
// System.out.printf("%04x: %d, tstates=%d\n", location, cycles, contentionCycles);
cpu.addCycles(cycles);
}
}
Expand Down Expand Up @@ -306,7 +309,7 @@ private void contendedPort(int portAddress) {

@Override
public void passedCycles(long tstates) {
contentionCycles = (contentionCycles + tstates) % (LINE_TSTATES + 14335);
contentionCycles = (contentionCycles + tstates) % FRAME_TSTATES;
}

private class ContendedDeviceProxy implements Context8080.CpuPortDevice {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Optional;
import java.util.ResourceBundle;

@SuppressWarnings("unused")
@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K ULA")
public class DeviceImpl extends AbstractDevice {

Expand All @@ -42,6 +43,7 @@ public class DeviceImpl extends AbstractDevice {
private boolean guiIOset = false;

private ULA ula;
private PassedCyclesMediator passedCyclesMediator;
private DisplayWindow gui;

public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) {
Expand All @@ -54,6 +56,8 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s
public void initialize() throws PluginInitializationException {
ZxSpectrumBus bus = applicationApi.getContextPool().getDeviceContext(pluginID, ZxSpectrumBus.class);
this.ula = new ULA(bus);
this.passedCyclesMediator = new PassedCyclesMediator(ula);
bus.addPassedCyclesListener(passedCyclesMediator);
keyboard.addOnKeyListener(ula);
bus.attachDevice(0xFE, ula);
}
Expand Down Expand Up @@ -88,6 +92,7 @@ public void showGUI(JFrame parent) {
if (guiSupported) {
if (!guiIOset) {
this.gui = new DisplayWindow(parent, ula, keyboard);
passedCyclesMediator.setCanvas(gui.getCanvas());
GuiUtils.addKeyListener(gui, keyboard);
guiIOset = true;
this.gui.setVisible(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* This file is part of emuStudio.
*
* Copyright (C) 2006-2024 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 <https://www.gnu.org/licenses/>.
*/
package net.emustudio.plugins.device.zxspectrum.ula;

import net.emustudio.emulib.plugins.cpu.CPUContext;
import net.emustudio.plugins.device.zxspectrum.ula.gui.DisplayCanvas;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

import static net.emustudio.plugins.device.zxspectrum.ula.ZxParameters.*;

/**
* Triggers actions based on passed CPU cycles.
* <p>
* For <a href="https://worldofspectrum.org/faq/reference/48kreference.htm">ZX Spectrum 48K</a> the actions are:
* <p>
* - 0: CPU interrupt
* - 0 - 14336: first 64 lines. From those, at least 48 are border-lines, others are either border or vertical retraces
* After an interrupt occurs, 64 line times (14336 T states; see below for exact timings) pass before
* - 14337 - 57344: 192 screen lines are displayed
* - 57345 - 69888: 56 border-lines are displayed
* <p>
* This means a frame is (64+192+56)*224=69888 T states long, which means that the CPU interrupt occurs
* at 3.5MHz/69888=50.08 Hz.
*/
public class PassedCyclesMediator implements CPUContext.PassedCyclesListener {
private static final long LINE_CYCLES = 224;
private static final long FRAME_CYCLES = (PRE_SCREEN_LINES + SCREEN_HEIGHT + POST_SCREEN_LINES) * LINE_CYCLES; // 69888;

private long frameCycles = 0;
private long lineCycles = 0;
private int lastLinePainted = 0;

private final AtomicReference<DisplayCanvas> canvas = new AtomicReference<>();
private final ULA ula;

public PassedCyclesMediator(ULA ula) {
this.ula = Objects.requireNonNull(ula);
}

public void setCanvas(DisplayCanvas canvas) {
this.canvas.set(canvas);
}

@Override
public void passedCycles(long cycles) {
frameCycles += cycles;
lineCycles += cycles;

DisplayCanvas canvas = this.canvas.get();
if (canvas != null) {
if (lineCycles >= LINE_CYCLES) {
canvas.drawNextLine(lastLinePainted++);
}
}
lineCycles = lineCycles % LINE_CYCLES;
if (frameCycles >= FRAME_CYCLES) {
lastLinePainted = 0;
ula.onNextFrame();
frameCycles = frameCycles % FRAME_CYCLES;
if (canvas != null) {
canvas.runPaintCycle(); // expensive operation
}
}
}
}
Loading

0 comments on commit 4e1e462

Please sign in to comment.