Microvision Technical Documentation ----------------------------------- V1.01 K.Horton 01032013 Sound: ------ Sound is simply a piezo element. On Connect Four it is simply connected between two port pins. Emulating it is not as straight forward as you'd expect, but it isn't difficult either. Basically, the two port pins bidirectionally drive it, first one way then the other. It's a capacitive load so this makes sense. The games don't HAVE to drive it this way, however, so I suggest using the following values to translate the output into noise: speaker 0, speaker 1 output ------------------------------ 0 0 0.00 1 0 +0.50 0 1 -0.50 1 1 0.00 This will properly handle cases where the software may only toggle one of the two lines. For the 8021, the speaker is connected to P2.0 and P2.1. For TMS1100, it is driven one of two ways- either using R0 and R1, or using just R0. The former method will be louder than the latter. For emulation, the R0/R1 method can be used. LCD: ---- The LCD is a 16*16 matrix, with a 40 pin ASIC driving it. The LCD is the usual passive matrix kind, albeit a very early iteration of it. It's renowned for breaking down and failing over time because of the seals leaking. Leaving a half dead battery in the system is another way to damage the LCD. The microprocessor stops running but the LCD is still getting biased, and since it is no longer getting driven properly, DC is applied to the glass which destroys the liquid crystal material. I dumped the Connect Four cartridge's 8021 CPU and inspected the code, and they are "short scanning" the LCD, only scanning 12 of the 16 rows. I don't think this is particularly bad for it, but it will definitely mess with the contrast compared to a game that scans the entire display (it will appear darker when short scanned). For the discussion about the LCD, I will use the following convention: +-----------+ | | row 0 | | | LCD | | | | | | | row 15 +-----------+ col col 0 15 Where column 0, row 0, is the upper left corner, and column 15, row 15 is the lower right corner. The LCD appears to be designed to be scanned in this fashion from what I can tell by the code and how it's hooked up to the ASIC. Speaking of ASIC, here is how it works: There's 6 control lines between the CPU and the ASIC. There's 2 control lines and 4 data lines. Data is written to it 4 bits at a time. This makes sense, since it was designed to be connected to a TMS1xxx 4 bit microcontroller. I will refer to the pins as per the DanB schematics and technical documentation. http://atarihq.com/danb/Microvision.shtml note: All of the connections to the LCD glass and keypad are shown reversed in the schematic, so I will not refer to them, and instead use my own. There's only really 6 pins of interest on the ASIC as far as using the display is concerned, so I will focus on them. The schematics for the unit and a typical cartridge are on his site. On the ASIC there are 6 control signals labelled LCD0 through LCD5. LCD0, 1, 2, 3 are the 4 data lines (D0, D1, D2, D3 respectively) and LCD4 and LCD5 are the two control lines. The controller only "does stuff" when the control lines CHANGE STATE. That is, everything is edge triggered. old new 5 4 5 4 (LCD control pins) ---------- 0 0 -> 0 1 Toggle XOR toggle latch 0 0 -> 1 0 Latch data in holding registers 1 0 -> 1 1 Update drive latches and reset pointer All other states are "do nothing" states. I will refer to the control word as a value between 0 and 3 to simplify: LCD5 LCD4 digit ---------------- 0 0 0 0 1 1 1 0 2 1 1 3 When the state changes from 2 to 3, the 32 bits of data in LAT0-LAT7 are transferred to the two 16 bit output latches, and the write pointer is reset. When the state changes from 0 to 2, data on D0-D3 is written to LATx, then the pointer is incremented. So the first write will go to LAT0, the next to LAT1, and so on. After all 8 are written to, the pointer wraps back around to LAT0. Here's a drawing of how the LCD system is connected: ------+ D0-D3 | ---+ | +----+ +-----+ +----+ +------------------------------------+ | +--| |----| |--| |--| | | 4 |LAT0| 4 | | | | | row 0 | | +--| |----| | | | | | | | +----+ | |1 | |1 | | | | | |6 | |6 | | | | +----+ | | | | | | | +--| |----| |b | |b | | | 4 |LAT1| 4 | |i | |i | LCD GLASS | | +--| |----| |t | |t | | | | +----+ |OUTPT|s | |s | | | | |LATCH| |XOR | | | | | +----+ | | | | | | | +--| |----| | | | | | | 4 |LAT2| 4 | | | | | | | +--| |----| | | | | | | | +----+ | | | | | | | | | | | | | | | | +----+ | | | | | | | +--| |----| | | | | | | 4 |LAT3| 4 | | | | | row 15 | | +--| |----| | | | | | | | +----+ | |--| |--| col 0 col 15 | | | +-----+ +----+ +------------------------------------+ | | | | 16 bits | | | | | | | | | +------------------------------------+ | | *----| | | | +-------+ | | XNOR | | | |invert |-----+ +------------------------------------+ | | |toggle | | 16 bits | | | +-------+ | | | | +------------------------------------+ | | | OUTPUT | | | | LATCH | | | +------------------------------------+ | | | 4 | | 4 | | 4 | | 4 | | | +-----+ +-----+ +-----+ +-----+ | | |LAT4 | |LAT5 | |LAT6 | |LAT7 | | | +-----+ +-----+ +-----+ +-----+ | | | 4 | | 4 | | 4 | | 4 | | +--------------------------------+ +----+ +----+ +----+ | | | +------------------------------------------------------------------+ Write mapping: LAT0: LAT4: D3 = row 0 D3 = col 0 D2 = row 1 D2 = col 1 D1 = row 2 D1 = col 2 D0 = row 3 D0 = col 3 LAT1: LAT5: D3 = row 4 D3 = col 4 D2 = row 5 D3 = col 5 D1 = row 6 D3 = col 6 D0 = row 7 D3 = col 7 LAT2: LAT6: D3 = row 8 D3 = col 8 D2 = row 9 D3 = col 9 D1 = row 10 D3 = col 10 D0 = row 11 D3 = col 11 LAT3: LAT7: D3 = row 12 D3 = col 12 D2 = row 13 D3 = col 13 D1 = row 14 D3 = col 14 D0 = row 15 D3 = col 15 Before continuing, a little "LCD 101". For a pixel on the LCD to darken, there must be a voltage differential across it. i.e. to darken the upper left corner pixel, column 0, row 0 must have a voltage across it. Say, v+ on col 0 and ground on row 0. This pixel will darken. The polarity of the voltage does not matter- ground on col 0 and v+ on row 0 will work just as well. However, if both electrodes are the same voltage (ground, ground or v+, v+) the pixel will not darken. Now, applying DC to the LCD glass like this is damaging to it in the long term. That's why every frame the invert toggle is toggled. This will change polarity of the row and column electrodes every frame. That way the average DC voltage across the glass is 0, because the inverse and true driving waveforms exactly cancel out over many frames. This is how LCDs are still driven to this day, and for the same reason. Now that's out of the way, the LCD is scanned by enabling a single row or column of it and outputting 16 pixels of data on the other. Connect Four scans the rows and outputs data to the columns, but the other games might do it by scanning columns and outputting pixels to the rows. Here's how Connect Four drives the chip, and what happens: At the entry to the display update routine, the control word is 2. 1) control = 3 ;this latches the 8 data latches into the output latches 2) control = 2 ;this is the falling edge of the latch command, does nothing 3) dec scanline count. if this is a new frame: 4) control = 0 ;this is another falling edge and does nothing 5) control = 1 ;this toggles the toggle latch 6) control = 0 ;falling edge and does nothing 7) the scanline count is reset to Ch. This game only has 12 rows to scan 9) the scan word is loaded with 0002h. this word is for the row drivers skip to here if not a new frame: 10) left shift scan word 11) send scan word to the LCD controller: a) output low 4 bits, control = 0 b) output low 4 bits, control = 2 ;this latches data into LAT0 c) output next 4 bits, control = 0 ;falling edge, does not latch d) output next 4 bits, control = 2 ;this latches data into LAT1 e) above 4 steps repeated for other byte 12) send two bytes of RAM to the LCD controller: a) output low 4 bits, control = 0 b) output low 4 bits, control = 2 ;this latches data into LAT4 c) output next 4 bits, control = 0 ;falling edge, does not latch d) output next 4 bits, control = 2 ;this latches data into LAT5 e) above 4 steps repeated for other byte 13) done thus, the last thing written to control was 2, so the update loop enters with it equal to 2. Connect Four stores its screen data at addresses 26h-3Dh, and the two bytes for the scanning word in 3Eh and 3Fh. The game loads a counter with 0ch (12d) at the start of the frame, then multiplies this counter by 2 and adds 24h to start reading data at 03ch. This address is used to fetch data at 03ch/03dh for the first scanline (which shows up at the bottom of the screen). The counter is decremented to 0bh (11d) which then will produce address 03ah, which is used to fetch data from 03ah/03bh for the next line above the first, and so on. It scans the display bottom to top, and reads data from RAM 'backwards' to compensate. The scanning word is loaded with 0002h which is first left shifted to 0004h before it's sent out. This selects row 13 as the first row to display data on. Next time it's shifted to 0008h which will select row 12, and so on until it is on the last displayed row. Data from RAM is sent to the columns, low byte on the left, high byte on the right of the row. So data appears like so: (addr) (addr+1) row x: 76543210 76543210 ---- Emulating the driver can be done using pseudocode like this: //pixel[0,0] is in the upper left corner //pixel[0,1] is to the right of pixel[0,0] int pixel[16,16] //256 pixels on the display. 16, 16 pixel rows int latches[8] //8 latch nybbles int oldcontrol //old control bit state int latpoint //latch pointer const onpixel = 10 //starting value for an "on" pixel //control = 2 bit control word //data = 4 bits of data lcdupdate(int control, int data) { int i,j; int row, col; int temp; if ((control == 2) && (oldcontrol == 0)) { latches[latpoint & 0x7] = data; // write data to latch latpoint++; // inc pointer } elseif ((control == 3) && (oldcontrol == 2)) { latpoint = 0; // reset pointer // build row and column variables row = latches[3] | (latches[2] << 4) | (latches[1] << 8) | (latches[0] << 12); col = latches[7] | (latches[6] << 4) | (latches[5] << 8) | (latches[4] << 12); for(i = 0; i < 16; i++) { temp = row; // make copy of row for(j = 0; j < 16; j++) { if (~temp ^ col & 0x8000) pixel[j,i] = onpixel; // if pixel on, load w/ onpixel value temp <<= 1; // check next pixel in row } col <<= 1; // check next column } } oldcontrol = control; // detect changes next time around } lcdframe() { int i; for(i = 0, i < 16; i++) for(j = 0, j < 16; j++) { if (pixel[i,j] > 0) pixel[i,j]--; } } lcdupdate() is called every time the LCD control port is written to. lcdframe() is called once a display frame of the emulator (i.e. 60Hz). Basically what happens is this: whenever pixels are lit up, they will stay that way until lcdframe() decrements them back down to 0. This simulates the ghosting effect on the LCD. I dunno the time this takes, so I just threw 10 in there for fun. Obviously this number can be changed to control how long it should be, as can the decrement rate or scale factor. But this is how it could be emulated. This code should properly handle all methods the games used to scan the LCD, be it row at a time or column at a time, left to right or right to left. I used XOR between the two bits, because the game might send inverted data or true data, and this handles both cases properly. The LCD inversion is not emulated, since it does not have to be. There's no visible effects of it on the LCD. --- Keypad ------ The keypad on the Microvision is a simple 3*4 membrane dealy. It directly connects to the microcontroller in the game cartridge, so emulating it might be slightly tricky, since it varies based on how they decided to read it. Though, I suspect only two methods were used: The 8021 uses the pullups on the chip, and outputs all 1's to all 7 of the keypad connections (4 rows and 3 columns). To read some keys, they pull one of the rows or columns low, and read the other looking for any 0's to come back. If they do, a key is pressed. 8021 keypad hookup: +----+ +----+ +----+ P0.7 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ P0.6 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ P0.5 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ P0.4 o---| |--| |--| | +----+ +----+ +----+ | | | o o o P0.2 P0.1 P0.0 The TMS1100 is the exact opposite. The Kx inputs have pulldowns on them, and connect to the 4 rows, while the 3 columns connect to Rx outputs. The TMS1100 then outputs a high on one of the row Rx pins, and reads the K inputs to determine if a key is pressed. TMS1100 keypad hookup: +----+ +----+ +----+ K8 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ K4 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ K2 o---| |--| |--| | +----+ +----+ +----+ | | | +----+ +----+ +----+ K1 o---| |--| |--| | +----+ +----+ +----+ | | | o o o R10 R9 R8 NOTE: If the game uses the paddle, the K8 row of buttons is not used. Pot: ---- The 8021 and TMS1100 read it differently as you can imagine. 8021 method: ------------ P2.2 and P2.3 are paralleled to increase output current. These two lines run to the RC circuit on the paddle: P2.2/3 o | < < | | *-----o T1 | --- --- | | < < | --- - P2.2/3 ----------------|___|------------------------------ T1 ------------------|_|------------------------------ closeup: P2.2/3 -------|__________________________|---------------- T1 ----------------------------|_____|---------------- ^ position of this pulse varies On Connect Four, the paddle is read very slowly, only every 388ms. P2.2/3 is pulsed low and T1 is tested to see how long it takes to go low. Here is the code that reads the pot: 005C: 23 01 MOV A,01 005E: 3A OUTL P2,A ;pull the pot pins (P2.2/3) low. 005F: BA 0C MOV R2,0C ;initial count 0061: 46 65 JNT1,65 ;is the T1 input low? 0063: EA 61 DJNZ R2 61 ;no it isn't, so decrement R2 and try again 0065: 97 CLR C ;clear carry 0066: FA MOV A,R2 ;move R2 to A 0067: 67 RRC A ;divide reading by 2 0068: AA MOV R2,A ;move it back into R2 0069: 1A INC R2 ;increment. R2 will be between 1 and 7 006A: 23 0D MOV A,0D 006C: 3A OUTL P2,A ;pull the pot pins high again. Emulating this is very easy. When P2.2/3 is high, T1 should be high. When P2.2/3 go low, a varying amount of time is taken before T1 should go low. T1 will stay low until P2.2/3 goes high again. You can count T0 reads, or use time. I measured the pulse widths of T1: Minimum time was 160uS when the paddle's turned clockwise, and max time was 670uS with it counter clockwise. These times are due to how long this piece of code takes to run. If you count T0 reads, it should take from 0 to 14 (in the case of Connect Four). I suggest a maximum number of more than this, though- say 25-30 to account for any other games if they are found. The game internally processes the read count to return a number from 1 to 7 as show in the code snippet above. TMS1100 method: --------------- There's two different methods that the pot is read. One uses an op-amp as a comparator, the other doesn't. It appears the method used to read both is the same. (The same game has been found to use both boards). I put the original first paddle circuit on the scope and tested it, and then tested the second improved version. Interestingly the first paddle circuit seems very crappy and the result of it was a horror show on the scope. It's using K8's trigger level to function and this cannot be very good. The second improved version works very well in contrast. I tested Blockbuster and Pinball. R2 is used to discharge the capacitor. When R2 is low, the capacitor on the paddle RC circuit is discharged. When R2 goes high, the capacitor charges through the paddle's pot and makes K8 go high after a delay determined by what position the pot is in. R2 ____________|---|_________________________|---|_________________ K8 _____________|--|__________________________|--|_________________ closeup: R2 _______|---------------------------------------------|___________ K8 __________________|----------------------------------|___________ ^ this point moves back and forth dependent on paddle pos. On Pinball, the R2 pulse occurs at a rate of 98Hz, and the pulse width is 1240uS. Because there is a 1.6K resistor in series with the paddle's pot, there is a minimum time delay, which is 360uS. The pot is 10K, so the maximum resistance is then 11.6K. When the paddle is turned all the way counter clockwise, the time delay is 360uS. When it is all the way clockwise, this delay is 2663uS. Pinball's R2 pulse is only 1240uS, so that means the entire paddle range is not used. Only a bit over 1/3rd of the paddle's range is useful on Pinball. Blockbuster works similar, but it reads the paddle at 54Hz instead of 98Hz. Emulating this is also very straight forward. When R2 goes low, K8 goes low. When R2 goes high, count CPU cycles (or some other quanta) then make K8 go high after the desired time delay. If R2 goes low again before the time delay is up, K8 also goes low. NOTE: If the game uses the paddle, the K8 row of buttons is not used. Individual game connections --------------------------- Boards: So far, I have found 5 different kinds of boards. 8021 boards: The first and only? version of this board is the 4971-REV-C. It's got the 8021 on it, and an LC for the CPU oscillator. There's an extremely low parts count on this board. Just the 8021, LC, an electrolytic cap, a diode and a resistor. The LC oscillator runs at 2MHz. 8021 CPU ports: P0.0 - keypad column 2 P0.1 - keypad column 1 P0.2 - keypad column 0 P0.3 - nc P0.4 - keypad row 3 P0.5 - keypad row 2 P0.6 - keypad row 1 P0.7 - keypad row 0 P1.0 - control 0 LCD driver P1.1 - control 1 LCD driver P1.2 - nc P1.3 - nc P1.4 - D0 LCD driver P1.5 - D1 LCD driver P1.6 - D2 LCD driver P1.7 - D3 LCD driver P2.0 - speaker 0 P2.1 - speaker 1 P2.2 - pot P2.3 - pot --- TMS1100 boards: The first version appears to be the 4952 REV-A. This board has a TMS1100, the first iteration of the paddle circuitry (no 741 op-amp) which apparently was somewhat flaky. There's two stuffing variations of 4952 REV-A; one has the paddle circuitry, and one does not. Various paddle games using this board changed the values of the resistors a little from game to game, probably to account for process variations in the TMS1100's. I suspect this is why the REV B board was made- to remove the effect of these variations on the paddle circuit. --- After the first board is the 4952-56 REV-. there is no revision listed- it just ends as shown. It appears to be the same circuit as the first board, just better layout and includes resistors on the LCD driver lines. --- The next version of this board is the 4952-79 REV B. The difference is the added paddle circuitry. This added circuit is composed of a 741 op-amp and a transistor. This circuit is simply a comparator- it sets a defined threshold voltage. The older REV-A board doesn't have this, and it just uses the TMS1100's input threshold voltage which could vary from unit to unit. As before, there's two stuffing variations of the 4952-79 REV B. One with the paddle circuitry and one without it. Every game that uses this board uses the same parts values on the paddle circuitry. --- The final? version of the board is the 7924952D02 was found on Super Blockbuster. The other Euro releases miiight have this board too. It's identical to the 4952-79 REV B board, except it's designed for the shrink DIP version of the TMS1100. --- There were three speeds used on the various TMS1100 boards: 550KHz oscillator: RC = 21.0K 1% / 100pf 500KHz oscillator: RC = 23.2K 1% / 100pf 300KHz oscillator: RC = 39.4K 1% / 100pf --- TMS1100 CPU ports: R0 - speaker 0 R1 - speaker 1 (not connected to the speaker on the 4952-79 REV B board) R2 - pot discharge (low = discharge, hi = allow RC charge) R3 - nc R4 - nc R5 - nc R6 - control 0 LCD driver R7 - control 1 LCD driver R8 - keypad column 2 R9 - keypad column 1 R10 - keypad column 0 K1 - keypad row 3 K2 - keypad row 2 K4 - keypad row 1 K8 - keypad row 0 or paddle input Cartridges: ----------- Below is a list of each game and the kind of board I found inside it, along with the type of CPU on it and the speed the CPU is clocked at. First is the handy-dandy short form grid name chip paddle clock dumped ------------------------------------------------- Alien Raiders M34009 X 500KHz Baseball MP3479 X 500KHz Blockbuster MP3450 X 500KHz X Bowling MP3475 500KHz Connect Four 2065 X 2MHz X Cosmic Hunter M34017 500KHz Mindbuster MP3457 550KHz X Pinball MP3455 X 550KHz Sea Duel MP3496 300KHz Phaser Strike MP3454 550KHz X Super Blockbuster M34047 X 500KHz Vegas Slots MP3474 500KHz X And what I found for each cartridge I took apart Cosmic Hunter (4177) -------------------- * 4952-79 REV B, no paddle circuitry. TMS1100NLL, M34017-N1 500KHz oscillator Alien Raiders (4176) -------------------- * 4952-79 REV B, has paddle circuitry. TMS1100NLL, M34009-N1 500KHz oscillator Super Blockbuster (4978) ------------------------ * 7924952D02, has paddle circuitry. M34047-N2LL (shrink dip) 500KHz oscillator Pinball (4974) -------------- * 4952 REV-A, has paddle circuitry. MP3455NLL 550KHz oscillator * 4952-79 REV B, has paddle circuitry. MP3455NLL 550KHz oscillator Baseball (4063) --------------- * 4952-79 REV B, no paddle circuitry. MP3479-N1NLL 500KHz oscillator * 4952-56 REV-, has paddle circuitry. MP3479-N1NLL 500KHz oscillator Sea Duel (4064) --------------- * 4952-79 REV B, no paddle circuitry. 4064, MP3496-N1 300KHz oscillator Bowling (4972) -------------- * 4952 REV-A, no paddle circuitry. MP3475NLL 500KHz oscillator Vegas Slots (4975) ------------------ * 4952 REV-A, no paddle circuitry. MP3474NLL 500KHz oscillator Mindbuster (4976) ----------------- * 4952 REV-A, no paddle circuitry. MP3457NLL 550KHz oscillator Phase Strike (4973) ------------------- * 4952 REV-A, no paddle circuitry. TMS1100NLL, MP3454 550KHz oscillator Blockbuster (4952) ------------------ * 4952 REV-A, has paddle circuitry TMS1100NLL, MP3450A 500KHz oscillator * 4952 REV-A, has paddle circuitry MP3450ANLL 500KHz oscillator Connect Four (4971) ------------------- * 4971-REV-C, has paddle circuitry P8021 2065 2MHz oscillator 01234567890123456789012345678901234567890123456789012345678901234567890123456789