Thursday, 14 September 2017

Minigraph disassembly complete!

So I've completed pulling apart MINIGRAPH (see my last blog post). Looks like it performs an integer version of Bresenham's Algorithm (what else?) to do the line drawing.

// da65 V2.15 - Git f7cdfbf
// Created:    2016-02-19 10:03:56
// Input file: minigraph.bin
// Page:       1

// Each 8x8 block of screen is actually a character and there are 40x25 chars
// For a given x e (0,319) and y e (0, 199) pixel
// CH.ROW = INT(Y/8)
// CH.COL = INT(X/8)
// CH.LINE = Y % 8
// BIT within byte = 7 - (X % 8)
// pixel address = ($E000 + CH.ROW*320 + CH.COL*8 + CH.LINE)
// pixel address = ($E000 + INT(Y/8)*320 + INT(X/8)*8 + (Y % 8))
// pixel address = ($E000 + ((Y & $FFF8) * $28) + (X & $F8) + (Y & 7))
// That is, there are 320 bytes per 320x8 pixel stripe (or line)
// Each byte within the stripe is 8 vertical pixels
// Total framebuffer memory is 8000 bytes (320 bytes/line x 25 lines)
// We can set the foreground and background colour of each 8x8 cell
// but MINIGRAPH only lets you set a single colour.

        .setcpu "6502"

basic_check_for_comma     := $AEFD // BASIC Check for comma
basic_illegal_qty         := $B248 // BASIC routine which emits ?ILLEGAL QUANTITY
basic_evaluate_x          := $B79E // BASIC Evaluate into X register
basic_get_adr_get_byte    := $B7EB // BASIC Get 16-bit address (into $14/$15) and get byte into X

COLOUR_MEMORY     := $C000 // fg/bg colour - up to $C3E7
COLOUR_MEMORY_END := $C3E7
PIXEL_MEMORY      := $E000 // Shadows KERNAL ROM - we write, but must set HIRAM to read
PIXEL_MEMORY_END  := $FF3F

// Free zero-page space
ZP_ADDR_LOW       := $FB
ZP_ADDR_HI        := $FC
FREE_ZEROPAGE_2   := $FD
FREE_ZEROPAGE_3   := $FE

//
// Global variables, from C400 to C412
//
DRAW_MODE         := $C400 // 0 = flip, 1 = draw, 2 = erase
CURRENT_X_LO        := $C401 // current 16-bit X co-ord
CURRENT_X_HI        := $C402 // -------- "" --------
CURRENT_Y_LO        := $C403 // current 16-bit Y co-ord
CURRENT_Y_HI        := $C404 // -------- "" --------
END_X_LO          := $C405 // end of line 16-bit X co-ord
END_X_HI          := $C406 // -------- "" --------
END_Y_LO          := $C407 // end of line Y co-ord
END_Y_HI          := $C408 // -------- "" --------
COLOUR            := $C409 // FG hi-nibble, BG lo-nibble
DEC_BINC_X        := $C40A // False/0 = Increment, True/$FF = Decrement
DEC_BINC_Y        := $C40B // False/0 = Increment, True/$FF = Decrement
DELTA_X_LO        := $C40C // Length of line in X direction
DELTA_X_HI        := $C40D
DELTA_Y_LO        := $C40E // Length of line in Y direction
DELTA_Y_HI        := $C40F
ERROR_ACC_LO  := $C410 // Larger of DELTA_X and DELTA_Y
ERROR_ACC_HI  := $C411
DELTA_Y_LARGER        := $C412 // True if delta-y > delta-x

// ------------------------------------------------------
//
// Entry points:
//
// TURN ON BITMAP -   SYS 50195
// TURN OFF BITMAP -  SYS 50198
// PLOT POINT @ X,Y - SYS 50201,X,Y,M
// DRAW LINE TO X,Y - SYS 50204,X,Y,M
// CLEAR BITMAP -     SYS 50207
// COLOUR BITMAP -    SYS 50210,F,B
//
// ------------------------------------------------------
bitmap_on:
        jmp     fn_bitmap_on

bitmap_off:
        jmp     fn_bitmap_off

plot_point:
        jmp     fn_plot_point

draw_line:
        jmp     fn_draw_line

clear_bmp:
        jmp     fn_clear_bmp

set_colour:
        jmp     fn_set_colour

