Hacking Asteroids

Macro

Active member
vacBacker
Feedback
4 (100%)
Credits
1,982CR
I always try to hit the ground running, could never be bothered with all that walking nonsense. of course, you fall over from time to time and get some grazes on the way, but makes it all the more fun!

apart from that it's pretty much the same as putting real pacman code on a world cup 90 PCB - one CPU runs the pac code, the other two (and the extra interrupt code on the first) try and convert the output from that into characters, sprites and noises

Look forward to seeing the results.
 

DanP

Administrator
Staff member
vacBacker
Feedback
5 (100%)
Credits
2,190CR
Macro said:
I always try to hit the ground running, could never be bothered with all that walking nonsense. of course, you fall over from time to time and get some grazes on the way, but makes it all the more fun!apart from that it's pretty much the same as putting real pacman code on a world cup 90 PCB - one CPU runs the pac code, the other two (and the extra interrupt code on the first) try and convert the output from that into characters, sprites and noisesLook forward to seeing the results.

Now that whole process is something I'd like to hear more about...
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
Interestingly I just burnt my code to ROM and it doesn't work on the real hardware.

1. When the test switch is in the game position is just resets all the time.

2. With the test switch in the test position it will go through about 4 asteroid changes and then crash into the test pattern and constantly reset to the test pattern.

3. When it does this the only way to get it out of it is to power cycle so the state machine must have crashed.

4. Even for the time it's writing the Asteroids are just single lines. Very odd.

Unless of course my only working PCB (out of about 6!) has just died on me. I'm just burning a proper set of ROMs so that I can tell!

So a bit of investigation to do between mame and the real hardware before progressing any further.

[EDIT] Something that I'm not doing is clearing the vector memory before I start so it may be worth me doing that to ensure that the RAM is in a known state first?

guddler2011-01-01 18:18:54
 

DanP

Administrator
Staff member
vacBacker
Feedback
5 (100%)
Credits
2,190CR
From memory I think the real code clears the vid memory before the next rewrite, it's something that's definitely worth checking/considering. Interesting to hear that your code goes into the self test pattern as well. I was using 0.128u5 for my testing, I'm guessing this is out of date by now.

Curious.

Dan
 

DanP

Administrator
Staff member
vacBacker
Feedback
5 (100%)
Credits
2,190CR
Here's my code for clearing the vid mem and low page memory;

Start of program (well for me anyway)...

LDA #$00

TAX

CLRMEM DEX
STA $0300,X
STA $0200,X
STA $0100,X
STA $00,X
BNE CLRMEM
BEQ LOOP2

LOOP2 LDA #$00
TAX
CLRVIDMEM DEX
STA $4000,X
STA $4100,X
STA $4200,X
STA $4300,X
STA $4400,X
STA $4500,X
STA $4600,X
STA $4700,X
STA $00,X
BNE CLRVIDMEM

Your code here...DanP2011-01-01 20:06:56
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
DanP said:
Interesting to hear that your code goes into the self test pattern as well
Only on the real hardware. In mame it works perfectly. I've tested the vector memory just after power up and it certainly contains random crap so that might not help. Though to be fair, the program counter should be getting reset on every DMAGO (i think), so it didn't ought to ever be getting as far as that random crap. I'm going to clear it anyway though to be sure.

DanP said:
I was using 0.128u5 for my testing, I'm guessing this is out of date by now.

Fraid so! It's on 0.140 now so I imagine 0.128 is probably a year or more old
smiley1.gif
Mame never seems to stand still!

At the moment I'm looking at how to run the code from the 9100 rather than keep burning ROMs. The technical manual is a bit sparse on details. It mentions "POD overlay RAM" which sounds exactly what I want, but I've not been able to work anything out further. I think you may have to do that from a program rather than from immediate mode.

However, you can certainly write from a file to the UUT's memory so what I'm going to do is relocate the program down so that it sits at 0x300 and then just do a "RUN UUT 300" until I have it working and then I can relocate it back up again.

That will also remove all the padding and make my file tiny for transferring backwards and forwards between 9100 and PC.

The method of executing code by writing it to the UUTs memory also works for the 9010 as far as I know.
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
First of all, this has gone way beyond my original post so I'm going to change the title!

Ok, I'm down to tweaking now.

I'm now clearing some memory. I'm not going mad and clearing the whole lot because I'm not going anywhere near anything other than zero page and the first page of vector memory so there's no point in clearing anything other than that.

Now that I'm clearing those two pages of memory it's working as I'd expect, give or take.

Here's the code I used. A bit smaller but only because I'm not clearing as much memory.

