********************************************************************************
* Micro-Painter, by Bob Bishop *
* Copyright 1980 Datasoft, Inc. All Rights Reserved. *
* *
* Disassembly of "PAINT" routines. *
********************************************************************************
* Disassembly by Andy McFadden, using 6502bench SourceGen v1.4. *
* Last updated 2019/10/25. *
********************************************************************************
color_black .eq 0 {const}
color_purple .eq 1 {const}
color_green .eq 2 {const}
color_blue .eq 3 {const}
color_orange .eq 4 {const}
color_white .eq 5 {const}
work_buffer .eq $7000 {addr/4096} ;work data area, from $7000-7fff
TXTCLR .eq $c050 ;RW display graphics
MIXCLR .eq $c052 ;RW display full screen
TXTPAGE1 .eq $c054 ;RW display page 1
LORES .eq $c056 ;RW display lo-res graphics
.org $6800
********************************************************************************
* FILL - flood fill with dither pattern. *
* *
* Uses a circular buffer at $7000-7fff to hold X/Y coordinates. The color of *
* the pixel at the initial X/Y is used as the to-fill color. *
* *
* Start by adding the initial X/Y to the work buffer. We then loop, removing *
* the first coordinate from the buffer and testing the color at that location. *
* If it matches, we draw the pixel, and then add the four adjacent pixels to *
* the list. Repeat until the list is empty. *
* *
* Warning: filling with the same color, e.g. filling a white area with white, *
* will likely hang. *
* *
* On entry: *
* $01 - X-coord *
* $02 - Y-coord *
* $04 - even color (0-5) *
* $05 - odd color (0-5) *
* *
* Preserves X/Y registers. *
********************************************************************************
xc .var $01 {addr/1}
yc .var $02 {addr/1}
back .var $03 {addr/1}
evenc .var $04 {addr/1}
oddc .var $05 {addr/1}
match_color .var $10 {addr/1}
add_coord_lo .var $12 {addr/1}
plot_coord_lo .var $13 {addr/1}
add_coord_ptr .var $14 {addr/2} ;new coords are added at this point
plot_coord_ptr .var $16 {addr/2} ;coords are read from this pointer and plotted
tmp .var $18 {addr/1}
6800: 8a FILL txa
6801: 48 pha
6802: 98 tya
6803: 48 pha
6804: a9 80 lda #$80
6806: 85 03 sta back
6808: 20 03 69 jsr PLT ;get current color at X,Y
680b: a5 03 lda back
680d: 85 10 sta match_color ;this is the color we're replacing
680f: a9 00 lda #<work_buffer
6811: 85 14 sta add_coord_ptr
6813: 85 16 sta plot_coord_ptr
6815: a9 70 lda #>work_buffer
6817: 85 15 sta add_coord_ptr+1
6819: 85 17 sta plot_coord_ptr+1
681b: a5 01 lda xc ;put first point into work buffer
681d: 8d 00 70 sta work_buffer
6820: a5 02 lda yc
6822: 8d 01 70 sta work_buffer+1
6825: a0 02 ldy #$02 ;point next output past the X,Y we just added
6827: 84 12 sty add_coord_lo
6829: a0 00 ldy #$00
682b: 84 13 sty plot_coord_lo
; Get the next candidate coordinate.
682d: b1 16 FillLoop lda (plot_coord_ptr),y
682f: 85 01 sta xc
6831: c8 iny
6832: b1 16 lda (plot_coord_ptr),y
6834: 85 02 sta yc
6836: c8 iny
6837: d0 0c bne L6845 ;still on same page, branch
6839: e6 17 inc plot_coord_ptr+1 ;move to next page
683b: a5 17 lda plot_coord_ptr+1
683d: c9 80 cmp #$80 ;did we reach the end of the buffer?
683f: d0 04 bne L6845 ;no, keep going
6841: a9 70 lda #>work_buffer ;yes, reset it
6843: 85 17 sta plot_coord_ptr+1
6845: 84 13 L6845 sty plot_coord_lo
6847: a9 80 lda #$80
6849: 85 03 sta back
684b: 20 03 69 jsr PLT ;get screen pixel color
684e: a5 03 lda back
6850: c5 10 cmp match_color ;matching color?
6852: d0 1f bne L6873 ;no, don't plot
; The current pixel matches the color we want to replace. Plot a pixel and add
; the four adjacent pixels to the work list.
6854: 20 00 69 jsr DITHER ;plot pixel with dither colors
6857: e6 01 inc xc
6859: 20 84 68 jsr AddCoord ;X+1,Y
685c: c6 01 dec xc
685e: e6 02 inc yc
6860: 20 84 68 jsr AddCoord ;X,Y+1
6863: c6 01 dec xc
6865: c6 02 dec yc
6867: 20 84 68 jsr AddCoord ;X-1,Y
686a: e6 01 inc xc
686c: c6 02 dec yc
686e: 20 84 68 jsr AddCoord ;X-1,Y-1
6871: e6 02 inc yc
6873: a4 13 L6873 ldy plot_coord_lo ;have we reached the end?
6875: c4 12 cpy add_coord_lo
6877: d0 b4 bne FillLoop ;low part differs, continue
6879: a5 17 lda plot_coord_ptr+1
687b: c5 15 cmp add_coord_ptr+1
687d: d0 ae bne FillLoop ;high part differs, continue
687f: 68 pla ;done!
6880: a8 tay
6881: 68 pla
6882: aa tax
6883: 60 rts
6884: a5 02 AddCoord lda yc ;check Y-coord
6886: c9 ff cmp #255 ;off top of screen?
6888: f0 40 beq L68CA ;yes, ignore
688a: c9 c0 cmp #192 ;off bottom of screen?
688c: f0 3c beq L68CA ;yes, ignore
688e: a5 01 lda xc ;check X-coord
6890: c9 ff cmp #$ff ;off left of screen?
6892: f0 36 beq L68CA ;yes, ignore
6894: c9 8c cmp #140 ;off right of screen?
6896: f0 32 beq L68CA ;yes, ignore
; Looks good, add X,Y to list.
; Note add_coord_ptr is always $xx00; the low byte is in add_coord_lo.
6898: a4 12 ldy add_coord_lo
689a: 91 14 sta (add_coord_ptr),y
689c: c8 iny
689d: a5 02 lda yc
689f: 91 14 sta (add_coord_ptr),y
68a1: c8 iny
68a2: 84 12 sty add_coord_lo
68a4: a5 15 lda add_coord_ptr+1
68a6: 85 18 sta tmp
68a8: c0 00 cpy #$00 ;did we advance to next page?
68aa: d0 0c bne L68B8 ;no, continue
68ac: e6 15 inc add_coord_ptr+1 ;yes, advance
68ae: a5 15 lda add_coord_ptr+1
68b0: c9 80 cmp #(>work_buffer)+16 ;did we reach end of work area?
68b2: d0 04 bne L68B8 ;no, still good
68b4: a9 70 lda #>work_buffer ;yes, wrap around
68b6: 85 15 sta add_coord_ptr+1
68b8: c4 13 L68B8 cpy plot_coord_lo ;did we run into the "write" ptr?
68ba: d0 0e bne L68CA ;no
68bc: a5 17 lda plot_coord_ptr+1 ;check the high byte
68be: c5 15 cmp add_coord_ptr+1
68c0: d0 08 bne L68CA ;still no
68c2: c6 12 dec add_coord_lo ;whoops; back up, discarding what we just added
68c4: c6 12 dec add_coord_lo
68c6: a5 18 lda tmp ;restore previous high byte
68c8: 85 15 sta add_coord_ptr+1
68ca: 60 L68CA rts
68cb: 01 ff ff 01+ .align $0100 (53 bytes)
6900: 4c 06 69 DITHER jmp DITHER1
6903: 4c 26 69 PLT jmp PLT1 ;external entry point
********************************************************************************
* DITHER - plot a point with dithered colors. *
* *
* On entry: *
* *
* $00 - hi-res page (zero for page 1, nonzero for page 2) *
* $01 - X coordinate [0,139] *
* $02 - Y coordinate [0,191] *
* $04 - even color value *
* $05 - odd color value *
* *
* Preserves X/Y registers. *
********************************************************************************
• Clear variables
pageflg .var $00 {addr/1}
xc .var $01 {addr/1}
yc .var $02 {addr/1}
back .var $03 {addr/1}
evenc .var $04 {addr/1}
oddc .var $05 {addr/1}
hptr .var $07 {addr/2}
6906: 8a DITHER1 txa
6907: 48 pha
6908: a5 02 lda yc ;start with the Y-coord
690a: a6 04 ldx evenc ;check the even color
690c: f0 0c beq L691A ;black, use checkerboard
690e: e0 05 cpx #color_white ;white?
6910: f0 08 beq L691A ;yes, use checkerboard pattern
6912: a6 05 ldx oddc ;check the odd color
6914: f0 04 beq L691A ;black, use checkerboard
6916: e0 05 cpx #color_white ;white?
6918: d0 02 bne L691C ;yes, use checkerboard
691a: 45 01 L691A eor xc ;factor in the X coord to get checkerboard
691c: 29 01 L691C and #$01 ;only low bit matters
691e: aa tax ;X=0 or 1
691f: b5 04 lda evenc,x ;load evenc or oddc
6921: 85 03 sta back ;set as color to draw
6923: 4c 28 69 jmp Plt2
********************************************************************************
* PLT - plot a point and return the current color. *
* *
* On entry: *
* *
* $00 = hi-res page (zero for page 1, nonzero for page 2) *
* $01 = X-coord [0,139] *
* $02 = Y-coord [0,191] *
* $03 = $80=no plot, 0-5=color to draw *
* *
* On exit: *
* $03 = screen color (0-5) (will be the new color if we're in draw mode) *
* *
* Preserves X/Y registers. *
********************************************************************************
screen_bit .var $06 {addr/1}
cflag .var $09 {addr/2}
6926: 8a PLT1 txa
6927: 48 pha
6928: 98 Plt2 tya
6929: 48 pha
692a: 20 c5 69 jsr SetRowBase ;set $07-08 as hi-res pointer
692d: a6 03 ldx back ;get color
692f: 30 0a bmi L693B ;not drawing, branch
6931: bd d8 69 lda color_flag_0,x ;get color flags for the two bits
6934: 85 09 sta cflag
6936: bd de 69 lda color_flag_1,x
6939: 85 0a sta cflag+1
693b: a6 01 L693B ldx xc
693d: bc 00 6f ldy div7_tab,x ;get byte offset
6940: bd 00 6e lda bit_tab,x ;get bit offset (low bit of pair)
6943: 85 06 sta screen_bit
; We want to read/write two hi-res bits, so we loop through here twice.
6945: a2 00 ldx #$00 ;first bit
6947: a5 06 BitLoop lda screen_bit
6949: 24 03 bit back ;are we writing?
694b: 10 16 bpl PlotWrite ;yes, branch
; Just reading the screen.
694d: 31 07 and (hptr),y ;test screen bit
694f: f0 36 beq BitLoopBottom ;not set
6951: 8a txa ;0 or 1
6952: 38 sec ;will add +1 or +2
6953: 65 03 adc back ;so this sets bit 0 or bit 1
6955: 85 03 sta back
6957: b1 07 lda (hptr),y ;check hi bit
6959: 10 2c bpl BitLoopBottom ;not set, branch
695b: a5 03 lda back ;set bit 2 if the hi-res pixel's high bit was set
695d: 09 04 ora #$04
695f: 85 03 sta back
6961: d0 24 bne BitLoopBottom
; Draw the pixel.
6963: 49 ff PlotWrite eor #$ff ;reverse screen bit to form mask
6965: 31 07 and (hptr),y ;AND with screen data
6967: 91 07 sta (hptr),y ;store, clearing previous value at that bit
6969: b5 09 lda cflag,x ;get color flag 0 or 1
696b: f0 1a beq BitLoopBottom ;zero, don't need to set pixel or high bit
696d: a5 06 lda screen_bit ;nonzero, set the appropriate bit in the pixel
696f: 11 07 ora (hptr),y
6971: 91 07 sta (hptr),y
6973: a5 09 lda cflag ;is it black or white?
6975: c5 0a cmp cflag+1 ;(want black/white to match hi bit of adjacent color)
6977: f0 0e beq BitLoopBottom ;yes, leave high bit alone
6979: b1 07 lda (hptr),y ;not black or white, so we need to set high bit
697b: 29 7f and #$7f ;clear whatever's there now
697d: 91 07 sta (hptr),y
697f: b5 09 lda cflag,x ;get high bit from color flag
6981: 29 80 and #$80
6983: 11 07 ora (hptr),y
6985: 91 07 sta (hptr),y ;set that on the screen
6987: e8 BitLoopBottom inx
6988: e0 02 cpx #$02 ;have we done it twice?
698a: f0 0b beq BitLoopDone ;yes, bail
698c: 06 06 asl screen_bit ;no, shift screen bit to next position
698e: 10 b7 bpl BitLoop ;didn't shift into high bit, loop
6990: c8 iny ;shifted into high bit, move on to next byte
6991: a9 01 lda #$01 ;and reset bit to low bit
6993: 85 06 sta screen_bit
6995: d0 b0 bne BitLoop ;(always)
6997: a5 03 BitLoopDone lda back ;were we writing?
6999: 10 08 bpl L69A3 ;yes, bail
699b: 29 07 and #$07 ;no, do a color lookup
699d: aa tax
699e: bd e4 69 lda bits_to_color,x ;convert 00000HBA to 0-5
69a1: 85 03 sta back
69a3: 68 L69A3 pla
69a4: a8 tay
69a5: 68 pla
69a6: aa tax
69a7: 60 rts
69a8: 08 29 07 aa+ .junk 29
;
; Sets $07-08 as the hi-res base pointer for the row in "yc".
;
69c5: a4 02 SetRowBase ldy yc
69c7: b9 00 6c lda ytable_lo,y
69ca: 85 07 sta hptr
69cc: a5 00 lda pageflg ;0 for page 1, nonzero for page 2
69ce: f0 02 beq L69D2
69d0: a9 60 lda #$60 ;configure for page 2
69d2: 59 00 6d L69D2 eor ytable_hi,y
69d5: 85 08 sta hptr+1
69d7: 60 rts
; These bytes have three possible values. They're used by PLT to figure out
; which bits to set on the hi-res screen for a given color (0-5).
;
; $00 = don't set this bit
; $7f = set this bit, clear high bit of byte
; $ff = set this bit, set high bit of byte
;
; Each hi-res color (in our 140x192 screen) requires two bits per pixel. One
; bit comes from each table.
69d8: 00 7f 00 ff+ color_flag_0 .bulk 007f00ff00ff
69de: 00 00 7f 00+ color_flag_1 .bulk 00007f00ffff
;
; Converts a bit pattern to a color, 0-5.
;
; Index is a 3-bit value 00000HBA, where A is set if the first bit of the hi-res
; pixel was set, B is set if the second bit of the hi-res pixel was set, and H
; is set if the high bit of at least one of the bytes with a pixel was set.
; (Remember that we're treating the screen as being 140 pixels across, so it's
; two bits per pixel.)
69e4: 00 bits_to_color .dd1 color_black
69e5: 01 .dd1 color_purple
69e6: 02 .dd1 color_green
69e7: 05 .dd1 color_white
69e8: 00 .dd1 color_black
69e9: 03 .dd1 color_blue
69ea: 04 .dd1 color_orange
69eb: 05 .dd1 color_white
69ec: 00 ff 01 01+ .align $0100 (20 bytes)
6a00: 4c 30 6a SCOPE jmp SCOPE1 ;entry point from Applesoft
********************************************************************************
* INIT - initialize "micro" / "scope" mode *
* *
* Clears the lo-res screen and enables lo-res graphics mode. *
* *
* Preserves X/Y registers. *
********************************************************************************
• Clear variables
ptr .var $0e {addr/2}
6a03: 8a INIT txa
6a04: 48 pha
6a05: 98 tya
6a06: 48 pha
; Clear lo-res screen to black.
6a07: a2 17 ldx #23 ;X = row
6a09: bd 86 6b ClearLoLoop lda lr_ytable_lo,x
6a0c: 85 0e sta ptr
6a0e: bd 9e 6b lda lr_ytable_hi,x
6a11: 85 0f sta ptr+1
6a13: a9 00 lda #$00
6a15: a0 27 ldy #39 ;Y = column
6a17: 91 0e L6A17 sta (ptr),y
6a19: 88 dey
6a1a: 10 fb bpl L6A17
6a1c: ca dex
6a1d: 10 ea bpl ClearLoLoop
; Configure soft-switches for lo-res.
6a1f: 8d 50 c0 sta TXTCLR
6a22: 8d 52 c0 sta MIXCLR
6a25: 8d 54 c0 sta TXTPAGE1
6a28: 8d 56 c0 sta LORES
6a2b: 68 pla
6a2c: a8 tay
6a2d: 68 pla
6a2e: aa tax
6a2f: 60 rts
********************************************************************************
* SCOPE - display part of the hi-res screen magnified on the lo-res screen. *
* *
* On entry: *
* $00 = X position [0,139] *
* $01 = Y position [0,191] *
* *
* Preserves X/Y registers. *
********************************************************************************
• Clear variables
xc .var $00 {addr/1}
yc .var $01 {addr/1}
col_ctr .var $02 {addr/1}
row_ctr .var $03 {addr/1}
saved_byte_off .var $04 {addr/1}
work_ptr_lo .var $05 {addr/1}
first_bit .var $06 {addr/1}
hr_byte .var $07 {addr/1}
hi_in_lo .var $08 {addr/1}
start_x .var $09 {addr/1}
hptr .var $0c {addr/2}
work_ptr .var $0e {addr/2}
6a30: 8a SCOPE1 txa
6a31: 48 pha
6a32: 98 tya
6a33: 48 pha
6a34: 38 sec ;left edge is XC - 9
6a35: a5 00 lda xc
6a37: e9 09 sbc #9
6a39: 85 00 sta xc
6a3b: 85 09 sta start_x
6a3d: 38 sec
6a3e: a5 01 lda yc ;top edge is YC - 11
6a40: e9 0b sbc #11
6a42: 85 01 sta yc
6a44: a9 00 lda #$00
6a46: 85 05 sta work_ptr_lo
6a48: 85 0e sta work_ptr
6a4a: a9 70 lda #>work_buffer
6a4c: 85 0f sta work_ptr+1 ;out_ptr = work buffer
;
; Phase 1: convert hi-res pixels to values in the work buffer.
;
; Each hi-res pixel in our window gets two adjacent values in the work buffer,
; one per bit. The value is from 0-3, and reflects the state of one bit on the
; pixel plus the high bit of the byte.
;
; Note: there's a 1-pixel black border on the left and right of the lo-res
; display, presumably to allow the central 2x2 block to be centered on the
; screen. There's also a 2-pixel black border on the bottom of the screen.
;
6a4e: a9 17 lda #23
6a50: 85 03 sta row_ctr
6a52: a9 26 RowLoop lda #38
6a54: 85 02 sta col_ctr
6a56: a6 01 ldx yc ;get the Y-coord
6a58: e0 c0 cpx #192 ;did we wrap off the top?
6a5a: b0 67 bcs OffEdge ;yes, bail
6a5c: bd 00 6c lda ytable_lo,x ;get the hi-res row base
6a5f: 85 0c sta hptr
6a61: bd 00 6d lda ytable_hi,x
6a64: 85 0d sta hptr+1
6a66: a6 00 ldx xc ;get the X-coord
6a68: e0 8c cpx #140 ;did we wrap around to the left when subtracting?
6a6a: 90 18 bcc ScanPixel ;no, scan it
; We're off the left edge, so just fill in black until we get on the screen.
6a6c: a4 05 ldy work_ptr_lo
6a6e: a9 00 lda #$00
6a70: 91 0e OffLeftLoop sta (work_ptr),y
6a72: c8 iny
6a73: 91 0e sta (work_ptr),y
6a75: c8 iny
6a76: d0 02 bne L6A7A
6a78: e6 0f inc work_ptr+1
6a7a: c6 02 L6A7A dec col_ctr
6a7c: c6 02 dec col_ctr
6a7e: e8 inx
6a7f: d0 ef bne OffLeftLoop
6a81: 84 05 sty work_ptr_lo
6a83: 18 clc
; Get the color of a pixel. X coordinate in X-reg, carry flag is clear.
6a84: bd 00 6e ScanPixel lda bit_tab,x ;get first hi-res pixel bit
6a87: 85 06 sta first_bit
6a89: bc 00 6f ldy div7_tab,x ;get byte offset
6a8c: a6 02 ldx col_ctr ;lo-res column counter
6a8e: b1 0c L6A8E lda (hptr),y ;get hi-res byte
6a90: 85 07 sta hr_byte
6a92: 29 80 and #$80 ;clear everything but the hi bit
6a94: 2a rol A ;roll it into the low bit
6a95: 2a rol A ;(note carry was clear)
6a96: 85 08 sta hi_in_lo
6a98: c8 iny
6a99: 84 04 sty saved_byte_off
6a9b: a4 05 ldy work_ptr_lo
6a9d: a5 07 L6A9D lda hr_byte ;get pixel byte
6a9f: 25 06 and first_bit ;mask off everything but interesting bit
6aa1: f0 02 beq L6AA5 ;bit not set, branch
6aa3: a9 02 lda #$02 ;bit set, use $02 regardless of bit position
6aa5: 05 08 L6AA5 ora hi_in_lo ;add high bit (so now value is 0-3)
6aa7: 91 0e sta (work_ptr),y ;save that off
6aa9: c8 iny ;advance work ptr
6aaa: d0 02 bne L6AAE
6aac: e6 0f inc work_ptr+1
6aae: ca L6AAE dex ;decrement column counter
6aaf: f0 21 beq L6AD2 ;bail when we reach column 0
6ab1: 06 06 asl first_bit ;shift to the next bit in the pixel
6ab3: 10 e8 bpl L6A9D ;still in same byte, repeat
6ab5: 84 05 sty work_ptr_lo
6ab7: a9 01 lda #$01 ;move to next byte, reset mask to bit 0
6ab9: 85 06 sta first_bit
6abb: a4 04 ldy saved_byte_off
6abd: c0 28 cpy #40 ;off right edge of hi-res screen?
6abf: 90 cd bcc L6A8E ;nope, keep going
6ac1: 86 02 stx col_ctr ;yes, go into "off edge" code
; We're off the edge, to the right or the bottom. Fill out the row with black
; pixels.
6ac3: a4 05 OffEdge ldy work_ptr_lo
6ac5: a9 00 lda #$00
6ac7: 91 0e L6AC7 sta (work_ptr),y
6ac9: c8 iny
6aca: d0 02 bne L6ACE
6acc: e6 0f inc work_ptr+1
6ace: c6 02 L6ACE dec col_ctr ;decrement the column counter
6ad0: d0 f5 bne L6AC7 ;not end of row yet, branch
6ad2: 84 05 L6AD2 sty work_ptr_lo
6ad4: a5 09 lda start_x ;reset X-coord
6ad6: 85 00 sta xc
6ad8: e6 01 inc yc ;advance to next row
6ada: c6 03 dec row_ctr ;are we done?
6adc: f0 22 beq Scope2 ;yes, move to rendering
6ade: 4c 52 6a jmp RowLoop ;no, loop
6ae1: 00 c6 03 f0+ .align $0100 (31 bytes)
; Phase 2: render the contents of the work buffer on the lo-res screen.
;
; The values in the work buffer are from 0-3. 0/2 indicates that the
; corresponding hi-res bit was set, +1 if the high bit in the byte was set.
work_ptr .var $0c {addr/2}
lr_ptr .var $0e {addr/2}
6b00: a9 01 Scope2 lda #$01 ;left edge; 1-pixel boundary at sides
6b02: 85 00 sta xc
6b04: a9 00 lda #$00 ;no border at top
6b06: 85 01 sta yc
6b08: 85 04 sta saved_byte_off
6b0a: 85 0c sta work_ptr
6b0c: a9 70 lda #>work_buffer
6b0e: 85 0d sta work_ptr+1
6b10: a6 01 ldx yc ;get lo-res screen row base
6b12: bd 86 6b L6B12 lda lr_ytable_lo,x
6b15: 85 0e sta lr_ptr
6b17: bd 9e 6b lda lr_ytable_hi,x
6b1a: 85 0f sta lr_ptr+1
6b1c: a4 04 DrawLoLoop ldy saved_byte_off
6b1e: b1 0c lda (work_ptr),y ;get the first value
6b20: c8 iny
6b21: 0a asl A ;shift it over
6b22: 0a asl A
6b23: 11 0c ora (work_ptr),y ;add in the second value
6b25: c8 iny ;advance work ptr
6b26: d0 02 bne L6B2A
6b28: e6 0d inc work_ptr+1
6b2a: 84 04 L6B2A sty saved_byte_off
6b2c: aa tax ;put color value (0-15) in X
6b2d: bd b6 6b lda lr_color_map,x ;convert it to a lo-res color
6b30: a4 00 ldy xc
6b32: 91 0e sta (lr_ptr),y ;plot 2x2 pixel (two bytes wide)
6b34: c8 iny
6b35: 91 0e sta (lr_ptr),y
6b37: c8 iny
6b38: 84 00 sty xc
6b3a: c0 27 cpy #39 ;end of row?
6b3c: d0 de bne DrawLoLoop ;not yet, loop
6b3e: a9 01 lda #$01 ;reset X-coord
6b40: 85 00 sta xc
6b42: e6 01 inc yc ;advance to next row
6b44: a6 01 ldx yc
6b46: e0 17 cpx #23 ;done? (leaves 1-pixel boundary at bottom)
6b48: d0 c8 bne L6B12 ;no, loop
; Draw crosshairs. It flickers a little because, on each loop, we draw the hi-
; res colors and then slam the crosshairs down.
6b4a: a9 dd lda #$dd ;two pixels, color=13 (yellow)
6b4c: a2 04 ldx #$04
6b4e: 9d b5 05 L6B4E sta $05b5,x ;hard-wired screen positions
6b51: 9d be 05 sta $05be,x
6b54: ca dex
6b55: 10 f7 bpl L6B4E
6b57: a2 01 ldx #$01
6b59: 9d 3b 04 L6B59 sta $043b,x
6b5c: 9d bb 04 sta $04bb,x
6b5f: 9d bb 06 sta $06bb,x
6b62: 9d 3b 07 sta $073b,x
6b65: ca dex
6b66: 10 f1 bpl L6B59
; Add "half-pixel" crosshair gap. The hi-res pixel at the center is a 2x2 lo-
; res block. We create a gap of 1 lo-res block between it and the crosshair.
; For the vertical line, that means we're not writing a full byte, because each
; text byte holds two lo-res blocks.
6b68: a2 01 ldx #$01
6b6a: bd 3b 05 L6B6A lda $053b,x ;draw one pixel with color=13
6b6d: 29 f0 and #$f0 ; leave other pixel alone
6b6f: 09 0d ora #$0d
6b71: 9d 3b 05 sta $053b,x
6b74: bd 3b 06 lda $063b,x
6b77: 29 0f and #$0f
6b79: 09 d0 ora #$d0
6b7b: 9d 3b 06 sta $063b,x
6b7e: ca dex
6b7f: 10 e9 bpl L6B6A
6b81: 68 pla
6b82: a8 tay
6b83: 68 pla
6b84: aa tax
6b85: 60 rts
; Low-res row address, low byte.
6b86: 00 80 00 80+ lr_ytable_lo .bulk 008000800080008028a828a828a828a850d050d050d050d0
; Low-res row address, high byte.
6b9e: 04 04 05 05+ lr_ytable_hi .bulk 040405050606070704040505060607070404050506060707
;
; Map hi-res pixel values to lo-res colors.
;
; Index is AHBH, where A and B are the hi-res pixel values, and H is the high
; bit of the hi-res byte. For example, green is 0010, purple is 1010, orange is
; 0111, blue is 1101.
;
; Some pixels straddle two bytes and potentially have different values for the
; high bit in each. Each color thus has two entries.
;
6bb6: 00 lr_color_map .dd1 $00 ;0000 lo-res color 0 = black
6bb7: 00 .dd1 $00 ;0001
6bb8: cc .dd1 $cc ;0010 12 = light green
6bb9: 99 .dd1 $99 ;0011 9 = orange
6bba: 00 .dd1 $00 ;0100
6bbb: 00 .dd1 $00 ;0101
6bbc: cc .dd1 $cc ;0110
6bbd: 99 .dd1 $99 ;0111
6bbe: 33 .dd1 $33 ;1000 3 = purple
6bbf: 33 .dd1 $33 ;1001
6bc0: ff .dd1 $ff ;1010 15 = white
6bc1: ff .dd1 $ff ;1011
6bc2: 66 .dd1 $66 ;1100 6 = medium blue
6bc3: 66 .dd1 $66 ;1101
6bc4: ff .dd1 $ff ;1110
6bc5: ff .dd1 $ff ;1111
6bc6: 00 ff ff 00+ .align $0100 (58 bytes)
; Hi-res row base address, low byte.
6c00: 00 00 00 00+ ytable_lo .bulk 0000000000000000808080808080808000000000000000008080808080808080
+ 0000000000000000808080808080808000000000000000008080808080808080
+ 2828282828282828a8a8a8a8a8a8a8a82828282828282828a8a8a8a8a8a8a8a8
+ 2828282828282828a8a8a8a8a8a8a8a82828282828282828a8a8a8a8a8a8a8a8
+ 5050505050505050d0d0d0d0d0d0d0d05050505050505050d0d0d0d0d0d0d0d0
+ 5050505050505050d0d0d0d0d0d0d0d05050505050505050d0d0d0d0d0d0d0d0
********************************************************************************
* CLEAN -- set all non-white pixels to black. *
* *
* Preserves X/Y registers. *
********************************************************************************
• Clear variables
xc .var $01 {addr/1}
yc .var $02 {addr/1}
back .var $03 {addr/1}
6cc0: 8a CLEAN txa
6cc1: 48 pha
6cc2: 98 tya
6cc3: 48 pha
6cc4: a0 00 ldy #$00
6cc6: a2 00 L6CC6 ldx #$00
6cc8: 86 01 L6CC8 stx xc
6cca: 84 02 sty yc
6ccc: a9 80 lda #$80 ;read only
6cce: 85 03 sta back
6cd0: 20 03 69 jsr PLT ;get current pixel color
6cd3: a5 03 lda back
6cd5: c9 05 cmp #color_white ;is it a white pixel?
6cd7: f0 07 beq L6CE0 ;yes, leave it alone
6cd9: a9 00 lda #color_black ;no, clear it
6cdb: 85 03 sta back
6cdd: 20 03 69 jsr PLT ;draw black pixel
6ce0: e8 L6CE0 inx
6ce1: e0 8c cpx #140 ;end of line?
6ce3: d0 e3 bne L6CC8 ;no, continue
6ce5: c8 iny
6ce6: c0 c0 cpy #192 ;end of screen?
6ce8: d0 dc bne L6CC6 ;no, continue
6cea: 68 pla
6ceb: a8 tay
6cec: 68 pla
6ced: aa tax
6cee: 60 rts
6cef: 20 40 01 02+ .align $0100 (17 bytes)
; Hi-res row base address, high byte.
6d00: 20 24 28 2c+ ytable_hi .bulk 2024282c3034383c2024282c3034383c2125292d3135393d2125292d3135393d
+ 22262a2e32363a3e22262a2e32363a3e23272b2f33373b3f23272b2f33373b3f
+ 2024282c3034383c2024282c3034383c2125292d3135393d2125292d3135393d
+ 22262a2e32363a3e22262a2e32363a3e23272b2f33373b3f23272b2f33373b3f
+ 2024282c3034383c2024282c3034383c2125292d3135393d2125292d3135393d
+ 22262a2e32363a3e22262a2e32363a3e23272b2f33373b3f23272b2f33373b3f
********************************************************************************
* NEG -- reverse colors on entire hi-res screen *
* *
* Does a top-to-bottom operation to avoid the Venetian-blind look. *
********************************************************************************
• Clear variables
xc .var $01 {addr/1}
yc .var $02 {addr/1}
hptr .var $07 {addr/2}
6dc0: 8a NEG txa
6dc1: 48 pha
6dc2: 98 tya
6dc3: 48 pha
6dc4: a2 00 ldx #$00 ;start at the top
6dc6: 86 02 L6DC6 stx yc
6dc8: 20 c5 69 jsr SetRowBase ;get address in hptr
6dcb: a0 27 ldy #39 ;for each byte in the row
6dcd: b1 07 L6DCD lda (hptr),y
6dcf: 49 ff eor #$ff ;reverse colors
6dd1: 91 07 sta (hptr),y
6dd3: 88 dey
6dd4: 10 f7 bpl L6DCD
6dd6: e8 inx ;next row
6dd7: e0 c0 cpx #192 ;done?
6dd9: d0 eb bne L6DC6
6ddb: 68 pla
6ddc: a8 tay
6ddd: 68 pla
6dde: aa tax
6ddf: 60 rts
6de0: 60 02 d0 dc+ .align $0100 (32 bytes)
; Maps X coordinate [0,139] to bit.
6e00: 01 04 10 40+ bit_tab .bulk 0104104002082001041040020820010410400208200104104002082001041040
+ 0208200104104002082001041040020820010410400208200104104002082001
+ 0410400208200104104002082001041040020820010410400208200104104002
+ 0820010410400208200104104002082001041040020820010410400208200104
+ 104002082001041040020820
6e8c: 00 00 00 00+ .align $0100 (116 bytes)
; Maps X coordinate [0,139] to byte [0,39].
6f00: 00 00 00 00+ div7_tab .bulk 0000000001010102020202030303040404040505050606060607070708080808
+ 0909090a0a0a0a0b0b0b0c0c0c0c0d0d0d0e0e0e0e0f0f0f1010101011111112
+ 1212121313131414141415151516161616171717181818181919191a1a1a1a1b
+ 1b1b1c1c1c1c1d1d1d1e1e1e1e1f1f1f20202020212121222222222323232424
+ 242425252526262626272727
6f8c: 00 00 00 00+ .align $0100 (116 bytes)