; $61-$72: free, used by BASIC for floating point operations
tmp = $61
i = $63
j = $65
count = $67
sum = $69
cursorScreen = $6d
cursorX = $6f
decimalZeroInhibit = $70
currentDigit = $71

; 10 SYS (2064)
*=$800

	BYTE	$00, $0E, $08, $0A, $00, $9E, $20, $28, $32, $30, $36, $34, $29, $00, $00, $00

*=$810

; clear screen
    lda #0
    sta $d020
    sta $d021
    ldx #249
clearScreen
    lda #32
    sta 1024,x
    sta 1224,x
    sta 1424,x
    sta 1624,x
    lda #5
    sta 55296,x
    sta 55496,x
    sta 55696,x
    sta 55896,x
    dex
    cpx #$ff
    bne clearScreen

; init prime table: 8192 * 0xaa (first step with 2 precalculated and set to 0)
    lda #<primes
    sta tmp
    lda #>primes
    sta tmp+1
    lda #$ff
    ldx #$20
clear1
    ldy #0
clear2
    sta (tmp),y
    iny
    bne clear2
    inc tmp+1
    dex
    bne clear1

; outer loop: from 2 to 32768
    lda #2
    sta i
    lda #0
    sta i+1
outerLoop
; calculate pointer to array element
    inc $d020
    inc $d021
    lda i
    sta tmp
    lda i+1
    sta tmp+1
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
; calculate bit mask in x
    lda i
    and #7
    tax
; test array
    clc
    lda tmp+1
    adc #>primes
    sta tmp+1
    lda (tmp),y  ; (y = 0)
    and mask,x
    beq nextOuter
; inner loop: set bits to 0, start with j=2*i
    clc
    lda i
    adc i
    sta j
    lda i+1
    adc i+1
    sta j+1
; calculate pointer to array element
innerLoop
    lda j
    sta tmp
    lda j+1
    sta tmp+1
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
; calculate bit mask in x
    lda j
    and #7
    tax
; set bit to 0
    clc
    lda tmp+1
    adc #>primes
    sta tmp+1
    lda mask,x
    eor #$ff
    and (tmp),y  ; (y = 0)
    sta (tmp),y
; next inner loop step: j += i
    clc
    lda j
    adc i
    sta j
    lda j+1
    adc i+1
    sta j+1
    bcc innerLoop  ; end on carry flag set: wrap around 65535
; next outer loop step
nextOuter
    inc i
    bne skipOuter
    inc i+1
skipOuter
    lda i+1
    cmp #$80
    bne outerLoop

; count primes
    lda #0
    sta count
    sta count+1
    sta sum
    sta sum+1
    sta sum+2
    sta sum+3
; loop from 2 to 65535
    lda #2
    sta i
    lda #0
    sta i+1
countLoop
; calculate pointer to array element
    lda i
    sta tmp
    lda i+1
    sta tmp+1
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
    lsr tmp+1
    ror tmp
; calculate bit mask in x
    lda i
    and #7
    tax
; test array
    clc
    lda tmp+1
    adc #>primes
    sta tmp+1
    lda (tmp),y  ; (y = 0)
    and mask,x
    beq nextCount
    inc count
    bne addSum
    inc count+1
addSum
    clc
    lda i
    adc sum
    sta sum
    lda i+1
    adc sum+1
    sta sum+1
    lda sum+2
    adc #0
    sta sum+2
    lda sum+3
    adc #0
    sta sum+3
nextCount
    inc i
    bne skipCount
    inc i+1
skipCount
    bne countLoop

; show result
    lda #0
    sta $d020
    sta $d021
    jsr initTextOutput
; count
    lda count
    sta i
    lda count+1
    sta i+1
    jsr print16unsigned
    ldx #<primesBelowText
    ldy #>primesBelowText
    jsr print
    jsr newline
; sum
    ldx #<sumText
    ldy #>sumText
    jsr print
    lda sum
    sta i
    lda sum+1
    sta i+1
    lda sum+2
    sta i+2
    lda sum+3
    sta i+3
    jsr print32unsigned

halt
    jmp halt

sumText
    text 'SUM:'
    byte 0
primesBelowText
    text 'PRIMES BELOW 65535'
    byte 0

mask
    byte $01, $02, $04, $08, $10, $20, $40, $80

; init variables for text output
initTextOutput
    lda #0
    sta cursorX
    sta cursorScreen
    lda #$04
    sta cursorScreen+1
    rts

; print a character in A at the current position and increment position
printChar
    ldy cursorX
    sta (cursorScreen),y
    inc cursorX
    lda #40
    cmp cursorX
    bne printCharEnd
    lda #0
    sta cursorX
printCharEnd
    rts

; set cursor to the beginning of the next line
newline
    lda #0
    sta cursorX
    lda cursorScreen
    clc
    adc #40
    sta cursorScreen
    lda cursorScreen+1
    adc #0
    sta cursorScreen+1
    rts

; print text in X/Y
print
    stx tmp
    sty tmp+1
printLoop
    ldy #0
    lda (tmp),y
    beq printEnd
    jsr printChar
    inc tmp
    bne printLoop
    inc tmp+1
    jmp printLoop
printEnd
    lda #32
    jmp printChar

; print 16 bit number in i
print16unsigned
    lda #0
    sta j
    sta j+1

; print 32 bit number in i/j
print32unsigned
    lda #1
    sta decimalZeroInhibit
    ldx #0
compareLoop
    lda #0
    sta currentDigit
compareStart
; substract until less than current decimal test
    lda i+3
    cmp decimals+3,x
    bne compareEnd
    lda i+2
    cmp decimals+2,x
    bne compareEnd
    lda i+1
    cmp decimals+1,x
    bne compareEnd
    lda i
    cmp decimals,x
compareEnd
    bcc compareLess
    sec
    lda i
    sbc decimals,x
    sta i
    lda i+1
    sbc decimals+1,x
    sta i+1
    lda i+2
    sbc decimals+2,x
    sta i+2
    lda i+3
    sbc decimals+3,x
    sta i+3
    inc currentDigit
    jmp compareStart
compareLess
; print current digit and prepare test for next digit
    lda currentDigit
    bne printDigit
    cpx #36
    beq printDigit
    lda decimalZeroInhibit
    bne nextDigit
printDigit
    ldy #0
    sty decimalZeroInhibit
    clc
    adc #"0"
    jsr printChar
nextDigit
    inx
    inx
    inx
    inx
    cpx #40
    bne compareLoop
    lda #32
    jmp printChar
    
decimals
    byte $00, $CA, $9A, $3B  ; 1000000000
    byte $00, $E1, $F5, $05  ; 100000000
    byte $80, $96, $98, $00  ; 10000000
    byte $40, $42, $0F, $00  ; 1000000
    byte $A0, $86, $01, $00  ; 100000
    byte $10, $27, $00, $00  ; 10000
    byte $E8, $03, $00, $00  ; 1000
    byte $64, $00, $00, $00  ; 100
    byte $0a, $00, $00, $00  ; 10
    byte $01, $00, $00, $00  ; 1

*=$2000
primes
