It is currently Wed Sep 19, 2018 3:33 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Thu Sep 29, 2016 3:11 pm 
Offline
User avatar

Joined: Mon Dec 29, 2014 1:46 pm
Posts: 817
Location: New York, NY
Here is the Nocash spec for the RacerMate Bicycle. How does the bicycle align the data packets? I.e. within the data stream, how does it know where the packet starts and ends?


Top
 Profile  
 
PostPosted: Sat Aug 04, 2018 2:46 pm 
Offline
User avatar

Joined: Mon Dec 29, 2014 1:46 pm
Posts: 817
Location: New York, NY
After a lot of trial and error, I managed to fill in the holes in Nocash's spec and I added support for the RacerMate CompuTrainer exercise bike to the latest build of Nintaco. If anyone wants to test their finger tapping skills, here's some information on how to use it.

For emulator authors, here's what I found:

First, the wiki describes a binary counter that triggers an interrupt every 1024 M2 cycles. However, Nocash claims:

Quote:
In practice, 1024 clks per IRQ seems to be too slow (video glitches), 512 clks too fast (1/10 second counter increases non-linear), so, the IRQ rate is probably something around 768 clks.


On this topic, I found the wiki to be accurate. 1024 clks per IRQ does the job.

Regarding IRQ acknowledgement, the wiki claims:

Quote:
Only one of the 9 above bits is used, but the software has no a priori reason to know which. The firmware thus writes $FF to $F080 and $00 to $F000.


However, Nocash says:

Quote:
[F080h]=FFh disable IRQ and/or reset IRQ-counter or so
[F000h]=00h enable IRQ and/or start IRQ-counter or so


To get it to function, I created a flag that turns the counter on and off. When the game writes to $F080, the flag is cleared, the counter is reset and the interrupt is acknowledged. When the game writes to $F000, the flag is set. When the flag is set, the counter advances once per CPU cycle, eventually triggering an interrupt after 1024 of them.

I found that Nocash's description of the communication protocol is generally correct. Writing to $4016 puts a bit into a temporary register and reading from $4016/$4017 transfers that bit out and simultaneously reads a bit in from one of the bikes. Each transfer packet contains 3 bytes of data. However, each bit to be transferred is converted to 2 bits during transmission. Zero is represented by 10 and one is represented by 01. Consequentially, 3 bytes gets turned into 48 bits. But only 24 bits go out per frame. To make matters worse, there maybe writes/reads between packet halves, adding noise that needs to be skipped.

The main complexity is alignment. The bike probably only detects when the signal drops (a zero bit) or the signal rises (a one bit); hence, the purpose of the bit doubling. The bike also contains a high precision clock. With this alternating scheme, it's possible for 2 of the same bit values to come in a row, but not 3 or more in a row. As a result, it's possible to look a stream of bits and work out the alignment parity. But the bike also needs to work out the transfer-packet-half start points. Per Nocash, the first packet half starts with 0 and the second half starts with 1. In addition, the first half starts with the sequence 110100. The bike uses all this information and the fact that it expects packet halves every 1/60th of a second to complete the alignment.

Luckily, an emulated implementation can cheat a bit. The start of each packet half is triggered by an NMI. The first bit transferred after that determines the packet half. Alternatively, and this what Nintaco does, the start of the packet can be determined by the value written to $4016. $BB or $EE indicates the start of the first half. And $33 or $CC indicates the start of the second half. Well, almost. Sometimes those values will appear within a packet. However, you can get around this by waiting for 24 bits to be transferred before using those indicators again. That scheme works for all the RacerMate Challenge II versions in GoodNES 3.23b. In fact, I suspect that Nocash also used this trick, though his source code is unavailable. But I think he only checked for $BB and $CC. Those are the values that appear in the latest US version. The older US version and the EU version requires the aforementioned additional checks.

Per Nocash's description, the transferred and received packets are offset by 1 bit. That is, the first bit out does not correspond to a bit in. However, the second bit out does. One thing that Nocash fails to mention is that for the second player bike, the receive packet is offset by 2 bits. Meaning, from that bike's point of view, the first and second bits out do not correspond to any bits in.

