What's new
Last night I popped in Nine Dragons just to verify normal carts were fine. I booted, then went into settings and did a system reset. I powered down, took out Nine Dragons and booted Espgaluda which then loaded normally. I then swapped to Ketsui and had garbled graphics again. Repeated the reset procedure with Nine Dragons, and then Ketsui loaded fine. If I reset with one of the conversion carts, a subsequent conversion won’t boot, but if I do a system reset after having booted Nine Dragons, all seems fine. I did this five times last night, and considered it a win for the evening. I’d still like to try a different PGM board with these at some point, but for now I have a quirky way of getting them to load.
 
I forgot to post this:

Python:
import struct

with open ("DOJDUAL.bin", "rb") as f:
	src = bytearray (f.read())

kovsh_tab = [
	0xe7, 0x06, 0xa3, 0x70, 0xf2, 0x58, 0xe6, 0x59, 0xe4, 0xcf, 0xc2, 0x79, 0x1d, 0xe3, 0x71, 0x0e,
	0xb6, 0x90, 0x9a, 0x2a, 0x8c, 0x41, 0xf7, 0x82, 0x9b, 0xef, 0x99, 0x0c, 0xfa, 0x2f, 0xf1, 0xfe,
	0x8f, 0x70, 0xf4, 0xc1, 0xb5, 0x3d, 0x7c, 0x60, 0x4c, 0x09, 0xf4, 0x2e, 0x7c, 0x87, 0x63, 0x5f,
	0xce, 0x99, 0x84, 0x95, 0x06, 0x9a, 0x20, 0x23, 0x5a, 0xb9, 0x52, 0x95, 0x48, 0x2c, 0x84, 0x60,
	0x69, 0xe3, 0x93, 0x49, 0xb9, 0xd6, 0xbb, 0xd6, 0x9e, 0xdc, 0x96, 0x12, 0xfa, 0x60, 0xda, 0x5f,
	0x55, 0x5d, 0x5b, 0x20, 0x07, 0x1e, 0x97, 0x42, 0x77, 0xea, 0x1d, 0xe0, 0x70, 0xfb, 0x6a, 0x00,
	0x77, 0x9a, 0xef, 0x1b, 0xe0, 0xf9, 0x0d, 0xc1, 0x2e, 0x2f, 0xef, 0x25, 0x29, 0xe5, 0xd8, 0x2c,
	0xaf, 0x01, 0xd9, 0x6c, 0x31, 0xce, 0x5c, 0xea, 0xab, 0x1c, 0x92, 0x16, 0x61, 0xbc, 0xe4, 0x7c,
	0x5a, 0x76, 0xe9, 0x92, 0x39, 0x5b, 0x97, 0x60, 0xea, 0x57, 0x83, 0x9c, 0x92, 0x29, 0xa7, 0x12,
	0xa9, 0x71, 0x7a, 0xf9, 0x07, 0x68, 0xa7, 0x45, 0x88, 0x10, 0x81, 0x12, 0x2c, 0x67, 0x4d, 0x55,
	0x33, 0xf0, 0xfa, 0xd7, 0x1d, 0x4d, 0x0e, 0x63, 0x03, 0x34, 0x65, 0xe2, 0x76, 0x0f, 0x98, 0xa9,
	0x5f, 0x9a, 0xd3, 0xca, 0xdd, 0xc1, 0x5b, 0x3d, 0x4d, 0xf8, 0x40, 0x08, 0xdc, 0x05, 0x38, 0x00,
	0xcb, 0x24, 0x02, 0xff, 0x39, 0xe2, 0x9e, 0x04, 0x9a, 0x08, 0x63, 0xc8, 0x2b, 0x5a, 0x34, 0x06,
	0x62, 0xc1, 0xbb, 0x8a, 0xd0, 0x54, 0x4c, 0x43, 0x21, 0x4e, 0x4c, 0x99, 0x80, 0xc2, 0x3d, 0xce,
	0x2a, 0x7b, 0x09, 0x62, 0x1a, 0x91, 0x9b, 0xc3, 0x41, 0x24, 0xa0, 0xfd, 0xb5, 0x67, 0x93, 0x07,
	0xa7, 0xb8, 0x85, 0x8a, 0xa1, 0x1e, 0x4f, 0xb6, 0x75, 0x38, 0x65, 0x8a, 0xf9, 0x7c, 0x00, 0xa0,
]

rom_size = len(src)

