BINTRIS C64 title screen implementation (series part 3)

Janne Hellsten on May 27, 2018

(Looking for the BINTRIS C64 disk image? Find it here.)

This blog post discusses the implementation of the BINTRIS C64 title screen.

The title screen consists of a multicolor bitmap at the top and a text mode scroller at the bottom. Here’s how it looks like:

This is a pretty standard text mode scroller: use the horizontal scroll register $d016 for 0-7 pixel shifting. When you reach pixel offset 7, reset to pixel offset 0 and move the whole character row left by one character (8 pixels). Additionally, the scroller text is colored with raster bars.

But wait a minute.. The screen is in multicolor bitmap mode. How can we use a text mode scroller at the bottom? Fortunately it’s pretty easy to mix bitmap and text mode within a single frame. Just switch to text-mode right before raster beam reaches the scroller, and switch back to bitmap mode once the raster beam is past it.

The below animation illustrates how the raster IRQs trigger:

bitmap mode text mode raster bar

In summary:

Line 16 ( irq0 ): set multicolor bitmap mode, move character row left by one character if framecount&7==0 .

): set multicolor bitmap mode, move character row left by one character if . Line 238 ( irq1 ): switch to text mode, set horizontal scroll based on framecount bits 0-2

): switch to text mode, set horizontal scroll based on bits 0-2 Line 241 ( irq2 ): raster bars (using the double IRQ trick for stable raster), loop back to Line 16

And the same in assembly:

.const irq0line = 16 .const textmodeswitchline = 50+200-12 .const rastercolorline = 50+200-9 framecount: .byte 0 // increased at the beginning of each frame // Macro to save&restore registers and setup the next routine in the // raster IRQ chain. .macro irq_start(end_lbl) { sta end_lbl-6 stx end_lbl-4 sty end_lbl-2 } .macro irq_end(next, line) { :EndIRQ(next, line, false) lda #$00 ldx #$00 ldy #$00 rti } irq0: { irq_start(end) inc framecount // Set screen mode lda #$3b // bitmap mode sta $d011 lda #$18 // multicolor sta $d016 // screen memory ptr lda #$18 sta $d018 jsr scroller_update_char_row irq_end(irq1, textmodeswitchline) end: rti } irq1: { irq_start(end) lda #$1b // screen on, text mode sta $d011 lda framecount and #7 eor #7 // xor bits 0-2 and leave bit 3 zero for 38 column mode sta $d016 lda #$10 // bank + $0400 sta $d018 irq_end(irq2, rastercolorline) end: } // Stable raster IRQ for color bars irq2: { double_irq(end, irq3) irq3: txs // Wait exactly 9 * (2+3) cycles so that the raster line is in the border ldx #$09 dex bne *-1 // First line is a bad line so we have only 23 cycles! lda colors1+0 // 4 cycles sta $d021 // 4 cycles .for (var i = 0; i < 6; i++) { nop } bit $fe // Next 7 lines are normal lines, so 63 cycles per color change ldx #$01 !: lda colors1,x // 4 cycles sta $d021 // 4 cycles .for (var i = 0; i < (63-15)/2; i++) { nop } inx // 2 cpx #colorend-colors1 // 2 bne !- // 3 lda #0 sta $d021 irq_end(irq0, irq0line) end: }

I put up a full stand-alone version of this on github – this should compile on KickAssembler. It’s a slightly cleaned up version of the BINTRIS titlescreen. For some historical reason I used VIC bank 1 instead of the default and made screen RAM reside at $4400 instead of $0400 . This can make the source a bit harder to follow.

Next in series

The next post will discuss how the main BINTRIS game screen is rendered.

All posts in this series: