; ============================================================ ; C64 HI-RES BITMAP DEMO ; Switches to 320x200 hi-res bitmap mode, draws a diagonal ; line, then waits for a key before restoring text mode. ; ; Assemble to $C000 and run with: ; LOAD"BITMAP",8,1 : SYS 49152 ; ; Bitmap: $A000-$BFFF (8000 bytes, under BASIC ROM) ; Screen color RAM: $0400-$07E7 (1000 bytes) ; ============================================================ * = $C000 ; --- Zero-page pointers --- PTR = $FB ; 2-byte pointer BPTR = $FD ; 2-byte bitmap pointer ; --- Constants --- BITMAP = $A000 ; bitmap base SCREEN = $0400 ; color nybble RAM (foreground hi/background lo) START: JSR INIT_BITMAP JSR DRAW_DIAGONAL JSR WAIT_KEY JSR RESTORE_TEXT RTS ; ============================================================ ; INIT_BITMAP ; Sets up VIC-II for hi-res bitmap mode ; ============================================================ INIT_BITMAP: ; Turn off interrupts temporarily SEI ; Set VIC bank to 0 ($0000-$3FFF is default bank) ; Bitmap at $A000 requires bank 2 ($8000-$BFFF) — switch! LDA $DD00 AND #$FC ; clear bits 0-1 ORA #$01 ; bank 2: VIC sees $8000-$BFFF STA $DD00 ; VIC memory setup: $D018 ; Bitmap at $A000 = offset $2000 from bank base $8000 ; $2000 >> 13 = bit 3 set → bitmap pointer bit = 1 ; Screen RAM at $8400 (color nybbles) — offset $0400 >> 10 = $0 → bits 7-4 = 0001 LDA #%00011000 ; screen at $8400 (bits 7-4 = 0001), bitmap at $A000 (bit 3) STA $D018 ; Enable bitmap mode: $D011 bit 5 = 1 LDA $D011 ORA #%00100000 STA $D011 ; Multicolor off (hi-res): $D016 bit 4 = 0 LDA $D016 AND #%11101111 STA $D016 ; Set border color to black LDA #0 STA $D020 ; Set background color to black STA $D021 ; Clear bitmap (8000 bytes of zeros = black pixels) LDA #BITMAP STA PTR+1 LDA #0 LDY #0 LDX #$1F ; 32 pages = 8192 bytes (covers 8000) CLRLOOP: STA (PTR),Y INY BNE CLRLOOP INC PTR+1 DEX BNE CLRLOOP ; Set all color RAM nybbles: foreground=white(1), background=black(0) ; Each byte = $10 = white fg, black bg LDA #SCREEN STA PTR+1 LDA #$10 LDY #0 COLLOOP: STA (PTR),Y INY CPY #232 ; 1000 - 8 = 232? No: LDY loops 0-255 then second pass BNE COLLOOP ; Handle full 1000 bytes (4 pages) ; Simple approach: just fill $0400-$07E7 LDX #3 LDY #0 COLLOOP2: STA (PTR),Y INY BNE COLLOOP2 INC PTR+1 DEX BNE COLLOOP2 CLI RTS ; ============================================================ ; DRAW_DIAGONAL ; Draws a white diagonal line from (0,0) to (199,199) ; In hi-res bitmap, pixel (x,y) is in: ; byte = bitmap + (y AND $F8)*40 + (x AND $F8) + (y AND 7) ; bit = 7 - (x AND 7) ; ============================================================ DRAW_DIAGONAL: LDX #0 ; X pixel (0-199) DLOOP: TXA ; Y = X (diagonal) JSR SETPIXEL INX CPX #200 BNE DLOOP RTS ; ============================================================ ; SETPIXEL — set pixel (.X=x, .A=y) ; ============================================================ SETPIXEL: ; Calculate byte address ; addr = $A000 + (Y>>3)*320 + (X>>3)*8 + (Y AND 7) ; Uses simple approach via table lookup or shift math STX XCOORD STA YCOORD ; Step 1: row base = (Y>>3) * 320 ; Y>>3 * 320 = Y>>3 * 256 + Y>>3 * 64 LSR ; Y>>1 LSR ; Y>>2 LSR ; Y>>3 (char row 0-24) TAX ; X = row number LDA ROWLO,X ; low byte of row base STA BPTR LDA ROWHI,X STA BPTR+1 ; Step 2: add (X>>3)*8 = column offset LDA XCOORD LSR ; X>>1 LSR ; X>>2 LSR ; X>>3 (char col 0-39) ASL ; *2 ASL ; *4 ASL ; *8 CLC ADC BPTR STA BPTR BCC NOINC1 INC BPTR+1 NOINC1: ; Step 3: add (Y AND 7) for sub-row LDA YCOORD AND #$07 CLC ADC BPTR STA BPTR BCC NOINC2 INC BPTR+1 NOINC2: ; Step 4: add bitmap base $A000 LDA BPTR+1 CLC ADC #>BITMAP STA BPTR+1 ; (low byte already correct) ; Step 5: set bit (7 - (X AND 7)) LDA XCOORD AND #$07 TAX LDA BITMASK,X LDY #0 ORA (BPTR),Y STA (BPTR),Y RTS XCOORD: .BYTE 0 YCOORD: .BYTE 0 ; Bit masks for bit positions 7..0 BITMASK: .BYTE %10000000 ; bit 7 (x mod 8 = 0) .BYTE %01000000 .BYTE %00100000 .BYTE %00010000 .BYTE %00001000 .BYTE %00000100 .BYTE %00000010 .BYTE %00000001 ; bit 0 (x mod 8 = 7) ; Row base address table (40*8 = 320 bytes per char row) ; Row N base = N * 320; precomputed for rows 0-24 ROWLO: .BYTE <(0*320),<(1*320),<(2*320),<(3*320),<(4*320) .BYTE <(5*320),<(6*320),<(7*320),<(8*320),<(9*320) .BYTE <(10*320),<(11*320),<(12*320),<(13*320),<(14*320) .BYTE <(15*320),<(16*320),<(17*320),<(18*320),<(19*320) .BYTE <(20*320),<(21*320),<(22*320),<(23*320),<(24*320) ROWHI: .BYTE >(0*320),>(1*320),>(2*320),>(3*320),>(4*320) .BYTE >(5*320),>(6*320),>(7*320),>(8*320),>(9*320) .BYTE >(10*320),>(11*320),>(12*320),>(13*320),>(14*320) .BYTE >(15*320),>(16*320),>(17*320),>(18*320),>(19*320) .BYTE >(20*320),>(21*320),>(22*320),>(23*320),>(24*320) ; ============================================================ ; WAIT_KEY — spin until any key pressed ; ============================================================ WAIT_KEY: JSR $FFE4 ; GETIN BEQ WAIT_KEY RTS ; ============================================================ ; RESTORE_TEXT — return to standard text mode ; ============================================================ RESTORE_TEXT: ; Restore VIC bank 0 LDA $DD00 ORA #$03 STA $DD00 ; Restore VIC memory map ($D018) LDA #$15 ; screen at $0400, charset at $1000 STA $D018 ; Turn off bitmap mode LDA $D011 AND #%11011111 STA $D011 ; Restore background/border LDA #14 ; light blue border (default) STA $D020 LDA #6 ; blue background (default) STA $D021 ; Clear screen LDA #147 ; PETSCII clear JSR $FFD2 RTS