// ------------------------------------------------------
//
// plot_point routine
// Arguments from from SYS command parameters: ,X,Y,mode
//
// ------------------------------------------------------
fn_plot_point:
        lda     #$00
        sta     CURRENT_Y_HI            // Zero high byte of CURRENT_Y
        jsr     basic_check_for_comma
        jsr     basic_get_adr_get_byte     // Read 8-bit Y-cordinate into X register and 16-bit X co-ord into $14/$15
        cpx     #$C8                       // Check if Y coord <= 200
        bcc     LC437
fn_plot_point_err:
        jmp     fn_error
LC437:  stx     CURRENT_Y_LO            // Store y-coordinate in CURRENT_Y_LO
        ldx     $14                        // get X co-ord
        lda     $15                        //
        beq     LC448                      // If x co-ord < 255 (i.e. high-byte == 0), that's OK
        cmp     #$01                       // if x co-ord >= 512 (i.e. high byte != 1), error
        bne     fn_plot_point_err
        cpx     #$40                       // If x co-ord >= 256, check x co-ord < 320
        bcs     fn_plot_point_err
LC448:  sta     CURRENT_X_HI            // Store x co-ord in CURRENT_X_LO/CURRENT_X_HI
        stx     CURRENT_X_LO
        jsr     basic_check_for_comma      // Now store mode (flip, draw or erase) in X
        jsr     basic_evaluate_x
        cpx     #$03                       // Check mode is < 3
        bcs     fn_plot_point_err
        stx     DRAW_MODE                  // Store mode in DRAW_MODE
// Mode (flip=0, draw=1 or erase=2) must be in DRAW_MODE
// X is in CURRENT_X_LO/CURRENT_X_HI
// Y is in CURRENT_Y_LO/CURRENT_Y_HI
set_pixel_mode_switch:
        lda     DRAW_MODE                  // Load mode from DRAW_MODE
        beq     flip_pixel                 // If mode == FLIP, goto flip_pixel
        lsr     a                          // divide mode by 2
        bcc     erase_pixel                // If mode == ERASE (i.e. carry clear), goto erase_pixel
draw_pixel:
        jsr     fn_get_pixel_addr           // CURRENT_X,CURRENT_Y_ => ZP_ADDR
        jsr     fn_load_pixel_byte          // Load pixel byte from ZP_ADDR and store byte index in X
        ora     data_bit_mirror_table,x     // OR => Set bit in pixel byte
        sta     (ZP_ADDR_LOW),y             // Store modified byte in pixel memory
        rts
erase_pixel:
        jsr     fn_get_pixel_addr           // CURRENT_X,CURRENT_Y_ => ZP_ADDR
        jsr     fn_load_pixel_byte          // Load pixel byte from ZP_ADDR and store byte index in X
        and     data_nbit_mirror_table,x    // AND => Clear bit in pixel byte
        sta     (ZP_ADDR_LOW),y             // Store modified byte in pixel memory
        rts
flip_pixel:
        jsr     fn_get_pixel_addr           // CURRENT_X,CURRENT_Y_ => ZP_ADDR
        jsr     fn_load_pixel_byte          // Load pixel byte from ZP_ADDR and store byte index in X
        eor     data_bit_mirror_table,x     // XOR => Flip pixel in pixel byte
        sta     (ZP_ADDR_LOW),y             // Store modified byte in pixel memory
        rts

// ------------------------------------------------------
//
// Load pixel byte and get bit index routine
// Output:
//    X = X co-ord modulo 8 (i.e. selects the bit in the pixel byte, but it needs flipping)
//    A = pixel byte loaded from ZP_ADDR
//
// Note on address $0001:
//    bit 0 : LORAM (0=RAM 1=BASIC_ROM at A000)
//    bit 1 : HIRAM (0=RAM or 1=KERNAL_ROM at E000)
//    bit 2 : CHAREN (0=CHAR_RAM/CHAR_ROM or 1=I/O at D000)
//    the other bits are Datasette related
//
//    So $34 banks all three RAMs in
//       $37 is the BASIC default (BASIC ROM, I/O and KERNAL ROM)
//
// We've stuck our frame buffer at E000 behind KERNAL ROM to save space, hence the bank switch to read it
//
// ------------------------------------------------------
fn_load_pixel_byte:
        lda     CURRENT_X_LO            // A = X co-ord % 8
        and     #$07                       //
        tax                                // X = A
        sei                                // disable interrupts
        ldy     #$34                       //
        sty     $01                        // write $34 to $0001 - banks RAM into all three regions
        ldy     #$00                       // Read pixel data from pixel memory
        lda     (ZP_ADDR_LOW),y            // A = *ZP_ADDR
        ldy     #$37                       // write $37 to $0001 - back to BASIC/IO/KERNAL
        sty     $01                        //
        cli                                // enable interrupts
        ldy     #$00                       //
        rts                                //

