Friday, February 26, 2016

Time Traveler supports a Pioneer player??

This may be common knowledge to most people, but I just made a startling discovery as I delved deeper into the Time Traveler ROM.

It all started innocently enough.  I was finding the function that issues the "still step forward" command:

I converted the line at d37e:0893 from being a constant value of 0xd9d to an enumeration (StepFwdArr) to make it easier to read.  And I noticed that this function at d37e:87b will either send the "still step forward" command by calling the function at D31C6_SomeSendByteToLDP (the name I  picked in my screenshot) or it will load in the array at 0xd9f and call sub_D33F1.  I found this... odd.  Why would it either call the LDP or do something unrelated?  I decided that 0xd9f was close enough to 0xd9d that they might be related.  So I jumped to that location in the ROM:

I thought "Huh, that's weird.  The stuff at d9f looks like some ascii with a carriage return termination."  And I thought "Why would that be in this ROM?  It doesn't have a need for carriage return terminating any string."

Having no answer at this point, I decided to look for other commands that called D31C6_SomeSendByteToLDP.  I found here:

And I checked to see what 0xDa3 pointed to and it was the 0x2C command which is "still step reverse".  And I noticed a similar pattern with this method.  It either sends to the LDP or else is calls this unknown D33F1 function which uses a pointer at 0xda5.  They definitely look related.

I looked closer...

Yes, 0xda3 has the 0x2C command... and then 0xda5 has that same ASCII array with a carriage return (0x0D) terminator!

And then I had the "ah ha" moment.

The 0xda5 stuff is commands for a Pioneer LD-V8000 (or similar) kind of player!!

So Time Traveler... has code in it... to control either a sony LDP-1450... or a Pioneer LD-V8000!  I couldn't believe it!  And I had this awesome feeling of "Whoa" once I figured it out :)

SF means... step forward... SR means.. step reverse.  I haven't confirmed this.. but it has to be right, dangit.  It has to! :)

Fixing Dexter so that it works with Time Traveler

Some of you may know that Dexter's Time Traveler support has been "almost working" for a year or two.  Now that Dexter is finally shipping, I've gotten serious about fixing problems like this.

Time Traveler presents a unique challenge.  It uses an 80188 Intel CPU which I am not as familiar with as I am with CPUs like the z80, 6502, or 6809E.  I've made a few half-hearted attempts to disassemble the Time Traveler ROM in the past but always gave up due to the Intel 'segments' paradigm which is basically a hack that Intel added to the 8086 to allow it to address up to 1 megabyte of RAM.  This hack makes disassembly more difficult.

Things working in my favor are that Mark Broadhead had mostly got Time Traveler emulated in Daphne (how he managed to do this, I have no idea!).  I had made a few attempts to run Time Traveler in Daphne in the past, but gave up due to problems that I can't quite recall.

Things working against me are that I do not currently have a Time Traveler PCB and no schematics seem to exist (other than a few unhelpful ones).  Again, somehow Mark B was able to get the game mostly figured out without using schematics.  I am pretty impressed.

Here is what I have done:

I had only tested Time Traveler with Dexter a few times.  The most recent time was at CAX a few years ago.  I had done some logging on Dexter while it was plugged into Time Traveler and concluded that the game was trying to send an 0xE8 command to the Sony LDP-1450.  Unfortunately, 0xE8 is not a documented command.  Also unfortunate is that I did not bother to have anyone re-test this and have been operating under this assumption for years.  This assumption has proved to be incorrect.

I had a choice.  Do I try to send an 0xE8 command to my real Sony LDP-1450 and observe results? (this might have been a wise thing to do as it would've likely confirmed to me that this is indeed an invalid command)  Do I try to finish the Time Traveler emulation in Daphne so that I can get the game to send this bad command?  Or do I try (again) to disassemble the ROM and find where the bad command gets sent?

I decided that since I was dealing with an undocumented command (or so I thought), I would eventually have to disassemble the ROM.  I finally broke down and learned about 'segments' for 8086 era CPU's (such as Time Traveler's 80188).  And then I loaded the Time Traveler ROM into IDA and went to work.  It was a slow process, but I was able to disassemble all of the segments in the ROM and get it into a sane state.  *phew*

I noticed as I was going that the code seems to be pretty poorly optimized.  I deduced that this code was written in C and compiled by a pretty crappy C compiler.  Most likely it was built on an MS-DOS based system.  The compiler could've been anything from Microsoft QuickC, Turbo C, or any other MS-DOS 16-bit 8086 compiler of that area.  I really don't know.  But compilers have come a long way since this time, I can assure you :)

I speculate that the development version of this game ran on an MS-DOS PC plugged into a serial port.  And when they were ready to ship, they compiled a special embedded version.

I decided that first piece of code I wanted to find was the code that sends commands to the serial port.  Daphne made this easy.  I simply had to put a breakpoint on the function that sends a command to the Sony LDP-1450 interpreter, and then examine the x86 emulator to see where the program counter was located.  I did so, and found this little method:

It is nothing special, just a helper method to send an arbitrary byte to an arbitrary port.

I entered the x86 CPU debugger in Daphne and stepped out of this method.  I came out into this method:

