Sunday, 17 April 2016

Space Invaders

And so it begins... with the Knight Lore ROM image emailed off to John for CocoFEST, I've decided to take a short break from filmation games until it's time to produce cartridges, in which case I'll need to look at code optimisation. However I've been in contact with another programmer who is in the final stages of porting Pentagram to the Atari 8-bit machines, and he's given me some invaluable insight into where the code can be improved. In fact, he has Pentagram running on the Atari slightly faster than the ZX Spectrum, and a lot of the code is still auto-generated from Z80 to 6502!

I was just playing around with the arcade version of Space Invaders, seeing how that would look on the Coco3. I fired up MAME and took a memory dump mid-game, played with the layout a bit, and then loaded it into the Coco3 under MESS.

Space Invaders (mock up) on the Coco3 under MESS

It looks pretty good to me, and tonight I couldn't resist starting on an actual port. Whether or not I decide to see it through just now will depend on how quickly it proceeds in the initial stages, but if my experience with Knight Lore is any indication, it might not take long to get things well along.

I'll retain the original video memory mapping (including rotated screen) until the game is all-but-ported, to simplify the process. I've done rotation on-the-fly in my TRS-80 Model 4 'bootleg', so it's not a big deal. Running MESS with the 'rol' option will give me the correct display during development. One thing I do need to do though is bit-reverse all the graphics data, as the pixels are laid out in the reverse order within each video RAM byte.

Space Invaders in 6809 (WIP)

I've also decided to work with the disassembly on Computer Archeology, rather than my own reverse-engineering,  for reasons I won't bother to explain.

I'm hoping to knock this one over fairly quickly, given all the reverse-engineering has already been done and it's a relatively small - and simple - program. I'm not going to bother producing a cartridge for Space Invaders; rather I'll make disk and ROM images freely available for download.

Friday, 15 April 2016

Bit Rot?

I thought I should bring all the C ports up-to-date today; Amiga is there and Neo Geo is all there bar the new (Mick Farrow graphics) sprite tiles being generated (ie. it has the dip-switch setting and the code just needs a simple tile bank offset to be added).

It wasn't all plain sailing though, the Neo Geo port gave me a bit of grief. Not having touched this in months, I just needed to add a few stubs for new palette routines so it would link and fire up MAME. I was a little surprised to be greeted by the cross-hatch screen. I generated a clean build, fired it up again, and same thing. The dreaded bit-rot... hmm...

After checking that the files were all being generated, and grasping at a few other straws, I decided to find out exactly what the cause of a cross-hatch screen is on the MVS. Turns out they're colour-coded, and my blue border meant that a cartridge could not be found! The only thing that could explain that under emulation would be a corrupt P1 (program) ROM.

Loading the P1 ROM into a hex editor revealed immediately that the file was all-but-blank! Time to go back and take a closer look at the compilation output. It's not easy to maintain a clean build on a multi-platform project, especially retro platforms with development toolchains that can be rather old, and as it turns out, the Neo Geo gcc (v2.95.2 circa 1999) complains quite a bit. So much so, that you tend to ignore it after a while. Examining the output more carefully revealed an assembler warning about incorrect attributes being set for .rodata in the newly-added Mick Farrow sprite graphics data arrays.

Without going into too much detail, I have needed to use section attributes to force gcc to place certain data structures into ROM - const just hasn't worked in some instances (yes I know the differences of placement). The confusing thing is, it was never an issue with the original ZX or CPC graphics arrays, and they're not significantly different to the new file. After using some Google Fu it seemed it was a known gcc bug at various times in the past, however the work-around didn't assemble in my toolchain. Again, grasping at straws, having noticed that the existing graphics files had additional arrays defined before the sprite arrays, I instantiated a dummy 1-byte array at the top of the new file and - viola - it worked! And for the record, exactly the same section attributes were still being set for the sprite data!

The whole process was probably a good hour or so.

I'm not about to ponder any further on this issue - it's not broke (anymore) so I won't fix it!

UPDATE: Mick Farrow's graphics on the Neo Geo port.

Mick Farrow's modified graphics on the Neo Geo

Incredibly the game now uses no less than six (6) sprite tile ROM's, not quite full but in the order of 40,000 tiles. In reality, at least half are never used by Knight Lore (ie. the VFLIP'ped versions, with the exception of a few border sprites) but at least the framework is there for the other filmation titles that may use them.

As a result, I had to find a larger host game, this time pspikes2. Basically each sprite tile ROM pair holds the sprites for an entire graphical variation. Note that Mick's panel graphics are not available (yet) as the panel is rendered on the FIX layer. I'd need to rip them and allocate another bank in the FIX ROM, which I will probably do soon.

UPDATE #2: Speaking of bit rot, in attempting to add another set of panel tiles for the Mick Farrow graphics, I've broken what was already there. I can't coax my tool into reproducing the existing panel data, let-alone a new one. Annoying...