//
// Bit mirror table - gives bit to set in pixel byte for given X % 8
// i.e. value = 1 << (7 - index) for index e 0..7
data_bit_mirror_table:
        .byte   $80     // 1 << 7
        .byte   $40     // 1 << 6
        .byte   $20     // 1 << 5
        .byte   $10     // 1 << 4
        .byte   $08     // 1 << 3
        .byte   $04     // 1 << 2
        .byte   $02     // 1 << 1
        .byte   $01     // 1 << 0

data_nbit_mirror_table:
        .byte   $7F    // ~(1 << 7)
        .byte   $BF    // ~(1 << 6)
        .byte   $DF    // ~(1 << 5)
        .byte   $EF    // ~(1 << 4)
        .byte   $F7    // ~(1 << 3)
        .byte   $FB    // ~(1 << 2)
        .byte   $FD    // ~(1 << 1)
        .byte   $FE    // ~(1 << 0)

// ------------------------------------------------------
//
// fn_get_pixel_addr routine
// Turns CURRENT_X/CURRENT_Y_LO into a pixel memory address
// Result comes back in ZP_ADDR
//
// ------------------------------------------------------
fn_get_pixel_addr:
        lda     #$00                  //
        sta     ZP_ADDR_LOW           // ZP_ADDR = $E000 (start of pixel memory)
        lda     #$E0                  //
        sta     ZP_ADDR_HI            //
        lda     CURRENT_X_LO       // read CURRENT_X_LO
        and     #$F8                  // get (INT(X/8) * 8)
        clc                           // clear carry flag
        adc     ZP_ADDR_LOW           // add memory to accumulator with carry
        sta     ZP_ADDR_LOW           // *ZP_ADDR_LOW = *ZP_ADDR_LOW + (*CURRENT_X_LO & 0xF8)
        lda     CURRENT_X_HI       //
        adc     ZP_ADDR_HI            //
        sta     ZP_ADDR_HI            // *ZP_ADDR_HI = *ZP_ADDR_HI + (*CURRENT_X_HI)
        lda     CURRENT_Y_LO          //
        pha                           // Keep original Y-coord
        and     #$07                  // get Y co-ord % 8
        clc                           //
        adc     ZP_ADDR_LOW           // Add to *ZP_ADDR_LOW
        sta     ZP_ADDR_LOW           //
        bcc     LC4D6                 // If wrapped, increment *ZP_ADDR_HI
        inc     ZP_ADDR_HI            //
LC4D6:  pla                           // Get original (unmasked) value of CURRENT_Y_LO back
        lsr     a                     // Divide it by 8 to give the character row we need
        lsr     a                     //
        lsr     a                     //
        // Now we need to multiply A by 320
        asl     a                     // Double it, because data_mult_32 is a table of 16-bit values
        tax                           //
        lda     data_mult_320_low,x   // Get the low byte from the table
        clc                           //
        adc     ZP_ADDR_LOW           // Add it to *ZP_ADDR_LOW
        sta     ZP_ADDR_LOW           //
        lda     data_mult_320_hi,x    // Get the high byte from the table
        adc     ZP_ADDR_HI            // Add it to *ZP_ADDR_HI
        sta     ZP_ADDR_HI            //
        rts                           //

// This is the 320 times table, as 16-bit values
// It's used for converting a character row (in a 40x25 screen) into a byte offset
// as there are 320 bytes per character row
// $0000 $0140 $0280 $03C0 etc
data_mult_320_low:  .byte $00
data_mult_320_hi:  .byte $00
        .byte $40
        .byte $01
        .byte $80
        .byte $02
        .byte $c0
        .byte $03
        .byte $00
        .byte $05
        .byte $40
        .byte $06
        .byte $80
        .byte $07
        .byte $c0
        .byte $08
        .byte $00
        .byte $0a
        .byte $40
        .byte $0b
        .byte $80
        .byte $0c
        .byte $c0
        .byte $0d
        .byte $00
        .byte $0f
        .byte $40
        .byte $10
        .byte $80
        .byte $11
        .byte $c0
        .byte $12
        .byte $00
        .byte $14
        .byte $40
        .byte $15
        .byte $80
        .byte $16
        .byte $c0
        .byte $17
        .byte $00
        .byte $19
        .byte $40
        .byte $1a
        .byte $80
        .byte $1b
        .byte $c0
        .byte $1c
        .byte $00
        .byte $1e