Code:
	; Clear vector memory and zero page

	lda #$0

	tay

.clear_loop

	sta 0,y

	sta vector_ram,y

	iny

	bne clear_loop

So, what don't I understand? Well, the only thing I'm not understanding here is why I'm having to clear the memory at all. I must have a bug in my vector commands which is letting the program counter go beyond the bounds of what I've written to the vector ram. It's not a big deal but I think it's a bug so it needs sorting. At the end of the day the bytes I've written to the vector ram are a complete set of instructions for the DVG, including a HALT. So it should execute them, enter a HALT state and then when it gets it's next GO signal it should start at the beginning of the instructions again. It just shouldn't be possible for it to shoot off the end.

What else needs doing then? Well, since I've got this far, I may as well make it vaguely useful so I'll add a beep at the beginning. As irritating as that is, it will let me know if it's resetting.

I need to work out what the NMI is used for in the real game and handle it somehow. When the test switch is on, NMI is disabled and it works perfectly. With NMI's enabled an NMI is happening every (3Khz / 12). The result is that you only get the cross displayed on the screen before it hits an NMI and gets sent back to the start again (defined by the interrupt vector we set).

It's also far too bright compared to a normal running game picture. Since the intensity of drawing the asteroids is set by the saved routines in the vector ROM I think I just need to slow the whole loop down so it doesn't overwrite itself so often. Ill experiment with that.

But before all of that I really need to suss out doing all this through the Fluke - I'm getting bored with erasing ROMs and I've only done it twice
smiley36.gif
 

trm

Who loves you, and who do you love?
Feedback
2 (100%)
Credits
2,876CR
Not got anything useful to contribute at this point, but I just wanted to say how interesting this is and I'm avidly following it!
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
I'm currently stuck working out how to run code through the 9100 without burning ROMs all the time. From what I'm reading in the manuals I'm 99% sure it's possible. Hell, I'm 99% sure it's possible on the 9010 if you write the code to UUT ram, it's just a bit shy on examples or details!
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
Ok, quick update...

I've managed to work out a method of getting the code to run from the 9100. It's a bit tortuous I have to say and I don't know if it will work on a 9010 or not.

  • All the code has been relocated down to 0x000 - 0x1FF. And there's still a bit spare for expansion. There's some blank space in there, plus I can go up to twice that before I hit the limits of the RAM.
  • I hit a problem with the assembler when I tried to stick my code right down at 0x00 so I reserved myself 16 bytes for variables from 0x10 to 0x1F, the code starts at 0x20 with it's data stored at 0x180 and finally, to keep the fluke transfer as simple as possible 0x00 - 0x1F is padded with 0's.
  • I've created a dummy ROM that has to go in the PCB in place of 035142-02. It has nothing more than the reset and interrupt vectors but they now point to 0x20.
  • Transferring it to the 9100 is as simple (hah!) as:
    • compile code in beebasm
    • converting it to Intel ASCII Hex representation - thankfully my programmers software can do this, though that is the reason for the padding. If I wrote something to do it myself then I could fudge the start address and avoid having to pad it.
    • use the serial terminal to get the file onto the 9100
    • finally, edit the file to remove the CRC that the conversion added
  • Load the code into RAM with a "WRITE BLOCK" command
  • RUN UUT.
A bit messy to say the least but if I do it much then I can write some batch files or something to help.

I've added an led / resistor to the PCB so I can see if it's resetting due to the watchdog.

And I'm pretty much back to where I was when I had it burnt to a ROM. It runs perfectly in test mode but in run mode the NMI is causing havoc (confirmed by probing the output from the NMI counter circuit).

More another day. Maybe tomorrow, maybe not. I fancy some fresh air tomorrow
smiley36.gif
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
Right then, the proverbial penny has dropped on the NMI crashing!

Two things.

Firstly, there is another vector that needs to be set. This time it's at 0xFFFA (or 0x7FFA on Asteroids) and it's for, the NMI vector
smiley1.gif


Secondly, this vector needs to point to a genuine routine, even if it does nothing. The reason for this is that the state machine may or may not be in the middle of drawing something when this interrupt occurs. If it is, then the main CPU absolutely must not tinker with the vector memory or it's going to crash the state machine.

So, at the moment we don't have anything valid in that vector. If we were to just point it to the start of our code then every time the NMI hits the program would start anew, overwriting the vector memory from underneath the state machine. It's bound to crash!

With nothing in there I guess it's just going off randomly and crashing anyway.

