; 1520 ROM 03 disassembly

                ; 2014 Soci/Singular

RAM_SIZE        = $40
ROM_START       = $800
ROM_SIZE        = $800

WIDTH           = 480
HEIGHT          = 999
COLORS          = 4
LINE_HEIGHT     = 10
FONT_WIDTH      = 6
FONT_SIZES      = 4
DASH_LENGTHS    = 16
MARGIN_STEPS    = 30
SETTLE_WAIT     = 11382

IEC             .block
ATN_IN          = %00000001
CLK_IN          = %00000010
ATN_ACK         = %00100000
DATA_OUT        = %01000000
DATA_IN         = %10000000
FIRST_DEVICE    = 4
DEVICE_NUMBERS  = 8
LISTEN          = $20
SECOND          = $60
WAIT            = 3800
                .bend

PEN             .block
IDLE            = %00
UP              = %01
DOWN            = %10
WAIT            = 4943
STEPS           = 35
                .bend

                ; I/O

port            .block
a               = $80                   ; ATNIN=0, CLKIN=1, ATNACK=5, DATAOUT=6, DATAIN=7
b               = $81                   ; DEVICE=0-2, LED=4, REMOVE=5, CHANGE=6, FEED=7
c               = $82                   ; PENDOWN=0, PENUP=1, COLORSWITH=7
d               = $83                   ; STEPX=0-3, STEPY=4-7
iec             = a
io              = b
pen             = c
stepper         = d
                .bend
latch_l         = $85
latch_now       = $88
control         = $8f

                *= $00                  ;RAM

coord_s         .struct
x               .word ?
y               .word ?
                .ends

accu            .word ?
longer          .word ?
shorter         .word ?
cmd             .dstruct coord_s
absorig         .dstruct coord_s
relorig         .dstruct coord_s
num_temp        .word ?
num_neg         .byte ?
count           .byte ?
fontp           .word ?
upper_lower     .byte ?
quote_counter   .byte ?
underline       .byte ?
font_tmp        .byte ?
char_size       .byte ?
current_color   .byte ?
color           .byte ?
cmd_use_pen     .byte ?
pen_state       .byte ?
char_rotation   .byte ?
dashed          .byte ?
dash_counter    .byte ?
                .byte ?                 ;unused
                .union
                .struct
step            .block
x               .byte ?
                .byte ?
y               .byte ?
                .bend
                .ends
                .struct
                .byte ?
sign            .block
x               .byte ?
                .byte ?
y               .byte ?
                .bend
                .ends
                .endu
stepper         .block
x               .byte ?
padding         .byte ?
y               .byte ?
                .bend
was_x           = stepper.padding
serial_buf      .byte ?
serial_eot      .byte ?

                .cerror * > RAM_SIZE - 10, "Too many RAM variables"

                *= ROM_START
;
; Font format:
;
; %EXXXYYYP
; E - last command in list (1)
; X - x coordinate (0-7)
; Y - y coordinate (0-7)
; P - use pen (1), or just move (0)
;
font            .block
LOW_LINE        = $5c
PI              = $5e
SQUARE          = $5f

; converts from $PXY to %0XXXYYYP for easier editing
convert         .function *v
                .endf (v >> 8) | ((v & 7) << 1) | (v & $70)

                .byte $ff               ;dummy
;SPACE
                .shift convert($000)
;EXCLAMATION MARK
                .shift convert($021, $122, $132, $131, $121, $023, $127, $137, $133, $123)
;QUOTATION MARK
                .shift convert($017, $116, $037, $136)
;NUMBER SIGN
                .shift convert($012, $116, $036, $132, $043, $103, $005, $145)
;DOLLAR SIGN
                .shift convert($012, $132, $143, $134, $114, $105, $116, $136, $027, $121)
;PERCENT SIGN
                .shift convert($002, $146, $016, $106, $105, $115, $116, $033, $143, $142, $132, $133)
