Jump to content
IGNORED

Fixing Robotron Emulation


Tursi

Recommended Posts

Thanks to Marc's pointing out that it works much better on hardware than under emulation, I was able to work out the problem with the code, and a way to fix the emulation to support it.

 

The problem occurs very early on Classic99, and to some extent there are problems on MESS and Win994A as well (caveat, my version of MESS is older - double check on the newest one. I did use the newest Win994A. I did not test V9T9 as I don't have a current environment for it.)

 

On the very first title page, we have a really limited set of inputs that don't work, so I focused my efforts there. Later issues include the lack of ability to start the game with Enter, select 2 player mode, and change difficulty. In addition, and this happened on all the emulator tests I ran, '+' sometimes starts the game instead of just changing difficulty. This fix solves all of those, best I can tell.

 

The following code was what I looke at. First, this code reads the fire button (this works):

 

  7BDE    clr  R1              
 7BE0    ai   R1,>0600         --?? Alternate entry for player 2?
 7BE4    li   R12,>0024        
 7BE8    ldcr R1,3             -- set keyboard select for joystick
 7BEA    li   R12,>0006        -- read back on fire line
 7BEE    seto R1              
 7BF0    stcr R1,8             -- R1 is >FFFF if nothing, >FEFF if pressed
 7BF2    inv  R1               -- now >0000 or >0100
 7BF4    swpb R1               -- now >0000 or >0001
 7BF6    mov  R1,R1            
 7BF8    jeq  >7c02            -- skip if zero     
 7BFA    mov  @>6008,@>83d6    -- writes >0000 to screen timeout
 7C00    mov  R1,R1            -- set equal bit again, in case it's needed                 
 7C02    b    *R11 

 6484    ci   R1,>0001         -- test for button press
 6488    jeq  >649e            -- jump ahead if button was pressed

 

This code reads the Enter key (this does not work):

 

  7ACE  0204  li   R4,>0001     -- scan only one column
 7AD2  1005  jmp  >7ade        

 7ADE  04C1  clr  R1           
 7AE0  04C2  clr  R2           
 7AE2  020C  li   R12,>0024    -- set keyboard mode
 7AE6  30C1  ldcr R1,3         -- column 0
 7AE8  020C  li   R12,>0006    -- read back from enter line (includes +/=, space, enter, FCTN, shift, CTRL)
 7AEC  0705  seto R5           
 7AEE  3605  stcr R5,8         -- read data - R5 has >FFFF if nothing pressed, >FBFF if enter pressed (others possible!)
 7AF0  0545  inv  R5           -- R5 now has >0000 or >0400 (if I disregard non-enter keys for the sake of this flow)
 7AF2  C145  mov  R5,R5        -- test for zero
 7AF4  1606  jne  >7b02        -- jump if key pressed

* here for NO key pressed
 7AF6  E085  soc  R5,R2        -- R2 is already zero, so is R5, this does nothing       
 7AF8  0221  ai   R1,>0100     -- next keyboard column         
 7AFC  0604  dec  R4           -- count down
 7AFE  16F1  jne  >7ae2        -- if columns are left, loop (there are not in this case)
 7B00  045B  b    *R11         -- back to caller

* here for key IS pressed (and these comments will assume ENTER)  
 7B02  020C  li   R12,>0024    -- going to read back from where we set...?    
 7B06  3602  stcr R2,8         -- 8 bits? This is the weirdness. It sets, from LSb: KB2, KB1, KB0, AlphaLock, CS1_Ctrl, CS2_Ctrl, Audio_Gate, Tape_Out
 7B08  2885  xor  R5,R2        -- XOR the newly read value into R2. R2 /was/ >0400
 7B0A  045B  b    *R11         -- back to caller

* back at caller  
 648E  0282  ci   R2,>3c00     -- we explicitly check for >3C00. We only expect enter here.
 6492  1305  jeq  >649e        -- jump if we got it.

 

The readback of the 9901 at 7B06 is causing the issue in Classic99, and probably the other emulators as well. Some of these bits were not intended to be read. Alpha Lock is not even being primed for reading (row 4 has to be set) and so its true value is actually not available. Likewise, the Cassette control lines, Audio Gate, and Tape Out are output bits. Classic99 didn't implement readback of any of these bits, and returned them all as '1'.

 

In order to get >3C00 back from this function when Enter is pressed, the code clearly expects a value of >3800 from that read. That is, it expects KB0,1,2 to be 0 (which we just set them to, so that is fair). It expects AlphaLock to be high (also fair, because it is not selected it can not pull the line low regardless as to whether it is up or down. Both Cassette control lines are expected to be high, which is the normal state for the console. Audio gate is expected to be low, which is a little surprising but it is an inverted control (0=audio on), so this is also normal. And mag tape out, of course, is low by default.

 

Besides the CRU bits, which arguably are probably handled in the emulators already (though double-check the behaviour of scanning alpha lock when row 4 is not selected), the handling of the reserved P0 (R12 address >0020), Audio Gate, Cassette Control lines and Mag Tape out needs to be handled. Of all of the I/O pins on the 9901 (R12 addresses >0020->003E), only P0 (>0020), P5 (>002A, Alpha lock input, oddly), Audio gate, and the cassette control lines are initialized by the console. Mag tape out is not, so it needs to be initialized to a zero level for this code to work.

 

Fixing this behaviour, including the unimplemented bits, makes the Robotron title screen work on Classic99, including player select and difficulty change (because the same routine is used to read keys there). Feel free to use this info elsewhere!

Edited by Tursi
  • Like 3
Link to comment
Share on other sites

Hi Tursi,

 

I just tried to run Robotron 2084 in MESS, and the Enter key is working properly, so this may be fixed in the meantime. Seems as if I fixed that when rewriting the 9901 some time ago. The only thing I notice is that sometimes I get a black screen after the intro with the colored frames, and for two player game this always happens, so I have not yet seen a successful level start with two players. Also, QUIT seems to be broken; I get a blue backdrop, and a lockup.

 

[Edit: Correction, I just got a two player game working (players take turns when one has been killed). Sometimes, though, I'm getting a black screen only, and also for the single player game.]

Edited by mizapf
Link to comment
Share on other sites

I'll have to re-test, but IIRC QUIT seems to fail sporadically on the hardware, too - Robotron changes up the user-defined interrupt constantly, and the user-defined interrupt /always/ executes on QUIT before it is cleared by the console, so it's very possible that is being properly emulated and just doesn't properly handle the case on some of those interrupt functions. I definitely saw the same issue you are describing there.

 

The keyboard glitch I saw in MESS has to do with '+' occasionally starting the game, so try hammering '+' on the difficulty select screen (alternately - just check and make sure you are emulating the unused CRU pins correctly ;) ) Enter /did/ work in MESS, so did '1' and '2', and '+' also normally incremented the difficulty. In short, MESS was closest to right. :)

 

I did not investigate any issues /past/ the title screen, so I can't help you a too much there... but I'd say fix the obvious issues first then see if the others still exist. :)

 