The original Asteroids code isn't desperately helpful in what it's doing. I can see the registers being saved at the beginning of the routine, and then restored again at the end, and there's a few bits going on in between like checking for the slam switch and jumping elsewhere but the guy's disassembler must have been doing something odd or something as there are two endless loops in there that the routine would never get out of and the watchdog would kick in, which clearly doesn't happen so something's wrong.

I'm referring to this incidentally: http://www.ionpool.net/arcade/astcode/asteroids_code_project.html

And a final issue, that I wasn't aware of as I hadn't read as far as that chapter in my book (!) is that the 6502 is hard wired to use the 256 addresses from 1FF down to 100 for it's stack. So that means when I relocate my code down to zero page for running on the Fluke I'm corrupting the stack and also leaving myself with even less memory to play with
smiley5.gif


Not easy this coding lark!
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
Ignore the bit about the endless loops. They're intentional and kinda like the modern way of throwing an exception. The first is a check to make sure we've not run out of stack space, if we have intentionally crash. Not sure what the other is for at the moment but it seems that they're intentional.
 

DanP

Administrator
Staff member
vacBacker
Feedback
5 (100%)
Credits
2,190CR
I just had a ding! moment after that. Without the NMI vector set I'm pretty sure my program is going to 0x0000 when the NMI hits. After this I think unless there's a branch to 0x5000 the next runnable code would be at 0x5000 (the start of the Vector ROM) which is the Cross Hatch Test routine, this would explain why mine worked and then drew the cross hatch. So I guess your NMI interrupt routine is just a NOP, reading up it seems that theres an implied return and the PC is retained during NMI processing. Off to give it a quick try now :)

Dan
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
Well, yes and no. Yes, when the NMI hits it's going to be shooting off to 0x0000 and the program's going to crash or do random stuff but that's not why you're getting the cross hatch.

Don't forget the code at 0x5000 isn't 6502 instructions, it's state machine instructions that have to either be copied into the vector memory at 0x4000 by the main CPU (in reality doesn't happen), or jumped to by a vector JSR instruction that IS put into vector memory by the main CPU (this does happen).

Essentially, the state machine is an early form of customer processor. The PROM at C8 is it's ROM code, the memory at 0x4000 (shared with the main CPU) is it's memory and it's internal wiring is not so internal, it's made up of 74 series logic.

So what's happening is that when the NMI hits, the main CPU is getting distracted. It's not properly finishing off it's instruction set for the state machine and therefore the state machine keeps on going and going, if it doesn't crash in the meantime and eventually ends up at 0x5000 where it hits valid instructions that it understands and those instructions tell it to draw the cross hatch pattern.

If just pushing instructions into vector memory with the Fluke like the original script you can get away with just having an '00 E0' at the end. JMP to 0x0000 (state machine address) and then firing off DMAGO. The state machine will then forever more sit in a loop.

If running the code from a program you have to have a HALT instruction at the end of the vector memory, a '00 B0' and then the CPU must properly wait for, and respect the HALT register bit at $2002. Anything else is going to make it crash.

So, back to the NMI.

Adding the following trivial code get's it all working:

Code:
; Our NMI Routine

.ORG $7E00

    rti

; Our new vector block

.ORG $7F00

    equb 0		; NMI

    equb $7E

    equb 0		; RESET

    equb $78

    equb 0		; IRQ

    equb $78

Moving on, I'm just looking into the timing of the NMI Vs. the timing of the watchdog. For normal code you wouldn't want to reset the watchdog in the NMI routine as you'd be guaranteed to never crash which somewhat defeats the object of it. But for a test routine that could be rather handy!
 

guddler

Busting vectors like it's 1982!
vacBacker
Feedback
10 (100%)
Credits
4,055CR
I've not really done much on this today as I've been doing other stuff but just now I went up and set up my development environment for final tweaking on the real hardware. I have added a beep on start up though. I'm going to make it so that it toggles from no display to just the cross to the full display, selected by the coin or start button. There's a reason for having the test mode do that but that's a post for another day.

astcode.jpg


What you've basically got here is the code being edited on the PC, then it get's transferred to a Dataman S3 (which I completely forgot I had on loan from someone!), the S3 then emulates the 2716. The Fluke 9100 is connected in place of the CPU so that if I want to I can stop the program and examine the memory content and do any immediate mode stuff. And on the left hand side you can see the routine running on the real hardware. The long grey wires on the PCB are the two wires going to the reset LED. Just a visual aid to know when it's resetting during debugging.

From left to right you've got:

1. PC Keyboard for 9100 (using my self built PC -> Fluke adapter)

2. HP XY display