;AMPERSAND
                .shift convert($041, $105, $106, $117, $126, $125, $103, $102, $111, $121, $143)
;APOSTROPHE
                .shift convert($025, $127)
;LEFT PARENTHESIS
                .shift convert($031, $121, $112, $116, $127, $137)
;RIGHT PARENTHESIS
                .shift convert($021, $131, $142, $146, $137, $127)
;ASTERISK
                .shift convert($002, $146, $006, $142, $026, $122)
;PLUS SIGN
                .shift convert($022, $126, $004, $144)
;COMMA
                .shift convert($020, $131, $132, $122, $121, $131)
;HYPHEN-MINUS
                .shift convert($004, $144)
;FULL STOP
                .shift convert($021, $122, $132, $131, $121)
;SOLIDUS
                .shift convert($001, $156)
;DIGIT ZERO
                .shift convert($002, $146, $137, $117, $106, $102, $111, $131, $142, $146)
;DIGIT ONE
                .shift convert($016, $127, $121, $011, $131)
;DIGIT TWO
                .shift convert($006, $117, $137, $146, $145, $101, $141)
;DIGIT THREE
                .shift convert($006, $117, $137, $146, $145, $134, $124, $034, $143, $142, $131, $111, $102)
;DIGIT FOUR
                .shift convert($031, $137, $104, $103, $143)
;DIGIT FIVE
                .shift convert($002, $111, $131, $142, $144, $135, $105, $107, $147)
;DIGIT SIX
                .shift convert($004, $115, $135, $144, $142, $131, $111, $102, $106, $117, $137, $146)
;DIGIT SEVEN
                .shift convert($001, $145, $147, $107)
;DIGIT EIGHT
                .shift convert($014, $105, $106, $117, $137, $146, $145, $134, $143, $142, $131, $111, $102, $103, $114, $134)
;DIGIT NINE
                .shift convert($002, $111, $131, $142, $146, $137, $117, $106, $105, $114, $134, $145)
;COLON
                .shift convert($012, $113, $123, $122, $112, $015, $116, $126, $125, $115)
;SEMICOLON
                .shift convert($011, $122, $123, $113, $112, $122, $025, $126, $116, $115, $125)
;LESS-THAN SIGN
                .shift convert($041, $114, $147)
;EQUALS SIGN
                .shift convert($013, $143, $015, $145)
;GREATER-THAN SIGN
                .shift convert($011, $144, $117)
;QUESTION MARK
                .shift convert($006, $117, $137, $146, $145, $134, $124, $123, $022, $121)
;COMMERCIAL AT
                .shift convert($033, $135, $115, $112, $132, $143, $145, $136, $116, $105, $102, $111, $141)
;LATIN CAPITAL LETTER A
                .shift convert($001, $105, $127, $145, $141, $004, $144)
;LATIN CAPITAL LETTER B
                .shift convert($001, $107, $137, $146, $145, $134, $004, $134, $143, $142, $131, $101)
;LATIN CAPITAL LETTER C
                .shift convert($042, $131, $111, $102, $106, $117, $137, $146)
;LATIN CAPITAL LETTER D
                .shift convert($001, $107, $137, $146, $142, $131, $101)
;LATIN CAPITAL LETTER E
                .shift convert($041, $101, $107, $147, $034, $104)
;LATIN CAPITAL LETTER F
                .shift convert($001, $107, $147, $004, $134)
;LATIN CAPITAL LETTER G
                .shift convert($046, $137, $117, $106, $102, $111, $141, $144, $124)
;LATIN CAPITAL LETTER H
                .shift convert($001, $107, $047, $141, $004, $144)
;LATIN CAPITAL LETTER I
                .shift convert($011, $131, $021, $127, $017, $137)
;LATIN CAPITAL LETTER J
                .shift convert($002, $111, $121, $132, $137)
