kickc/src/test/ref/millfork-benchmarks/plasma-kc.asm

508 lines
11 KiB
NASM

/// @file
/// A lightweight library for printing on the C64.
///
/// Printing with this library is done by calling print_ function for each element
// Commodore 64 PRG executable file
.file [name="plasma-kc.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(__start)
.const PAGE1 = SCREEN1>>6&$f0|CHARSET>>$a&$e
.const PAGE2 = SCREEN2>>6&$f0|CHARSET>>$a&$e
/// $D018 VIC-II base addresses
/// - Bit#0: not used
/// - Bit#1-#3: CB Address Bits 11-13 of the Character Set (*2048)
/// - Bit#4-#7: VM Address Bits 10-13 of the Screen RAM (*1024)
/// Initial Value: %00010100
.label VICII_MEMORY = $d018
/// The CIA#2: Serial bus, RS-232, VIC memory bank
.label CIA2 = $dd00
.label SCREEN1 = $e000
.label SCREEN2 = $e400
.label CHARSET = $e800
.label print_screen = $400
// The random state variable
.label rand_state = $e
.label last_time = $18
.label print_line_cursor = $16
.label Ticks = 8
.label Ticks_1 = 2
.label print_char_cursor = $11
.segment Code
__start: {
// volatile unsigned int rand_state = 1
lda #<1
sta.z rand_state
lda #>1
sta.z rand_state+1
// unsigned int last_time
sta.z last_time
sta.z last_time+1
jsr main
rts
}
main: {
.label block = $1a
.label v = $1b
.label count = $16
// makechar()
jsr makechar
// start()
jsr start
// block = CIA2->PORT_A
lda CIA2
sta.z block
// tmp = block & 0xFC
lda #$fc
and.z block
// CIA2->PORT_A = tmp
sta CIA2
// v = *VICII_MEMORY
lda VICII_MEMORY
sta.z v
lda #<$1f4
sta.z count
lda #>$1f4
sta.z count+1
/* Run the demo until a key was hit */
__b1:
// while (count)
lda.z count
ora.z count+1
bne __b2
// *VICII_MEMORY = v
lda.z v
sta VICII_MEMORY
// CIA2->PORT_A = block
lda.z block
sta CIA2
// end()
/* Reset screen colors */
jsr end
// }
rts
__b2:
// doplasma ((char*)SCREEN1)
/* Build page 1, then make it visible */
lda #<SCREEN1
sta.z doplasma.scrn
lda #>SCREEN1
sta.z doplasma.scrn+1
jsr doplasma
// *VICII_MEMORY = PAGE1
lda #PAGE1
sta VICII_MEMORY
// doplasma ((char*)SCREEN2)
/* Build page 2, then make it visible */
lda #<SCREEN2
sta.z doplasma.scrn
lda #>SCREEN2
sta.z doplasma.scrn+1
jsr doplasma
// *VICII_MEMORY = PAGE2
lda #PAGE2
sta VICII_MEMORY
// --count;
lda.z count
bne !+
dec.z count+1
!:
dec.z count
jmp __b1
}
makechar: {
.label __3 = 8
.label __4 = $a
.label __7 = $11
.label __8 = $11
.label s = $14
.label c = $b
.label i = $d
.label __10 = $11
lda #<0
sta.z c
sta.z c+1
__b1:
// for (c = 0; c < 0x100; ++c)
lda.z c+1
cmp #>$100
bcc __b2
bne !+
lda.z c
cmp #<$100
bcc __b2
!:
// }
rts
__b2:
// s = sinetable[(char)c]
ldx.z c
lda sinetable,x
sta.z s
lda #0
sta.z i
__b3:
// for (i = 0; i < 8; ++i)
lda.z i
cmp #8
bcc __b4
// for (c = 0; c < 0x100; ++c)
inc.z c
bne !+
inc.z c+1
!:
jmp __b1
__b4:
ldy #0
ldx #0
__b5:
// for (ii = 0; ii < 8; ++ii)
cpx #8
bcc __b6
// c<<3
lda.z c
asl
sta.z __7
lda.z c+1
rol
sta.z __7+1
asl.z __7
rol.z __7+1
asl.z __7
rol.z __7+1
// (c<<3) + i
lda.z i
clc
adc.z __8
sta.z __8
bcc !+
inc.z __8+1
!:
// ((char*)CHARSET) [(c<<3) + i] = b
lda.z __10
clc
adc #<CHARSET
sta.z __10
lda.z __10+1
adc #>CHARSET
sta.z __10+1
tya
ldy #0
sta (__10),y
// for (i = 0; i < 8; ++i)
inc.z i
jmp __b3
__b6:
// rand()
jsr rand
// rand() & 0xFF
lda #$ff
and.z __3
sta.z __4
// if ((rand() & 0xFF) > s)
lda.z s
cmp.z __4
bcs __b8
// b |= bittab[ii]
tya
ora bittab,x
tay
__b8:
// for (ii = 0; ii < 8; ++ii)
inx
jmp __b5
}
start: {
.label LAST_TIME = last_time
// asm
jsr $ffde
sta LAST_TIME
stx LAST_TIME+1
// }
rts
}
end: {
// Ticks = last_time
lda.z last_time
sta.z Ticks
lda.z last_time+1
sta.z Ticks+1
// start()
jsr start
// last_time -= Ticks
lda.z last_time
sec
sbc.z Ticks
sta.z last_time
lda.z last_time+1
sbc.z Ticks+1
sta.z last_time+1
// Ticks = last_time
lda.z last_time
sta.z Ticks_1
lda.z last_time+1
sta.z Ticks_1+1
// print_uint(Ticks)
jsr print_uint
// print_ln()
jsr print_ln
// }
rts
}
// void doplasma(__zp($b) char *scrn)
doplasma: {
.const c2A = 0
.const c2B = 0
.label c1a = $14
.label c1b = $a
.label ii = $d
.label c2a = $15
.label c2b = $13
.label i = $10
.label scrn = $b
lda #0
sta.z c1b
sta.z c1a
sta.z ii
__b1:
// for (ii = 0; ii < 25; ++ii)
lda.z ii
cmp #$19
bcc __b2
lda #c2B
sta.z c2b
lda #c2A
sta.z c2a
lda #0
sta.z i
__b3:
// for (i = 0; i < 40; ++i)
lda.z i
cmp #$28
bcc __b4
ldx #0
__b5:
// for (jj = 0; jj < 25; ++jj)
cpx #$19
bcc __b8
// }
rts
__b8:
ldy #0
__b6:
// for (j = 0; j < 40; ++j)
cpy #$28
bcc __b7
// scrn += 40
lda #$28
clc
adc.z scrn
sta.z scrn
bcc !+
inc.z scrn+1
!:
// for (jj = 0; jj < 25; ++jj)
inx
jmp __b5
__b7:
// xbuf[j] + ybuf[jj]
lda xbuf,y
clc
adc ybuf,x
// scrn[j] = (xbuf[j] + ybuf[jj])
sta (scrn),y
// for (j = 0; j < 40; ++j)
iny
jmp __b6
__b4:
// sinetable[c2a] + sinetable[c2b]
ldy.z c2a
lda sinetable,y
ldy.z c2b
clc
adc sinetable,y
// xbuf[i] = (sinetable[c2a] + sinetable[c2b])
ldy.z i
sta xbuf,y
// c2a += 3
lax.z c2a
axs #-[3]
stx.z c2a
// c2b += 7
lax.z c2b
axs #-[7]
stx.z c2b
// for (i = 0; i < 40; ++i)
inc.z i
jmp __b3
__b2:
// sinetable[c1a] + sinetable[c1b]
ldy.z c1a
lda sinetable,y
ldy.z c1b
clc
adc sinetable,y
// ybuf[ii] = (sinetable[c1a] + sinetable[c1b])
ldy.z ii
sta ybuf,y
// c1a += 4
lax.z c1a
axs #-[4]
stx.z c1a
// c1b += 9
lax.z c1b
axs #-[9]
stx.z c1b
// for (ii = 0; ii < 25; ++ii)
inc.z ii
jmp __b1
}
// Returns a pseudo-random number in the range of 0 to RAND_MAX (65535)
// Uses an xorshift pseudorandom number generator that hits all different values
// Information https://en.wikipedia.org/wiki/Xorshift
// Source http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html
rand: {
.label __0 = 2
.label __1 = 4
.label __2 = 6
.label return = 8
// rand_state << 7
lda.z rand_state+1
lsr
lda.z rand_state
ror
sta.z __0+1
lda #0
ror
sta.z __0
// rand_state ^= rand_state << 7
lda.z rand_state
eor.z __0
sta.z rand_state
lda.z rand_state+1
eor.z __0+1
sta.z rand_state+1
// rand_state >> 9
lsr
sta.z __1
lda #0
sta.z __1+1
// rand_state ^= rand_state >> 9
lda.z rand_state
eor.z __1
sta.z rand_state
lda.z rand_state+1
eor.z __1+1
sta.z rand_state+1
// rand_state << 8
lda.z rand_state
sta.z __2+1
lda #0
sta.z __2
// rand_state ^= rand_state << 8
lda.z rand_state
eor.z __2
sta.z rand_state
lda.z rand_state+1
eor.z __2+1
sta.z rand_state+1
// return rand_state;
lda.z rand_state
sta.z return
lda.z rand_state+1
sta.z return+1
// }
rts
}
// Print a unsigned int as HEX
// void print_uint(__zp(2) unsigned int w)
print_uint: {
.label w = 2
// 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 newline
print_ln: {
lda #<print_screen
sta.z print_line_cursor
lda #>print_screen
sta.z print_line_cursor+1
__b1:
// print_line_cursor + 0x28
lda #$28
clc
adc.z print_line_cursor
sta.z print_line_cursor
bcc !+
inc.z print_line_cursor+1
!:
// while (print_line_cursor<print_char_cursor)
lda.z print_line_cursor+1
cmp.z print_char_cursor+1
bcc __b1
bne !+
lda.z print_line_cursor
cmp.z print_char_cursor
bcc __b1
!:
// }
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&0xf
lda #$f
axs #0
// print_char(print_hextab[b&0xf])
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
print_hextab: .text "0123456789abcdef"
.align $100
sinetable: .byte $80, $7d, $7a, $77, $74, $70, $6d, $6a, $67, $64, $61, $5e, $5b, $58, $55, $52, $4f, $4d, $4a, $47, $44, $41, $3f, $3c, $39, $37, $34, $32, $2f, $2d, $2b, $28, $26, $24, $22, $20, $1e, $1c, $1a, $18, $16, $15, $13, $11, $10, $f, $d, $c, $b, $a, 8, 7, 6, 6, 5, 4, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 6, 7, 8, $a, $b, $c, $d, $f, $10, $11, $13, $15, $16, $18, $1a, $1c, $1e, $20, $22, $24, $26, $28, $2b, $2d, $2f, $32, $34, $37, $39, $3c, $3f, $41, $44, $47, $4a, $4d, $4f, $52, $55, $58, $5b, $5e, $61, $64, $67, $6a, $6d, $70, $74, $77, $7a, $7d, $80, $83, $86, $89, $8c, $90, $93, $96, $99, $9c, $9f, $a2, $a5, $a8, $ab, $ae, $b1, $b3, $b6, $b9, $bc, $bf, $c1, $c4, $c7, $c9, $cc, $ce, $d1, $d3, $d5, $d8, $da, $dc, $de, $e0, $e2, $e4, $e6, $e8, $ea, $eb, $ed, $ef, $f0, $f1, $f3, $f4, $f5, $f6, $f8, $f9, $fa, $fa, $fb, $fc, $fd, $fd, $fe, $fe, $fe, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $fe, $fe, $fe, $fd, $fd, $fc, $fb, $fa, $fa, $f9, $f8, $f6, $f5, $f4, $f3, $f1, $f0, $ef, $ed, $eb, $ea, $e8, $e6, $e4, $e2, $e0, $de, $dc, $da, $d8, $d5, $d3, $d1, $ce, $cc, $c9, $c7, $c4, $c1, $bf, $bc, $b9, $b6, $b3, $b1, $ae, $ab, $a8, $a5, $a2, $9f, $9c, $99, $96, $93, $90, $8c, $89, $86, $83
xbuf: .fill $28, 0
ybuf: .fill $19, 0
bittab: .byte 1, 2, 4, 8, $10, $20, $40, $80