diff --git a/demos/lovebyte2024/plasma/Makefile b/demos/lovebyte2024/plasma/Makefile new file mode 100644 index 00000000..83c7d4bf --- /dev/null +++ b/demos/lovebyte2024/plasma/Makefile @@ -0,0 +1,31 @@ +include ../../../Makefile.inc + +DOS33 = ../../../utils/dos33fs-utils/dos33 +TOKENIZE = ../../../utils/asoft_basic-utils/tokenize_asoft +LINKERSCRIPTS = ../../../linker_scripts +EMPTYDISK = ../../../empty_disk/empty.dsk + +all: plasmag.dsk + +plasmag.dsk: HELLO PLASMAG_TINY + cp $(EMPTYDISK) plasmag.dsk + $(DOS33) -y plasmag.dsk SAVE A HELLO + $(DOS33) -y plasmag.dsk BSAVE -a 0x4000 PLASMAG_TINY + +### + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + +### + +PLASMAG_TINY: plasmag_tiny.o + ld65 -o PLASMAG_TINY plasmag_tiny.o -C $(LINKERSCRIPTS)/apple2_4000.inc + +plasmag_tiny.o: plasmag_tiny.s gr_gbascalc.s make_tables.s + ca65 -o plasmag_tiny.o plasmag_tiny.s -l plasmag_tiny.lst + +### + +clean: + rm -f *~ *.o *.lst HELLO PLASMAG_TINY diff --git a/demos/lovebyte2024/plasma/TODO b/demos/lovebyte2024/plasma/TODO new file mode 100644 index 00000000..dc169d04 --- /dev/null +++ b/demos/lovebyte2024/plasma/TODO @@ -0,0 +1,4 @@ +optimize music code: + + depending on alignment can hard-code the high value for track0/track1 + + check the frequencies, high freq might always be 0 + diff --git a/demos/lovebyte2024/plasma/ay3_write_regs.s b/demos/lovebyte2024/plasma/ay3_write_regs.s new file mode 100644 index 00000000..63eee339 --- /dev/null +++ b/demos/lovebyte2024/plasma/ay3_write_regs.s @@ -0,0 +1,34 @@ + ;===================== + ;===================== + ;===================== + ; ay3 write regs + ;===================== + ;===================== + ;===================== + ; write all 14 registers at AY_REGS + +ay3_write_regs: + + ldx #13 +ay3_write_reg_loop: + + lda #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2 + ldy #MOCK_AY_INACTIVE ; go inactive ; 2 + + stx MOCK_6522_ORA1 ; put address on PA1 ; 4 + sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4 + sty MOCK_6522_ORB1 ; 4 + + ; value + lda AY_REGS,X + sta MOCK_6522_ORA1 ; put value on PA1 ; 4 + lda #MOCK_AY_WRITE ; ; 2 + sta MOCK_6522_ORB1 ; write on PB1 ; 4 + sty MOCK_6522_ORB1 ; 4 + + dex + bpl ay3_write_reg_loop + +; rts + + diff --git a/demos/lovebyte2024/plasma/interrupt_handler.s b/demos/lovebyte2024/plasma/interrupt_handler.s new file mode 100644 index 00000000..0197a712 --- /dev/null +++ b/demos/lovebyte2024/plasma/interrupt_handler.s @@ -0,0 +1,68 @@ + ;================================ + ;================================ + ; mockingboard interrupt handler + ;================================ + ;================================ + ; On Apple II/6502 the interrupt handler jumps to address in 0xfffe + ; This is in the ROM, which saves the registers + ; on older IIe it saved A to $45 (which could mess with DISK II) + ; newer IIe doesn't do that. + ; It then calculates if it is a BRK or not (which trashes A) + ; Then it sets up the stack like an interrupt and calls 0x3fe + + ; Note: the IIc is much more complicated + ; its firmware tries to decode the proper source + ; based on various things, including screen hole values + ; we bypass that by switching out ROM and replacing the + ; $fffe vector with this, but that does mean we have + ; to be sure status flag and accumulator set properly + +interrupt_handler: + php ; save status flags + cld ; clear decimal mode + pha ; save A ; 3 + ; A is saved in $45 by firmware + txa + pha ; save X + tya + pha ; save Y + + inc $0404 ; debug (flashes char onscreen) + + +ay3_irq_handler: + bit MOCK_6522_T1CL ; clear 6522 interrupt by reading T1C-L ; 4 + + +.include "play_frame.s" +.include "ay3_write_regs.s" + + ;================================= + ; Finally done with this interrupt + ;================================= + +done_ay3_irq_handler: + + pla + tay ; restore Y + pla + tax ; restore X + pla ; restore a ; 4 + + ; on II+/IIe (but not IIc) we need to do this? +interrupt_smc: + lda $45 ; restore A + plp ; restore flags + + rti ; return from interrupt ; 6 + + ;============ + ; typical + ; ???? cycles + + + + + + + diff --git a/demos/lovebyte2024/plasma/mA2E_2.s b/demos/lovebyte2024/plasma/mA2E_2.s new file mode 100644 index 00000000..6f56be72 --- /dev/null +++ b/demos/lovebyte2024/plasma/mA2E_2.s @@ -0,0 +1,167 @@ +; Made with version 1.0 (2024 Lovebyte) +peasant_song: +; register init + +track0: + +; A: 'A 5' 57 +; B: 'A 5' 57 + .byte $04 ; frame=2 A=0 L=2 +; A: 'C 6' 60 + .byte $05 ; frame=4 B=0 L=2 +; B: 'C 6' 60 + .byte $14 ; frame=6 A=1 L=2 +; A: 'F 5' 53 + .byte $15 ; frame=8 B=1 L=2 +; B: 'F 5' 53 + .byte $24 ; frame=10 A=2 L=2 +; A: 'G 5' 55 + .byte $2D ; frame=16 B=2 L=6 +; B: 'G 5' 55 + .byte $34 ; frame=18 A=3 L=2 +; A: 'E 5' 52 + .byte $35 ; frame=20 B=3 L=2 +; A: 'E 5' 50 +; B: 'E 5' 52 + .byte $44 ; frame=22 A=4 L=2 +; A: 'D 5' 57 +; B: 'D 5' 50 + .byte $50 ; frame=24 A=5 L=0 + .byte $45 ; frame=24 B=4 L=2 +; B: 'A 5' 57 + .byte $00 ; frame=26 A=0 L=0 + .byte $55 ; frame=26 B=5 L=2 +; A: 'E 5' 52 + .byte $05 ; frame=28 B=0 L=2 +; B: 'E 5' 52 + .byte $44 ; frame=30 A=4 L=2 +; A: 'A 5' 57 + .byte $45 ; frame=32 B=4 L=2 +; B: 'A 5' 57 + .byte $04 ; frame=34 A=0 L=2 +; A: 'C 6' 60 + .byte $05 ; frame=36 B=0 L=2 +; B: 'C 6' 60 + .byte $14 ; frame=38 A=1 L=2 +; A: 'F 5' 53 + .byte $15 ; frame=40 B=1 L=2 +; B: 'F 5' 53 + .byte $24 ; frame=42 A=2 L=2 +; A: 'G 5' 55 + .byte $2D ; frame=48 B=2 L=6 +; B: 'G 5' 55 + .byte $34 ; frame=50 A=3 L=2 +; A: 'E 5' 52 + .byte $35 ; frame=52 B=3 L=2 +; A: 'E 5' 50 +; B: 'E 5' 52 + .byte $44 ; frame=54 A=4 L=2 +; A: 'D 5' 45 +; B: 'D 5' 50 + .byte $50 ; frame=56 A=5 L=0 + .byte $45 ; frame=56 B=4 L=2 +; B: 'A 4' 45 + .byte $60 ; frame=58 A=6 L=0 + .byte $55 ; frame=58 B=5 L=2 +; A: 'E 4' 40 + .byte $65 ; frame=60 B=6 L=2 +; B: 'E 4' 40 + .byte $74 ; frame=62 A=7 L=2 +; last: a=-1 b=7 len=2 + .byte $75 ; frame=64 B=7 L=2 +.byte $ff +track1: + +; A: 'A 4' 57 +; B: 'A 4' 45 +; A: 'A 4' 60 +; B: 'A 4' 45 + .byte $00 ; frame=4 A=0 L=0 + .byte $69 ; frame=4 B=6 L=4 +; B: 'B 4' 47 + .byte $10 ; frame=6 A=1 L=0 + .byte $65 ; frame=6 B=6 L=2 +; A: 'C 5' 53 +; B: 'C 5' 48 + .byte $85 ; frame=8 B=8 L=2 +; B: 'A 4' 45 + .byte $20 ; frame=10 A=2 L=0 + .byte $95 ; frame=10 B=9 L=2 +; B: 'D 5' 50 + .byte $69 ; frame=14 B=6 L=4 +; A: 'G 5' 55 + .byte $55 ; frame=16 B=5 L=2 +; B: 'D 5' 50 + .byte $34 ; frame=18 A=3 L=2 +; A: 'C 5' 52 +; B: 'C 5' 48 + .byte $55 ; frame=20 B=5 L=2 +; A: 'B 4' 50 +; B: 'B 4' 47 + .byte $40 ; frame=22 A=4 L=0 + .byte $95 ; frame=22 B=9 L=2 +; A: 'C 5' 57 +; B: 'C 5' 48 + .byte $50 ; frame=24 A=5 L=0 + .byte $85 ; frame=24 B=8 L=2 +; B: 'A 4' 45 + .byte $00 ; frame=26 A=0 L=0 + .byte $95 ; frame=26 B=9 L=2 +; A: 'E 5' 52 + .byte $65 ; frame=28 B=6 L=2 +; A: 'A 4' 57 +; B: 'A 4' 45 + .byte $48 ; frame=32 A=4 L=4 +; A: 'A 4' 60 +; B: 'A 4' 45 + .byte $00 ; frame=36 A=0 L=0 + .byte $69 ; frame=36 B=6 L=4 +; B: 'B 4' 47 + .byte $10 ; frame=38 A=1 L=0 + .byte $65 ; frame=38 B=6 L=2 +; A: 'C 5' 53 +; B: 'C 5' 48 + .byte $85 ; frame=40 B=8 L=2 +; B: 'A 4' 45 + .byte $20 ; frame=42 A=2 L=0 + .byte $95 ; frame=42 B=9 L=2 +; B: 'A 4' 45 + .byte $69 ; frame=46 B=6 L=4 +; B: 'B 4' 47 + .byte $63 ; frame=47 B=6 L=1 +; A: 'D 5' 55 +; B: 'D 5' 50 + .byte $83 ; frame=48 B=8 L=1 +; B: 'D 5' 50 + .byte $30 ; frame=50 A=3 L=0 + .byte $55 ; frame=50 B=5 L=2 +; A: 'C 5' 52 +; B: 'C 5' 48 + .byte $55 ; frame=52 B=5 L=2 +; A: 'B 4' 50 +; B: 'B 4' 47 + .byte $40 ; frame=54 A=4 L=0 + .byte $95 ; frame=54 B=9 L=2 +; A: 'A 4' 45 +; B: 'A 4' 45 + .byte $50 ; frame=56 A=5 L=0 + .byte $85 ; frame=56 B=8 L=2 +; A: 'E 4' 40 + .byte $60 ; frame=60 A=6 L=0 + .byte $69 ; frame=60 B=6 L=4 +; last: a=7 b=-1 len=4 + .byte $78 ; frame=64 A=7 L=4 + .byte $FF ; end +; Octave 0 : 0 0 0 0 0 0 0 0 0 0 0 0 +; Octave 1 : 0 0 0 0 0 0 0 0 0 0 0 0 +; Octave 2 : 0 0 0 0 0 0 0 0 0 0 0 0 +; Octave 3 : 0 0 0 0 3 0 0 0 0 12 0 5 +; Octave 4 : 5 0 10 0 9 6 0 6 0 9 0 0 +; Octave 5 : 6 0 0 0 0 0 0 0 0 0 0 0 +; 10 notes allocated +;.byte 57,60,53,55,52,50,45,40,47,48, +frequencies_low: +.byte $48,$3D,$5B,$51,$60,$6C,$91,$C1,$81,$7A +frequencies_high: +.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +; total len=21 diff --git a/demos/lovebyte2024/plasma/mockingboard_constants.s b/demos/lovebyte2024/plasma/mockingboard_constants.s new file mode 100644 index 00000000..0d70c32f --- /dev/null +++ b/demos/lovebyte2024/plasma/mockingboard_constants.s @@ -0,0 +1,21 @@ +init_addresses: + .byte interrupt_handler ; 2 + sta $03ff ; 3 + ;========= + ; 10 + ;========================= + ; Initialize the 6522s + ; Reset Left AY-3-8910 + ;=========================== + + ; entries=10 + ; 14 + 2*entries = 34 bytes + +; assume Y=0 on entry? + + ldy #0 ; 2 +init_it_loop: + lda init_values,Y ; 3 + ldx init_addresses,Y ; 3 + bmi doneit ; 2 + iny ; 1 + sta $c400,X ; 3 + bne init_it_loop ; 2 +doneit: diff --git a/demos/lovebyte2024/plasma/plasmag_tiny.s b/demos/lovebyte2024/plasma/plasmag_tiny.s new file mode 100644 index 00000000..e138ef7b --- /dev/null +++ b/demos/lovebyte2024/plasma/plasmag_tiny.s @@ -0,0 +1,210 @@ +; Plasma Tiny + +; originally based on Plasmagoria code by French Touch + +; trying to see how small I can get it + + +; note can use $F000 (or similar) for color lookup to get passable +; effect on fewer bytes + +; 347 bytes -- initial with FAC +; 343 bytes -- optimize init +; 340 bytes -- move Table1 + Table2 to zero page +; 331 bytes -- init not necessary +; 319 bytes -- inline precalc + display + init lores colors +; 316 bytes -- fallthrough in make_tiny + +.include "hardware.inc" +.include "zp.inc" + +;Table1 = $8000 +;Table2 = $8000+64 + + +lores_colors_fine=$8100 + + ;====================================== + ; start of code + ;====================================== + +plasma_tiny: + jsr HGR ; have table gen appear on hgr page1 + bit FULLGR + + + + + ;================= + ; init music + + lda #0 + sta FRAME + sta WHICH_TRACK + +;=================== + ; music Player Setup + +tracker_song = peasant_song + + ; assume mockingboard in slot#4 + + ; inline mockingboard_init + +.include "mockingboard_init.s" + +.include "tracker_init.s" + + cli ; start music + + jsr make_tables + + bit LORES ; set lo-res + +; ============================================================================ +; init lores colors (inline) +; ============================================================================ + +init_lores_colors: + ldx #0 + ldy #0 + +init_lores_colors_loop: + lda lores_colors_lookup,X + sta lores_colors_fine,Y + iny + sta lores_colors_fine,Y + iny + sta lores_colors_fine,Y + iny + sta lores_colors_fine,Y + iny + beq done_init_lores_colors + + inx + txa + and #$f + tax + jmp init_lores_colors_loop + +done_init_lores_colors: + + ;==================================== + ; do plasma + ;==================================== + +do_plasma: + ; init + +; lda #02 +; ldx #5 +;init_loop: +; sta COMPT1,X +; dex +; bne init_loop + +BP3: + +; ============================================================================ +; Precalculate some values (inlined) +; ROUTINES PRE CALCUL +; ============================================================================ +precalc: + lda PARAM1 ; self modify various parts + sta pc_off1+1 + lda PARAM2 + sta pc_off2+1 + lda PARAM3 + sta pc_off3+1 + lda PARAM4 + sta pc_off4+1 + + ; Table1(X) = sin1(PARAM1+X)+sin2(PARAM1+X) + ; Table2(X) = sin3(PARAM3+X)+sin1(PARAM4+X) + + ldx #$28 ; 40 +pc_b1: +pc_off1: + lda sin1 +pc_off2: + adc sin2 + sta Table1,X +pc_off3: + lda sin3 +pc_off4: + adc sin1 + sta Table2,X + + inc pc_off1+1 + inc pc_off2+1 + inc pc_off3+1 + inc pc_off4+1 + + dex + bpl pc_b1 + + inc PARAM1 + inc PARAM1 + dec PARAM2 + inc PARAM3 + dec PARAM4 + +; ============================================================================ +; Display Routines +; ROUTINES AFFICHAGES +; ============================================================================ + +; Display "Normal" +; AFFICHAGE "NORMAL" + +display_normal: + + ldx #23 ; lines 0-23 lignes 0-23 + +display_line_loop: + + txa + jsr GBASCALC + + ldy #39 ; col 0-39 + + lda Table2,X ; setup base sine value for row + sta display_row_sin_smc+1 +display_col_loop: + lda Table1,Y ; load in column sine value +display_row_sin_smc: + adc #00 ; add in row value + sta display_lookup_smc+1 ; patch in low byte of lookup +display_lookup_smc: + lda lores_colors_fine ; attention: must be aligned + sta (GBASL),Y + dey + bpl display_col_loop + dex + bpl display_line_loop + +; ============================================================================ + + inc COMPT1 + bne BP3 + + dec COMPT2 + bne BP3 + + beq do_plasma ; bra + + + + + +lores_colors_lookup: +.byte $00,$88,$55,$99,$ff,$bb,$33,$22,$66,$77,$44,$cc,$ee,$dd,$99,$11 + + +.include "make_tables.s" + +.include "interrupt_handler.s" +.include "mockingboard_constants.s" + +; music +.include "mA2E_2.s" diff --git a/demos/lovebyte2024/plasma/play_frame.s b/demos/lovebyte2024/plasma/play_frame.s new file mode 100644 index 00000000..bb64cd4c --- /dev/null +++ b/demos/lovebyte2024/plasma/play_frame.s @@ -0,0 +1,182 @@ +play_frame: + + ;=============================== + ;=============================== + ; things that happen every frame + ;=============================== + ;=============================== + + + ;======================================== + ; patch b channel volumes based on track + + lda WHICH_TRACK + and #$2 + bne switch_to_b1 + lda #track0,>track0,>track1,>track1 + + +skip_data: diff --git a/demos/lovebyte2024/plasma/tracker_init.s b/demos/lovebyte2024/plasma/tracker_init.s new file mode 100644 index 00000000..af7f389e --- /dev/null +++ b/demos/lovebyte2024/plasma/tracker_init.s @@ -0,0 +1,22 @@ +tracker_init: + + ; setup initial ay-3-8910 values (this depends on song) + +init_registers_to_zero: + ldx #$13 ; zero $70--$83 + lda #0 +; sta SONG_OFFSET ; also init song stuff +; sta SONG_COUNTDOWN +init_loop: + sta AY_REGS,X + dex + bpl init_loop + + lda #$38 + sta AY_REGS+7 ; $07 mixer (ABC on) +; lda #$0E +; sta AY_REGS+8 ; $08 volume A +; lda #$0C +; sta AY_REGS+9 ; $09 volume B +; sta AY_REGS+10 ; $0A volume C + diff --git a/demos/lovebyte2024/plasma/zp.inc b/demos/lovebyte2024/plasma/zp.inc new file mode 100644 index 00000000..938ac24c --- /dev/null +++ b/demos/lovebyte2024/plasma/zp.inc @@ -0,0 +1,46 @@ +; zero page + +; pre-defined applesoft vars + +CH = $24 +CV = $25 +GBASL = $26 +GBASH = $27 +BASL = $28 +BASH = $29 + +COMPT1 = $30 +COMPT2 = $31 + +PARAM1 = $60 +PARAM2 = $61 +PARAM3 = $62 +PARAM4 = $63 + +AY_REGS = $70 +; through = $7F + +SONG_L = $80 +SONG_H = $81 +SONG_OFFSET = $82 +SONG_COUNTDOWN = $83 +OCTAVE = $84 +REGISTER = $85 +A_COUNTDOWN = $86 +B_COUNTDOWN = $87 + +Table1 = $A0 ; 40 bytes ($28) +Table2 = $D0 ; 40 bytes ($28) + +OUR_ROT = $A5 + +HGR_X = $E0 +HGR_XH = $E1 +HGR_Y = $E2 +HGR_COLOR = $E4 +HGR_PAGE = $E6 +HGR_SCALE = $E7 + +COUNT = $FB +FRAME = $FC +WHICH_TRACK = $FD diff --git a/demos/lovebyte2024/plasma/zx02_optim.s b/demos/lovebyte2024/plasma/zx02_optim.s new file mode 100644 index 00000000..5eebc2e0 --- /dev/null +++ b/demos/lovebyte2024/plasma/zx02_optim.s @@ -0,0 +1,159 @@ +; De-compressor for ZX02 files +; ---------------------------- +; +; Decompress ZX02 data (6502 optimized format), optimized for speed and size +; 138 bytes code, 58.0 cycles/byte in test file. +; +; Compress with: +; zx02 input.bin output.zx0 +; +; (c) 2022 DMSC +; Code under MIT license, see LICENSE file. + + +;ZP=$80 + +;offset = ZP+0 +;ZX0_src = ZP+2 +;ZX0_dst = ZP+4 +;bitr = ZP+6 +;pntr = ZP+7 + + ; Initial values for offset, source, destination and bitr +;zx0_ini_block: +; .byte $00, $00, comp_data, out_addr, $80 + +;-------------------------------------------------- +; Decompress ZX0 data (6502 optimized format) + +zx02_full_decomp: +; ; Get initialization block +; ldy #7 +; +;copy_init: lda zx0_ini_block-1, y +; sta offset-1, y +; dey +; bne copy_init + + + sta ZX0_dst+1 ; page to output to in A +zx_src_l: + ldy #$dd + sty ZX0_src +zx_src_h: + ldy #$dd + sty ZX0_src+1 + ldy #$80 + sty bitr + ldy #0 + sty offset + sty offset+1 + sty ZX0_dst ; always on even page + +; Decode literal: Ccopy next N bytes from compressed file +; Elias(length) byte[1] byte[2] ... byte[N] +decode_literal: + jsr get_elias + +cop0: lda (ZX0_src), y + inc ZX0_src + bne plus1 + inc ZX0_src+1 +plus1: sta (ZX0_dst),y + inc ZX0_dst + bne plus2 + inc ZX0_dst+1 +plus2: dex + bne cop0 + + asl bitr + bcs dzx0s_new_offset + +; Copy from last offset (repeat N bytes from last offset) +; Elias(length) + jsr get_elias +dzx0s_copy: + lda ZX0_dst + sbc offset ; C=0 from get_elias + sta pntr + lda ZX0_dst+1 + sbc offset+1 + sta pntr+1 + +cop1: + lda (pntr), y + inc pntr + bne plus3 + inc pntr+1 +plus3: sta (ZX0_dst),y + inc ZX0_dst + bne plus4 + inc ZX0_dst+1 +plus4: dex + bne cop1 + + asl bitr + bcc decode_literal + +; Copy from new offset (repeat N bytes from new offset) +; Elias(MSB(offset)) LSB(offset) Elias(length-1) +dzx0s_new_offset: + ; Read elias code for high part of offset + jsr get_elias + beq exit ; Read a 0, signals the end + ; Decrease and divide by 2 + dex + txa + lsr ; @ + sta offset+1 + + ; Get low part of offset, a literal 7 bits + lda (ZX0_src), y + inc ZX0_src + bne plus5 + inc ZX0_src+1 +plus5: + ; Divide by 2 + ror ; @ + sta offset + + ; And get the copy length. + ; Start elias reading with the bit already in carry: + ldx #1 + jsr elias_skip1 + + inx + bcc dzx0s_copy + +; Read an elias-gamma interlaced code. +; ------------------------------------ +get_elias: + ; Initialize return value to #1 + ldx #1 + bne elias_start + +elias_get: ; Read next data bit to result + asl bitr + rol ; @ + tax + +elias_start: + ; Get one bit + asl bitr + bne elias_skip1 + + ; Read new bit from stream + lda (ZX0_src), y + inc ZX0_src + bne plus6 + inc ZX0_src+1 +plus6: ;sec ; not needed, C=1 guaranteed from last bit + rol ;@ + sta bitr + +elias_skip1: + txa + bcs elias_get + ; Got ending bit, stop reading +exit: + rts