// Exploring C64DTV Screen Modes
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
  // Processor port data direction register
  .label PROCPORT_DDR = 0
  // Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
  .const PROCPORT_DDR_MEMORY_MASK = 7
  // Processor Port Register controlling RAM/ROM configuration and the datasette
  .label PROCPORT = 1
  // RAM in $A000, $E000 I/O in $D000
  .const PROCPORT_RAM_IO = $35
  // RAM in $A000, $E000 CHAR ROM in $D000
  .const PROCPORT_RAM_CHARROM = $31
  .label RASTER = $d012
  .label BORDERCOL = $d020
  .label BGCOL = $d021
  .label BGCOL1 = $d021
  .label BGCOL2 = $d022
  .label BGCOL3 = $d023
  .label BGCOL4 = $d024
  .label VIC_CONTROL = $d011
  .const VIC_ECM = $40
  .const VIC_BMM = $20
  .const VIC_DEN = $10
  .const VIC_RSEL = 8
  .label VIC_CONTROL2 = $d016
  .const VIC_MCM = $10
  .const VIC_CSEL = 8
  .label VIC_MEMORY = $d018
  // Color Ram
  .label COLS = $d800
  // CIA#1 Port A: keyboard matrix columns and joystick #2
  .label CIA1_PORT_A = $dc00
  // CIA#1 Port B: keyboard matrix rows and joystick #1.
  .label CIA1_PORT_B = $dc01
  // CIA#2 Port A: Serial bus, RS-232, VIC memory bank
  .label CIA2_PORT_A = $dd00
  // CIA #2 Port A data direction register.
  .label CIA2_PORT_A_DDR = $dd02
  // The colors of the C64
  .const BLACK = 0
  .const GREEN = 5
  .const BLUE = 6
  .const LIGHT_GREEN = $d
  // Feature enables or disables the extra C64 DTV features
  .label DTV_FEATURE = $d03f
  .const DTV_FEATURE_ENABLE = 1
  // Controls the graphics modes of the C64 DTV
  .label DTV_CONTROL = $d03c
  .const DTV_LINEAR = 1
  .const DTV_BORDER_OFF = 2
  .const DTV_HIGHCOLOR = 4
  .const DTV_OVERSCAN = 8
  .const DTV_COLORRAM_OFF = $10
  .const DTV_CHUNKY = $40
  // Defines colors for the 16 first colors ($00-$0f)
  .label DTV_PALETTE = $d200
  // Linear Graphics Plane A Counter Control
  .label DTV_PLANEA_START_LO = $d03a
  .label DTV_PLANEA_START_MI = $d03b
  .label DTV_PLANEA_START_HI = $d045
  .label DTV_PLANEA_STEP = $d046
  .label DTV_PLANEA_MODULO_LO = $d038
  .label DTV_PLANEA_MODULO_HI = $d039
  // Linear Graphics Plane B Counter Control
  .label DTV_PLANEB_START_LO = $d049
  .label DTV_PLANEB_START_MI = $d04a
  .label DTV_PLANEB_START_HI = $d04b
  .label DTV_PLANEB_STEP = $d04c
  .label DTV_PLANEB_MODULO_LO = $d047
  .label DTV_PLANEB_MODULO_HI = $d048
  // Select memory bank where color data is fetched from (bits 11:0)
  // Memory address of Color RAM is ColorBank*$400
  .label DTV_COLOR_BANK_LO = $d036
  .label DTV_COLOR_BANK_HI = $d037
  .const DTV_COLOR_BANK_DEFAULT = $1d800
  // Selects memory bank for normal VIC color mode and lower data for high color modes. (bits 5:0)
  // Memory address of VIC Graphics is GraphicsBank*$10000
  .label DTV_GRAPHICS_VIC_BANK = $d03d
  .const KEY_3 = 8
  .const KEY_A = $a
  .const KEY_4 = $b
  .const KEY_E = $e
  .const KEY_D = $12
  .const KEY_6 = $13
  .const KEY_C = $14
  .const KEY_7 = $18
  .const KEY_8 = $1b
  .const KEY_B = $1c
  .const KEY_H = $1d
  .const KEY_U = $1e
  .const KEY_0 = $23
  .const KEY_O = $26
  .const KEY_L = $2a
  .const KEY_1 = $38
  .const KEY_2 = $3b
  .const KEY_SPACE = $3c
  .label print_char_cursor = $69
  .label dtv_control = 9
  .label print_line_cursor = $6b