;LATIN CAPITAL LETTER K
                .shift convert($001, $107, $047, $103, $014, $141)
;LATIN CAPITAL LETTER L
                .shift convert($007, $101, $141)
;LATIN CAPITAL LETTER M
                .shift convert($001, $107, $125, $124, $125, $147, $141)
;LATIN CAPITAL LETTER N
                .shift convert($001, $107, $006, $142, $047, $141)
;LATIN CAPITAL LETTER O
                .shift convert($002, $106, $117, $137, $146, $142, $131, $111, $102)
;LATIN CAPITAL LETTER P
                .shift convert($001, $107, $137, $146, $145, $134, $104)
;LATIN CAPITAL LETTER Q
                .shift convert($023, $141, $031, $111, $102, $106, $117, $137, $146, $142, $131)
;LATIN CAPITAL LETTER R
                .shift convert($001, $107, $137, $146, $145, $134, $104, $014, $141)
;LATIN CAPITAL LETTER S
                .shift convert($002, $111, $131, $142, $143, $134, $114, $105, $106, $117, $137, $146)
;LATIN CAPITAL LETTER T
                .shift convert($021, $127, $007, $147)
;LATIN CAPITAL LETTER U
                .shift convert($007, $102, $111, $131, $142, $147)
;LATIN CAPITAL LETTER V
                .shift convert($007, $103, $121, $143, $147)
;LATIN CAPITAL LETTER W
                .shift convert($007, $101, $123, $024, $123, $141, $147)
;LATIN CAPITAL LETTER X
                .shift convert($001, $102, $146, $147, $007, $106, $142, $141)
;LATIN CAPITAL LETTER Y
                .shift convert($021, $124, $146, $147, $007, $106, $124)
;LATIN CAPITAL LETTER Z
                .shift convert($007, $147, $146, $102, $101, $141)
;LEFT SQUARE BRACKET
                .shift convert($021, $101, $107, $127)
;POUND SIGN
                .shift convert($056, $146, $135, $132, $121, $111, $102, $113, $131, $151, $024, $144)
;RIGHT SQUARE BRACKET
                .shift convert($011, $131, $137, $117)
;UPWARDS ARROW
                .shift convert($021, $126, $004, $126, $144)
;LEFTWARDS ARROW
                .shift convert($022, $104, $126, $004, $154)
;BOX DRAWINGS LIGHT HORIZONTAL
                .shift convert($004, $174)
;LATIN SMALL LETTER A
                .shift convert($032, $121, $111, $102, $103, $114, $124, $133, $005, $125, $134, $132, $141)
;LATIN SMALL LETTER B
                .shift convert($007, $101, $121, $132, $134, $125, $105)
;LATIN SMALL LETTER C
                .shift convert($032, $121, $111, $102, $104, $115, $125, $134)
;LATIN SMALL LETTER D
                .shift convert($035, $115, $104, $102, $111, $131, $137)
;LATIN SMALL LETTER E
                .shift convert($003, $133, $134, $125, $115, $104, $102, $111, $131)
;LATIN SMALL LETTER F
                .shift convert($021, $127, $137, $014, $134)
;LATIN SMALL LETTER G
                .shift convert($001, $110, $120, $131, $134, $125, $115, $104, $103, $112, $122, $133)
;LATIN SMALL LETTER H
                .shift convert($001, $107, $005, $125, $134, $131)
;LATIN SMALL LETTER I
                .shift convert($021, $124, $025, $126)
;LATIN SMALL LETTER J
                .shift convert($001, $110, $120, $131, $134, $035, $136)
;LATIN SMALL LETTER K
                .shift convert($031, $113, $007, $101, $002, $135)
;LATIN SMALL LETTER L
                .shift convert($017, $111, $121)
;LATIN SMALL LETTER M
                .shift convert($001, $105, $004, $115, $124, $121, $024, $135, $144, $141)
