/// @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+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+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+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+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+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>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