Custom Bally OS, Pt 2: Let's Blink a Light
With I/O figured out, I theoretically know everything necessary to start writing code, so I want to start with the simplest possible thing: getting an infinite loop to run in pinMAME. The CPU (Motorola 6800) is fairly basic, it only needs to know one thing to run code: where to start. You do this by putting the address of your starting code at the highest location available in memory, so I wrote a quick assembly file:
.orq $1800 ; start of U6
main:
jmp main
.orq $1FFF-1 ; two bytes before end of U6
.dw main ; address of main
It doesn't get much simpler! And besides from a classic off-by-one error (I did $1FFF-2 instead of -1), it worked on the first (heh) try. Loading this up in PinMAME I was able to open the debugger and see it dutifully running around its tiny loop, forever.
My next step, then, is to initialize the PIAs. With this helpful guide I'm able to transfer my notes from part 1 into some shorthand instructions on how the PIAs will need to be initially configured:
U10
Bank A:
control: |self test irq|n/u|1|1|!blanking 0|D|0|1|
direction: out (1)
data: 11110000
- bits 0-3 go to display latches, start low
- bits 4-7 go to display data, start high (1111 = blank)
Bank B:
control: |zero crossing irq|n/u|1|1|lamp strobe 1|D|1|1|
direction: in (0)
U11
Bank A:
control: |display irq|n/u|1|1|led 0|D|0|1|
direction: out (1)
data: 00000000
- bit 0: credit display latch, start low
- but 1: not used
- bits 2-7: digits 1 thru 100k, start low
Bank B:
control: |n/u|n/u|1|1|solenoid0|D|0|0|
direction: out (1)
data: 10011111
- bits 0-3: number of solenoid to fire, use 1111 to fire none
- bits 4-8: continuous solenoid data (turn flippers off, coin lockout on)
Configuring the PIAs is a bit of a pain as they have three bytes of memory internally (the control byte, the direction byte, and the data byte) per bank, but you can only access two at a time. Therefore, one bit (2) of the control byte chooses which (direction or data) the other byte goes to. Fully configuring a PIA involves first initializing the control byte so that you can access the direction byte, then initializing the direction byte (read or write), then changing the control byte to let you access the data byte so you can actually do some I/O:
ldaA 00110001b ; irq state | n/u | CA2 output | ...mode | CA2 value 0 = blank displays | enable direction register | irq on | ...self test ->low
staA u10AControl
ldaA 11111111b ; all outputs
staA u10A
ldaA 00000100b ; toggle DDRA (3rd) bit to write to ports
oraA >u10AControl
staA u10AControl
ldaA 11110000b ; blanking means any outputs here will affect displays
staA u10A ; 0-3 set all display latches low, 4-7 blank disp data
Finally, I can use the PIA to start controlling the LED, toggling it on and off repeatedly:
inc counter
ifeq ; counter = 0, it wrapped around from 255
ldaA 00001000b ; led bit
bitA >u11AControl
ifne ; led on?
; turn led off
ldaA 11110111b
andA >u11AControl
staA u11AControl
else
; turn led on
oraA >u11AControl
staA u11AControl
endif
endif
and it works! At least in PinMAME. I don't have any Bally/Stern machines on hand and configured correctly to easily test it in game right now, but that's alright. PinMAME isn't perfect but you can at least get most of the logic ironed out when it's easily debuggable before throwing it on the black box of a real machine.
The code for all this is available on my github, if you want to check it out
blog comments powered by Disqus