;LATIN SMALL LETTER N
                .shift convert($001, $105, $104, $115, $125, $134, $131)
;LATIN SMALL LETTER O
                .shift convert($002, $104, $115, $125, $134, $132, $121, $111, $102)
;LATIN SMALL LETTER P
                .shift convert($002, $122, $133, $134, $125, $105, $100)
;LATIN SMALL LETTER Q
                .shift convert($040, $130, $135, $115, $104, $103, $112, $132)
;LATIN SMALL LETTER R
                .shift convert($005, $114, $111, $014, $125, $135)
;LATIN SMALL LETTER S
                .shift convert($002, $111, $121, $132, $123, $113, $104, $115, $125, $134)
;LATIN SMALL LETTER T
                .shift convert($005, $125, $017, $111, $121)
;LATIN SMALL LETTER U
                .shift convert($005, $101, $131, $135)
;LATIN SMALL LETTER V
                .shift convert($005, $103, $121, $143, $145)
;LATIN SMALL LETTER W
                .shift convert($005, $102, $111, $122, $123, $122, $131, $142, $145)
;LATIN SMALL LETTER X
                .shift convert($001, $145, $005, $141)
;LATIN SMALL LETTER Y
                .shift convert($005, $104, $122, $045, $144, $100)
;LATIN SMALL LETTER Z
                .shift convert($005, $145, $101, $141)
;BOX DRAWINGS LIGHT VERTICAL
                .shift convert($030, $137)
;LOW LINE
                .shift convert($070, $100)
;WHITE UP-POINTING TRIANGLE
                .shift convert($001, $134, $161, $101)
;GREEK CAPITAL LETTER PI
                .shift convert($003, $114, $134, $131, $011, $114, $134, $145)
;WHITE MEDIUM SQUARE
                .shift convert($001, $107, $157, $151, $101)
                .bend
;---------------
reset           sei
                ldx #RAM_SIZE-1
                txs
                lda #~IEC.DATA_OUT
                sta port.iec
                ldx #$ff
                stx port.io
                stx port.pen
                inx
                stx port.stepper
                lda #%11100000
                sta control
                txa
                ldx #RAM_SIZE-3
zp_init         sta 0,x
                dex
                bne zp_init
                jsr line_feed
                lda #4
                sta count
                lsr
                sta char_size
stepper_init    ldx #round((WIDTH + MARGIN_STEPS * 2.5) / 4)
                jsr stepper_left
                dec count
                bne stepper_init
                lda #COLORS * 3
                sta count
pen_init        jsr stepper_rl
                lda port.pen
                bpl pen_ok
                dec count
                bne pen_init
flash_led       dex
                stx port.io
                jsr wait_settle
                sta port.stepper
                beq flash_led
pen_ok          ldx #PEN.STEPS + MARGIN_STEPS + 2
                jsr stepper_right
-               jsr next_color
                ldx #font.SQUARE
                jsr print_char
                lda color
                bne -
                dec char_size
paper_feed      jsr carriage_return
idle_loop       jsr wait_settle
                sta port.stepper
iec_loop2       jsr atnack_hi
iec_loop        lda port.io
                bpl paper_feed
                asl
                bmi nchange
                jsr next_color
                beq idle_loop
nchange         asl
                bmi nremove
                lda #>(WIDTH + 255)
                sta cmd.x+1
                jsr move_abs_pup
nremove         jsr check_iec
                bpl iec_loop
                lda #IEC.DATA_OUT | IEC.ATN_ACK
                jsr set_iec_lines
                jsr wait_iec
                jsr iecin
                lda port.io
                and #IEC.DEVICE_NUMBERS-1
                clc
                adc #IEC.LISTEN + IEC.FIRST_DEVICE
                cmp serial_buf
                beq device_ok
iec_skip        jsr data_hi_check
                bmi iec_skip
                bpl iec_loop2
                .cerror IEC.DEVICE_NUMBERS & (IEC.DEVICE_NUMBERS - 1), "Number of modes must be power of two"