// ------------------------------------------------------
//
// clear_bmp routine
// No arguments
//
// Writes $00 to $E000..$FFFF
// Writes $100 bytes (y) $20 times (x)
//
// ------------------------------------------------------
fn_clear_bmp:
        ldx     #$20
        lda     #$E0
        sta     ZP_ADDR_HI
        lda     #$00
        sta     ZP_ADDR_LOW     // write $E000 to ZP_ADDR_LOW/ZP_ADDR_HI
        tay
LC529:  sta     (ZP_ADDR_LOW),y // loop y 0..ff
        iny
        bne     LC529
        inc     ZP_ADDR_HI
        dex             // loop x 20..1
        bne     LC529
        rts
// ------------------------------------------------------
//
// load_colour sub-routine
// Read a value from the SYS command
// into X and check it's less than 16
//
// ------------------------------------------------------
fn_load_colour_param:
        jsr     basic_check_for_comma
        jsr     basic_evaluate_x
        cpx     #$10
        bcc     LC541
        jmp     fn_error
LC541:  rts

// ------------------------------------------------------
//
// set_colour routine
// Arguments from from SYS command parameters: ,FG,BG
// Modifies 1000 (40 x 25) bytes of colour memory in $C000 to $C3E7
//
// ------------------------------------------------------
fn_set_colour:
        lda     #$C0                     // COLOUR_MEMORY in ZP_ADDR_LOW,ZP_ADDR_HI
        sta     ZP_ADDR_HI
        lda     #$00
        sta     ZP_ADDR_LOW
        jsr     fn_load_colour_param     // Read fg colour
        txa                              // into A
        asl     a
        asl     a
        asl     a
        asl     a                        // Multiply it by 16 (move it to high nibble)
        sta     COLOUR                   // Write to C409
        jsr     fn_load_colour_param     // Read bg colour
        txa                              // into A
        ora     COLOUR                   // Add to fg colour
// There are 1000 ($3E8) colour cells (each represents an 8x8) in the hi-res
// image. Write the same colour to all of them. 4-bits background/4-bits
// foreground.
        ldx     #$02
        ldy     #$00
LC560:  sta     (ZP_ADDR_LOW),y          // Write colour to COLOUR_RAM[$0000..$02FF] (x=0..2, y=0..255)
        iny
        bne     LC560
        inc     ZP_ADDR_HI
        dex
        bpl     LC560
LC56A:  sta     (ZP_ADDR_LOW),y          // Write another $E8 bytes, to COLOUR_RAM[$0300..$03E7]
        iny
        cpy     #$E8
        bcc     LC56A
        rts
// ------------------------------------------------------
//
// draw_line routine
// Arguments from from SYS command parameters: ,X,Y,mode
//
// ------------------------------------------------------
fn_draw_line:
        lda     #$00
        sta     END_Y_HI                   // END_Y_HI = 0
        sta     DEC_BINC_X                 // DEC_BINC_X = Increment (Assume CURRENT_X < END_X)
        jsr     basic_check_for_comma
        jsr     basic_get_adr_get_byte     // Read 8-bit Y-cordinate into X register and 16-bit X co-ord into $14/$15
        cpx     #$C8                       // Check Y co-ord is < 200
        bcc     LC587
LC584:  jmp     fn_error
LC587:  stx     END_Y_LO                   // Store Y co-ord in END_Y_LO
        ldx     $14                        // Get X co-ord
        lda     $15                        // Check X co-ord is < 256, or >= 256 and < 320
        beq     LC598                      // --""--
        cmp     #$01                       // --""--
        bne     LC584                      // --""--
        cpx     #$40                       // --""--
        bcs     LC584                      // --""--
LC598:  sta     END_X_HI                   // Store 16-bit X co-ord in END_X
        stx     END_X_LO
        jsr     basic_check_for_comma
        jsr     basic_evaluate_x
        cmp     #$03                       // Load mode into X and check < 3
        bcs     LC584
        stx     DRAW_MODE                  // Store draw mode

        lda     END_X_LO
        sec
        sbc     CURRENT_X_LO
        sta     DELTA_X_LO                 // DELTA_X_LO = END_X_LO - CURRENT_X_LO
        lda     END_X_HI
        sbc     CURRENT_X_HI
        sta     DELTA_X_HI                 // DELTA_X_HI = END_X_HI - CURRENT_X_HI
        bpl     LC5D4                      // Unless DELTA_X is positive
        dec     DEC_BINC_X                 //   Set to decrement mode for X
        sec
        lda     #$00
        sbc     DELTA_X_LO                 //   DELTA_X_LO = -DELTA_X_LO
        sta     DELTA_X_LO
        lda     #$00
        sbc     DELTA_X_HI                 //   DELTA_X_HI = -DELTA_X_HI
        sta     DELTA_X_HI

