Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fe189f2
add logic file
PastorL69 Feb 3, 2026
5c3bebf
Correct logic file, previous one was bad sample
PastorL69 Feb 3, 2026
6df7871
prepare dex16
PastorL69 Feb 3, 2026
ae3f5bd
rename
PastorL69 Feb 6, 2026
ee438ef
Re-order logic files
PastorL69 Feb 6, 2026
72dbdc5
de x16 auto detection
PastorL69 Feb 6, 2026
b6fed9f
new header name
PastorL69 Feb 6, 2026
88480f7
frame start implemented
PastorL69 Feb 7, 2026
d009322
set jump pin and configure input pins
PastorL69 Feb 7, 2026
1383791
Need to invert the DOTCLK signal to take advantage of JMP pin in the …
PastorL69 Feb 7, 2026
05ce62c
started with pio
PastorL69 Feb 8, 2026
fa36aa2
few changes and added some comments
PastorL69 Feb 8, 2026
32fe1ec
first real version of PIO finalized.
PastorL69 Feb 9, 2026
a7dc421
add nop and fix naming of label
PastorL69 Feb 9, 2026
52a1353
extra nop test
PastorL69 Feb 9, 2026
43bab5d
add comments and fixes
PastorL69 Feb 9, 2026
95e3618
WPC pio test
PastorL69 Feb 10, 2026
e71fa49
revert back WPC pio
PastorL69 Feb 10, 2026
a9da451
revert
PastorL69 Feb 10, 2026
f732fff
optimize frame start detection
PastorL69 Feb 10, 2026
1ee1911
done for the day
PastorL69 Feb 11, 2026
e083249
adjust frame start pins
PastorL69 Feb 11, 2026
4757259
final changes for the day
PastorL69 Feb 11, 2026
4e80a7e
READER DONE.. ?
PastorL69 Feb 11, 2026
c5abefb
Few adjustments and comments
PastorL69 Feb 11, 2026
ec5bc7b
source bpp to 4
PastorL69 Feb 11, 2026
b29df7f
invert dotclk signal
PastorL69 Feb 11, 2026
509fbb2
adjust comment
PastorL69 Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions src/dmd_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "dmd_interface_alving.pio.h"
#include "dmd_interface_capcom.pio.h"
#include "dmd_interface_capcom_hd.pio.h"
#include "dmd_interface_de_x16.pio.h"
#include "dmd_interface_desega.pio.h"
#include "dmd_interface_gottlieb.pio.h"
#include "dmd_interface_sega_hd.pio.h"
Expand Down
74 changes: 74 additions & 0 deletions src/dmd_interface_de_x16.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.define DE 7
.define RDATA 6
.define RCLK 5
.define COLLAT 4
.define DOTCLK 3
.define SDATA 2
.define SDATAEX 1
.define FRAME_START_IRQ 5

.program dmd_reader_de_x16

set x, 27 ; for the first irq based on DE, we need a delay of ~19.5 µs
wait irq FRAME_START_IRQ

.wrap_target


msb_check:
nop[31]
nop[31]
jmp x-- msb_check[22] ; loop for ~19.5 µs (first irq) / ~22.25 µs
jmp pin reload_y_msb_lsb ; if DOTCLK is high, it means we will have LSB + MSB

; Padding for no MSB row case
set x, 5 ; load 6 b(0b101) for 3 bits of LSB + 3 bits of MSB
set y, 31 ; add padding 32 times
no_msb_loop:
; For the no MSB case we create a "fake" MSB row with custom padding, which is always 0101 per pixel.
; Because it is MSB, it will later be processed and multiplioed by 2, always resulting in 1010 (0101 * 2)
; This can then be summed up with the LSB row to create either an ON state (pixval 3) or off state (pixval 0)
in null 1 ; padding 0
in x, 3 ; padding 101
in null 1 ; padding 0
in x, 3 ; padding 101
jmp y-- no_msb_loop
jmp reload_x_msb_lsb