device_ok       jsr check_iec
                bcs device_ok
                lda #IEC.SECOND
                sta serial_buf
                jsr check_iec
                bpl +
                jsr iecin
+               lda serial_buf
                cmp #IEC.SECOND
                blt iec_skip
                cmp #IEC.SECOND + size(modes)/2
                bge iec_skip
                and #size(modes)/2-1
                asl
                tay
                lda modes+1,y
                pha
                lda modes,y
                pha
                cpy #modes.with_param - modes
                blt +
                jsr iecin_number
                tya
+               rts

                .cerror size(modes) & (size(modes) - 1), "Number of modes must be power of two"
modes           .block
                .rta petscii_mode
                .rta plotter_mode
with_param      .rta set_color
                .rta set_size
                .rta set_rotation
                .rta set_dashed
                .rta set_uplower
                .rta reset
                .bend
;---------------
set_color       jsr select_pen
                beq skip_rest
;---------------
                .cerror FONT_SIZES & (FONT_SIZES - 1), "Font sizes must be a power of 2"
set_size        and #FONT_SIZES-1
                sta char_size
                bpl skip_rest
;---------------
set_rotation    sta char_rotation
                bpl skip_rest
;---------------
                .cerror DASH_LENGTHS & (DASH_LENGTHS - 1), "Dash length must be a power of 2"
set_dashed      and #DASH_LENGTHS-1
                sta dashed
                bpl skip_rest
;---------------
set_uplower     and #1
                lsr
                ror
                sta upper_lower
                bcc skip_rest
-               jsr iecin
skip_rest       lda serial_eot
                beq -
                jmp idle_loop
;---------------
iecin2          lda serial_eot
                eor #%11111111
                beq at_eot
;---------------
iecin           jsr check_iec
                bcs iecin
-               jsr data_hi_check
                and #IEC.DATA_IN >> 2
                bne -
                sta serial_eot
                ldx #9
-               jsr check_iec
                bcs neot
                dex
                bne -
                jsr data_lo
                dec serial_eot
                ldx #7
-               dex
                bne -
                jsr data_hi_check
neot            ldx #8
iecbitloop      lda port.iec
                and #IEC.CLK_IN
                beq iecbitloop
-               lda port.iec
                and #IEC.CLK_IN
                bne -
                lda port.iec
                eor #$ff
                asl                     ;data
                ror serial_buf
                dex
                bne iecbitloop
-               jsr check_iec           ;clk?
                bcc -
                jsr data_lo
                ldx #20
-               dex
                bne -
                lda serial_eot
                bpl +
                jsr atnack_hi
+               lda serial_buf
                cmp #"{cr}"
at_eot          rts
;---------------
atn_hi          lda #IEC.ATN_ACK        ;unused
                bne set_iec_lines
;---------------
data_lo         lda #IEC.DATA_OUT
;---------------
set_iec_lines   ora port.iec
                bne sta_iec
;---------------
atnack_hi       lda #~IEC.ATN_ACK       ;atnack
                and port.iec
                sta port.iec
;---------------
data_hi_check   lda #~IEC.DATA_OUT      ;data
                and port.iec
sta_iec         sta port.iec
;---------------
check_iec       lda port.iec
                cmp port.iec
                bne check_iec
                lsr
                ror
                rts
;---------------
petscii_mode    jsr iecin
                beq do_cr
                cmp #"{lf}"
                beq do_cr
                cmp #"{shift return}"
                beq do_shcr
                cmp #"{pi}"
                bne +
                lda #font.PI + $80
+               cmp #'"'
                bne +
                inc quote_counter
+               eor upper_lower
                sta serial_buf
                and #%01111111
                sec
                sbc #32
                bge +
                lda quote_counter
                and #1
                sta underline
                beq nextchar
                lda serial_buf
                and #%01111111
                ora #%00100000