3. 14" Polo displaying the 9100 programmers station stuff

4. The 9100 itself.

5. My custom Atari rig

6. Dell monitor for the PC

7. Just in front of that, tucked behind the PCB, the 9000 series 6502 pod

8. The Asteroids PCB (obviously)

9. Acer Revo 3600 PC connected to...

10. Dataman S3, emulating the ROM.

On top of the 9100 is the control box for the vector output of the Atari rig - X, Y & Z pots- allows me to adjust the picture for my screen without touching the controls of a PCB that isn't mine so it shouldn't need adjustment when the owner gets it back. This is largely redundant now as I don't do repairs for anyone other than myself any more really (the odd exception aside). There's also my Dataman 48Pro+ but that's not really being used in this setup.

Just thought I'd share take a snap and share as it's starting to look a bit like a mad professors lab, and frnakly I'm surprised the electrics haven't popped in the house with that lot plugged in!!!
 

DanP

Administrator
Staff member
vacBacker
Feedback
5 (100%)
Credits
2,190CR
Well, how did you start? How did the actual development process start,evolve, work? How did you map specific parts of the Pac Man address space to the ones on the WC90 hardware. I'd guess that you used your experience on the Galaxian Multigame as a basis but it's all a mystery to the likes of me :)

Dan
 

Macro

Active member
vacBacker
Feedback
4 (100%)
Credits
1,982CR
It started at a UKVAC meet, when 3 of us had a challenge to take a worthless game, and make it into something that would sell.

I had a WC90 pcb, and an empty pacman cab, so decided that pacman on a wc90 was the way to go.

wc90 has 3 CPU's, 1 and 2 have 1k of shared ram, only 1 can see the background ram, and only 2 can see the sprites. It can handle more colours, but less pallette entries! - so duplicate character set to give me the correct number of pallettes, first 16 using characters 1-256, next 16 using 257-512

now take pacman code, change the start address of the sprite ram (to the shared 1k) and of the screen (to a normal block of ram), change it to read controls from a byte in ram and write sound commands to the 3rd cpu using the port setup for that. (this was all done with a hex editor)

run the pacman code, should run same as always, but no picture ('cos you have now got it writing to blocks of ram)

now add your own code to the interrupt routine. it needs to do a couple of things
a) copy the screen in ram to the real screen, changing the layout a bit as it does it (since pacman has 4 extra rows compared to wc90)
b) read the controls, re-map into pacman layout and store in the byte in memory for the real game code to read.

now running that should give you pacman background and dots dissapear as they are eaten by an imaginary pac! (and you can steer said invisible pac)

so, now write some code for the second CPU, that (on the interrupt again) reads the pacman sprite info from the shared 1k or ram, remaps it to my character set and pallette and stores it in the wc90 sprite locations.

so, run both, and we now have pacman running with ghosts you can see and pac that you can control but it is very quiet.

sound is a big problem, pacman can basically do the same as a tracker on the amiga - it has 4 pre-defined waveforms, which it can play back at different frequency and supports more than one voice. wc90 has a yamaha sound chip that can play samples, and can also play back built in waveforms at any frequency. (it can also do 3 voices)

so, using mame, get wav files of all of the pacman sound effects, convert them to the correct delta-t compression for the yamaha chip (now that is NOT easy, it's not the same as the delta-T used on PC's!! - for a clue how, the soundchip is also used in MSX computers) and via a couple of lookup tables to convert the three pacman background tunes into yamaha data versions. add a program to accept the music commands from the pac game and add that to the mix. (interupt driven again to play the tunes)

spot effects (eating dots, dying etc) are samples, and can play at the same time as the background tunes, although I had to knock them up an octave since for some unknown reason, if you reprogram the YM soundchip down to the same frequency on a wc90, it makes no noise!

so there you go, took me about a week to have background running, an extra couple of days for the sprites and about 3 months to finally get it sounding right (with some FM advice and help from the guy in the mame team who wrote the YM soundchip code for it)

end result, I sold the first pac90 on ebay for £74 (not bad for a PCB that cost me £5 in the first place) and wc90 pcb's still fetch about 5 times the price that they once did.

oh, and some little b*gger made more money than I did out of it by selling sets of eproms to 'upgrade' your wc90 pcb.

all testing was done using an updated verison of mame, and then lots of head scratching when it didn't work the same on the real PCB - multigame code done same way.

p.s. I have one working wc90 pcb in my collection, and it still runs the original wc90 code!

p.p.s the other 2 never did finish their conversions, so I declare myself the winner
smiley32.gif
 
Top