for i in range(rom_size//2):
	x, = struct.unpack_from("<H", src, i * 2)

	if ((i & 0x040080) != 0x000080): x ^= 0x0001
	if((i & 0x004008) == 0x004008 and (i & 0x180000) != 0x000000): x ^= 0x0002
	if ((i & 0x000030) == 0x000010): x ^= 0x0004
	if ((i & 0x000242) != 0x000042): x ^= 0x0008
	if ((i & 0x008100) == 0x008000): x ^= 0x0010
	if ((i & 0x002004) != 0x000004): x ^= 0x0020
	if ((i & 0x011800) != 0x010000): x ^= 0x0040
	if ((i & 0x000820) == 0x000820): x ^= 0x0080

	x ^= kovsh_tab[i & 0xff] << 8

	struct.pack_into("<H", src, i * 2, x)

with open("DDPDOJ_P1.bin", "wb") as f:
	f.write(src)
This is the decryption code from Mame for KOVSH. This will take the version of DoDonPachi that is used for KOVSH boards, and makes it usable in boards where the ASIC doesn't decrypt the ROM.
You'll need Python 3.x and run it in a directory with DOJDUAL.BIN to produce DDPDOJ_P1.BIN.

DoDonPachi uses the default boot address, so should run without the modifications to the PAL you need for Ketsui or Espgaluda.

(Obviously now someone needs to link the encryption/decryption tool I missed ...)
 
Last night I popped in Nine Dragons just to verify normal carts were fine. I booted, then went into settings and did a system reset. I powered down, took out Nine Dragons and booted Espgaluda which then loaded normally. I then swapped to Ketsui and had garbled graphics again. Repeated the reset procedure with Nine Dragons, and then Ketsui loaded fine. If I reset with one of the conversion carts, a subsequent conversion won’t boot, but if I do a system reset after having booted Nine Dragons, all seems fine. I did this five times last night, and considered it a win for the evening. I’d still like to try a different PGM board with these at some point, but for now I have a quirky way of getting them to load.
Check your PGM board to see if the main chip has been reworked or replaced. On one of my boards the main QFP chip had been shoddily replaced and when I tapped my finger on the cart, the glitching would come and go.
 
If anyone is still having issues getting the dual version of DDP to function properly I have a possible solution for you.

Turn DIP 8 off and load black or white label. Once the high score table has been displayed, power off and turn dip 8 back on.

Tried this on 3 different PGM boards and worked every time.
 
If anyone is still having issues getting the dual version of DDP to function properly I have a possible solution for you.

Turn DIP 8 off and load black or white label. Once the high score table has been displayed, power off and turn dip 8 back on.

Tried this on 3 different PGM boards and worked every time.
Isn't the real problem that the white label doesn't initialise backup RAM properly?
To me a patch is required.
 
No idea what's functionally wrong the rom, just a work around in the short term for people having issues getting it running.
Just a wild guess though, it seems to me it's the high score table that's causing the errors, if you turn off the high score save hack on DIP 8 it seems to work perfectly.
 
This is the code I used to generate the PAL equations for KOV2:
Code:
from qm import QM

# produce a pld-compatible equation from the miniterms
def get_equation(minterms, variables):
	if isinstance(minterms,str):
		return "'b'%s" % minterms

	def parentheses(glue, array):
		if len(array) > 1:
			return ''.join(['(',glue.join(array),')'])
		else:
			return glue.join(array)

	or_terms = []
	for minterm in minterms:
		and_terms = []
		for j in range(len(variables)):
			if minterm[0] & 1<<j:
				and_terms.append(variables[j])
			elif not minterm[1] & 1<<j:
				and_terms.append('!%s' % variables[j])
		or_terms.append(parentheses(' & ', and_terms))
	return ' # '.join(or_terms)


def generatePal(a, b, csvName, pldName, siName, pins, desc):
	pinIn = [11,10,9,8,7,6,5,4,3,2,1,13]
	pinOut = [23,22,21,20,19,18,17,16,15,14]

	# generate simple csv table
	with open(csvName, "wt") as f:
		f.write ("%s\n" % ",".join([pins[x] for x in pinIn]+[pins[x] for x in pinOut]))
		for i in range(len(a)):
			s = []
			for j in range(12):
				if i & (1<<j):
					s += ["1"]
				else:
					s += ["0"]
			x = a[i] | ((b[i] & 0xc0) << 2)
			for j in range(10):
				if x & (1<<j):
					s += ["1"]
				else:
					s += ["0"]
			f.write ("%s\n" % ",".join(s))

	# generate test vector
	with open(siName, "wt") as f:
		for key, value in desc.items():
			f.write("%s %s;\n" % (key, value))
		f.write("\nORDER: %s;\n" % ",".join([pins[x] for x in pinIn]+[pins[x] for x in pinOut]))
		f.write("\nVECTORS:\n")
		for i in range(len(a)):
			s = []
			for j in range(12):
				if i & (1<<j):
					s += ["1"]
				else:
					s += ["0"]
			x = a[i] | ((b[i] & 0xc0) << 2)
			for j in range(10):
				if x & (1<<j):
					s += ["H"]
				else:
					s += ["L"]
			f.write ("%s\n" % "".join(s))

	# generate pld file
	with open(pldName, "wt") as f:
		for key, value in desc.items():
			f.write("%s %s;\n" % (key, value))

		f.write("\n/* Inputs */\n")
		for x in pinIn:
			f.write("Pin %i = %s;\n" % (x, pins[x]))
		
		f.write("\n/* Outputs */\n")
		for x in pinOut:
			f.write("Pin %i = %s;\n" % (x, pins[x]))

		f.write("\n/* Logic */\n")
		qm = QM([pins[x] for x in pinIn])
		for i in range(len(pinOut)):
			ones = []
			for j in range(len(a)):
				x = a[j] | ((b[j] & 0xc0) << 2)
				if ((x >> i) & 1) != 0:
					ones.append(j)
			
			print ("solve %s" % pins[pinOut[i]])
			f.flush()
			f.write("%s = %s;\n" % (pins[pinOut[i]], get_equation(qm.solve(ones,[])[1], qm.variables)))

# common description			
desc = {
	"PartNo":	"PAL_CE",
	"Date":     "27/01/2019",
	"Revision": "01",
	"Designer": "Fluffy",
	"Company": 	"None",
	"Assembly": "None",
	"Location": "None",
	"Device":  	"g22v10"
}

# Generate FI_U14
pins = {
	1:"U14_1",
	2:"TA18",
	3:"TA19",
	4:"TA20",
	5:"TA21",
	6:"TA22",
	7:"U14_7",
	8:"U14_8",
	9:"U14_9",
	10:"U14_10",
	11:"U14_11",

	23:"U14_23",
	22:"U14_22",
	21:"TO_U15",
	20:"U14_20",
	19:"TA21_I",
	18:"TA20_I",
	17:"TA19_I",
	16:"TA18_I",
	15:"T_ROM_OE",
	14:"INT_T_ROM_OE",
	13:"U14_13"
}

desc["Name"] = "PGM_FI_U14"

with open("FI_U14_A.bin", "rb") as f:
    a = f.read()
with open("FI_U14_B.bin", "rb") as f:
    b = f.read()

generatePal(a, b, "fi_u14.csv", "fi_u14.pld", "fi_u14.si", pins, desc)

# Generate FI_U15
pins = {
	1:"AS",
	2:"PA16",
	3:"PA23",
	4:"PA22",
	5:"PA21",
	6:"PA20",
	7:"FROM_U14",
	8:"FROM_U17_1",
	9:"U15_9",
	10:"U15_10",
	11:"U15_11",

	23:"INT_P_ROM_OE",
	22:"P_ROM_OE",
	21:"PA21_I",
	20:"PA20_I",
	19:"TO_U10_1",
	18:"TO_U9_15",
	17:"U15_17",
	16:"U15_16",
	15:"M68K_LATCH_ENABLE",
	14:"SRAM_ENABLE",
	13:"U15_13"
}

desc["Name"] = "PGM_FI_U15"

with open("FI_U15_A.bin", "rb") as f:
    a = f.read()
with open("FI_U15_B.bin", "rb") as f:
    b = f.read()

generatePal(a, b, "fi_u15.csv", "fi_u15.pld", "fi_u15.si", pins, desc)
It was just slapped together for those two PALs, so doesn't have a proper user interface. It depends on https://github.com/prekageo/optistate to convert what is essentially a truth table into PLD equations.

This is for 22V10, so it combines the output of two passes. The input is essentially a PAL read like a ROM, i.e. the address lines go through all values from 0 to the end of the ROM, and the values are whatever the PAL returned for that input. At that time I only had a G540, which seems to only support 8-bit ROMs. With a Top3000 you could treat this as a 16-bit ROM and read all 10 output values in one go.

It doesn't detect high impedance outputs, though that could probably be done by comparing two passes with pull-up and pull-down resistors. It doesn't detect registers, or outputs configured for input, either, so you should have rough idea what the PAL does, and look at what they pins are connected to in the circuit.
 
I was looking through the PCB scans and noticed this one:
http://www.gc8tech.com/wp-content/uploads/2019/03/HC2_BOTTOM_1.jpg

This uses an off-the-shelf Lattice CPLD:
https://uk.farnell.com/lattice-semi...0c/cpld-128mc-3-3v-ispmach-100tqfp/dp/2252885
and an ARM cpu:
https://uk.farnell.com/nxp/lpc2132fbd64/mcu-32bit-arm7tdmi-60mhz-lqfp/dp/1727702

Later games (like Demon Front) apparently run a significant amount of the game logic on the cartridge, so this may be interesting for people developing multi carts.

http://www.gc8tech.com/uncategorized/pgm-hacked-cart-2-pcbs/
 
My friend planning to make a stock clearance(,let me know if u want^+^.)
 

Attachments

  • 78.jpg
    78.jpg
    183.5 KB · Views: 231
No idea what's functionally wrong the rom, just a work around in the short term for people having issues getting it running.
Just a wild guess though, it seems to me it's the high score table that's causing the errors, if you turn off the high score save hack on DIP 8 it seems to work perfectly.
I didn't test this by credit feeding, but it's likely the stage 4 freeze/crash bug that got reported earlier is still in this one.
It's not related to the protection ASIC though, so possibly this could fix it. Way too busy with work and that damned addictive Apex Legends game still. (100 Kills now and my first win in the pocket ;).)
 
I've played through till the end with dip 8 off without any issues at all.
 
Back
Top