+               cmp #64
                bge nextchar
                cmp #32
                blt +
                ldx serial_buf
                bpl +
                adc #%00011111
+               sta serial_buf
                jsr in_printarea_x
                bcc +
                jsr carriage_return
+               jsr print_buf
                lsr underline
                bcc nextchar
                jsr set_absorigin
                ldx #font.LOW_LINE
                jsr print_char
nextchar        lda serial_eot
                beq petscii_mode
                bne skip_rest2

do_cr           jsr carriage_return
                stx quote_counter
                stx underline
                beq nextchar
do_shcr         jsr move_left_side
                beq nextchar
;---------------
plotter_mode    jsr iecin
                stx cmd_use_pen
                cmp #"i"
                bne +
                jsr set_relorigin
+               cmp #"h"
                bne +
                jsr set_absorigin
+               cmp #"m"
                beq nuse_pen
                cmp #"r"
                beq nuse_pen
                cmp #"d"
                beq +
                cmp #"j"
                bne skip_rest2
+               inc cmd_use_pen
nuse_pen        pha
                jsr iecin_number
                sty cmd.x
                sta cmd.x+1
                jsr iecin_number
                sty cmd.y
                sta cmd.y+1
                pla
                and #%00000100
                beq +
                jsr move_abs
                beq skip_rest2
+               jsr move_rel
skip_rest2      jmp skip_rest
;---------------
                .cerror HEIGHT > 10000, "Coordinate overflow possible"
iecin_number    lda #ceil(log10(HEIGHT-1))
                sta count
                jsr num_clr
-               jsr iecin2
                beq num_end
                cmp #"."
                beq digits_finished
                cmp #"-"
                bne +
                dec num_neg
+               jsr is_digit
                bcs -
next_digit      pha
                asl num_temp
                rol num_temp+1
                ldx num_temp
                ldy num_temp+1
                asl num_temp
                rol num_temp+1
                asl num_temp
                rol num_temp+1
                clc
                txa
                adc num_temp
                sta num_temp
                tya
                adc num_temp+1
                sta num_temp+1
                pla
                clc
                adc num_temp
                sta num_temp
                bcc +
                inc num_temp+1
+               dec count
                beq digits_finished
                jsr iecin2
                beq num_end
                jsr is_digit
                bcc next_digit
-               cmp #"e"
                bne +
                jsr num_clr
+               cmp #" "
                beq num_end
                cmp #","
                beq num_end
digits_finished jsr iecin2
                bne -
num_end         ldy num_temp
                lda num_temp+1
                ldx num_neg
                beq nneg
;---------------
negate          pha
                tya
                eor #$ff
                tay
                pla
                eor #$ff
                iny
                bne nneg
                clc
                adc #1
nneg            rts
;---------------
num_clr         lda #0
                sta num_neg
                sta num_temp
                sta num_temp+1
                rts
;---------------
is_digit        tax
                sec
                sbc #"0"
                blt +
                cmp #10
                blt its_digit
+               txa
                sec
its_digit       rts
;---------------
print_buf       ldx serial_buf
;---------------
print_char      inx
                lda #>font
                sta fontp+1
                ldy #<font
                sty fontp
-               lda (fontp),y
                bpl +
                dex
                beq char_found
+               inc fontp
                bne -
                inc fontp+1
                bne -
char_found      jsr set_relorigin
print_loop      ldy #1
                lda (fontp),y           ;exxxyyyp
                sta font_tmp
print_last      lsr
                tax
                and #%111
                sta cmd.y
                lda #0
                sta cmd.x+1
                sta cmd.y+1
                rol
                sta cmd_use_pen
                txa
                lsr
                lsr
                lsr
                and #%111
                sta cmd.x
                ldx font_tmp
                inx
                beq +
                lda char_rotation
                beq +
                ldy cmd.y
                lda cmd.x
                eor #%111
                sta cmd.y
                sty cmd.x
