Skip to content

Commit

Permalink
[#314] zxspectrum-ula: implement flashing
Browse files Browse the repository at this point in the history
  • Loading branch information
vbmacher committed Apr 28, 2023
1 parent 1272e55 commit d220ffd
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

// Pulse length:
// https://worldofspectrum.org/faq/reference/48kreference.htm

//Machine Pilot pulse Length Sync1 Sync2 Bit 0 Bit 1
//ZX Spectrum 2168 (1) 667 735 855 1710
public class PlaybackListenerImpl implements Loader.PlaybackListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,14 @@
* 0xfefe SHIFT, Z, X, C, V 0xeffe 0, 9, 8, 7, 6
* 0xfdfe A, S, D, F, G 0xdffe P, O, I, U, Y
* 0xfbfe Q, W, E, R, T 0xbffe ENTER, L, K, J, H
* 0xf7fe 1, 2, 3, 4, 5 0x7ffe SPACE, SYM SHFT, M, N, B
* 0xf7fe 1, 2, 3, 4, 5 0x7ffe SPACE, SYM SHIFT, M, N, B
* <p>
* The colour attribute data overlays the monochrome bitmap data and is arranged in a linear fashion from left to right,
* top to bottom.
* Each attribute byte colours an 8x8 character on the screen and is encoded as follows:
* Each attribute byte colours is 8x8 character on the screen and is encoded as follows:
* <p>
* 7 6 5 4 3 2 1 0
* +-------------------------------+
* | F | B | P2| P1| P0| I2| I1| I0|
* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* F | B | P2| P1| P0| I2| I1| I0|
* +-------------------------------+
* <p>
* - F sets the attribute FLASH mode
Expand All @@ -73,24 +72,35 @@ public class ULA implements Context8080.CpuPortDevice, Keyboard.OnKeyListener {
public final byte[][] attributeMemory = new byte[SCREEN_WIDTH][ATTRIBUTE_HEIGHT];
private final static int[] lineStartOffsets = computeLineStartOffsets();

// The Spectrum's 'FLASH' effect is also produced by the ULA: Every 16 frames, the ink and paper of all flashing
// bytes is swapped; ie a normal to inverted to normal cycle takes 32 frames, which is (good as) 0.64 seconds.
public boolean videoFlash = false;
private int flashFramesCount = 0;

private final ZxSpectrumBus bus;

private int borderColor;
private boolean microphoneAndEar;

private static int[] computeLineStartOffsets() {
final int[] result = new int[SCREEN_HEIGHT];
for (int y = 0; y < SCREEN_HEIGHT; y++) {
result[y] = ((y & 0xC0) << 5) | ((y & 7) << 8) | ((y & 0x38) << 2);
}
return result;
}

public ULA(ZxSpectrumBus bus) {
this.bus = Objects.requireNonNull(bus);
Arrays.fill(keymap, (byte) 0xBF);
}

public void reset() {
borderColor = 7;
microphoneAndEar = false;
Arrays.fill(keymap, (byte) 0xBF);
}

public void onNextFrame() {
if (flashFramesCount == 15) {
videoFlash = !videoFlash;
}
flashFramesCount = (flashFramesCount + 1) % 16;
}

public void readScreen() {
for (int x = 0; x < SCREEN_WIDTH; x++) {
for (int y = 0; y < SCREEN_HEIGHT; y++) {
Expand Down Expand Up @@ -125,11 +135,7 @@ public void readLine(int y) {
}
}

public void reset() {
borderColor = 7;
microphoneAndEar = false;
Arrays.fill(keymap, (byte) 0xBF);
}


public int getBorderColor() {
return borderColor;
Expand Down Expand Up @@ -587,4 +593,11 @@ public void onKeyDown(byte data) {
}
}

private static int[] computeLineStartOffsets() {
final int[] result = new int[SCREEN_HEIGHT];
for (int y = 0; y < SCREEN_HEIGHT; y++) {
result[y] = ((y & 0xC0) << 5) | ((y & 7) << 8) | ((y & 0x38) << 2);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public void start() {
createBufferStrategy(2);

ted.schedule(REPAINT_CPU_TSTATES, this::triggerCpuInterrupt);
ted.schedule(REPAINT_CPU_TSTATES, ula::onNextFrame);
for (int i = 0; i < SCREEN_IMAGE_HEIGHT; i++) {
int finalI = i;
ted.schedule(i * LINE_CPU_TSTATES + 1, () -> drawNextLine(finalI));
Expand Down Expand Up @@ -131,10 +132,17 @@ private void drawNextLine(int line) {
byte row = ula.videoMemory[byteX][y];
int attr = ula.attributeMemory[byteX][y / 8];
Color[] colorMap = ((attr & 0x40) == 0x40) ? BRIGHT_COLOR_MAP : COLOR_MAP;
boolean flash = (attr & 0x80) == 0x80;

for (int i = 0; i < 8; i++) {
boolean bit = ((row << i) & 0x80) == 0x80;
int color = (bit ? colorMap[attr & 7] : colorMap[(attr >>> 3) & 7]).getRGB();
int color;
if (ula.videoFlash && flash) {
color = (bit ? colorMap[(attr >>> 3) & 7] : colorMap[attr & 7]).getRGB();
} else {
color = (bit ? colorMap[attr & 7] : colorMap[(attr >>> 3) & 7]).getRGB();
}

int offset = line * SCREEN_IMAGE_WIDTH + BORDER_WIDTH + screenX + i;
screenImageData[offset] = color;
}
Expand Down

0 comments on commit d220ffd

Please sign in to comment.