Regarding the button bits, Nocash could not figure out the purpose of bit 7:

Quote:
7 Unknown/unused? (?)


I found that in the EU version, one button bit must always be set and multiple buttons cannot be pressed simultaneously. I think bit 7 is set when no other buttons are pressed. Without doing that, the EU version does not work. And the US version does not care about the bit 7 value either way.

Nocash could not figure out RPM either either:

Quote:
Unknown if/how/where RPM is transferred.


I discovered that RPM is transferred using index 6. However, the game will only accept it if the highest data bit (data bit 11) is set.

In fact, index 4 and index 5 may do something RPM related as well. There is a screen in the program that shows a torque chart. Torque is computed from RPM, but I never figure out a way for anything to show up on that plot. The plot is supposed to show the difference in torque between your left and right legs. Maybe separate left and right cadence values go over those indices. But nothing showed up while I was experimenting with it. I could just be using that screen incorrectly; I'm not sure.

Each transfer packet contains one of the grade, wind speed, player weight, pulse target, etc. values. The device responds to this data by adjusting the resistance of the bike. The bike does not physically tilt based on the grade. Nintaco uses a simple physics model to simulate the bike; basically, you have to tap faster when going up hill or when there is a lot of wind.

The wiki also mentions that the game has 64K of battery-backed CHR RAM. That appears to be the case. The game records a history of it's user. I don't recall any other game with so much CHR RAM and certainly none that had nonvolatile CHR RAM.

The Nintaco source is available here for anyone else crazy enough to implement this. Simply search the code for "racermate".


Top
 Profile  
 
PostPosted: Sat Aug 04, 2018 3:50 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7519
Location: Seattle
zeroone wrote:
To get it to function, I created a flag that turns the counter on and off. When the game writes to $F080, the flag is cleared, the counter is reset and the interrupt is acknowledged. When the game writes to $F000, the flag is set. When the flag is set, the counter advances once per CPU cycle, eventually triggering an interrupt after 1024 of them.
To be perfectly clear, the IRQ is implemented using a 74'4040 (U10) on the PCB, and this bit is specifically stored in the pins 8-13 half of the 74'74 (U9). Just like all the various pirate IRQs, when the bit is high, the 74'4040 is held in reset, and its contents are forced to 0 continuously. When the bit is low, the counter counts M2 cycles.

As the wiki says, the bit is latched on writes to $C000-$FFFF.

The IRQ output is the inversion of the 1024s bit of the 74'4040.

... I should probably rewrite the wiki a little to make this clearer.

Quote:
The wiki also mentions that the game has 64K of battery-backed CHR RAM. That appears to be the case. The game records a history of its user. I don't recall any other game with so much CHR RAM and certainly none that had nonvolatile CHR RAM.
Pedantically, only half of it is battery backed. Even so, it's more than a little ridiculous.


Top
 Profile  
 
PostPosted: Sat Aug 04, 2018 4:23 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6801
Location: Canada
It's the one that directly inspired those strange new fields in the iNES 2 spec for partially battery backed CHR-RAM.

Though I would say that battery backed CHR-RAM is a really practical idea, especially given how popular CHR-RAM is for homebrew these days, so I'm glad it kinda creeped into the spec via this less sane precedent.


Top
 Profile  
 
PostPosted: Mon Aug 06, 2018 7:04 am 
Offline
User avatar

Joined: Mon Dec 29, 2014 1:46 pm
Posts: 817
Location: New York, NY
One other thing, the EU version of RacerMate Challenge II detects the TV system type on startup and it adjusts itself accordingly. It actually displays NTSC / PAL Mode on its title screen. The handlebar controller is able to detect and compensate for this during packet synchronization. However, as mentioned above, an emulator has other means of doing this that will work in either mode.

Related, did anyone ever assemble a list of all the known games capable of functioning in both TV modes?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group