After studying this method a bit both in IDA and the debugger, I concluded that this method takes a null-terminated byte array and sends it to the LDP-1450, then checks to make sure that the LDP-1450 has returned a 0x0A byte (which indicates success).  In other words, this method is probably a general purpose "send these bytes to the LDP" method.  I was getting closer.  Just had to step out one of the method one more time.

I was initially pretty confused about what this method did, but I realized later that it prints the words "SERIAL PORT" on the Time Traveler LEDs, then sends a 0x41 ("clear") command to the LDP-1450 (at d37e:0078), then sends "TESTING" to the LEDs, and loops until it gets a response from the LDP-1450.  Apparently this is where the game would get stuck if the LDP-1450 was not available or not communicating properly.

Coincidentally, around this time, someone who already had a Dexter decided to test Dexter with Time Traveler and informed me that the "undocumented command" problem occurs after successfully completing the first stage.

I fired Daphne up and played Time Traveler through to the end of the first stage and set a break point on any bad LDP-1450 commands.  Sure enough, after I completed the stage my breakpoint was hit.  But instead of seeing the bad command of 0xE8, the 'bad' command was 0x2B!  A quick check of the LDP-1450 manual shows this command to be "still step forward".  And sure enough, I had failed to implement this command in my LDP-1450 interpreter!

The good news is that this will be super easy to implement and I have hopes that Time Traveler will be fully functional after I am done.

Wednesday, February 24, 2016

Dexter's MACH 3 status changed from "mostly working" to "fully working"

The new sound code change fixed it!  Warren ran through five consecutive runs of MACH 3 using Dexter with no "DISC ERROR STAY PUT" error!  I'm not going to claim that you will never ever see one of these errors ever again, but I think this kind of performance is way better than the original player ever achieved and should be awesome for any MACH 3 cabinet owner.

Made some more progress with MACH 3 audio and Dexter

So I looked at the sound code in Dexter and saw some places that may be contributing to the MACH 3 audio decoding problems.  I've applied fixes.  I was able to run through the whole disc this morning without errors.  I figure if I can do that 5 times in a row, that will probably be "good enough."

Tuesday, February 23, 2016

MACH 3 audio decoding troubleshooting with Dexter (with video)

Me trying to improve Dexter's performance when used with MACH 3 hardware.

Summary of what the video covers:
- Powering up MACH 3 interface board
- Going over schematics to decide what to attach scope to
- Attaching scope to view audio and audio decoding
- Fixing bad RCA jack
- Getting MACH 3 audio decoder to throw an error inadvertently
- Playing MACH 3 disc all the way through on Dexter with no errors (proving that it does work 'perfectly' at least part of the time)

Saturday, February 20, 2016

Fixing Dexter's problems with MACH 3

More info than you ever wanted to know about why Dexter struggles to support MACH 3 and how I am fixing it.

Saturday, February 13, 2016

More Dexter+Merlin integration video

I gave Dexter and Merlin "a spin" on my Dragon's Lair arcade cabinet. It was awesome! :)

NOTE : Merlin update is still in beta and not available yet

Friday, February 12, 2016

Dexter/Merlin auto disc switching is working!!! (video)

People have waited for this and the day is finally here!  A real multi-game Dragon's Lair solution!  Pre-orders for Dexter will end at the end of this month, so if you were on the fence, now is the time to place your order! :)

NOTE : Merlin update is still in beta and is not available yet

Video here:

Wednesday, February 10, 2016

Software Development Insights: Debugging a Dexter audio problem

Dexter was not playing audio after doing a disc switch. What could the problem be?

Software Development Insights: Unit Testing in C++, Mocks, and Debugging

I show some unit testing (with mocks) in C++ using Daphne as an example, and also some debugging.

Disc auto-switching working in Dexter!

Dexter now supports switching its active laserdisc automatically with any other available disc that it has installed!  Merlin integration soon?

Monday, February 8, 2016

Software Development Insights: Coupling and why it is bad

Ever heard the term 'coupling' before?  I am not fond of it and I go into ridiculous amounts of detail ranting about why it's bad :)  I also talk about what enums are, touch on if/else "nesting", and unit testing.  All related to work on Daphne/Dexter.

Sunday, February 7, 2016

Software Development Insights: Why hard-coding numbers is a Bad Idea

Ever written something like this?

int count = 2;
int count2 = 4;
int count3 = 6;

Watch this stunningly insightful video (sarcasm) to find out why this is a Bad Idea.

Saturday, February 6, 2016

Dexter disc auto-swapping is getting closer!

Dexter disc auto-swapping is becoming closer to being a reality.  Here is a video showing me demo'ing the feature in Daphne.

Software Development Insights: Debugging multiple threads on a raspberry pi (Dexter/Daphne)

Wanna see how to debug threads on a raspberry pi?  Or do you like anything geeky related to Daphne and Dexter?  This video may be of interest to you.

Friday, February 5, 2016

Software development insights: Debugging OpenMax problem related to Dexter

If you are an aspiring software developer, here is a 30 minute video I just recorded of me troubleshooting a software problem with Dexter.  It could be interest or boring depending on what you are looking for, haha.