Link to comment
Share on other sites

By the way, Robotron reminds me of another game which I very much enjoyed, and I just tried it once more: Guardian. Also with robots, they try to carry away the energy pods on the screen, and with later levels you're getting more and more stressed, as several of them carry them away in different directions.

 

Guardian has some peculiarity: it makes use of the IDLE opcode, which you can notice by the dimmed flex cable interface LED. (Too bad I still have not included things like external LEDs in MESS :) )

Link to comment
Share on other sites

Slymoids uses IDLE too, which I always found interesting. I understand why they were discouraged in the 99/4A but I've always meant to spend some time investigating what side effects are possible on a fully loaded system.

 

The game you describe sounds a lot like the arcade Rip-Off. I had the Vectrex port of that, and it was pretty fun. :)

 

Link to comment
Share on other sites

By the way, the TM990/189 systems had a bunch of features invoked by the "discouraged commands", i.e. there was circuitry for LREX (reboot via LOAD interrupt), RSET (not used), CKOF/CKON (tape motor control), IDLE (idle state, signalled by a LED). I had to learn a bit of these systems when I rewrote the 9902 (RS232) and 9901 in MESS and after that earned the job to get that 990/189 running again.

 

With the IDLE you could do a "wait for vsync".

Link to comment
Share on other sites

Yep. IDLE would be a useful command on the 4A, the others not so much (without hardware). But they pulse the CRU lines all the same, so I wanted to compare against existing peripheral cards and see if they had any side effects.

 

Link to comment
Share on other sites

You should have a look at the document ftp://ftp.whtech.com/datasheets%20and%20manuals/Datasheets%20-%20TI/9900-FamilySystemsDesign-1stEdition/9900-FamilySystemsDesign-04-Hardware%20Design.pdf. This was arguably the most important document for my works on the 99xx CPUs in MESS. On pages 4-45 ff. you have a detailed description of the CRU and external instructions.

 

I am not 100% sure, but my guess would be that nothing noticeable happens except that the 9901 may be put into interrupt mode if it was in clock mode before. This is the case because the console does not decode A0-A2, which are nonzero for the external instructions, and I *assume* that A3-A15 are zero (but I have not found real evidence for this) which would select the 9901.

 

In the same document on page 4-102 we can find the steps of command execution, and after setting the address bus with the location of the command there is a sequence of "NC" (no change) until there is a line "AB=external instruction code" (AB=address bus). Bu they do not say whether bits A3-A15 are affected, only which values show up on A0-A2. If A3-A15 are zeroed, we have an access to address 0 of the console 9901 (which is the mode bit); if not, there would be the part of the address of the control instruction (where it was loaded from), and this could have an effect on any device connected to the CRU bus (depending on the location of the instruction).

 

There is also some note that there is no output on the CRUOUT during an external instruction. This would also raise the question if the line is floating during that time or if it is low. In any case, this would only mean something for the 9901 if the above thoughts are right.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...