diff --git a/logicanalyzer/Als Garage Band - Alvin G 128x32 (PCA020A).sal b/logicanalyzer/Alvin G/Als Garage Band - Alvin G 128x32 (PCA020A).sal similarity index 100% rename from logicanalyzer/Als Garage Band - Alvin G 128x32 (PCA020A).sal rename to logicanalyzer/Alvin G/Als Garage Band - Alvin G 128x32 (PCA020A).sal diff --git a/logicanalyzer/Arcade Games/Island - redemption game.sal b/logicanalyzer/Arcade Games/Island - unknown 128x32.sal similarity index 100% rename from logicanalyzer/Arcade Games/Island - redemption game.sal rename to logicanalyzer/Arcade Games/Island - unknown 128x32.sal diff --git a/logicanalyzer/Airborne - Capcom 128x32.sal b/logicanalyzer/Capcom/Airborne - Capcom 128x32.sal similarity index 100% rename from logicanalyzer/Airborne - Capcom 128x32.sal rename to logicanalyzer/Capcom/Airborne - Capcom 128x32.sal diff --git a/logicanalyzer/Flipper Football - Capcom 256x64.sal b/logicanalyzer/Capcom/Flipper Football - Capcom 256x64.sal similarity index 100% rename from logicanalyzer/Flipper Football - Capcom 256x64.sal rename to logicanalyzer/Capcom/Flipper Football - Capcom 256x64.sal diff --git a/logicanalyzer/Stargate - Gottlieb 128x32.sal b/logicanalyzer/Gottlieb/Stargate - Gottlieb 128x32.sal similarity index 100% rename from logicanalyzer/Stargate - Gottlieb 128x32.sal rename to logicanalyzer/Gottlieb/Stargate - Gottlieb 128x32.sal diff --git a/logicanalyzer/World Challenge Soccer - Gottlieb 128x32.sal b/logicanalyzer/Gottlieb/World Challenge Soccer - Gottlieb 128x32.sal similarity index 100% rename from logicanalyzer/World Challenge Soccer - Gottlieb 128x32.sal rename to logicanalyzer/Gottlieb/World Challenge Soccer - Gottlieb 128x32.sal diff --git a/logicanalyzer/Baywatch - Sega 192x64.sal b/logicanalyzer/Sega & Data East/Baywatch - Sega 192x64.sal similarity index 100% rename from logicanalyzer/Baywatch - Sega 192x64.sal rename to logicanalyzer/Sega & Data East/Baywatch - Sega 192x64.sal diff --git a/logicanalyzer/Sega & Data East/Hook - Data East 128x16.sal b/logicanalyzer/Sega & Data East/Hook - Data East 128x16.sal new file mode 100644 index 0000000..1dbc3e7 Binary files /dev/null and b/logicanalyzer/Sega & Data East/Hook - Data East 128x16.sal differ diff --git a/logicanalyzer/Rocky and Bullwinkle - Data East 128x32.sal b/logicanalyzer/Sega & Data East/Rocky and Bullwinkle - Data East 128x32.sal similarity index 100% rename from logicanalyzer/Rocky and Bullwinkle - Data East 128x32.sal rename to logicanalyzer/Sega & Data East/Rocky and Bullwinkle - Data East 128x32.sal diff --git a/logicanalyzer/Sega & Data East/TMNT - Data East 128x16.sal b/logicanalyzer/Sega & Data East/TMNT - Data East 128x16.sal new file mode 100644 index 0000000..a0f39e8 Binary files /dev/null and b/logicanalyzer/Sega & Data East/TMNT - Data East 128x16.sal differ diff --git a/logicanalyzer/Ghostbusters - SPIKE 1 128x32.sal b/logicanalyzer/Stern/Ghostbusters - SPIKE 1 128x32.sal similarity index 100% rename from logicanalyzer/Ghostbusters - SPIKE 1 128x32.sal rename to logicanalyzer/Stern/Ghostbusters - SPIKE 1 128x32.sal diff --git a/logicanalyzer/Playboy - Whitestar 128x32.sal b/logicanalyzer/Stern/Playboy - Whitestar 128x32.sal similarity index 100% rename from logicanalyzer/Playboy - Whitestar 128x32.sal rename to logicanalyzer/Stern/Playboy - Whitestar 128x32.sal diff --git a/logicanalyzer/Walking Dead - SAM 128x32.sal b/logicanalyzer/Stern/Walking Dead - SAM 128x32.sal similarity index 100% rename from logicanalyzer/Walking Dead - SAM 128x32.sal rename to logicanalyzer/Stern/Walking Dead - SAM 128x32.sal diff --git a/src/dmd_interface.h b/src/dmd_interface.h index 4e60c5c..2bf49b7 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -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" diff --git a/src/dmd_interface_de_x16.pio b/src/dmd_interface_de_x16.pio new file mode 100644 index 0000000..ea3377c --- /dev/null +++ b/src/dmd_interface_de_x16.pio @@ -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 diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 76bccc3..c688e57 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -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; @@ -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, diff --git a/src/dmdreader.h b/src/dmdreader.h index bee0400..a9f528b 100644 --- a/src/dmdreader.h +++ b/src/dmdreader.h @@ -22,6 +22,7 @@ enum DmdType : uint8_t { DMD_WHITESTAR, DMD_SPIKE1, DMD_SAM, + DMD_DE_X16, DMD_DESEGA, DMD_SEGA_HD, DMD_GOTTLIEB,