Star Rider is an overly complicated system and has many points of potential failure. How can one test whether Dexter is to blame for problems with one's Star Rider game?
Fortunately, Williams included some nice built-in diagnostic tools in Star Rider. To access it, press the ADVANCE button during the red 'moire' test (shown below), or any point thereafter during the attract mode. Make sure the AUTO-UP/MANUAL-DOWN switch is in the DOWN position when doing this. Both of these controls are supposedly inside of the coin door on a real cabinet but I've never had access to a real cabinet, so I am only going off what I've heard.
Press ADVANCE once you see this screen to get into the diagnostics screens.
The first test that comes up is the ROM test. The board on the left is the ROM board that sits on top of the VGG board. If all of the ROMs are failing, check the ribbon cable going from the ROM board to the VGG board. Also check the two PROMs on the VGG board as they need to be good in order for these ROMs to be correctly read by the CPU.
The board on the right is the CPU board. If any of these 5 tests fail, do not even bother continuing as nothing else is likely to work if you have CPU ROM read problems.
There are several more tests before the disc test: RAM test (uses rug pattern, failures here may be non-fatal or fatal depending on whether it's bad video RAM or CPU RAM), CMOS test (tests battery backed up RAM, failures here may be non-fatal), sound test (a missing or defective sound board will cause this test to not allow you to advance to the next test without spamming the ADVANCE button for about 30 seconds), and input test (steering mechanism, brakes, turbo, throttle, etc).
None of these aforementioned tests will tell you anything about Dexter so examine them at your leisure.
After the input test, hold down advance to get to the DISC TEST. Make sure the AUTO-UP/MANUAL-DOWN switch is in MANUAL mode.
The four tests on the DISC TEST screen are controlled using the AUTO-UP/MANUAL-DOWN switch. When in manual mode, the same test will execute over and over again. When in auto mode, each test will execute in sequence one time. I prefer a combination of the two: going into auto mode just long enough to advance to the next test, then switching back to manual mode.
Reset response test: This tests the communication from the VGG board to the PIF board. It has nothing to d with whether Dexter is operational. If this test fails, your game will not work period because it will not be able to talk to Dexter. There are many points of failure that could cause this test to fail, but in my experience, a bad or unreliable PIF ROM is the #1 culprit. The next thing I would check is the cable going from the PIF board to the VGG board. I have yet to see a bad PIA6821. Again, if this test fails, it's I/O from the VGG board to the PIF board, and so Dexter is not the cause of this problem.
The walking bit test is similar to the Reset Response test. It tests communication from the VGG board to the PIF board. It tests each of the 8 data bits one by one to make sure each bit is working properly. If this test fails, it's a problem somewhere from the CPU/VGG to the PIF board, not Dexter.
The third test is the SEARCH TO test. This test does test Dexter's ability to receive and execute search commands from the PIF board. This test _does_ test whether Dexter is working properly. If this test occasionally fails, it may be because you have not performed my PIF ROM modification yet (only needed for Dexter rev 3f, which is an older version!). Other reasons for this test failing are the VGG board not being able to correctly decode picture numbers from the video stream that Dexter generates, but this is just theoretical as I haven't actually seen a VGG board with this defect (yet).
Last but not least is the STEP DISC test. This test checks to see whether the PIF board can run the laserdisc player in a variable speed manner, which is what the game needs to do in order to make your 'motorcycle' accelerate. I've never seen this test fail if the SEARCH TO test is passing. If it is failing but SEARCH TO is passing, then I would suspect that it's not Dexter's fault but instead a hardware defect on the VGG board or PIF board somewhere. Like I said, there are many things that can fail to cause the whole system to break.
Whether your motorcycle gives hope to the helpless is in your hands... good luck. Oh wait, wrong game!
UPDATE: This mod is only necessary for Dexter rev 3f. Dexter rev 3g (or later versions) does not need it!
TLDR: Star Rider will work with Dexter as it is today if one is willing to modify the Star Rider PIF ROM slightly. Original EPROM is "AMD AM2732DC", I've successfully used a 2732A.
The Details:
My goal with Dexter is to never make users have to modify their hardware. I want Dexter to be a drop-in replacement. However, I don't think I am going to be able to do it in this case without a new revision of the Dexter hardware. Even then, this modification may also be a wise choice for people who may be using a real PR-8210A laserdisc player and/or arcade operators who don't have time to restart games which are too fussy and crash easily.
Inside the PIF ROM, here is the function that performs a laserdisc search:
ROM:F69B PR8210A_SEARCH: ; CODE XREF: ROM:FCBA P ROM:F69B ; DATA XREF: ROM:F048 o ... ROM:F69B pshs cc,a,b,x ROM:F69D lda #3 ROM:F69F sta LastCallbackCmd ; Last callback we executed (only a handful keep track here). ROM:F69F ; FF: IRQ should do timer test, nothing else ROM:F69F ; 1: PLAY was called (f5af) ROM:F69F ; 3: SEARCH callback was called, either by cmd in 0x300 or from FIRQ command 03 ROM:F69F ; 4: jump trigger count does not get cleared after jump trigger is sent (FIRQ cmd 4 received) ROM:F69F ; 18: No cmd executed yet (or NOP) - IRQ jump triggers disabled, even when on IRQ count 8 (see FD2D) ROM:F69F ; 1B: disc is in default paused state after IRQ test is finished, jump triggers are active (f564) ROM:F6A1 lda PIAB_PolicyActive ; Holds byte that should be output to PR-8210A PIA port B whenever we aren't in the middle of an operation ROM:F6A3 sta PIA_B_DATA ROM:F6A6 orcc #$10 ; disable IRQ' ROM:F6A8 clra ROM:F6A9 clrb ROM:F6AA std SlowTimer ; This appears to be a timer that increases very slowly (or not at all) ROM:F6AA ; Can get increased by IRQ ROM:F6AA ; written by FD68 ROM:F6AC clr UnknownSlowTimerHelper ; gets a variation of what was stored in $43 ROM:F6AE std Cmd04MysteryWord ; may get modified by ChangePlaybackDirection function (F771) ROM:F6AE ; may have something to do with playback speed ROM:F6AE ; If high bit is set, playback direction is reverse, otherwise it's forward. ROM:F6B0 clr HowManyJmpTriggersToSend ; This value determines how many jump triggers the IRQ will send at once. ROM:F6B0 ; 0: none ROM:F6B0 ; 1: one ROM:F6B0 ; 2: two ROM:F6B0 ; 3: three ROM:F6B0 ; 4: four ROM:F6B0 ; (no more than 4 is supported) ROM:F6B2 clr HowManyJmpTriggersToSendSrc ; holds jmp trigger count (F78C) ROM:F6B4 clr IsDiscNotPaused ; will be non-zero if PLAY or REJECT command was last issued, ROM:F6B4 ; will be 0 if the STEP FWD/REV (pause) command was last issued. ROM:F6B6 ldx #SearchArrayEnd ; start at memory location 62 (and work backward) ROM:F6B9 clr ,x ; put 00 terminator at the end so send loop knows when to stop ROM:F6BB lda #$E8 ; 'F' ; PR-8210A search command ROM:F6BD sta ,-x ; 61 = E8, 60 = E8, 5F = E8 ROM:F6BF sta ,-x ROM:F6C1 sta ,-x ROM:F6C3 ldb #5 ; may indicate 5 digits ROM:F6C5 pshs b ROM:F6C7 ldd [Pointer] ; load the frame number (unsigned binary format) ROM:F6CB ROM:F6CB DigitLoop: ; CODE XREF: PR8210A_SEARCH+35 j ROM:F6CB jsr Pr8210ALoadLeastSigDecimalDigit ; This call computes the least significant frame number digit (in decimal format), ROM:F6CB ; converts it to the PR-8210A expected format, then loads it into X-1 3 times. ROM:F6CB ; It also loads a filler byte (0x80). ROM:F6CB ; X will be equal to where to put the digit + 1 ROM:F6CB ; the frame number will be in D ROM:F6CE dec ,s ; the 'b' that we pushed on earlier, subtract it ROM:F6D0 bgt DigitLoop ROM:F6D2 leas 1,s ; pop off digit loop counter ROM:F6D4 lda #$AC ; '¼' ; PR-8210A FRAME DISPLAY command ROM:F6D6 sta ,-x ROM:F6D8 sta ,-x ROM:F6DA sta ,-x ROM:F6DC lda #$E8 ; 'F' ; PR-8210A SEARCH command ROM:F6DE sta ,-x ROM:F6E0 sta ,-x ROM:F6E2 sta ,-x ROM:F6E4 jsr Sleep50Ms ; this delays for 49,993 cycles (from $FA16 until the last RTS has finished) ROM:F6E4 ; So about 50 milliseconds ROM:F6E7 lda ,x+ ROM:F6E9 ROM:F6E9 WhileCmdArrayNotAllSent: ; CODE XREF: PR8210A_SEARCH+56 j ROM:F6E9 jsr Sleep10Ms ; this method stalls for 10,004 cycles (from the JSR $FA21 until after RTS has completed) ROM:F6E9 ; So about 10 milliseconds ROM:F6EC jsr SendPR8210ACmdNoFirq ; Sends two leading 0 bits to remote control line, ROM:F6EC ; then sends 8 bits stored in A, starting with ROM:F6EC ; bit 7 and shifting left. ROM:F6EC ; So for example, the play command would be 0xD0 ROM:F6EC ; (1101 0000) ROM:F6EC ; FIRQ' is always suppressed, IRQ' may or may not be allowed ROM:F6EF lda ,x+ ROM:F6F1 bne WhileCmdArrayNotAllSent ; if we haven't hit the end (memory location 62) keep going ROM:F6F3 jsr WaitForStandByToStopBlinking ; This waits for the STAND BY line to stop blinking. ROM:F6F3 ; (it will also exit if the STAND BY line is held low) ROM:F6F3 ; If it does not go low initially after about 450 milliseconds, the game will error out with code 0x86. ROM:F6F3 ; ROM:F6F6 ldx Pointer ; appears to hold pointer to frame number ROM:F6F8 leax 2,x ; Advance to the next pointer in the FRAME NUMBER lookup table. ROM:F6F8 ; This only seems to apply when SEARCH is called via (currently unknown) callback method. ROM:F6F8 ; If it is called from FIRQ cmd, any change to this pointer gets reverted when this function returns. ROM:F6FA stx Pointer ; appears to hold pointer to frame number ROM:F6FC lda ,s ROM:F6FE tfr a, cc ROM:F700 jsr SyncIrqCounterToVsyncAndField ; Syncs up IRQ counter with vsync/field ROM:F703 andcc #$EF ; 'n' ; allow IRQ ROM:F705 jsr DisableLeftAndRightAudio ; Disables left/right audio ROM:F708 jsr PR8210A_PLAY_FIRQ_OK ROM:F70B jsr PrepareDiscPauseViaJmpTrig ; Sets default behavior to pause the disc using 1 jump trigger (in reverse direction) per track ROM:F70E lda #1 ROM:F710 ROM:F710 WaitUntilIrqCounterIs1: ; CODE XREF: PR8210A_SEARCH+77 j ROM:F710 cmpa IRQCounter ; Counts how many times IRQ handler has been called. ROM:F710 ; When this value is 8, the IRQ handler may issue JUMP TRIGGERS. ROM:F710 ; This gets called every 4 MS approximately, so the JUMP TRIGGERS will occur ROM:F710 ; once per frame if they happen at all. ROM:F710 ; ROM:F712 bne WaitUntilIrqCounterIs1 ROM:F714 puls x,b,a,cc ROM:F716 rts ROM:F716 ; End of function PR8210A_SEARCH
Notice at $F6A6, IRQs are disabled, and then they are re-enabled at $F703, right after the internal Irq Counter has synced up with vsync and the current field. The reason that this needs to happen (IMO) is because during searches, there is no sync, and the game relies on being in sync in order to send jump triggers at the right time. So it makes sense that after a search, the game would need to go through a period of re-sync.
However, this is where things get inconsistent.
ROM:F880 SyncIrqCountToVsyncEnd: ; CODE XREF: SyncIrqCounterToVsyncAndField+33 P
ROM:F880 ; SyncIrqCounterToVsyncAndField+54 P
ROM:F880 pshs cc,a,b,x
ROM:F882 andcc #$EF ; 'n' ; enable IRQ
ROM:F884 jsr Wait20msForVsync ; returns carry clear if vsync can be detected within ~20ms or carry set if timeout happens first
ROM:F887 lbcs PrepareToReset ; prepares state to start the ROM program over from the RESET entry point (ie reboot)
ROM:F887 ; NOTE : RESET will clobber the log stored at 0x100 and 0x200
ROM:F88F bita PIA_B_DATA ; read bit 7 from PR-8210A (VSYNC)
ROM:F892 bne LoopUntilVsyncIsInactive ; if bit 7 is set, loop until it's clear (ie until vsync signal is inactive)
ROM:F894 lda PIA_B_DATA
ROM:F897 bita #$40 ; '@' ; test bit 6 (FIELD) from PIA B port
ROM:F897 ; NOTE : field is expected to be up to date when vsync goes inactive
ROM:F899 bne TopField ; if bit 6 is set, it means field is ODD, and to branch
ROM:F899 ; NOTE : I think this branch will always be taken because this subroutine only gets called when the bottom field is active.
ROM:F89B lda #4 ; even field
ROM:F89D bra loc_F8A1
This routine will wait 20ms to see a vsync, which seems reasonable since vsync occurs every 16 ms. However, it also enables IRQs at $F882!! This means that it is not uncommon for the IRQ handler to be active when a vsync comes in.
Now on a real PR-8210A, the vsync pulse is quite long, so usually, the IRQ handler exits while vsync is still active. But on Dexter, this vsync pulse is much shorter which means by the time the IRQ handler exits, vsync is no longer active, and the PIF ROM will reboot, starting at $F887.
The 20 ms timeout is really quite aggressive and I can't see any reason for it (I also can't see any reason to enable IRQs right before waiting for vsync). I suspect that except on a brand new laserdisc player, this aggressive timeout could cause the game to crash needlessly.
My solution? Increase the 20 ms timeout to something much larger.
ROM:F95E ; returns carry clear if vsync can be detected within ~20ms or carry set if timeout happens first
ROM:F95E
ROM:F95E Wait20msForVsync: ; CODE XREF: RebootIfVsyncIsNotPresent P
I changed $F96F so instead of waiting until the counter (stored in X) reaches #$AA, I wait until it reaches #$3FF. Why #$3FF? This choice is somewhat arbitrary. I just picked a value that covers many fields instead of just 1 field.
This change did the trick and now Dexter seems to be working perfectly with Star Rider! Woohoo!
For those curious, there is a function called at $F963 which sleeps for about .122ms and #$AA is 170 in decimal, and 170 * 0.122 is 20.74 which is where I calculated that this method waits about 20 ms for vsync to appear.
The change to make to the PIF ROM to increase this timeout value:
Change address 0x005 from #$F2 to #$4A . This makes it so the internal checksum test still passes.
Change address 0x970 and 0x971 from 0x00 0xAA to 0x03 0xFF
I've suspected for a while that something was a little off with Dexter's image quality. However, this is almost unnoticeable on a CRT, so I haven't prioritized investigating it. Now that I am trying to finish Star Rider support, which relies on data being decoded from the video signal, I looked into video quality issues further and found a couple of minor problems.
After some troubleshooting, I found that there are two issues with Dexter's image quality:
1) the video is shifted one line from what it should be,
2) the video has an unfocused look
Issue #1 is caused by the raspberry pi itself. I don't have a "proper" fix, but I can compensate by shifting the video 1 line within the Dexter software which seems to do the trick.
Issue #2 is caused because I am using bilinear filtering inside of the OpenGLES2 code that Dexter is using. Combined with my shader to implement interlaced video, this was creating a bunch of subtle artifacts that give the unfocused look. I turned off the bilinear filtering and that did the trick!
I've fixed both of these issues internally and am working on a public fix for everyone. It will be free for all Dexter customers, new and old.
UPDATE: the fix is live now! :)
Here are two images showing before and after.
Before
After (ignore the extra text)
Please ignore the "Current video line shift" and "Scale factor" text in the second screenshot. Those are debug messages that I added while troubleshooting this problem.