Friday, January 31, 2014

Raster IRQs now work

Today I implemented a small but important feature that has been in the pipeline for a while: raster interrupts triggered by the VIC-IV.

I already had much of the machinery in place for raster IRQs, I just hadn't finished tying it all together.

So a few lines of VHDL later, I set the FPGA building.  Unfortunately, just adding a few ties for the IRQ pushed the timing out by about 2ns from the 5.6ns required for the 192MHz pixel clock to around 7ns.  As a result it didn't work.

I scratched my head for a while wondering how about 7 logic gates could ruin the timing so badly, and eventually realised that I needed to pipeline the IRQ line by adding a drive stage, so that the IRQ had time to propagate across the FPGA.  Without it, ISE was rearranging everything else (badly) to make the IRQ line get to the CPU in one cycle.  Net result, the IRQ triggers one pixel clock cycle late on the CPU, which isn't really an issue, since the CPU runs at half that clock speed, so it should still trigger the CPU interrupt on the correct cycle.

So then I set about writing a little raster interrupt routine to test it.  This was an important step, not only to make sure that the raster interrupt line worked, but also that clearing VIC-IV interrupts worked in a C64 compatible way, unlike the C65 where the usual ASL $D019 or INC $D019 doesn't clear VIC interrupts.  This is a big source of incompatibility on the C65.

Interestingly, this incompatibility on the C65 is not the VIC-III's fault, but rather the 4510 CPU's.  This is because the 4510 uses the CMOS 65CE02 core that changed the behaviour of ASL, INC and other read-modify-write instructions.  On the 6510, the instructions read the original value, write the original value and then write the modified value.  This is why ASL $D019 or INC $D019 works to clear interrupts on the C64, because writing the value read from $D019 will clear all triggered interrupts.

But on the 4510, the original value is read, and the modified value is written, saving a cycle, and in the process really breaking compatibility.  The SuperCPU has a similar problem because it uses the 65816 that includes the same "optimisation".  Aware of this problem, I resolved that this problem would not exist in the C65GS, and today it was time to test it.

The interrupt routine I wrote is:
 ; CIA IRQ disable
 lda #$7f
 sta $DC0D
 ; clear bit 8 of raster compare
 and $D011
 sta $D011
 ; set raster for split
 lda #$80
 sta $D012
 ; enable raster IRQ
 lda #$01
 sta $D01A
 ; set IRQ vector
 lda #irq
 sta $0315

irq: ; border yellow
 lda #$07
 sta $D020
 ; wait for a bit
 ldx #$ff
l1: dex
 bne l1
 ; border back to light blue
 lda #$0e
 sta $D020
 ; acknowledge IRQ
 inc $D019
 ; return from interrupt, via keyboard scan etc.
 jmp $EA31

As can be seen, I am using my usual INC $D019 to clear the raster IRQ.

Now to see if it worked.  Bingo! A nice little raster bar.  There is a few cycles jitter as you would expect, but of course with a 96MHz CPU the jitter is only about one character wide.  Since each character is 20 cycles wide, that means a jitter of less than 10 cycles.  That's more than on a real C64 because I still have some wait states in the C65GS CPU memory access that I have yet to work around, and so some instructions can take a dozen or so cycles, in particular things like INC that include six memory accesses can take 12 or 13 cycles.

For comparison, here is the same routing running on VICE.  

The keen observer will notice that not only is the raster bar much narrow on the C65GS, but it is also not in quite the same position.  This is because the 1920x1200 frame has 1248 physical rasters (including flyback), which is 4x PAL's 312 lines.  However, to keep the vertical borders small, in C64 mode the C65GS makes each logical raster equal to five physical rasters.

I'll have to do something about this so that raster splits occur on the correct logical line.  This will most likely consist of having logical rasters spaced 3-lines apart before the display, 5-lines apart during the display, and 3-lines after.  It all gets a bit fun, because 1920x1200@60Hz has only one invisible raster at the beginning of frame, while PAL has more, so the logical raster counter will have to start during flyback in the previous frame.  Entirely possible, just a bit fiddly.


  1. This is an impressive project! will it fully emulate a c65 too when ready?
    i'm follow you with interest. have you an "estimated" project done date?
    thank you!

    1. No estimated completion date, as this is something I am doing in my spare time. My aim is that it will fairly well emulate the C65, at least so that the C65 software I wrote years ago will run on it. But I am not aiming for 100% compatibility, rather a bit of reimagining the C65 for the 21st century with good backward compatibility.