main: {
    sei
    // Disable normal interrupt (prevent keyboard reading glitches and allows to hide basic/kernal)
    // Disable kernal & basic
    lda #PROCPORT_DDR_MEMORY_MASK
    sta PROCPORT_DDR
    lda #PROCPORT_RAM_IO
    sta PROCPORT
    // Enable DTV extended modes
    lda #DTV_FEATURE_ENABLE
    sta DTV_FEATURE
  b1:
    jsr menu
    jmp b1
}
menu: {
    .label SCREEN = $8000
    .label CHARSET = $9800
    .label c = 2
    // Charset ROM
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<DTV_COLOR_BANK_DEFAULT/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    // DTV Graphics Mode
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - default
  b1:
    lda DTV_PALETTE_DEFAULT,x
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    lda #<COLS
    sta c
    lda #>COLS
    sta c+1
  // Char Colors
  b2:
    lda #LIGHT_GREEN
    ldy #0
    sta (c),y
    inc c
    bne !+
    inc c+1
  !:
    lda c+1
    cmp #>COLS+$3e8
    bne b2
    lda c
    cmp #<COLS+$3e8
    bne b2
    // Screen colors
    lda #0
    sta BGCOL
    sta BORDERCOL
    jsr print_set_screen
    jsr print_cls
    jsr print_str_lines
  b4:
    ldy #KEY_1
    jsr keyboard_key_pressed
    cmp #0
    beq b5
    jsr mode_stdchar
    rts
  b5:
    ldy #KEY_2
    jsr keyboard_key_pressed
    cmp #0
    beq b6
    jsr mode_ecmchar
    rts
  b6:
    ldy #KEY_3
    jsr keyboard_key_pressed
    cmp #0
    beq b7
    jsr mode_mcchar
    rts
  b7:
    ldy #KEY_4
    jsr keyboard_key_pressed
    cmp #0
    beq b8
    jsr mode_stdbitmap
    rts
  b8:
    ldy #KEY_6
    jsr keyboard_key_pressed
    cmp #0
    beq b9
    jsr mode_hicolstdchar
    rts
  b9:
    ldy #KEY_7
    jsr keyboard_key_pressed
    cmp #0
    beq b10
    jsr mode_hicolecmchar
    rts
  b10:
    ldy #KEY_8
    jsr keyboard_key_pressed
    cmp #0
    beq b11
    jsr mode_hicolmcchar
    rts
  b11:
    ldy #KEY_A
    jsr keyboard_key_pressed
    cmp #0
    beq b12
    jsr mode_sixsfred2
    rts
  b12:
    ldy #KEY_B
    jsr keyboard_key_pressed
    cmp #0
    beq b13
    jsr mode_twoplanebitmap
    rts
  b13:
    ldy #KEY_C
    jsr keyboard_key_pressed
    cmp #0
    beq b14
    jsr mode_sixsfred
    rts
  b14:
    ldy #KEY_D
    jsr keyboard_key_pressed
    cmp #0
    beq b15
    jsr mode_8bpppixelcell
    rts
  b15:
    ldy #KEY_E
    jsr keyboard_key_pressed
    cmp #0
    bne !b4+
    jmp b4
  !b4:
    jsr mode_8bppchunkybmm
    rts
}
//Chunky 8bpp Bitmap Mode (BMM = 0, ECM/MCM/HICOL/LINEAR/CHUNK/COLDIS = 1)
// Resolution: 320x200
// Linear Adressing
// CharData/PlaneB Pixel Shifter (8):
// - 8bpp color PlaneB[7:0]
// To set up a linear video frame buffer the step size must be set to 8.
mode_8bppchunkybmm: {
    // 8BPP Chunky Bitmap (contains 8bpp pixels)
    .const PLANEB = $20000
    .label _26 = $6f
    .label gfxb = 7
    .label x = 5
    .label y = 4
    lda #DTV_HIGHCOLOR|DTV_LINEAR|DTV_CHUNKY|DTV_COLORRAM_OFF
    sta DTV_CONTROL
    // VIC Graphics Mode
    lda #VIC_ECM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_MCM|VIC_CSEL
    sta VIC_CONTROL2
    // Linear Graphics Plane B Counter
    lda #0
    sta DTV_PLANEB_START_LO
    sta DTV_PLANEB_START_MI
    lda #<PLANEB>>$10
    sta DTV_PLANEB_START_HI
    lda #8
    sta DTV_PLANEB_STEP
    lda #0
    sta DTV_PLANEB_MODULO_LO
    sta DTV_PLANEB_MODULO_HI
    // Border color
    sta BORDERCOL
    tax
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    lda #PLANEB/$4000
    jsr dtvSetCpuBankSegment1
    ldx #PLANEB/$4000+1
    lda #0
    sta y
    lda #<$4000
    sta gfxb
    lda #>$4000
    sta gfxb+1
  b3:
    lda #<0
    sta x
    sta x+1
  b4:
    lda gfxb+1
    cmp #>$8000
    bne b5
    lda gfxb
    cmp #<$8000
    bne b5
    txa
    jsr dtvSetCpuBankSegment1
    inx
    lda #<$4000
    sta gfxb
    lda #>$4000
    sta gfxb+1
  b5:
    lda y
    clc
    adc x
    sta _26
    lda #0
    adc x+1
    sta _26+1
    lda _26
    ldy #0
    sta (gfxb),y
    inc gfxb
    bne !+
    inc gfxb+1
  !:
    inc x
    bne !+
    inc x+1
  !:
    lda x+1
    cmp #>$140
    bne b4
    lda x
    cmp #<$140
    bne b4
    inc y
    lda #$c8
    cmp y
    bne b3
    lda #$4000/$4000
    jsr dtvSetCpuBankSegment1
    lda #DTV_HIGHCOLOR|DTV_LINEAR|DTV_CHUNKY|DTV_COLORRAM_OFF
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Allow the user to control the DTV graphics using different keys
mode_ctrl: {
  b1:
  // Wait for the raster
  b2:
    lda #$ff
    cmp RASTER
    bne b2
    ldy #KEY_SPACE
    jsr keyboard_key_pressed
    cmp #0
    beq b4
    rts
  b4:
    // Read the current control byte
    ldx dtv_control
    ldy #KEY_L
    jsr keyboard_key_pressed
    cmp #0
    beq b5
    txa
    ora #DTV_LINEAR
    tax
  b5:
    ldy #KEY_H
    jsr keyboard_key_pressed
    cmp #0
    beq b6
    txa
    ora #DTV_HIGHCOLOR
    tax
  b6:
    ldy #KEY_O
    jsr keyboard_key_pressed
    cmp #0
    beq b7
    txa
    ora #DTV_OVERSCAN
    tax
  b7:
    ldy #KEY_B
    jsr keyboard_key_pressed
    cmp #0
    beq b8
    txa
    ora #DTV_BORDER_OFF
    tax
  b8:
    ldy #KEY_U
    jsr keyboard_key_pressed
    cmp #0
    beq b9
    txa
    ora #DTV_CHUNKY
    tax
  b9:
    ldy #KEY_C
    jsr keyboard_key_pressed
    cmp #0
    beq b10
    txa
    ora #DTV_COLORRAM_OFF
    tax
  b10:
    ldy #KEY_0
    jsr keyboard_key_pressed
    cmp #0
    beq b11
    ldx #0
  b11:
    cpx dtv_control
    beq b1
    stx dtv_control
    stx DTV_CONTROL
    stx BORDERCOL
    jmp b1
}
// Determines whether a specific key is currently pressed by accessing the matrix directly
// The key is a keyboard code defined from the keyboard matrix by %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
// All keys exist as as KEY_XXX constants.
// Returns zero if the key is not pressed and a non-zero value if the key is currently pressed
// keyboard_key_pressed(byte register(Y) key)
keyboard_key_pressed: {
    .label colidx = $71
    tya
    and #7
    sta colidx
    tya
    lsr
    lsr
    lsr
    tay
    jsr keyboard_matrix_read
    ldy colidx
    and keyboard_matrix_col_bitmask,y
    rts
}
// Read a single row of the keyboard matrix
// The row ID (0-7) of the keyboard matrix row to read. See the C64 key matrix for row IDs.
// Returns the keys pressed on the row as bits according to the C64 key matrix.
// Notice: If the C64 normal interrupt is still running it will occasionally interrupt right between the read & write
// leading to erroneous readings. You must disable kill the normal interrupt or sei/cli around calls to the keyboard matrix reader.
// keyboard_matrix_read(byte register(Y) rowid)
keyboard_matrix_read: {
    lda keyboard_matrix_row_bitmask,y
    sta CIA1_PORT_A
    lda CIA1_PORT_B
    eor #$ff
    rts
}
// Set the memory pointed to by CPU BANK 1 SEGMENT ($4000-$7fff)
// This sets which actual memory is addressed when the CPU reads/writes to $4000-$7fff
// The actual memory addressed will be $4000*cpuSegmentIdx
// dtvSetCpuBankSegment1(byte register(A) cpuBankIdx)
dtvSetCpuBankSegment1: {
    // Move CPU BANK 1 SEGMENT ($4000-$7fff)
    .label cpuBank = $ff
    sta cpuBank
    .byte $32, $dd
    lda $ff
    .byte $32, $00
    rts
}
//8bpp Pixel Cell Mode (BMM/COLDIS = 0, ECM/MCM/HICOL/LINEAR/CHUNK = 1)
//Pixel Cell Adressing
//CharData[8]: (PlaneA[21:0])
//GfxData[8]: (PlaneB[21:14] & CharData[7:0] & RowCounter[3:0] & PixelCounter[7:0] )
//GfxData Pixel Shifter (8):
//- 8bpp color GfxData[7:0]
//Pixel cell mode can be thought of as a text mode that uses a 8x8 pixel 8bpp font (64 bytes/char).
//The characters come from counter A and the font (or "cells") from counter B.
//Counter B step and modulo should be set to 0, counter A modulo to 0 and counter A step to 1 for normal operation.
mode_8bpppixelcell: {
    // 8BPP Pixel Cell Screen (contains 40x25=1000 chars)
    .label PLANEA = $3c00
    // 8BPP Pixel Cell Charset (contains 256 64 byte chars)
    .label PLANEB = $4000
    .label CHARGEN = $d000
    .label _15 = $72
    .label gfxa = $b
    .label ay = $a
    .label bits = $11
    .label chargen = $e
    .label gfxb = $12
    .label col = $14
    .label cr = $10
    .label ch = $d
    lda #DTV_HIGHCOLOR|DTV_LINEAR|DTV_CHUNKY
    sta DTV_CONTROL
    // VIC Graphics Mode
    lda #VIC_ECM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_MCM|VIC_CSEL
    sta VIC_CONTROL2
    // Linear Graphics Plane A Counter
    lda #0
    sta DTV_PLANEA_START_LO
    lda #>PLANEA
    sta DTV_PLANEA_START_MI
    lda #0
    sta DTV_PLANEA_START_HI
    lda #1
    sta DTV_PLANEA_STEP
    lda #0
    sta DTV_PLANEA_MODULO_LO
    sta DTV_PLANEA_MODULO_HI
    // Linear Graphics Plane B Counter
    sta DTV_PLANEB_START_LO
    lda #>PLANEB
    sta DTV_PLANEB_START_MI
    lda #0
    sta DTV_PLANEB_START_HI
    sta DTV_PLANEB_STEP
    sta DTV_PLANEB_MODULO_LO
    sta DTV_PLANEB_MODULO_HI
    // Border color
    sta BORDERCOL
    tax
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    lda #<PLANEA
    sta gfxa
    lda #>PLANEA
    sta gfxa+1
    lda #0
    sta ay
  b2:
    ldx #0
  b3:
    lda #$f
    and ay
    asl
    asl
    asl
    asl
    sta _15
    txa
    and #$f
    ora _15
    ldy #0
    sta (gfxa),y
    inc gfxa
    bne !+
    inc gfxa+1
  !:
    inx
    cpx #$28
    bne b3
    inc ay
    lda #$19
    cmp ay
    bne b2
    // 8bpp cells for Plane B (charset) - ROM charset with 256 colors
    lda #PROCPORT_RAM_CHARROM
    sta PROCPORT
    lda #0
    sta ch
    sta col
    lda #<PLANEB
    sta gfxb
    lda #>PLANEB
    sta gfxb+1
    lda #<CHARGEN
    sta chargen
    lda #>CHARGEN
    sta chargen+1
  b6:
    lda #0
    sta cr
  b7:
    ldy #0
    lda (chargen),y
    sta bits
    inc chargen
    bne !+
    inc chargen+1
  !:
    ldx #0
  b8:
    lda #$80
    and bits
    cmp #0
    beq b4
    lda col
    jmp b9
  b4:
    lda #0
  b9:
    ldy #0
    sta (gfxb),y
    inc gfxb
    bne !+
    inc gfxb+1
  !:
    asl bits
    inc col
    inx
    cpx #8
    bne b8
    inc cr
    lda #8
    cmp cr
    bne b7
    inc ch
    lda ch
    cmp #0
    bne b6
    lda #PROCPORT_RAM_IO
    sta PROCPORT
    lda #DTV_HIGHCOLOR|DTV_LINEAR|DTV_CHUNKY
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Sixs Fred Mode - 8bpp Packed Bitmap - Generated from the two DTV linear graphics plane counters
// Two Plane MultiColor Bitmap - 8bpp Packed Bitmap (CHUNK/COLDIS = 0, ECM/BMM/MCM/HICOL/LINEAR = 1)
// Resolution: 160x200
// Linear Adressing
// GfxData/PlaneA Pixel Shifter (2), CharData/PlaneB Pixel Shifter (2):
// - 8bpp color (ColorData[3:0],CharData/PlaneB[1:0], GfxData/PlaneA[1:0])
mode_sixsfred: {
    .label PLANEA = $4000
    .label PLANEB = $6000
    .label COLORS = $8000
    .label col = $16
    .label cy = $15
    .label gfxa = $19
    .label ay = $18
    .label gfxb = $1c
    .label by = $1b
    lda #DTV_HIGHCOLOR|DTV_LINEAR
    sta DTV_CONTROL
    // VIC Graphics Mode
    lda #VIC_ECM|VIC_BMM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_MCM|VIC_CSEL
    sta VIC_CONTROL2
    // Linear Graphics Plane A Counter
    lda #0
    sta DTV_PLANEA_START_LO
    lda #>PLANEA
    sta DTV_PLANEA_START_MI
    lda #0
    sta DTV_PLANEA_START_HI
    lda #1
    sta DTV_PLANEA_STEP
    lda #0
    sta DTV_PLANEA_MODULO_LO
    sta DTV_PLANEA_MODULO_HI
    // Linear Graphics Plane B Counter
    sta DTV_PLANEB_START_LO
    lda #>PLANEB
    sta DTV_PLANEB_START_MI
    lda #0
    sta DTV_PLANEB_START_HI
    lda #1
    sta DTV_PLANEB_STEP
    lda #0
    sta DTV_PLANEB_MODULO_LO
    sta DTV_PLANEB_MODULO_HI
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    tax
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    clc
    adc cy
    and #$f
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #<PLANEA
    sta gfxa
    lda #>PLANEA
    sta gfxa+1
    lda #0
    sta ay
  b6:
    ldx #0
  b7:
    lda ay
    lsr
    and #3
    tay
    lda row_bitmask,y
    ldy #0
    sta (gfxa),y
    inc gfxa
    bne !+
    inc gfxa+1
  !:
    inx
    cpx #$28
    bne b7
    inc ay
    lda #$c8
    cmp ay
    bne b6
    lda #0
    sta by
    lda #<PLANEB
    sta gfxb
    lda #>PLANEB
    sta gfxb+1
  b9:
    ldx #0
  b10:
    lda #$1b
    ldy #0
    sta (gfxb),y
    inc gfxb
    bne !+
    inc gfxb+1
  !:
    inx
    cpx #$28
    bne b10
    inc by
    lda #$c8
    cmp by
    bne b9
    lda #DTV_HIGHCOLOR|DTV_LINEAR
    sta dtv_control
    jsr mode_ctrl
    rts
    row_bitmask: .byte 0, $55, $aa, $ff
}
// Two Plane Bitmap - generated from the two DTV linear graphics plane counters
// Two Plane Bitmap Mode (CHUNK/COLDIS/MCM = 0, ECM/BMM/HICOL/LINEAR = 1)
// Resolution: 320x200
// Linear Adressing
// GfxData/PlaneA Pixel Shifter (1), CharData/PlaneB Pixel Shifter (1):
// - Plane A = 0 Plane B = 0: 8bpp BgColor0[7:0]
// - Plane A = 0 Plane B = 1: 8bpp "0000" & ColorData[7:4]
// - Plane A = 1 Plane B = 0: 8bpp "0000" & ColorData[3:0]
// - Plane A = 1 Plane B = 1: 8bpp BgColor1[7:0]
mode_twoplanebitmap: {
    .label PLANEA = $4000
    .label PLANEB = $6000
    .label COLORS = $8000
    .label _17 = $73
    .label col = $1f
    .label cy = $1e
    .label gfxa = $22
    .label ay = $21
    .label gfxb = $25
    .label by = $24
    lda #DTV_HIGHCOLOR|DTV_LINEAR
    sta DTV_CONTROL
    // VIC Graphics Mode
    lda #VIC_ECM|VIC_BMM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // Linear Graphics Plane A Counter
    lda #0
    sta DTV_PLANEA_START_LO
    lda #>PLANEA
    sta DTV_PLANEA_START_MI
    lda #0
    sta DTV_PLANEA_START_HI
    lda #1
    sta DTV_PLANEA_STEP
    lda #0
    sta DTV_PLANEA_MODULO_LO
    sta DTV_PLANEA_MODULO_HI
    // Linear Graphics Plane B Counter
    sta DTV_PLANEB_START_LO
    lda #>PLANEB
    sta DTV_PLANEB_START_MI
    lda #0
    sta DTV_PLANEB_START_HI
    lda #1
    sta DTV_PLANEB_STEP
    lda #0
    sta DTV_PLANEB_MODULO_LO
    sta DTV_PLANEB_MODULO_HI
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    tax
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #$70
    sta BGCOL1
    // Color for bits 00
    lda #$d4
    sta BGCOL2
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _17
    txa
    and #$f
    ora _17
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #<PLANEA
    sta gfxa
    lda #>PLANEA
    sta gfxa+1
    lda #0
    sta ay
  b6:
    ldx #0
  b7:
    lda #4
    and ay
    cmp #0
    beq b8
    lda #$ff
    ldy #0
    sta (gfxa),y
    inc gfxa
    bne !+
    inc gfxa+1
  !:
  b9:
    inx
    cpx #$28
    bne b7
    inc ay
    lda #$c8
    cmp ay
    bne b6
    lda #0
    sta by
    lda #<PLANEB
    sta gfxb
    lda #>PLANEB
    sta gfxb+1
  b12:
    ldx #0
  b13:
    lda #$f
    ldy #0
    sta (gfxb),y
    inc gfxb
    bne !+
    inc gfxb+1
  !:
    inx
    cpx #$28
    bne b13
    inc by
    lda #$c8
    cmp by
    bne b12
    lda #DTV_HIGHCOLOR|DTV_LINEAR
    sta dtv_control
    jsr mode_ctrl
    rts
  b8:
    lda #0
    tay
    sta (gfxa),y
    inc gfxa
    bne !+
    inc gfxa+1
  !:
    jmp b9
}
// Sixs Fred Mode 2 - 8bpp Packed Bitmap - Generated from the two DTV linear graphics plane counters
// Two Plane MultiColor Bitmap - 8bpp Packed Bitmap (CHUNK/COLDIS/HICOL = 0, ECM/BMM/MCM/LINEAR = 1)
// Resolution: 160x200
// Linear Adressing
// PlaneA Pixel Shifter (2), PlaneB Pixel Shifter (2):
// - 8bpp color (PlaneB[1:0],ColorData[5:4],PlaneA[1:0],ColorData[1:0])
mode_sixsfred2: {
    .label PLANEA = $4000
    .label PLANEB = $6000
    .label COLORS = $8000
    .label _16 = $74
    .label col = $28
    .label cy = $27
    .label gfxa = $2b
    .label ay = $2a
    .label gfxb = $2e
    .label by = $2d
    lda #DTV_LINEAR
    sta DTV_CONTROL
    // VIC Graphics Mode
    lda #VIC_ECM|VIC_BMM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_MCM|VIC_CSEL
    sta VIC_CONTROL2
    // Linear Graphics Plane A Counter
    lda #0
    sta DTV_PLANEA_START_LO
    lda #>PLANEA
    sta DTV_PLANEA_START_MI
    lda #0
    sta DTV_PLANEA_START_HI
    lda #1
    sta DTV_PLANEA_STEP
    lda #0
    sta DTV_PLANEA_MODULO_LO
    sta DTV_PLANEA_MODULO_HI
    // Linear Graphics Plane B Counter
    sta DTV_PLANEB_START_LO
    lda #>PLANEB
    sta DTV_PLANEB_START_MI
    lda #0
    sta DTV_PLANEB_START_HI
    lda #1
    sta DTV_PLANEB_STEP
    lda #0
    sta DTV_PLANEB_MODULO_LO
    sta DTV_PLANEB_MODULO_HI
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    tax
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    and #3
    asl
    asl
    asl
    asl
    sta _16
    lda #3
    and cy
    ora _16
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #<PLANEA
    sta gfxa
    lda #>PLANEA
    sta gfxa+1
    lda #0
    sta ay
  b6:
    ldx #0
  b7:
    lda ay
    lsr
    and #3
    tay
    lda row_bitmask,y
    ldy #0
    sta (gfxa),y
    inc gfxa
    bne !+
    inc gfxa+1
  !:
    inx
    cpx #$28
    bne b7
    inc ay
    lda #$c8
    cmp ay
    bne b6
    lda #0
    sta by
    lda #<PLANEB
    sta gfxb
    lda #>PLANEB
    sta gfxb+1
  b9:
    ldx #0
  b10:
    lda #$1b
    ldy #0
    sta (gfxb),y
    inc gfxb
    bne !+
    inc gfxb+1
  !:
    inx
    cpx #$28
    bne b10
    inc by
    lda #$c8
    cmp by
    bne b9
    lda #DTV_LINEAR
    sta dtv_control
    jsr mode_ctrl
    rts
    row_bitmask: .byte 0, $55, $aa, $ff
}
// High Color Multicolor Character Mode (LINEAR/CHUNK/COLDIS/BMM/ECM = 0, MCM/HICOL = 1)
// Resolution: 160x200 (320x200)
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & CharData[7:0] & RowCounter[2:0] )
//GfxData Pixel Shifter (1) if ColorData[3:3] = 0:
// - 0: 8bpp BgColor0[7:0]
// - 1: 8bpp ColorData[7:4] "0" & Color[2:0]
//GfxData Pixel Shifter (2) if ColorData[3:3] = 1:
// - 00: 8bpp BgColor0[7:0]
// - 01: 8bpp BgColor1[7:0]
// - 10: 8bpp BgColor2[7:0]
// - 11: 8bpp ColorData[7:4] "0" & Color[2:0]
mode_hicolmcchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $8400
    .label _27 = $75
    .label col = $31
    .label ch = $33
    .label cy = $30
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    lda #DTV_HIGHCOLOR
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL|VIC_MCM
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #$50
    sta BGCOL1
    lda #$54
    sta BGCOL2
    lda #$58
    sta BGCOL3
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _27
    txa
    and #$f
    ora _27
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #DTV_HIGHCOLOR
    sta dtv_control
    jsr mode_ctrl
    rts
}
// High Color Extended Background Color Character Mode (LINEAR/CHUNK/COLDIS/MCM/BMM = 0, ECM/HICOL = 1)
// Resolution: 320x200
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & "00" & CharData[5:0] & RowCounter[2:0] )
// GfxData Pixel Shifter (1)
//  - 0: 8bpp Background Color
//    - CharData[7:6] 00: 8bpp BgColor0[7:0]
//    - CharData[7:6] 01: 8bpp BgColor1[7:0]
//    - CharData[7:6] 10: 8bpp BgColor2[7:0]
//    - CharData[7:6] 11: 8bpp BgColor3[7:0]
//  - 1: 8bpp ColorData[7:0]
mode_hicolecmchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $8400
    .label _27 = $76
    .label col = $36
    .label ch = $38
    .label cy = $35
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    lda #DTV_HIGHCOLOR
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|VIC_ECM|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #$50
    sta BGCOL1
    lda #$54
    sta BGCOL2
    lda #$58
    sta BGCOL3
    lda #$5c
    sta BGCOL4
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _27
    txa
    and #$f
    ora _27
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #DTV_HIGHCOLOR
    sta dtv_control
    jsr mode_ctrl
    rts
}
// High Color Standard Character Mode (LINEAR/CHUNK/COLDIS/ECM/MCM/BMM = 0, HICOL = 1)
// Resolution: 320x200
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & CharData[7:0] & RowCounter[2:0] )
// Pixel Shifter (1)
//  - 0: 8bpp BgColor0[7:0]
//  - 1: 8bpp ColorData[7:0]
mode_hicolstdchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $8400
    .label _26 = $77
    .label col = $3b
    .label ch = $3d
    .label cy = $3a
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<COLORS/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    lda #DTV_HIGHCOLOR
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - Grey Tones
  b1:
    txa
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BGCOL
    sta BORDERCOL
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _26
    txa
    and #$f
    ora _26
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #DTV_HIGHCOLOR
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Standard Bitmap Mode (LINEAR/HICOL/CHUNK/COLDIS/MCM/ECM = 0, BMM = 1)
// Resolution: 320x200
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:2] & Matrix[9:0] & RowCounter[2:0] )
// Pixel Shifter (1)
//  - 0: 4bpp CharData[3:0]
//  - 1: 4bpp CharData[7:4]
mode_stdbitmap: {
    .label SCREEN = $4000
    .label BITMAP = $6000
    .const lines_cnt = 9
    .label col2 = $78
    .label ch = $40
    .label cy = $3f
    .label l = $42
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^BITMAP/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_BMM|VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(BITMAP&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - default
  b1:
    lda DTV_PALETTE_DEFAULT,x
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #BLACK
    sta BGCOL
    sta BORDERCOL
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    clc
    adc cy
    and #$f
    tay
    tya
    eor #$ff
    clc
    adc #$f+1
    sta col2
    tya
    asl
    asl
    asl
    asl
    ora col2
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    jsr bitmap_init
    jsr bitmap_clear
    lda #0
    sta l
  b7:
    ldy l
    lda lines_x,y
    sta bitmap_line.x0
    ldx lines_x+1,y
    lda lines_y,y
    sta bitmap_line.y0
    lda lines_y+1,y
    sta bitmap_line.y1
    jsr bitmap_line
    inc l
    lda l
    cmp #lines_cnt
    bcc b7
    lda #0
    sta dtv_control
    jsr mode_ctrl
    rts
    lines_x: .byte 0, $ff, $ff, 0, 0, $80, $ff, $80, 0, $80
    lines_y: .byte 0, 0, $c7, $c7, 0, 0, $64, $c7, $64, 0
}
// Draw a line on the bitmap
// bitmap_line(byte zeropage($45) x0, byte register(X) x1, byte zeropage($47) y0, byte zeropage($4a) y1)
bitmap_line: {
    .label xd = $44
    .label x0 = $45
    .label y0 = $47
    .label y1 = $4a
    txa
    cmp x0
    beq !+
    bcs b1
  !:
    txa
    eor #$ff
    sec
    adc x0
    sta xd
    lda y0
    cmp y1
    bcc b7
    sec
    sbc y1
    tay
    cpy xd
    bcc b8
    lda y1
    sta bitmap_line_ydxi.y
    lda y0
    sta bitmap_line_ydxi.y1
    sty bitmap_line_ydxi.yd
    jsr bitmap_line_ydxi
    rts
  b8:
    stx bitmap_line_xdyi.x
    lda y1
    sta bitmap_line_xdyi.y
    sty bitmap_line_xdyi.yd
    jsr bitmap_line_xdyi
    rts
  b7:
    lda y1
    sec
    sbc y0
    tay
    cpy xd
    bcc b9
    lda y0
    sta bitmap_line_ydxd.y
    ldx x0
    lda y1
    sta bitmap_line_ydxd.y1
    sty bitmap_line_ydxd.yd
    jsr bitmap_line_ydxd
    rts
  b9:
    stx bitmap_line_xdyd.x
    lda y1
    sta bitmap_line_xdyd.y
    sty bitmap_line_xdyd.yd
    jsr bitmap_line_xdyd
    rts
  b1:
    txa
    sec
    sbc x0
    sta xd
    lda y0
    cmp y1
    bcc b11
    sec
    sbc y1
    tay
    cpy xd
    bcc b12
    lda y1
    sta bitmap_line_ydxd.y
    sty bitmap_line_ydxd.yd
    jsr bitmap_line_ydxd
    rts
  b12:
    lda x0
    sta bitmap_line_xdyd.x
    stx bitmap_line_xdyd.x1
    sty bitmap_line_xdyd.yd
    jsr bitmap_line_xdyd
    rts
  b11:
    lda y1
    sec
    sbc y0
    tay
    cpy xd
    bcc b13
    lda y0
    sta bitmap_line_ydxi.y
    ldx x0
    sty bitmap_line_ydxi.yd
    jsr bitmap_line_ydxi
    rts
  b13:
    lda x0
    sta bitmap_line_xdyi.x
    stx bitmap_line_xdyi.x1
    sty bitmap_line_xdyi.yd
    jsr bitmap_line_xdyi
    rts
}
// bitmap_line_xdyi(byte zeropage($46) x, byte zeropage($47) y, byte zeropage($45) x1, byte zeropage($44) xd, byte zeropage($43) yd)
bitmap_line_xdyi: {
    .label x = $46
    .label y = $47
    .label x1 = $45
    .label xd = $44
    .label yd = $43
    .label e = $48
    lda yd
    lsr
    sta e
  b1:
    ldx x
    ldy y
    jsr bitmap_plot
    inc x
    lda e
    clc
    adc yd
    sta e
    lda xd
    cmp e
    bcs b2
    inc y
    lda e
    sec
    sbc xd
    sta e
  b2:
    ldx x1
    inx
    cpx x
    bne b1
    rts
}
// bitmap_plot(byte register(X) x, byte register(Y) y)
bitmap_plot: {
    .label plotter_x = $79
    .label plotter_y = $7b
    .label plotter = $79
    lda bitmap_plot_xhi,x
    sta plotter_x+1
    lda bitmap_plot_xlo,x
    sta plotter_x
    lda bitmap_plot_yhi,y
    sta plotter_y+1
    lda bitmap_plot_ylo,y
    sta plotter_y
    lda plotter
    clc
    adc plotter_y
    sta plotter
    lda plotter+1
    adc plotter_y+1
    sta plotter+1
    lda bitmap_plot_bit,x
    ldy #0
    ora (plotter),y
    sta (plotter),y
    rts
}
// bitmap_line_ydxi(byte zeropage($4b) y, byte register(X) x, byte zeropage($4a) y1, byte zeropage($49) yd, byte zeropage($44) xd)
bitmap_line_ydxi: {
    .label y = $4b
    .label y1 = $4a
    .label yd = $49
    .label xd = $44
    .label e = $4c
    lda xd
    lsr
    sta e
  b1:
    ldy y
    jsr bitmap_plot
    inc y
    lda e
    clc
    adc xd
    sta e
    lda yd
    cmp e
    bcs b2
    inx
    lda e
    sec
    sbc yd
    sta e
  b2:
    lda y1
    clc
    adc #1
    cmp y
    bne b1
    rts
}
// bitmap_line_xdyd(byte zeropage($4e) x, byte zeropage($47) y, byte zeropage($45) x1, byte zeropage($44) xd, byte zeropage($4d) yd)
bitmap_line_xdyd: {
    .label x = $4e
    .label y = $47
    .label x1 = $45
    .label xd = $44
    .label yd = $4d
    .label e = $4f
    lda yd
    lsr
    sta e
  b1:
    ldx x
    ldy y
    jsr bitmap_plot
    inc x
    lda e
    clc
    adc yd
    sta e
    lda xd
    cmp e
    bcs b2
    dec y
    lda e
    sec
    sbc xd
    sta e
  b2:
    ldx x1
    inx
    cpx x
    bne b1
    rts
}
// bitmap_line_ydxd(byte zeropage($51) y, byte register(X) x, byte zeropage($47) y1, byte zeropage($50) yd, byte zeropage($44) xd)
bitmap_line_ydxd: {
    .label y = $51
    .label y1 = $47
    .label yd = $50
    .label xd = $44
    .label e = $52
    lda xd
    lsr
    sta e
  b1:
    ldy y
    jsr bitmap_plot
    inc y
    lda e
    clc
    adc xd
    sta e
    lda yd
    cmp e
    bcs b2
    dex
    lda e
    sec
    sbc yd
    sta e
  b2:
    lda y1
    clc
    adc #1
    cmp y
    bne b1
    rts
}
// Clear all graphics on the bitmap
bitmap_clear: {
    .label bitmap = $54
    .label y = $53
    lda bitmap_plot_xlo
    sta bitmap
    lda bitmap_plot_xhi
    sta bitmap+1
    lda #0
    sta y
  b1:
    ldx #0
  b2:
    lda #0
    tay
    sta (bitmap),y
    inc bitmap
    bne !+
    inc bitmap+1
  !:
    inx
    cpx #$c8
    bne b2
    inc y
    lda #$28
    cmp y
    bne b1
    rts
}
// Initialize the bitmap plotter tables for a specific bitmap
bitmap_init: {
    .label _10 = $7d
    .label yoffs = $56
    ldy #$80
    ldx #0
  b1:
    txa
    and #$f8
    sta bitmap_plot_xlo,x
    lda #>mode_stdbitmap.BITMAP
    sta bitmap_plot_xhi,x
    tya
    sta bitmap_plot_bit,x
    tya
    lsr
    tay
    cpy #0
    bne b2
    ldy #$80
  b2:
    inx
    cpx #0
    bne b1
    lda #<0
    sta yoffs
    sta yoffs+1
    tax
  b3:
    lda #7
    sax _10
    lda yoffs
    ora _10
    sta bitmap_plot_ylo,x
    lda yoffs+1
    sta bitmap_plot_yhi,x
    lda #7
    cmp _10
    bne b4
    clc
    lda yoffs
    adc #<$28*8
    sta yoffs
    lda yoffs+1
    adc #>$28*8
    sta yoffs+1
  b4:
    inx
    cpx #0
    bne b3
    rts
}
// Multicolor Character Mode (LINEAR/HICOL/CHUNK/COLDIS/BMM/ECM = 0, MCM = 1)
// Resolution: 160x200 (320x200)
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & CharData[7:0] & RowCounter[2:0] )
// GfxData Pixel Shifter (1) if ColorData[3:3] = 0:
//  - 0: 4bpp BgColor0[3:0]
//  - 1: 4bpp ColorData[2:0]
// GfxData Pixel Shifter (2) if ColorData[3:3] = 1:
//  - 00: 4bpp BgColor0[3:0]
//  - 01: 4bpp BgColor1[3:0]
//  - 10: 4bpp BgColor2[3:0]
//  - 11: 4bpp ColorData[2:0]// Standard Character Mode (LINEAR/HICOL/CHUNK/COLDIS/ECM/MCM/BMM = 0)
mode_mcchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $d800
    .label _29 = $7e
    .label col = $59
    .label ch = $5b
    .label cy = $58
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<DTV_COLOR_BANK_DEFAULT/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL|VIC_MCM
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - default
  b1:
    lda DTV_PALETTE_DEFAULT,x
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    lda #BLACK
    sta BGCOL1
    lda #GREEN
    sta BGCOL2
    lda #BLUE
    sta BGCOL3
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    clc
    adc cy
    and #$f
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _29
    txa
    and #$f
    ora _29
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #0
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Extended Background Color Character Mode (LINEAR/HICOL/CHUNK/COLDIS/MCM/BMM = 0, ECM = 1)
// Resolution: 320x200
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & "00" & CharData[5:0] & RowCounter[2:0] ) 
// GfxData Pixel Shifter (1)
//  - 0: 4bpp Background Color
//    - CharData[7:6] 00: 4bpp BgColor0[3:0]
//    - CharData[7:6] 01: 4bpp BgColor1[3:0]
//    - CharData[7:6] 10: 4bpp BgColor2[3:0]
//    - CharData[7:6] 11: 4bpp BgColor3[3:0]
//  - 1: 4bpp ColorData[3:0]
mode_ecmchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $d800
    .label _29 = $7f
    .label col = $5e
    .label ch = $60
    .label cy = $5d
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<DTV_COLOR_BANK_DEFAULT/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|VIC_ECM|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - default
  b1:
    lda DTV_PALETTE_DEFAULT,x
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BORDERCOL
    sta BGCOL1
    lda #2
    sta BGCOL2
    lda #5
    sta BGCOL3
    lda #6
    sta BGCOL4
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    clc
    adc cy
    and #$f
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _29
    txa
    and #$f
    ora _29
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #0
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Standard Character Mode (LINEAR/HICOL/CHUNK/COLDIS/ECM/MCM/BMM = 0)
// Resolution: 320x200
// Normal VIC Adressing:
// VicGfxData[16]: ( VicBank[1:0] & CharBase[2:0] & CharData[7:0] & RowCounter[2:0] )
// Pixel Shifter (1)
// - 0: 4bpp BgColor0[3:0]
// - 1: 4bpp ColorData[3:0]
mode_stdchar: {
    .label SCREEN = $8000
    .label CHARSET = $9000
    // Charset ROM
    .label COLORS = $d800
    .label _28 = $80
    .label col = $63
    .label ch = $65
    .label cy = $62
    // DTV Graphics Bank
    lda #0
    sta DTV_GRAPHICS_VIC_BANK
    // DTV Color Bank
    lda #<DTV_COLOR_BANK_DEFAULT/$400
    sta DTV_COLOR_BANK_LO
    lda #0
    sta DTV_COLOR_BANK_HI
    sta DTV_CONTROL
    // VIC Graphics Bank
    lda #3
    sta CIA2_PORT_A_DDR
    // Set VIC Bank bits to output - all others to input
    lda #3^CHARSET/$4000
    sta CIA2_PORT_A
    // Set VIC Bank
    // VIC Graphics Mode
    lda #VIC_DEN|VIC_RSEL|3
    sta VIC_CONTROL
    lda #VIC_CSEL
    sta VIC_CONTROL2
    // VIC Memory Pointers
    lda #(CHARSET&$3fff)/$400
    sta VIC_MEMORY
    ldx #0
  // DTV Palette - default
  b1:
    lda DTV_PALETTE_DEFAULT,x
    sta DTV_PALETTE,x
    inx
    cpx #$10
    bne b1
    // Screen colors
    lda #0
    sta BGCOL
    sta BORDERCOL
    lda #<SCREEN
    sta ch
    lda #>SCREEN
    sta ch+1
    lda #<COLORS
    sta col
    lda #>COLORS
    sta col+1
    lda #0
    sta cy
  b3:
    ldx #0
  b4:
    txa
    clc
    adc cy
    and #$f
    ldy #0
    sta (col),y
    inc col
    bne !+
    inc col+1
  !:
    lda #$f
    and cy
    asl
    asl
    asl
    asl
    sta _28
    txa
    and #$f
    ora _28
    ldy #0
    sta (ch),y
    inc ch
    bne !+
    inc ch+1
  !:
    inx
    cpx #$28
    bne b4
    inc cy
    lda #$19
    cmp cy
    bne b3
    lda #0
    sta dtv_control
    jsr mode_ctrl
    rts
}
// Print a number of zero-terminated strings, each followed by a newline.
// The sequence of lines is terminated by another zero.
// print_str_lines(byte* zeropage($67) str)
print_str_lines: {
    .label str = $67
    lda #<menu.SCREEN
    sta print_line_cursor
    lda #>menu.SCREEN
    sta print_line_cursor+1
    lda #<menu.SCREEN
    sta print_char_cursor
    lda #>menu.SCREEN
    sta print_char_cursor+1
    lda #<MENU_TEXT
    sta str
    lda #>MENU_TEXT
    sta str+1
  b1:
    ldy #0
    lda (str),y
    cmp #'@'
    bne b2
    rts
  b2:
    ldy #0
    lda (str),y
    inc str
    bne !+
    inc str+1
  !:
    cmp #'@'
    beq b3
    ldy #0
    sta (print_char_cursor),y
    inc print_char_cursor
    bne !+
    inc print_char_cursor+1
  !:
  b3:
    cmp #'@'
    bne b2
    jsr print_ln
    lda print_line_cursor
    sta print_char_cursor
    lda print_line_cursor+1
    sta print_char_cursor+1
    jmp b1
}
// Print a newline
print_ln: {
  b1:
    lda #$28
    clc
    adc print_line_cursor
    sta print_line_cursor
    bcc !+
    inc print_line_cursor+1
  !:
    lda print_line_cursor+1
    cmp print_char_cursor+1
    bcc b1
    bne !+
    lda print_line_cursor
    cmp print_char_cursor
    bcc b1
  !:
    rts
}
// Clear the screen. Also resets current line/char cursor.
print_cls: {
    .label sc = $6d
    lda #<menu.SCREEN
    sta sc
    lda #>menu.SCREEN
    sta sc+1
  b1:
    lda #' '
    ldy #0
    sta (sc),y
    inc sc
    bne !+
    inc sc+1
  !:
    lda sc+1
    cmp #>menu.SCREEN+$3e8
    bne b1
    lda sc
    cmp #<menu.SCREEN+$3e8
    bne b1
    rts
}
// Set the screen to print on. Also resets current line/char cursor.
print_set_screen: {
    rts
}
  // Default vallues for the palette
  DTV_PALETTE_DEFAULT: .byte 0, $f, $36, $be, $58, $db, $86, $ff, $29, $26, $3b, 5, 7, $df, $9a, $a
  // Keyboard row bitmask as expected by CIA#1 Port A when reading a specific keyboard matrix row (rows are numbered 0-7)
  keyboard_matrix_row_bitmask: .byte $fe, $fd, $fb, $f7, $ef, $df, $bf, $7f
  // Keyboard matrix column bitmasks for a specific keybooard matrix column when reading the keyboard. (columns are numbered 0-7)
  keyboard_matrix_col_bitmask: .byte 1, 2, 4, 8, $10, $20, $40, $80
  // Tables for the plotter - initialized by calling bitmap_draw_init();
  bitmap_plot_xlo: .fill $100, 0
  bitmap_plot_xhi: .fill $100, 0
  bitmap_plot_ylo: .fill $100, 0
  bitmap_plot_yhi: .fill $100, 0
  bitmap_plot_bit: .fill $100, 0
  MENU_TEXT: .text "C64DTV Graphics Modes            CCLHBME@                                 OHIIMCC@                                 LUNCMMM@----------------------------------------@1. Standard Char             (V) 0000000@2. Extended Color Char       (V) 0000001@3. Multicolor Char           (V) 0000010@4. Standard Bitmap           (V) 0000100@5. Multicolor Bitmap         (V) 0000110@6. High Color Standard Char  (H) 0001000@7. High Extended Color Char  (H) 0001001@8. High Multicolor Char      (H) 0001010@9. High Multicolor Bitmap    (H) 0001110@a. Sixs Fred 2               (D) 0010111@b. Two Plane Bitmap          (D) 0011101@c. Sixs Fred (2 Plane MC BM) (D) 0011111@d. 8bpp Pixel Cell           (D) 0111011@e. Chunky 8bpp Bitmap        (D) 1111011@----------------------------------------@    (V) vicII (H) vicII+hicol (D) c64dtv@@"
