;********************************************************************* ;* Title: ax2-psg-v00.asm ;********************************************************************* ;* Author: R. Allen Murphey ;* ;* License: Copyright (c) 2020-2023 R. Allen Murphey. All Rights Reserved. ;* ;* Description: Support for General Instruments AY-3-8910 ;* ;* Documentation: ;* https://en.wikipedia.org/wiki/General_Instrument_AY-3-8910 ;* ;* Include Files: Requires PIA0, PIA1 and MPI equates ;* ;* Assembler: lwasm from lwtools 4.21 ;* ;* Revision History: ;* Rev # Date Who Comments ;* ----- ----------- ------ --------------------------------------- ;* 00 2020-2023 RAM Initial AY3 PSG driver ;********************************************************************* PSGPORTA equ $FF5E ; CoCoPSG Location PSGPORTB equ $FF5F ; CoCoPSG Location ;SSCPORTA: equ $FF7D ; Speech Sound Cart Location ;SSCPORTB: equ $FF7E ; Speech Sound Cart Location ; TONE PERIOD / FREQUENCY OF CHANNEL A 1-4095 PSGTONAL: equ $00 ; |TP7|TP6|TP5|TP4|TP3|TP2|TP1|TP0| 8-bits fine tone adjustment PSGTONAH: equ $01 ; | - | - | - | - |TPB|TPA|TP9|TP8| 4-bits rough tone adjustment ; TONE PERIOD / FREQUENCY OF CHANNEL B 1-4095 PSGTONBL: equ $02 ; |TP7|TP6|TP5|TP4|TP3|TP2|TP1|TP0| 8-bits fine tone adjustment PSGTONBH: equ $03 ; | - | - | - | - |TPB|TPA|TP9|TP8| 4-bits rough tone adjustment ; TONE PERIOD / FREQUENCY OF CHANNEL C 1-4095 PSGTONCL: equ $04 ; |TP7|TP6|TP5|TP4|TP3|TP2|TP1|TP0| 8-bits fine tone adjustment PSGTONCH: equ $05 ; | - | - | - | - |TPB|TPA|TP9|TP8| 4-bits rough tone adjustment ; NOISE PERIOD / FREQUENCY OF NOISE 1-31 PSGNOISE: equ $06 ; | - | - | - |NP4|NP3|NP2|NP1|NP0| ; IO PORT AND MIXER SETTINGS PSGMIXER: equ $07 ; IOB|IOA|NOISEC|NOISEB|NOISEA|TONEC|TONE|TONEA ; 0 = Input selected for IO port, or noise/tone output when 0 ; LEVEL OF CHANNEL A PSGVOLA: equ $08 ; -|-|-|M|L3|L2|L1|L0 ; M 0=fixed level 1=variable by envelope generator ; LEVEL OF CHANNEL B PSGVOLB: equ $09 ; -|-|-|M|L3|L2|L1|L0 ; M 0=fixed level 1=variable by envelope generator ; LEVEL OF CHANNEL C PSGVOLC: equ $0A ; -|-|-|M|L3|L2|L1|L0 ; M 0=fixed level 1=variable by envelope generator ; ENVELOPE PERIOD / FREQUENCY OF ENVELOPE (1-65535) PSGENVLO: equ $0B ; |EP7|EP6|EP5|EP5|EP3|EP2|EP1|EP0| 8-bit fine adjustment PSGENVHI: equ $0C ; |EPF|EPE|EPD|EPC|EPB|EPA|EP9|EP8| 8-bit rough adjustment ; ENVELOPE SHAPE CONTROL PSGENVSH: equ $0D ; -|-|-|-|CONT|ATT|ALT|HOLD ; CONT - 1=cycle pattern will be as defined by hold bit ; 0=envelope generate resets to 0000 after 1 cycle and hold at that count ; ATT - 1=envelope counter counts up (attack) from 0000 to 1111 ; 0=envelope counter counts down (decay) from 1111 to 0000 ; ALT - 1=envelope counter reverses count direction (up-down) after each cycle ; HOLD - 1=limit envelope to 1 cycle holding last count of envelope E3-E0 ; DATA OF I/O PORT A PSGIOA: equ $0E ; 8-bit data ; DATA OF I/O PORT B PSGIOB: equ $0F ; 8-bit data ;********************************************************************* ; DETECT_PSG ;********************************************************************* DETECT_PSG: ; Detect the PSG rts ; Go back where we came from ;********************************************************************* ; INIT_PSG ;********************************************************************* INIT_PSG: ; Initialize the PSG rts ; Go back where we came from ;********************************************************************* ; TEST_PSG ;********************************************************************* TEST_PSG: ; Test the PSG jsr MPISLOT1 ; setup for PSG in MPI slot 1 ; SETUP - enable CART SOUND jsr MUXCART ; Setup PIA0 MUX for Cart Sound Source jsr SOUNDON ; Setup PIA1 SNDEN for Cart Sound Output ; MAIN clrb ; clear pointer to current note in table ldy #PSGNOTES ; get pointer to note data table PLAYPSG: lda #PSGTONAH ; PSG Tone A Lower 8 bits sta PSGPORTB ; write to PSG to latch register 1 lda b,y ; load upper 4 bits of note sta PSGPORTB ; write to PSG register 1 lda #PSGTONAL ; PSG Tone A Upper 4 bits register 1 sta PSGPORTB ; write to SSH to latch register 1 incb ; move to next value in note table lda b,y ; load it from table sta PSGPORTB ; write the lower eight bits of note lda #PSGMIXER ; PSG IO port and mixer settings Register 7 sta PSGPORTB ; write to register latch lda #%11111110 ; Enable Tone A with bit zero 0 sta PSGPORTB ; write mixer out lda #PSGVOLA ; PSG Level of Channel A Register 8 sta PSGPORTB ; write Channel A volume register to PSG lda #%00001111 ; 0% attention (volume full) sta PSGPORTB ; write attenuation message to PSG bsr PSGDLY1 ; big delay while note sounds incb ; move to next item in table cmpb #24 ; have we read all 12 x 12bit notes? bne PLAYPSG ; no keep playing notes ; TEARDOWN lda #PSGVOLA ; Register 8 Level of Channel A sta PSGPORTB ; write Channel A volume register to PSG lda #%00000000 ; volume off sta PSGPORTB ; turn off volume ; ALL OFF lda #$CF ; PSG Command to stop ALL sound sta PSGPORTB ; turn off all sound rts ; return PSGDLY1: ldx #$4000 ; countdown $4000 times PSGDLY2: leax -1,X ; let X=X-1 bne PSGDLY2 ; if X > 0 goto PSGDLY2 rts ; return PSGNOTES: ; Tone Periods at 1.789MHz clock fcb $01,$AC ; C4 261.626 Hz Middle C fcb $01,$94 ; C#4 277.183 Hz fcb $01,$7D ; D4 293.665 Hz fcb $01,$68 ; D#4 311.127 Hz fcb $01,$53 ; E4 329.628 Hz fcb $01,$40 ; F4 349.228 Hz fcb $01,$2E ; F#4 369.994 Hz fcb $01,$1D ; G4 391.995 Hz fcb $01,$0D ; G#4 415.305 Hz fcb $00,$FE ; A4 440.000 Hz fcb $00,$F0 ; A#4 466.164 Hz fcb $00,$E2 ; B4 493.883 Hz rts ; Go back where we came from ;********************************************************************* ; GET_PSG ;********************************************************************* GET_PSG: ; Get PSG status or settings rts ; Go back where we came from ;********************************************************************* ; SET_PSG ;********************************************************************* SET_PSG: ; Set PSG status or settings rts ; Go back where we came from ;********************************************************************* ; READ_PSG ;********************************************************************* READ_PSG: ; Read from PSG rts ; Go back where we came from ;********************************************************************* ; WRITE_PSG ;********************************************************************* WRITE_PSG: ; Write to PSG rts ; Go back where we came from ;********************************************************************* ; TERM_PSG ;********************************************************************* TERM_PSG: ; Terminate the PSG rts ; Go back where we came from ;********************************************************************* ;* End of ax2-psg-v00.asm ;*********************************************************************