reload_y_msb_lsb:
set y, 1
reload_x_msb_lsb:
set x, 31
dotloop:
; Because of PIO limitations, we read px 1 as 000v and px 2 as 0v00 (px1 = 0001 / 0000 & px 2 = 0100 / 0000)
; The first bit of px 2 therefore always has a padding 0, which is supplied by GPIO 1 because it's pulled low permanently.
; in pins 3 = (px 1 -> v)0(v <- px 2). Here the zero in the middle is the padding bit (GPIO 1), and the 1s on either side are the actual pixel values
; This lets us create a unique combination which can now be processed by a LUT to create the correct pixel values for all X16 games
wait 1 gpio DOTCLK ; rising edge
in null 3 ; 000 padding for 4bpp
in pins 3 ; read value of px 1(GPIO2), padding 0 (GPIO1) and px 2 (GPIO0) as they're sampled on the same DOTCLK edge
in null 2 ; 00 padding for 4bpp
wait 0 gpio DOTCLK ; falling edge
jmp x-- dotloop
jmp y-- reload_x_msb_lsb

set x, 31 ; reload x to create 22.5 µs delay for lsb_msb_check
wait 1 gpio COLLAT ; sync on COLLAT so our lsb_msb_check will work
.wrap

; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ.
.program dmd_framedetect_de_x16
.wrap_target

; Data East 128x16 frame detection
; When DE goes low, check for the next rising edge of DE. If RDATA is high at that point we have found the start.

detect_loop:
wait 0 gpio DE
wait 1 gpio DE
jmp pin, frame_start ; Check if RDATA is high, otherwise back to beginning
jmp detect_loop

frame_start:
irq FRAME_START_IRQ
.wrap
32 changes: 31 additions & 1 deletion src/dmdreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,12 @@ DmdType detect_dmd() {
(de < 4000) && (rdata > 115) && (rdata < 130)) {
return DMD_WPC;

// Data East: DOTCLK: 640000 | DE: 5000 | RDATA: 80
// Data East X16: DOTCLK: 121000 or 60544 | DE: 1955 | RDATA: 120
} else if ((dotclk > 55000) && (dotclk < 125000) && (de > 1900) &&
(de < 2000) && (rdata > 110) && (rdata < 120)) {
return DMD_DE_X16;

// Data East X32: DOTCLK: 640000 | DE: 5000 | RDATA: 80
} else if ((dotclk > 630000) && (dotclk < 650000) && (de > 4930) &&
(de < 5070) && (rdata > 75) && (rdata < 85)) {
return DMD_DESEGA;
Expand Down Expand Up @@ -798,6 +803,31 @@ bool dmdreader_init(bool return_on_no_detection) {
break;
}

case DMD_DE_X16: {
uint input_pins[] = {DE, RDATA};
gpio_set_inover(DOTCLK, GPIO_OVERRIDE_INVERT); // Needs to be inverted
// because it triggers on the falling edge in the original signal
dmdreader_programs_init(&dmd_reader_de_x16_program,
dmd_reader_de_x16_program_get_default_config,
&dmd_framedetect_de_x16_program,
dmd_framedetect_de_x16_program_get_default_config,
input_pins, 2, RDATA);
gpio_set_inover(DOTCLK, GPIO_OVERRIDE_INVERT); // invert DOTCLK signal

source_width = 128;
source_height = 16;
source_bitsperpixel = 4; // Data East and Sega are 2bpp
target_bitsperpixel = 2;
// in DE-Sega, there's only one plane,
// containg one LSB row followed by one MSB row and so on
source_planesperframe = 1;
source_planehistoryperframe = 0;
// in DE-Sega each line is sent twice
source_lineoversampling = LINEOVERSAMPLING_2X;
source_mergeplanes = MERGEPLANES_NONE;
break;
}

case DMD_DESEGA: {
uint input_pins[] = {DE};
dmdreader_programs_init(&dmd_reader_desega_program,
Expand Down
1 change: 1 addition & 0 deletions src/dmdreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum DmdType : uint8_t {
DMD_WHITESTAR,
DMD_SPIKE1,
DMD_SAM,
DMD_DE_X16,
DMD_DESEGA,
DMD_SEGA_HD,
DMD_GOTTLIEB,
Expand Down
Loading