I had made a version 3 of the VBI injector board some time ago, and had even made a first attempt at soldering it together. However, the AVR did not work and I already suspected that it was bad. I finally ordered a new one. It became time to solder it on and I decided to use the "hot plate/skillet" method.
This method is to basically apply some solder paste on the PCB, put the surface mount components on the solder paste, and then heat the entire bottom of the board on a skillet. Melting point of the solder paste is between 425-450F (I forget the C conversion).
Unfortunately, as I had already soldered on some (previously de-soldered) pin headers, the PCB could not get good contact with the skillet. I was hoping that by heating up the pins that the board would slide down once the solder on the pins heated up, and as you can see in the video, it does slide down, but not quite enough.
NOTE : almost all of these components have been desoldered from a previous board which is why they look charred. Only the AVR is new.
So the right side of the board gets hot enough but the left side does not. This means that half of the AVR pins are done.
I decided to use my newly acquired hot air gun to finish the job. As you can see, it worked quite nicely. I was able to finish the 10k resistor, the rest of the AVR, and the MUX IC.
Friday, February 28, 2014
Sunday, February 23, 2014
Been a tough few days for Star Rider
Well, since the last update, I hooked up most/all of the Star Rider inputs and then tried inserting two coins to see how well a game would play. At this point, the game locked up. I started debugging/disassembling to find out what why, and as far as I can tell, the game has either entered an error state and locked up intentionally, or... I am not sure. It is basically looping/waiting for VBLANK to start but every time VBLANK starts, the interrupt service routine starts, preventing the non-interrupt loop from ever ending.
Disassembling the main CPU is much harder than the PIF CPU because it has a lot more RAM (and uses a lot more of it), and has a lot more code.
Disassembling the main CPU is much harder than the PIF CPU because it has a lot more RAM (and uses a lot more of it), and has a lot more code.
Thursday, February 20, 2014
Star Rider's steering mechanism
As some of you may know, Star Rider had a motorcycle-styled steering mechanism. From the CPU's point of view, this steering mechanism is digital and is composed of 6 bits.
When I saw this, I was quite confused because all it does is a loop that does an eXclusive-OR and right shift. I decided to write a quick C program to replicate this algorithm and print out all of the possible results to see if I could see any pattern at all.
Here is the C equivalent algorithm I came up with:
unsigned char shifter(unsigned char u8)
{
unsigned char u8A = 0;
do
{
u8A ^= u8;
u8 >>= 1;
} while (u8 != 0);
return u8A;
}
u8A represents 6809 register A (from the assembly language) and u8 represents the value stored on the stack.
The results of this program are here:
0 => 0 (00000000 => 00000000
1 => 1 (00000001 => 00000001
2 => 3 (00000010 => 00000011
3 => 2 (00000011 => 00000010
4 => 7 (00000100 => 00000111
5 => 6 (00000101 => 00000110
6 => 4 (00000110 => 00000100
7 => 5 (00000111 => 00000101
8 => f (00001000 => 00001111
9 => e (00001001 => 00001110
a => c (00001010 => 00001100
b => d (00001011 => 00001101
c => 8 (00001100 => 00001000
d => 9 (00001101 => 00001001
e => b (00001110 => 00001011
f => a (00001111 => 00001010
10 => 1f (00010000 => 00011111
11 => 1e (00010001 => 00011110
12 => 1c (00010010 => 00011100
13 => 1d (00010011 => 00011101
14 => 18 (00010100 => 00011000
15 => 19 (00010101 => 00011001
16 => 1b (00010110 => 00011011
17 => 1a (00010111 => 00011010
18 => 10 (00011000 => 00010000
19 => 11 (00011001 => 00010001
1a => 13 (00011010 => 00010011
1b => 12 (00011011 => 00010010
1c => 17 (00011100 => 00010111
1d => 16 (00011101 => 00010110
1e => 14 (00011110 => 00010100
1f => 15 (00011111 => 00010101
20 => 3f (00100000 => 00111111
21 => 3e (00100001 => 00111110
22 => 3c (00100010 => 00111100
23 => 3d (00100011 => 00111101
24 => 38 (00100100 => 00111000
25 => 39 (00100101 => 00111001
26 => 3b (00100110 => 00111011
27 => 3a (00100111 => 00111010
28 => 30 (00101000 => 00110000
29 => 31 (00101001 => 00110001
2a => 33 (00101010 => 00110011
2b => 32 (00101011 => 00110010
2c => 37 (00101100 => 00110111
2d => 36 (00101101 => 00110110
2e => 34 (00101110 => 00110100
2f => 35 (00101111 => 00110101
30 => 20 (00110000 => 00100000
31 => 21 (00110001 => 00100001
32 => 23 (00110010 => 00100011
33 => 22 (00110011 => 00100010
34 => 27 (00110100 => 00100111
35 => 26 (00110101 => 00100110
36 => 24 (00110110 => 00100100
37 => 25 (00110111 => 00100101
38 => 2f (00111000 => 00101111
39 => 2e (00111001 => 00101110
3a => 2c (00111010 => 00101100
3b => 2d (00111011 => 00101101
3c => 28 (00111100 => 00101000
3d => 29 (00111101 => 00101001
3e => 2b (00111110 => 00101011
3f => 2a (00111111 => 00101010
My observation here is that while it's nice to understand exactly how everything about a game works, one does not need to understand everything in order to emulate it to some degree (although understanding things definitely improves the likelihood of accurate emulation).
Unfortunately, I was unable to see anywhere in the schematics that described what each of these 6 bits (ST0-ST5) actually mean.
Fortunately, Star Rider has a rather robust suite of diagnostics tests, one of which tests the steering mechanism. Ah ha! I decided to use this to figure it out by trial and error. After passing in some guesses for what the bits meant, I was left with a confused set of notes:
STEERING:
0 (all on): FAR LEFT (active low?)
8: mid left
12: 3/4 left
16+4 : 1/4 left
8+16 : mid left
4+8+16 : 1/4 left
32: FAR RIGHT
32 + 8 : MID RIGHT
32 + 4 + 8 : 3/4 right
32 + 16 + 8: MID RIGHT
32 + 16 + 8 + 4 : 1/4 right
32 + 16 : DEAD CENTER
In other words, I could see no pattern whatsoever.
So, I decided to look at the ROM program to see how it determined where the steering was positioned. I found the relevant routine right here after a bit of searching:
When I saw this, I was quite confused because all it does is a loop that does an eXclusive-OR and right shift. I decided to write a quick C program to replicate this algorithm and print out all of the possible results to see if I could see any pattern at all.
Here is the C equivalent algorithm I came up with:
unsigned char shifter(unsigned char u8)
{
unsigned char u8A = 0;
do
{
u8A ^= u8;
u8 >>= 1;
} while (u8 != 0);
return u8A;
}
u8A represents 6809 register A (from the assembly language) and u8 represents the value stored on the stack.
The results of this program are here:
0 => 0 (00000000 => 00000000
1 => 1 (00000001 => 00000001
2 => 3 (00000010 => 00000011
3 => 2 (00000011 => 00000010
4 => 7 (00000100 => 00000111
5 => 6 (00000101 => 00000110
6 => 4 (00000110 => 00000100
7 => 5 (00000111 => 00000101
8 => f (00001000 => 00001111
9 => e (00001001 => 00001110
a => c (00001010 => 00001100
b => d (00001011 => 00001101
c => 8 (00001100 => 00001000
d => 9 (00001101 => 00001001
e => b (00001110 => 00001011
f => a (00001111 => 00001010
10 => 1f (00010000 => 00011111
11 => 1e (00010001 => 00011110
12 => 1c (00010010 => 00011100
13 => 1d (00010011 => 00011101
14 => 18 (00010100 => 00011000
15 => 19 (00010101 => 00011001
16 => 1b (00010110 => 00011011
17 => 1a (00010111 => 00011010
18 => 10 (00011000 => 00010000
19 => 11 (00011001 => 00010001
1a => 13 (00011010 => 00010011
1b => 12 (00011011 => 00010010
1c => 17 (00011100 => 00010111
1d => 16 (00011101 => 00010110
1e => 14 (00011110 => 00010100
1f => 15 (00011111 => 00010101
20 => 3f (00100000 => 00111111
21 => 3e (00100001 => 00111110
22 => 3c (00100010 => 00111100
23 => 3d (00100011 => 00111101
24 => 38 (00100100 => 00111000
25 => 39 (00100101 => 00111001
26 => 3b (00100110 => 00111011
27 => 3a (00100111 => 00111010
28 => 30 (00101000 => 00110000
29 => 31 (00101001 => 00110001
2a => 33 (00101010 => 00110011
2b => 32 (00101011 => 00110010
2c => 37 (00101100 => 00110111
2d => 36 (00101101 => 00110110
2e => 34 (00101110 => 00110100
2f => 35 (00101111 => 00110101
30 => 20 (00110000 => 00100000
31 => 21 (00110001 => 00100001
32 => 23 (00110010 => 00100011
33 => 22 (00110011 => 00100010
34 => 27 (00110100 => 00100111
35 => 26 (00110101 => 00100110
36 => 24 (00110110 => 00100100
37 => 25 (00110111 => 00100101
38 => 2f (00111000 => 00101111
39 => 2e (00111001 => 00101110
3a => 2c (00111010 => 00101100
3b => 2d (00111011 => 00101101
3c => 28 (00111100 => 00101000
3d => 29 (00111101 => 00101001
3e => 2b (00111110 => 00101011
3f => 2a (00111111 => 00101010
The value on the left are the steering bits. The value on the right are what they get converted to by this algorithm.
After staring at this for a few minutes, I still could not see an obvious pattern. Maybe some smart guy reading this will be able to figure out the relationship of the source and destination values and impress us all? :)
UPDATE: As the comments say, this is Gray Code. The algorithm to convert the steering position back into Gray code is:
uint8_t u8GrayCode = (u8SteeringPosition >> 1) ^ u8SteeringPosition;
So for example, 0x3F is indeed (0x2A >> 1) ^ 0x2A.
At any rate, it occurred to me that I did not NEED to understand how the steering bits mapped to the steering mechanism. All I had to understand was what the algorithm was. And I had already found the algorithm in the assembly language.
So without understanding what the steering bits actually mean, I was able to implement the algorithm in Daphne and hook up my XBOX 360 wireless controller's analog stick to control the steering mechanism.
Here is a video of me carefully moving my analog joystick right to left:
My observation here is that while it's nice to understand exactly how everything about a game works, one does not need to understand everything in order to emulate it to some degree (although understanding things definitely improves the likelihood of accurate emulation).
Wednesday, February 19, 2014
Star Rider 19 Feb 2014
Now this is some exciting progress :)
Tuesday, February 18, 2014
Star Rider 18 feb 2014
I really was hoping to have a new, meaningful Star Rider video to show off today. But alas, it is not to be.
The accuracy level demanded by emulating this game properly is greater than most of the other laserdisc games that Daphne emulates. And thus, I had to take some time to improve Daphne's overall accuracy.
I am now pleased to report that Daphne will now provide hyper-accurate emulation of VBLANK* begin and end (relative to NTSC, I have not implemented the PAL counterpart). And when I say hyper-accurate, I mean that from the emulated ROM program's point of view, VBLANK will be accurate to within +/- 1 CPU instruction. And the accuracy won't drift over time, it will self-correct itself and stay accurate. This is something that's been on my TODO list for a long time so I am very happy to have finally implemented it. All games will benefit. This is something I felt like Star Rider needed since the ROM program relies heavily on accurately knowing the current vertical line.
So that part is done.
I also enabled strict CPU interleaving which basically means that each of Star Rider's CPUs will execute 1 instruction and then switch to the next CPU. This carries with it a potential significant performance hit but in practice, since each CPU is only 1 MHz, and since I designed my 6809 emulator with this scenario in mind, performance still perfectly adequate on my i5 CPU (may not be so good on a Raspberry Pi, though!). This pleases me greatly because accurate emulation really doesn't get any better than this (at least not in my book!). This was also something I felt was necessary for Star Rider because 1 CPU will send a signal to another CPU and expect a pretty fast response. That means they truly need to be executing in parallel.
Unfortunately, none of this can be portrayed in a video.
I am working on hooking up the frame number decoder now which should potentially allow me to show off a looping attract mode (woohoo!)
The accuracy level demanded by emulating this game properly is greater than most of the other laserdisc games that Daphne emulates. And thus, I had to take some time to improve Daphne's overall accuracy.
I am now pleased to report that Daphne will now provide hyper-accurate emulation of VBLANK* begin and end (relative to NTSC, I have not implemented the PAL counterpart). And when I say hyper-accurate, I mean that from the emulated ROM program's point of view, VBLANK will be accurate to within +/- 1 CPU instruction. And the accuracy won't drift over time, it will self-correct itself and stay accurate. This is something that's been on my TODO list for a long time so I am very happy to have finally implemented it. All games will benefit. This is something I felt like Star Rider needed since the ROM program relies heavily on accurately knowing the current vertical line.
So that part is done.
I also enabled strict CPU interleaving which basically means that each of Star Rider's CPUs will execute 1 instruction and then switch to the next CPU. This carries with it a potential significant performance hit but in practice, since each CPU is only 1 MHz, and since I designed my 6809 emulator with this scenario in mind, performance still perfectly adequate on my i5 CPU (may not be so good on a Raspberry Pi, though!). This pleases me greatly because accurate emulation really doesn't get any better than this (at least not in my book!). This was also something I felt was necessary for Star Rider because 1 CPU will send a signal to another CPU and expect a pretty fast response. That means they truly need to be executing in parallel.
Unfortunately, none of this can be portrayed in a video.
I am working on hooking up the frame number decoder now which should potentially allow me to show off a looping attract mode (woohoo!)
Thursday, February 13, 2014
Star Rider emulation progress
Got most of the ROM tests passing, two of them are still failing.
Colors are not correct, I just did a rough hack for the color palette.
Colors are not correct, I just did a rough hack for the color palette.
Tuesday, February 11, 2014
Star Rider boot
Got Star Rider booting inside Daphne. Don't have blitter chips (or the ROM PCB) emulated yet so this is as far as it's gonna go for a while.
Sunday, February 9, 2014
Star Rider VGG timers
If you designed this timer system, in 6 months, would you really be able to explain how it worked? :)
These were really hard to get because the design (and hence schematic) is a huge mess (I don't even know if the designers of the game knew what half of this crap did) and the timings came from a PROM. In other words, figuring this out by hand is really hard (I foolishly made an attempt). I ended up writing a little C program to figure it out for me which was a lot easier. The above graph is the results of my C program.
UPDATE: Warren got a capture on real hardware and it matches my emulated version perfectly! :)
A few observations:
- The main 6809E CPU runs at 1 MHz. This was what I assumed for a long time but now I've "proven" it for sure.
- The 4 MHz signal does not have a smooth rhythm. I had also assumed this since it gets derived from the 6 MZ clock. Had they derived it from the 12 MHz clock, they could've got the rhythm smooth. I assume that despite the unusual cadence that it still performs its function just fine (controlling the blitters).
- Plugging in the laserdisc video signal will throw these timers off temporarily. The game has a (pretty neat) mechanism to sync up to the laserdisc's video. Once in sync, I assume the timers will resume normal operation (not confirmed).
- Despite Q2 and CAS' being slightly different on the schematic, they appear to be identical in practice (at least as long as the laserdisc video input is not plugged in)
- Same thing with Q7 and 4 MHz. Q7 is connected to the 4 MHz flip-flop's clear pin, but this seems to have no effect (either that or I made a mistake).
- LATCH seems intended to begin after E and end before E.
- RAS' and CAS' are used to keep the video DRAM chips from losing their state. What a horrid thing to have to deal with from a designer's perspective :)
Friday, February 7, 2014
How to calculate the duration of NTSC lines and fields
I don't want to have to figure this out again, so here is the "exact" length of one horizontal line in microseconds. If you want seconds, remove the 1,000,000 number.
H = (1001 * 1000000 * 2) / (1000 * 60 * 525)
(this can be simplified down to 4004/63)
The "exact" length of one field (ie space between start of two adjacent vsync pulses) in microseconds is:
V = (1001 * 1000000) / (1000 * 60)
(simplified down to 50050/3)
H = (1001 * 1000000 * 2) / (1000 * 60 * 525)
(this can be simplified down to 4004/63)
The "exact" length of one field (ie space between start of two adjacent vsync pulses) in microseconds is:
V = (1001 * 1000000) / (1000 * 60)
(simplified down to 50050/3)
Physics/Engineering question (Composite sync to Vertical/Horizontal sync)
I remember learning some equations about capacitors in school but I've long since forgotten this stuff and now I find that it would actually be useful for solving the below problem.
Here is how the game, Star Rider, derives vertical and horizontal sync by getting a composite sync input. My question is, how? How can one solve this on paper and predict when vsync and hsync will go low by only knowing the timing to csync and the resistance and capacitor values of this circuit?
The timing to csync (composite sync) is shown here (item 'b'):
Csync will either be 5V or ground.
Here is the circuit used in Star Rider:
W3 is connected, W4 is unconnected. All of the NOT gates are a 74LS14.
Here is how the game, Star Rider, derives vertical and horizontal sync by getting a composite sync input. My question is, how? How can one solve this on paper and predict when vsync and hsync will go low by only knowing the timing to csync and the resistance and capacitor values of this circuit?
The timing to csync (composite sync) is shown here (item 'b'):
Csync will either be 5V or ground.
Here is the circuit used in Star Rider:
W3 is connected, W4 is unconnected. All of the NOT gates are a 74LS14.
Thursday, February 6, 2014
Testing response performance of solid state relay
So in my last blog post, I tested how responsive passing CSYNC was when passed through two open collector NAND gates. As you may have noticed, there was some delay due to the pull-up resistors we were using. So last night, I decided to test out how responsive passing CSYNC through a solid state relay would be. I did have a couple of extra solid state relays from when Dexter rev2 was built, but unfortunately, they are surface mount, so they are not very bread board friendly.
I decided to try to solder wires to the legs of the relay since it only has 4 legs.
My first attempt was disastrous because I used too thick of wires and it broke off one of the legs. Fortunately, I had two of these things!
My second attempt involved using much thinner wire, soldered to the thick stuff, and then inserted in the bread board. It worked, although it did take me a VERY LONG time to get the wires soldered to the legs.
The big question is, how did it perform?
Very well! In fact, even capturing at the maximum stable frequency, I was not able to see any lag from the source CSYNC and the CSYNC signal coming out of the relay.
I decided to try to solder wires to the legs of the relay since it only has 4 legs.
My first attempt was disastrous because I used too thick of wires and it broke off one of the legs. Fortunately, I had two of these things!
My second attempt involved using much thinner wire, soldered to the thick stuff, and then inserted in the bread board. It worked, although it did take me a VERY LONG time to get the wires soldered to the legs.
The big question is, how did it perform?
Very well! In fact, even capturing at the maximum stable frequency, I was not able to see any lag from the source CSYNC and the CSYNC signal coming out of the relay.
Sunday, February 2, 2014
Better CSYNC capture
Here's a better capture showing what I am talking about.
The green line is supposed to match the red line. The yellow line represents an intermediate state.
Red high to low transition:
The yellow line's initial lag of the red line is caused (in my opinion) by our use of a 10k pull-up resistor. Decrease the resistance may improve the timing here. The green line changes at the same time as the yellow line because we are using an open-collector NAND gate which goes low super-fast (much faster than it goes high).
Red low to high transition:
The yellow line responds "instantly" to the red's change here because again, we are using an open-collector NAND gate which responds much faster when going low (which the yellow line is doing in this case). However, since it's time for the green line to go high, it is very slow because it is using the AVR's internal pull-up resistor which has more resistance (apparently) than 10k. You may look at the timing and think "Ahh, it's just a few microseconds off, it won't matter" but I have yet to arrive at this conclusion.
I think it may be important to tweak this solution to try to get the green line more in sync with the red line.
The green line is supposed to match the red line. The yellow line represents an intermediate state.
Red high to low transition:
The yellow line's initial lag of the red line is caused (in my opinion) by our use of a 10k pull-up resistor. Decrease the resistance may improve the timing here. The green line changes at the same time as the yellow line because we are using an open-collector NAND gate which goes low super-fast (much faster than it goes high).
Red low to high transition:
The yellow line responds "instantly" to the red's change here because again, we are using an open-collector NAND gate which responds much faster when going low (which the yellow line is doing in this case). However, since it's time for the green line to go high, it is very slow because it is using the AVR's internal pull-up resistor which has more resistance (apparently) than 10k. You may look at the timing and think "Ahh, it's just a few microseconds off, it won't matter" but I have yet to arrive at this conclusion.
I think it may be important to tweak this solution to try to get the green line more in sync with the red line.
NAND gate speed with pull-up resistors?
In designing rev3, I noticed that we have 10k pull-up resistors on the NAND gate that is used to pass CSYNC to the PR-8210A interface. I decided to do a quick test to see how responsive this pass-thru was. I will want to do a more thorough test later.
This is the beginning of vblank:
Here is an extreme close-up of one of the small pulses. It's hard to tell at the moment whether we should reduce the resistance of that pull-up.
This is the beginning of vblank:
Here is an extreme close-up of one of the small pulses. It's hard to tell at the moment whether we should reduce the resistance of that pull-up.
Saturday, February 1, 2014
Subscribe to:
Posts (Atom)