I 'C' no more bugs!

Continuing on with testing the C port, and you can complete the game and see the end-of-game animation and messages. There were a few more bugs, but none too nasty. For the record, most bugs in the C port have been signed/unsigned issues.

I've also added Mick Farrow's modified graphics as a run-time option.

I need to propagate the changes through to the Amiga and Neo Geo ports. The latter will be more fiddly as it will require the generation of another few thousand sprite tiles, but the tool is already there.

I realised recently it would (probably) be relatively trivial to add an Atari ST port - then I could add another target platform to my CV! I'm also still deciding whether I have the motivation left in me to attempt a Sega Genesis port as well, or whether I'm well-and-truly over Knight Lore by now.

Thursday, 14 April 2016

On optimisations

Over on the AtariAge forums, user mariuszw has been porting the ZX Spectrum version of Pentagram (the 3rd filmation title) to the 6502-based Atari 8-bit computers. He started with an automated translation of Z80 to 6502 which he got running but, not surprisingly, was too slow.

He has spent some time both profiling and analysing the code, and aside from actual pixel rendering has identified areas in the Z-order rendering logic that can be significantly optimised. I was aware that it took a rather brute force approach and that it spent quite a while in there, but was surprised to learn that the code can spend up to 40% of CPU time in that routine!

And to give some idea of the effect of these optimisations, one user observes that the code now runs as least as fast as the Spectrum version, if not slightly faster. And keep in mind that significant portions of the code are still implemented from the auto-translation process. Impressive!

The dilemma I face now is how far do I go with implementing any optimisations on the Coco3? The original intention was to port the game faithfully, warts-and-all. I have no issue rewriting the platform-specific portions of the game - such as rendering routines - but re-implementing the sorting logic encroaches on modifying the way the game works. You could argue that if it doesn't change the outcome (ie. the same objects are rendered each frame) then it's still the same, but the purist in me is struggling with that argument regardless.

Either way, I'll study the code for interest's sake, if nothing else, then make a judgement call. I guess more people are likely to play it if it runs smoothly, and won't really care what's going on underneath the hood.

Wednesday, 13 April 2016

Back to C

I've managed to find and fix the three known bugs in the C port.

I expect there to be a few more as I continue testing.

Monday, 11 April 2016

Use The Source, Luke

I've just uploaded the disassemblies - those of which I am entitled to - of the remaining projects to the download page, with the exception of Donkey Kong, which is very much WIP and I have every intention of completing it.

A few of the earlier projects are rather incomplete, and will probably remain so.

I do have a handful of diassemblies - all very much incomplete - that were used when reverse-engineering the hardware in order to assist with an FPGA implementation. Since they're not really part of any (software) porting project, I won't include them here.

Enjoy.

Finally! Joy after getting past my sticking point!

To say that adding joystick support was frustrating is an understatement!

There's not a whole lot of information on the net about sampling the joysticks, less still about reading the buttons, and some of the information that is available is, well, wrong. And to confuse matters further, I was having issues in MESS with the 2nd joystick button. Not having a physical 2-button joystick to test on real hardware is fraught with impediments to success.

Still at this point unable to test on real hardware, I at least seem to have sorted out the details and MESS finally behaves as I'd expect, given the Coco 3 schematics. I guess I should have gone to them in the first place, rather than as a last resort.

I thought I'd post my joystick code here on the off chance that someone else has similar issues in the future.

Let's define some useful constants.

PIA0        .equ    0xFF00
PIA1        .equ    0xFF20
DATAA       .equ    0x00
DDRA        .equ    DATAA
CRA         .equ    0x01
DATAB       .equ    0x02
DDRB        .equ    DATAB
CRB         .equ    0x03

; equates to keyboard rows
; - phantom keys appear accordingly
RJOY_BTN1   .equ    (1<<0)
LJOY_BTN1   .equ    (1<<1)
RJOY_BTN2   .equ    (1<<2)
LJOY_BTN2   .equ    (1<<3)

;.define LEFT_JOYSTICK
.ifdef LEFT_JOYSTICK
  JOY_BTN1  .equ    LJOY_BTN1
  JOY_BTN2  .equ    LJOY_BTN2
.else
  .define RIGHT_JOYSTICK
  JOY_BTN1  .equ    RJOY_BTN1
  JOY_BTN2  .equ    RJOY_BTN2
.endif
; high and low thresholds
; for 'digital' operation
JOY_LO_TH   .equ    0x64                ; ~40%
JOY_HI_TH   .equ    0x98                ; ~60%