+               ldx char_size
                beq +
-               asl cmd.x
                rol cmd.x+1
                asl cmd.y
                rol cmd.y+1
                dex
                bne -
+               jsr move_rel
                inc fontp
                bne +
                inc fontp+1
+               lda font_tmp
                bpl print_loop
                cmp #$ff
                beq +
                lda #$ff
                sta font_tmp
                lda #$80 + (FONT_WIDTH << 4)
                bne print_last

+               rts
;---------------
move_rel        ldx #coord_s.y
-               clc
                lda cmd,x
                adc relorig,x
                sta cmd,x
                lda cmd+1,x
                adc relorig+1,x
                sta cmd+1,x
                dex
                dex
                beq -
;---------------
move_abs        ldx #coord_s.y
-               sec
                lda cmd,x
                sbc absorig,x
                sta cmd,x
                lda cmd+1,x
                sbc absorig+1,x
                sta cmd+1,x
                dex
                dex
                beq -

                ldx #coord_s.y
-               ldy cmd,x
                lda cmd+1,x
                sta sign,x
                bpl +
                jsr negate
                sta cmd+1,x
                sty cmd,x
+               dex
                dex
                beq -

                sec
                lda cmd.y
                sbc cmd.x
                lda cmd.y+1
                sbc cmd.x+1
                lda #0
                sta dash_counter
                rol
                rol
                tax
                lda cmd+1,x
                sta longer+1
                lsr
                sta accu+1
                lda cmd,x
                sta longer
                ror
                sta accu
                txa
                eor #coord_s.y
                tax
                sta was_x
                lda cmd,x
                sta shorter
                lda cmd+1,x
                sta shorter+1

move_loop       lda cmd.x
                ora cmd.x+1
                bne +
                lda cmd.y
                ora cmd.y+1
                bne move_v1
                rts

+               lda cmd.y
                ora cmd.y+1
                beq move_h1

                sec
                lda accu
                sbc shorter
                sta accu
                lda accu+1
                sbc shorter+1
                sta accu+1
                blt overf

                lda was_x
                beq move_v1
move_h1         inc step.x
                bne +

overf           clc
                lda accu
                adc longer
                sta accu
                lda accu+1
                adc longer+1
                sta accu+1

                inc step.x
move_v1         inc step.y

+               ldx #coord_s.y
move_xy_loop    lda sign,x
                bmi +
                jsr step1
+               ldy absorig,x
                lda absorig+1,x
                bpl +
                jsr negate
+               pha
                tya
                sec
                sbc #<HEIGHT
                pla
                sbc #>HEIGHT
                bge +
                txa
                bne move_ib
                .cerror HEIGHT < WIDTH, "Width can't be smaller than height"
                jsr in_printarea_x
                bcc move_ib
+               rol cmd_use_pen
                sec
                ror cmd_use_pen
                bmi move_oob

move_ib         lda step,x
                beq nstep
                lda sign,x
                bmi +
                inc stepper,x
                inc stepper,x
+               dec stepper,x

move_oob        lda step,x
                beq nstep
                lda cmd,x
                bne +
                dec cmd+1,x
+               dec cmd,x

nstep           lda sign,x
                bpl +
                jsr step1
+               dex
                dex
                beq move_xy_loop

                lda cmd_use_pen
                bpl +
                lda #0
                sta cmd_use_pen
                sta pen_state
+               beq pen_up
                ldx dashed
                beq pen_down
                lda dash_counter
                bne skip_pen
                stx dash_counter
                lda pen_state
                and #PEN.UP
                beq pen_down
;---------------
pen_up          ldx #~PEN.UP
                bne +

pen_down        ldx #~PEN.DOWN
+               cpx pen_state
                beq skip_pen
                cpx #~PEN.DOWN
                beq +
                jsr wait_pen
