mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-09-29 03:56:15 +00:00
532 lines
9.6 KiB
NASM
532 lines
9.6 KiB
NASM
// Find atan2(x, y) using the CORDIC method
|
|
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
|
// Commodore 64 PRG executable file
|
|
.file [name="cordic-atan2-16-ref.prg", type="prg", segments="Program"]
|
|
.segmentdef Program [segments="Basic, Code, Data"]
|
|
.segmentdef Basic [start=$0801]
|
|
.segmentdef Code [start=$80d]
|
|
.segmentdef Data [startAfter="Code"]
|
|
.segment Basic
|
|
:BasicUpstart(main)
|
|
// The number of iterations performed during 16-bit CORDIC atan2 calculation
|
|
.const CORDIC_ITERATIONS_16 = $f
|
|
/// $D018 VIC-II base addresses
|
|
// @see #VICII_MEMORY
|
|
.label D018 = $d018
|
|
/// Color Ram
|
|
.label COLS = $d800
|
|
.label CHARSET = $2000
|
|
.label SCREEN = $2800
|
|
.label print_screen = $400
|
|
.label print_char_cursor = $f
|
|
.segment Code
|
|
main: {
|
|
.const toD0181_return = (>(SCREEN&$3fff)*4)|(>CHARSET)/4&$f
|
|
.label col00 = COLS+$c*$28+$13
|
|
.label __6 = 6
|
|
.label xw = $13
|
|
.label yw = $15
|
|
.label angle_w = 6
|
|
.label diff_sum = $19
|
|
.label screen = $17
|
|
.label screen_ref = $f
|
|
.label x = $12
|
|
.label y = $1b
|
|
// init_font_hex(CHARSET)
|
|
jsr init_font_hex
|
|
// *D018 = toD018(SCREEN, CHARSET)
|
|
lda #toD0181_return
|
|
sta D018
|
|
lda #<SCREEN
|
|
sta.z screen
|
|
lda #>SCREEN
|
|
sta.z screen+1
|
|
lda #<0
|
|
sta.z diff_sum
|
|
sta.z diff_sum+1
|
|
lda #<SCREEN_REF
|
|
sta.z screen_ref
|
|
lda #>SCREEN_REF
|
|
sta.z screen_ref+1
|
|
lda #-$c
|
|
sta.z y
|
|
__b1:
|
|
lda #-$13
|
|
sta.z x
|
|
__b2:
|
|
// MAKEWORD( (byte)x, 0 )
|
|
lda #0
|
|
ldy.z x
|
|
sty.z xw+1
|
|
sta.z xw
|
|
// MAKEWORD( (byte)y, 0 )
|
|
ldy.z y
|
|
sty.z yw+1
|
|
sta.z yw
|
|
// word angle_w = atan2_16(xw, yw)
|
|
jsr atan2_16
|
|
// angle_w+0x0080
|
|
lda #$80
|
|
clc
|
|
adc.z __6
|
|
sta.z __6
|
|
bcc !+
|
|
inc.z __6+1
|
|
!:
|
|
// byte ang_w = BYTE1(angle_w+0x0080)
|
|
ldx.z __6+1
|
|
// diff(ang_w, *screen_ref)
|
|
ldy #0
|
|
lda (screen_ref),y
|
|
jsr diff
|
|
// diff_sum += diff(ang_w, *screen_ref)
|
|
//*screen = (>angle_w)-angle_b;
|
|
//*screen = >angle_w;
|
|
clc
|
|
adc.z diff_sum
|
|
sta.z diff_sum
|
|
bcc !+
|
|
inc.z diff_sum+1
|
|
!:
|
|
// ang_w - *screen_ref
|
|
txa
|
|
sec
|
|
ldy #0
|
|
sbc (screen_ref),y
|
|
// *screen = ang_w - *screen_ref
|
|
sta (screen),y
|
|
// screen++;
|
|
inc.z screen
|
|
bne !+
|
|
inc.z screen+1
|
|
!:
|
|
// screen_ref++;
|
|
inc.z screen_ref
|
|
bne !+
|
|
inc.z screen_ref+1
|
|
!:
|
|
// for(signed byte x: -19..20)
|
|
inc.z x
|
|
lda #$15
|
|
cmp.z x
|
|
bne __b2
|
|
// for(signed byte y: -12..12)
|
|
inc.z y
|
|
lda #$d
|
|
cmp.z y
|
|
bne __b1
|
|
// print_uint(diff_sum)
|
|
jsr print_uint
|
|
__b5:
|
|
// (*col00)++;
|
|
inc col00
|
|
jmp __b5
|
|
}
|
|
// Make charset from proto chars
|
|
// void init_font_hex(__zp($a) char *charset)
|
|
init_font_hex: {
|
|
.label __0 = $d
|
|
.label idx = $c
|
|
.label proto_lo = 6
|
|
.label charset = $a
|
|
.label c1 = $e
|
|
.label proto_hi = 8
|
|
.label c = $11
|
|
lda #0
|
|
sta.z c
|
|
lda #<FONT_HEX_PROTO
|
|
sta.z proto_hi
|
|
lda #>FONT_HEX_PROTO
|
|
sta.z proto_hi+1
|
|
lda #<CHARSET
|
|
sta.z charset
|
|
lda #>CHARSET
|
|
sta.z charset+1
|
|
__b1:
|
|
lda #0
|
|
sta.z c1
|
|
lda #<FONT_HEX_PROTO
|
|
sta.z proto_lo
|
|
lda #>FONT_HEX_PROTO
|
|
sta.z proto_lo+1
|
|
__b2:
|
|
// charset[idx++] = 0
|
|
lda #0
|
|
tay
|
|
sta (charset),y
|
|
lda #1
|
|
sta.z idx
|
|
ldx #0
|
|
__b3:
|
|
// proto_hi[i]<<4
|
|
txa
|
|
tay
|
|
lda (proto_hi),y
|
|
asl
|
|
asl
|
|
asl
|
|
asl
|
|
sta.z __0
|
|
// proto_lo[i]<<1
|
|
txa
|
|
tay
|
|
lda (proto_lo),y
|
|
asl
|
|
// proto_hi[i]<<4 | proto_lo[i]<<1
|
|
ora.z __0
|
|
// charset[idx++] = proto_hi[i]<<4 | proto_lo[i]<<1
|
|
ldy.z idx
|
|
sta (charset),y
|
|
// charset[idx++] = proto_hi[i]<<4 | proto_lo[i]<<1;
|
|
inc.z idx
|
|
// for( byte i: 0..4)
|
|
inx
|
|
cpx #5
|
|
bne __b3
|
|
// charset[idx++] = 0
|
|
lda #0
|
|
ldy.z idx
|
|
sta (charset),y
|
|
// charset[idx++] = 0;
|
|
iny
|
|
// charset[idx++] = 0
|
|
sta (charset),y
|
|
// proto_lo += 5
|
|
lda #5
|
|
clc
|
|
adc.z proto_lo
|
|
sta.z proto_lo
|
|
bcc !+
|
|
inc.z proto_lo+1
|
|
!:
|
|
// charset += 8
|
|
lda #8
|
|
clc
|
|
adc.z charset
|
|
sta.z charset
|
|
bcc !+
|
|
inc.z charset+1
|
|
!:
|
|
// for( byte c: 0..15 )
|
|
inc.z c1
|
|
lda #$10
|
|
cmp.z c1
|
|
bne __b2
|
|
// proto_hi += 5
|
|
lda #5
|
|
clc
|
|
adc.z proto_hi
|
|
sta.z proto_hi
|
|
bcc !+
|
|
inc.z proto_hi+1
|
|
!:
|
|
// for( byte c: 0..15 )
|
|
inc.z c
|
|
lda #$10
|
|
cmp.z c
|
|
bne __b1
|
|
// }
|
|
rts
|
|
}
|
|
// Find the atan2(x, y) - which is the angle of the line from (0,0) to (x,y)
|
|
// Finding the angle requires a binary search using CORDIC_ITERATIONS_16
|
|
// Returns the angle in hex-degrees (0=0, 0x8000=PI, 0x10000=2*PI)
|
|
// __zp(6) unsigned int atan2_16(__zp($13) int x, __zp($15) int y)
|
|
atan2_16: {
|
|
.label __2 = 8
|
|
.label __7 = $a
|
|
.label yi = 8
|
|
.label xi = $a
|
|
.label angle = 6
|
|
.label xd = 4
|
|
.label yd = 2
|
|
.label return = 6
|
|
.label x = $13
|
|
.label y = $15
|
|
// (y>=0)?y:-y
|
|
lda.z y+1
|
|
bmi !__b1+
|
|
jmp __b1
|
|
!__b1:
|
|
sec
|
|
lda #0
|
|
sbc.z y
|
|
sta.z __2
|
|
lda #0
|
|
sbc.z y+1
|
|
sta.z __2+1
|
|
__b3:
|
|
// (x>=0)?x:-x
|
|
lda.z x+1
|
|
bmi !__b4+
|
|
jmp __b4
|
|
!__b4:
|
|
sec
|
|
lda #0
|
|
sbc.z x
|
|
sta.z __7
|
|
lda #0
|
|
sbc.z x+1
|
|
sta.z __7+1
|
|
__b6:
|
|
lda #<0
|
|
sta.z angle
|
|
sta.z angle+1
|
|
tax
|
|
__b10:
|
|
// if(yi==0)
|
|
lda.z yi+1
|
|
ora.z yi
|
|
bne __b11
|
|
__b12:
|
|
// angle /=2
|
|
lsr.z angle+1
|
|
ror.z angle
|
|
// if(x<0)
|
|
lda.z x+1
|
|
bpl __b7
|
|
// angle = 0x8000-angle
|
|
lda #<$8000
|
|
sec
|
|
sbc.z angle
|
|
sta.z angle
|
|
lda #>$8000
|
|
sbc.z angle+1
|
|
sta.z angle+1
|
|
__b7:
|
|
// if(y<0)
|
|
lda.z y+1
|
|
bpl __b8
|
|
// angle = -angle
|
|
sec
|
|
lda #0
|
|
sbc.z angle
|
|
sta.z angle
|
|
lda #0
|
|
sbc.z angle+1
|
|
sta.z angle+1
|
|
__b8:
|
|
// }
|
|
rts
|
|
__b11:
|
|
txa
|
|
tay
|
|
lda.z xi
|
|
sta.z xd
|
|
lda.z xi+1
|
|
sta.z xd+1
|
|
lda.z yi
|
|
sta.z yd
|
|
lda.z yi+1
|
|
sta.z yd+1
|
|
__b13:
|
|
// while(shift>=2)
|
|
cpy #2
|
|
bcs __b14
|
|
// if(shift)
|
|
cpy #0
|
|
beq __b17
|
|
// xd >>= 1
|
|
lda.z xd+1
|
|
cmp #$80
|
|
ror.z xd+1
|
|
ror.z xd
|
|
// yd >>= 1
|
|
lda.z yd+1
|
|
cmp #$80
|
|
ror.z yd+1
|
|
ror.z yd
|
|
__b17:
|
|
// if(yi>=0)
|
|
lda.z yi+1
|
|
bpl __b18
|
|
// xi -= yd
|
|
lda.z xi
|
|
sec
|
|
sbc.z yd
|
|
sta.z xi
|
|
lda.z xi+1
|
|
sbc.z yd+1
|
|
sta.z xi+1
|
|
// yi += xd
|
|
clc
|
|
lda.z yi
|
|
adc.z xd
|
|
sta.z yi
|
|
lda.z yi+1
|
|
adc.z xd+1
|
|
sta.z yi+1
|
|
// angle -= CORDIC_ATAN2_ANGLES_16[i]
|
|
txa
|
|
asl
|
|
tay
|
|
lda.z angle
|
|
sec
|
|
sbc CORDIC_ATAN2_ANGLES_16,y
|
|
sta.z angle
|
|
lda.z angle+1
|
|
sbc CORDIC_ATAN2_ANGLES_16+1,y
|
|
sta.z angle+1
|
|
__b19:
|
|
// for( char i: 0..CORDIC_ITERATIONS_16-1)
|
|
inx
|
|
cpx #CORDIC_ITERATIONS_16-1+1
|
|
bne !__b12+
|
|
jmp __b12
|
|
!__b12:
|
|
jmp __b10
|
|
__b18:
|
|
// xi += yd
|
|
clc
|
|
lda.z xi
|
|
adc.z yd
|
|
sta.z xi
|
|
lda.z xi+1
|
|
adc.z yd+1
|
|
sta.z xi+1
|
|
// yi -= xd
|
|
lda.z yi
|
|
sec
|
|
sbc.z xd
|
|
sta.z yi
|
|
lda.z yi+1
|
|
sbc.z xd+1
|
|
sta.z yi+1
|
|
// angle += CORDIC_ATAN2_ANGLES_16[i]
|
|
txa
|
|
asl
|
|
tay
|
|
clc
|
|
lda.z angle
|
|
adc CORDIC_ATAN2_ANGLES_16,y
|
|
sta.z angle
|
|
lda.z angle+1
|
|
adc CORDIC_ATAN2_ANGLES_16+1,y
|
|
sta.z angle+1
|
|
jmp __b19
|
|
__b14:
|
|
// xd >>= 2
|
|
lda.z xd+1
|
|
cmp #$80
|
|
ror.z xd+1
|
|
ror.z xd
|
|
lda.z xd+1
|
|
cmp #$80
|
|
ror.z xd+1
|
|
ror.z xd
|
|
// yd >>= 2
|
|
lda.z yd+1
|
|
cmp #$80
|
|
ror.z yd+1
|
|
ror.z yd
|
|
lda.z yd+1
|
|
cmp #$80
|
|
ror.z yd+1
|
|
ror.z yd
|
|
// shift -=2
|
|
dey
|
|
dey
|
|
jmp __b13
|
|
__b4:
|
|
// (x>=0)?x:-x
|
|
lda.z x
|
|
sta.z xi
|
|
lda.z x+1
|
|
sta.z xi+1
|
|
jmp __b6
|
|
__b1:
|
|
// (y>=0)?y:-y
|
|
lda.z y
|
|
sta.z yi
|
|
lda.z y+1
|
|
sta.z yi+1
|
|
jmp __b3
|
|
}
|
|
// __register(A) char diff(__register(X) char bb1, __register(A) char bb2)
|
|
diff: {
|
|
// (bb1<bb2)?(bb2-bb1):bb1-bb2
|
|
sta.z $ff
|
|
cpx.z $ff
|
|
bcc __b1
|
|
sta.z $ff
|
|
txa
|
|
sec
|
|
sbc.z $ff
|
|
// }
|
|
rts
|
|
__b1:
|
|
// (bb1<bb2)?(bb2-bb1):bb1-bb2
|
|
stx.z $ff
|
|
sec
|
|
sbc.z $ff
|
|
rts
|
|
}
|
|
// Print a unsigned int as HEX
|
|
// void print_uint(__zp($19) unsigned int w)
|
|
print_uint: {
|
|
.label w = $19
|
|
// print_uchar(BYTE1(w))
|
|
ldx.z w+1
|
|
lda #<print_screen
|
|
sta.z print_char_cursor
|
|
lda #>print_screen
|
|
sta.z print_char_cursor+1
|
|
jsr print_uchar
|
|
// print_uchar(BYTE0(w))
|
|
ldx.z w
|
|
jsr print_uchar
|
|
// }
|
|
rts
|
|
}
|
|
// Print a char as HEX
|
|
// void print_uchar(__register(X) char b)
|
|
print_uchar: {
|
|
// b>>4
|
|
txa
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
// print_char(print_hextab[b>>4])
|
|
tay
|
|
lda print_hextab,y
|
|
// Table of hexadecimal digits
|
|
jsr print_char
|
|
// b&$f
|
|
lda #$f
|
|
axs #0
|
|
// print_char(print_hextab[b&$f])
|
|
lda print_hextab,x
|
|
jsr print_char
|
|
// }
|
|
rts
|
|
}
|
|
// Print a single char
|
|
// void print_char(__register(A) char ch)
|
|
print_char: {
|
|
// *(print_char_cursor++) = ch
|
|
ldy #0
|
|
sta (print_char_cursor),y
|
|
// *(print_char_cursor++) = ch;
|
|
inc.z print_char_cursor
|
|
bne !+
|
|
inc.z print_char_cursor+1
|
|
!:
|
|
// }
|
|
rts
|
|
}
|
|
.segment Data
|
|
// Bit patterns for symbols 0-f (3x5 pixels) used in font hex
|
|
FONT_HEX_PROTO: .byte 2, 5, 5, 5, 2, 6, 2, 2, 2, 7, 6, 1, 2, 4, 7, 6, 1, 2, 1, 6, 5, 5, 7, 1, 1, 7, 4, 6, 1, 6, 3, 4, 6, 5, 2, 7, 1, 1, 1, 1, 2, 5, 2, 5, 2, 2, 5, 3, 1, 1, 2, 5, 7, 5, 5, 6, 5, 6, 5, 6, 2, 5, 4, 5, 2, 6, 5, 5, 5, 6, 7, 4, 6, 4, 7, 7, 4, 6, 4, 4
|
|
// Angles representing ATAN(0.5), ATAN(0.25), ATAN(0.125), ...
|
|
CORDIC_ATAN2_ANGLES_16:
|
|
.for (var i=0; i<CORDIC_ITERATIONS_16; i++)
|
|
.word 256*2*256*atan(1/pow(2,i))/PI/2
|
|
|
|
print_hextab: .text "0123456789abcdef"
|
|
SCREEN_REF:
|
|
.for(var y=-12;y<=12;y++)
|
|
.for(var x=-19;x<=20;x++)
|
|
.byte round(256*atan2(y, x)/PI/2)
|
|
|