LC5D4:  lda     #$00                       // DEC_BINC_X = Increment (Assume CURRENT_Y < END_Y)
        sta     DEC_BINC_Y
        lda     END_Y_LO
        sec                                // Calculate deltas (as per X above)
        sbc     CURRENT_Y_LO
        sta     DELTA_Y_LO
        lda     END_Y_HI
        sbc     CURRENT_Y_HI
        sta     DELTA_Y_HI
        bpl     LC602                      // Unless DELTA_Y is positive
        dec     DEC_BINC_Y                 //   Switch to decrement mode
        sec                                //   Negate Delta Y
        lda     #$00
        sbc     DELTA_Y_LO
        sta     DELTA_Y_LO
        lda     #$00
        sbc     DELTA_Y_HI
        sta     DELTA_Y_HI
LC602:  lda     #$00
        sta     DELTA_Y_LARGER            // DELTA_Y_LARGER = False
        lda     DELTA_Y_LO
        sec
        sbc     DELTA_X_LO                // Check if DELTA_X or DELTA_Y is larger
        lda     DELTA_Y_HI                // By performing DELTA_Y - DELTA_X
        sbc     DELTA_X_HI
        bcc     LC631                     // Unless DELTA_X > DELTA_Y:
        ldx     DELTA_Y_LO                //   swap DELTA_X and DELTA_Y (because DELTA_X <= DELTA_Y)
        lda     DELTA_X_LO
        sta     DELTA_Y_LO
        stx     DELTA_X_LO
        ldx     DELTA_Y_HI
        lda     DELTA_X_HI
        sta     DELTA_Y_HI
        stx     DELTA_X_HI
        dec     DELTA_Y_LARGER            //   Set DELTA_Y_LARGER to True
LC631:  lda     DELTA_X_LO                // Pre-load ERROR_ACC with the larger delta
        sta     ERROR_ACC_LO
        lda     DELTA_X_HI
        sta     ERROR_ACC_HI

// Line drawing loop
// At this point DELTA_X is now the larger of the actual DELTA_X/DELTA_Y
// DELTA_Y is the smaller of the actual DELTA_X/DELTA_Y. But we can ignore
// that and assume we're in the first octant. This routine now performs an
// integer version of Bresenham's Algorithm. Note that instead of comparing
// with 0.5, things are doubled so we add or subtract each delta twice
//
//        \    |    /
//          \  |  /
//            \|/ HERE
//       ------o------
//            /|\
//          /  |  \
//        /    |    \
//
        jsr     set_pixel_mode_switch     // Write pixel at CURRENT_X/CURRENT_Y
finish_check:
// Check if we're at the end of the line yet
// If DELTA_Y_LARGER, check Y co-ord, else check X co-ord
        lda     DELTA_Y_LARGER            // If NOT(DELTA_Y_LARGER)
        bne     LC657
        lda     CURRENT_X_LO              //   Compare CURRENT_X and END_X (the longer axis)
        cmp     END_X_LO
        bne     do_maths                  //   If not equal, draw some more
        lda     CURRENT_X_HI
        cmp     END_X_HI
        bne     do_maths                  //   If not equal, draw some more
        beq     exit_fn                   //   They are equal, so terminate line draw

LC657:  lda     CURRENT_Y_LO              // Else, compare CURRENT_Y and END_Y (the longer axis)
        cmp     END_Y_LO
        bne     do_maths                  //   If not equal, draw some more
        lda     CURRENT_Y_HI
        cmp     END_Y_HI
        bne     do_maths                  //   If not equal, draw some more
exit_fn:
        rts                               // At end of line - leave
do_maths:
        lda     DELTA_Y_LARGER            // If NOT(DELTA_Y_LARGER)
        bne     LC673
        jsr     fn_inc_dec_x              //     Move along X (long axis)
        jmp     LC676                     // Else
LC673:  jsr     fn_inc_dec_y              //     Move along Y (long axis)