+               stx port.pen
                stx pen_state
                jsr wait_pen
                lda #~PEN.IDLE
                sta port.pen
skip_pen        jsr set_stepper
                sta step.x
                sta step.y
                dec dash_counter
                jmp move_loop
;---------------
step1           ldy step,x
                beq +
                asl
                bcs step1_m
                inc absorig,x
                bne +
                inc absorig+1,x
+               rts

step1_m         lda absorig,x
                bne +
                dec absorig+1,x
+               dec absorig,x
                rts
;---------------
in_printarea_x  sec
                lda absorig.x
                sbc #<WIDTH
                lda absorig.x+1
                sbc #>WIDTH
                rts
;---------------
set_stepper     lda stepper.x
                and #size(stepconst.x)-1
                tay
                lda stepconst.x,y
                pha
                lda stepper.y
                and #size(stepconst.y)-1
                tay
                pla
                ora stepconst.y,y
                sta port.stepper
;---------------
wait_iec        lda #<IEC.WAIT
                ldy #>IEC.WAIT
                bne wait
;---------------
wait_pen        lda #<PEN.WAIT
                ldy #>PEN.WAIT
                bne wait
;---------------
wait_settle     lda #<SETTLE_WAIT
                ldy #>SETTLE_WAIT
wait            sta latch_l
                sty latch_now
-               lda control
                bpl -
                lda #0
                rts

stepconst       .block
consts          = [%1001, %1010, %0110, %0101]
x               .byte consts
y               .byte consts << 4
                .bend
;---------------
carriage_return jsr move_left_side
;---------------
                .cerror (LINE_HEIGHT / 2 * FONT_SIZES) > 255, "Line height too big"
line_feed       ldx char_size
                inx
                lda #LINE_HEIGHT / 2
-               asl
                dex
                bne -
                sta absorig.y
                stx absorig.y+1
                jsr move_abs_pup
;---------------
set_relorigin   ldx #size(relorig)
-               lda absorig-1,x
                sta relorig-1,x
                dex
                bne -
                rts
;---------------
set_absorigin   ldx #size(cmd)
-               lda relorig-1,x
                sta cmd-1,x
                dex
                bne -
                beq move_abs_pup
;---------------
move_left_side  lda #0
                sta cmd.x
                sta cmd.x+1
                beq move_horiz
;---------------
next_color      inc color
                lda color
;---------------
                .cerror COLORS & (COLORS - 1), "Colors must be a power of 2"
select_pen      and #COLORS-1
                sta color
                lda current_color
                cmp color
                beq same_color
                lda absorig.x
                pha
                lda absorig.x+1
                pha
                jsr pen_up
                jsr move_left_side
-               ldx #PEN.STEPS + MARGIN_STEPS
                jsr stepper_left
                jsr stepper_rl
                jsr stepper_rl
                ldx #PEN.STEPS + MARGIN_STEPS
                jsr stepper_right
                inc current_color
                lda current_color
                and #COLORS-1
                sta current_color
                cmp color
                bne -
                pla
                sta cmd.x+1
                pla
                sta cmd.x
move_horiz      lda absorig.y
                sta cmd.y
                lda absorig.y+1
                sta cmd.y+1
;---------------
move_abs_pup    lda #%10000000
                sta cmd_use_pen
                jmp move_abs
;---------------
stepper_rl      jsr stepper_r
                ldx #PEN.STEPS
;---------------
stepper_left    dec stepper.x
                jsr set_stepper
                dex
                bne stepper_left
same_color      rts
;---------------
stepper_r       ldx #PEN.STEPS
;---------------
stepper_right   inc stepper.x
                jsr set_stepper
                dex
                bne stepper_right
                rts

                .cerror * > vectors, "Code too long by ", * - vectors, " bytes"
                .fill vectors - *, $aa

                *= ROM_START + ROM_SIZE - size(vectors)
vectors         .word reset, reset, reset