First up, the one-off initialisation, which sets all the appropriate PIA data-direction registers. Bear in mind that Knight Lore takes full control of the Coco 3 hardware, swapping out ROM and disabling all interrupts except a simple (F)ISR used to emulate the Z80 Refresh register. So the PIA's are immune to any reconfiguration behind-the-scenes.

  ; configure joystick axis selection as outputs
  ; and also select left/right joystick
        lda     PIA0+CRA
        ldb     PIA0+CRB
        ora     #(1<<5)|(1<<4)          ; CA2 as output
        orb     #(1<<5)|(1<<4)          ; CB2 as output
.ifdef LEFT_JOYSTICK
        orb     #(1<<3)                 ; CB2=1 left joystick
.else
        andb    #~(1<<3)                ; CB2=0 right joystick
.endif
        sta     PIA0+CRA
        stb     PIA0+CRB
  ; configure comparator as input
        lda     PIA0+CRA
        anda    #~(1<<2)                ; select DDRA
        sta     PIA0+CRA
        lda     PIA0+DDRA
        anda    #~(1<<7)                ; PA7 as input
        sta     PIA0+DDRA
        lda     PIA0+CRA
        ora     #(1<<2)                 ; select DATAA
        sta     PIA0+CRA
  ; configure sound register as outputs
        lda     PIA1+CRA
        anda    #~(1<<2)                ; select DDRA
        sta     PIA1+CRA
        lda     PIA1+DDRA
        ora     #0xfc                   ; PA[7..2] as output
        sta     PIA1+DDRA
        lda     PIA1+CRA
        ora     #(1<<2)                 ; select DATAA
        sta     PIA1+CRA


Now the joystick and button sampling. Note that Knight Lore uses a 'digital' joystick so it's only concerned with checking the position on each axis within three zones - left, middle and right.

        ; select hoizontal axis
        lda     PIA0+CRA
        anda    #~(1<<3)                ; CA2=0 horizontal
        sta     PIA0+CRA
        ; set comparator value to 40%
        lda     PIA1+DATAA
        anda    #0x03                   ; clear value
        ora     #JOY_LO_TH              ; low threshold
        sta     PIA1+DATAA
        lda     PIA0+DATAA              ; comparator
        bita    #(1<<7)                 ; joystick greater?
        bne     1$                      ; yes, skip
        orb     #INP_LEFT               ; aka #INP_W
        bra     2$
        ; set comparator value to 60%
1$:     lda     PIA1+DATAA
        anda    #3                      ; clear value
        ora     #JOY_HI_TH              ; high threshold
        sta     PIA1+DATAA
        lda     PIA0+DATAA              ; comparator
        bita    #(1<<7)                 ; joystick greater?
        beq     2$                      ; no, skip
        orb     #INP_RIGHT              ; aka #INP_E
        ; select vertical axis
2$:     lda     PIA0+CRA
        ora     #(1<<3)                 ; CA2=1 vertical
        sta     PIA0+CRA
        ; set comparator value to 40%
        lda     PIA1+DATAA
        anda    #0x03                   ; clear value
        ora     #JOY_LO_TH              ; low threshold
        sta     PIA1+DATAA
        lda     PIA0+DATAA              ; comparator
        bita    #(1<<7)                 ; joystick greater?
        bne     3$                      ; yes, skip
        orb     #INP_FORWARD            ; aka #INP_N
        bra     4$
        ; set comparator value to 60%
3$:     lda     PIA1+DATAA
        anda    #3                      ; clear value
        ora     #JOY_HI_TH              ; hi threshold
        sta     PIA1+DATAA
        lda     PIA0+DATAA              ; comparator
        bita    #(1<<7)                 ; joystick greater?
        beq     4$                      ; no, skip
        orb     #INP_PICKUP_DROP        ; aka #INP_S
        ; read joystick buttons
4$:     lda     #0xff                   ; no keys, only buttons
        jsr     read_port
        bita    #JOY_BTN1
        beq     5$
        orb     #INP_JUMP
5$:     bita    #JOY_BTN2
        beq     6$
        orb     #INP_DIR_PICKUP_DROP
6$:     bra     finished_input               


I haven't done any timing nor studied the BASIC joystick routines but short of hand-picking registers and instructions that minimise clock cycles, I don't think there's much you could do to get a faster sampling routine. Happy to be proven wrong by any astute reader.

Waiting for a 2-button adapter to turn up; hopefully that'll arrive in time for me to test before sending the final version off to John for demonstrating at the CocoFEST. I was going to try to experiment with some optimisation to speed up the rendering, but I think I'll take a short break from Knight Lore - or the 6809 port at least - until after CocoFEST.

I'm already thinking about the next port, which is dangerous before finishing off Knight Lore completely. But I've got a couple of new ideas which I need to investigate further. One is an actual arcade port; not a new game for the Coco (or any platform really) but it would be cool to have the actual arcade code and graphics, effectively, running on the Coco3. And reverse-engineering is already complete, so the port would be relatively quick. We'll see...