LC676:  jsr     fn_subtract_delta_y       // ERROR_ACC -= 2 * SMALLER_DELTA
        jsr     fn_subtract_delta_y

        bpl     LC692                     // If NOT(ERROR_ACC is +ve)

        lda     DELTA_Y_LARGER            //     If NOT(DELTA_Y_LARGER)
        bne     LC689
        jsr     fn_inc_dec_y              //         Move along Y (short axis)
        jmp     LC68C                     //     Else
LC689:  jsr     fn_inc_dec_x              //         Move along X (short axis)

LC68C:  jsr     fn_add_delta_x            //     ERROR_ACC += 2 * LARGER_DELTA
        jsr     fn_add_delta_x

LC692:  jsr     set_pixel_mode_switch     // Set pixel

        jmp     finish_check              // Repeat this loop

// ------------------------------------------------------
// ERROR_ACC -= DELTA_Y
// ------------------------------------------------------
fn_subtract_delta_y:
        lda     ERROR_ACC_LO
        sec
        sbc     DELTA_Y_LO
        sta     ERROR_ACC_LO   // ERROR_ACC_LO -= DELTA_Y_LO
        lda     ERROR_ACC_HI
        sbc     DELTA_Y_HI
        sta     ERROR_ACC_HI   // ERROR_ACC_HI -= DELTA_Y_HI
        rts

// ------------------------------------------------------
// ERROR_ACC += DELTA_X
// ------------------------------------------------------
fn_add_delta_x:
        lda     ERROR_ACC_LO
        clc
        adc     DELTA_X_LO
        sta     ERROR_ACC_LO    // ERROR_ACC_LO += DELTA_X_LO
        lda     ERROR_ACC_HI
        adc     DELTA_X_HI
        sta     ERROR_ACC_HI    // ERROR_ACC_HI += DELTA_X_HI
        rts

// ------------------------------------------------------
// Inc/Dec X Co-ordinate
//
// If DEC_BINC_X is True, decrement
// If DEC_BINC_X is False, increment
// ------------------------------------------------------
fn_inc_dec_x:
        lda     DEC_BINC_X
        bne     LC6CE
        inc     CURRENT_X_LO
        bne     LC6CD
        inc     CURRENT_X_HI
LC6CD:  rts
LC6CE:  lda     CURRENT_X_LO
        bne     LC6D6
        dec     CURRENT_X_HI
LC6D6:  dec     CURRENT_X_LO
        rts

// ------------------------------------------------------
// Inc/Dec Y Co-ordinate
//
// If DEC_BINC_Y is True, decrement
// If DEC_BINC_Y is False, increment
// ------------------------------------------------------
fn_inc_dec_y:
        lda     DEC_BINC_Y
        bne     LC6E8
        inc     CURRENT_Y_LO      // Inc low byte
        bne     LC6E7           // If it wraps...
        inc     CURRENT_Y_HI      // Inc high byte
LC6E7:  rts
LC6E8:  lda     CURRENT_Y_LO      // Check low byte
        bne     LC6F0           // If zero..
        dec     CURRENT_Y_HI      // Dec high byte too
LC6F0:  dec     CURRENT_Y_LO      // Either way, dec low byte
        rts

// ------------------------------------------------------
//
// bitmap_on routine
// No arguments
//
// ------------------------------------------------------
fn_bitmap_on:
        lda     $DD00 // Clear bottom two bits
        and     #ZP_ADDR_HI  // of
        sta     $DD00 // cia2_data_port_a
        lda     #$3B  // Write $3B to
        sta     $D011 // vic_control_reg_1
        lda     #$08  // Write $08 to
        sta     $D018 // vic_memory_control_reg
        rts

// ------------------------------------------------------
//
// bitmap_off routine
// No arguments
//
// ------------------------------------------------------
fn_bitmap_off:
        lda     $DD00 // Set bottom two bits
        ora     #$03  // of
        sta     $DD00 // cia2_data_port_a
        lda     #$1B  // Write $1B to
        sta     $D011 // vic_control_reg_1
        lda     #$15  // Write $15 to
        sta     $D018 // vic_memory_control_reg
        rts

// ------------------------------------------------------
//
// Error handler.
// No arguments.
// Turns bitmap off and prints
// ?ILLEGAL QUANTITY
//
// ------------------------------------------------------
fn_error:
        jsr     fn_bitmap_off
        jmp     basic_illegal_qty

// ------------------------------------------------------
// End of file
// ------------------------------------------------------

No comments:

Post a Comment