CPU 8080 TUNE EQU 1000H ; LOCATION OF MUSIC FIFO EQU 006H ; PAGE OF FIFO TYPEWAIT EQU 12 ; NUMBER OF TICKS FOR EACH CHARACTER TTY0D EQU 80H ; 8251 USART PORTS TTY0C EQU 81H TTY1D EQU 82H TTY1C EQU 83H INTER EQU 0FEH ; ADDRESS OF 8214 CONSOLE EQU 0FFH FREQL1 EQU 0A0H ; FREQUENCY HIGH CHANNEL 1 FREQH1 EQU 0A1H ; FREQUENCY LOW CHANNEL 1 PWLO1 EQU 0A2H ; PULSE WIDTH LOW CHANNEL 1 PWHI1 EQU 0A3H ; PULSE WIDTH HIGH CHANNEL 1 CTRL1 EQU 0A4H ; CONTROL CHANNEL 1 AD1 EQU 0A5H ; ATTACK/DECAY CHANNEL 1 SR1 EQU 0A6H ; SUSTAIN/RELEASE CHANNEL 1 FREQL2 EQU 0A7H ; FREQUENCY HIGH CHANNEL 1 FREQH2 EQU 0A8H ; FREQUENCY LOW CHANNEL 1 PWLO2 EQU 0A9H ; PULSE WIDTH LOW CHANNEL 1 PWHI2 EQU 0AAH ; PULSE WIDTH HIGH CHANNEL 1 CTRL2 EQU 0ABH ; CONTROL CHANNEL 1 AD2 EQU 0ACH ; ATTACK/DECAY CHANNEL 1 SR2 EQU 0ADH ; SUSTAIN/RELEASE CHANNEL 1 FREQL3 EQU 0AEH ; FREQUENCY HIGH CHANNEL 1 FREQH3 EQU 0AFH ; FREQUENCY LOW CHANNEL 1 PWLO3 EQU 0B0H ; PULSE WIDTH LOW CHANNEL 1 PWHI3 EQU 0B1H ; PULSE WIDTH HIGH CHANNEL 1 CTRL3 EQU 0B2H ; CONTROL CHANNEL 1 AD3 EQU 0B3H ; ATTACK/DECAY CHANNEL 1 SR3 EQU 0B4H ; SUSTAIN/RELEASE CHANNEL 1 FCLO EQU 0B5H ; FILTER FREQUNECY LOW FCHI EQU 0B6H ; FILTER FREQUENCY HIGH RESFILT EQU 0B7H ; RESONANCE AND FILTERS MODEVOL EQU 0B8H ; FILTER MODE AND VOLUME RTCISR EQU 0D0H ; INTERRUPT STATUS RTCICR EQU 0D1H ; INTERRUPT CONTROL RAMRST EQU 0D3H ; RAM RESET RTCSBI EQU 0D6H ; STANDBY INTERRUPT RMS EQU 0C9H RHUNDREDS EQU 0CAH RSECONDS EQU 0CBH RMINUTES EQU 0CCH RHOURS EQU 0CDH RDAYS EQU 0CEH RMONTHS EQU 0CFH DEFTEMPO EQU 33 ; DEFAULT TEMPO FADEOUT EQU 20 ; DEFAULT DECAY ARPSPEED EQU 1 ; DEFAULT ARPEGGIO SPEED ORG 0000H ; IRQ0 TIMER SERVICE PUSH H PUSH D PUSH B PUSH PSW JMP LEV0 ORG 0008H ; IRQ1 PUSH PSW JMP LEV1 ORG 0010H ; IRQ2 EI RET ORG 0018H ; IRQ3 EI RET ORG 0020H ; IRQ4 EI RET ORG 0028H ; IRQ5 EI RET ORG 0030H ; IRQ6 EI RET ORG 0038H ; IRQ7 EI RET ORG 0100H START: LXI SP, 0EFFFH MVI A, 0FFH OUT RAMRST MVI A, 0CCH OUT RMS OUT RSECONDS OUT RHUNDREDS OUT RMINUTES OUT RHOURS OUT RDAYS OUT RMONTHS MVI A, 01H OUT RTCICR IN RTCISR MVI A, 008H OUT PWHI1 OUT PWHI2 OUT PWHI3 MVI A, 010H OUT CTRL1 OUT CTRL2 OUT CTRL3 MVI A, 00AH OUT AD1 OUT AD2 OUT AD3 MVI A, 000H OUT SR1 OUT SR2 OUT SR3 MVI A, 000H OUT RESFILT MVI A, 00FH OUT MODEVOL LXI H, TUNE MVI A, DEFTEMPO STA TEMPO MVI A, 0 STA FIFOIN STA FIFOOUT STA USEC MVI A, TYPEWAIT STA TYPECOUNT MVI A, 08H ; LOWEST IRQ (7), IRQ ENABLED STA CURLEV ORI 10H ; ENABLE IRQ ON BOARD OUT INTER EI LOOP: LDA TEMPO ; WAIT FOR N HUNDREDTHS OF A SECOND MOV B, A LDA USEC CMP B JC LOOP ; LOOP WHILE A < B XRA A ; RESET TIMER STA USEC VOICES: MOV A, M CPI 133 JZ TYPE CPI 131 JZ CHDECAY CPI 132 ; 132, SET TEMPO JZ CHTEMPO CPI 130 ; 130, VOLUME TABLE JNZ VOICE1 ; OTHERS ARE NOTES INX H MOV A, M OUT AD1 INX H MOV A, M OUT SR1 INX H MOV A, M OUT AD2 INX H MOV A, M OUT SR2 INX H MOV A, M OUT AD3 INX H MOV A, M OUT SR3 INX H JMP VOICES TYPE: INX H CALL PUTFIFO JMP VOICES CHTEMPO: INX H ; STORE NEW TEMPO MOV A, M STA TEMPO INX H JMP VOICES CHDECAY: INX H MOV A, M OUT CTRL1 STA FORM1 INX H MOV A, M OUT CTRL2 STA FORM2 INX H MOV A, M OUT CTRL3 STA FORM3 INX H JMP VOICES VOICE1: MOV A, M INX H CPI 255 JZ END CPI 129 ; CONTINUE NOTE? JZ VOICE2 CPI 128 ; STOP NOTE? JNZ VOICE1A LDA FORM1 OUT CTRL1 JMP VOICE2 VOICE1A: LXI D, FREQU ADD A ADD E MOV E, A LDA FORM1 OUT CTRL1 XCHG MOV A, M OUT FREQL1 INX H MOV A, M OUT FREQH1 XCHG LDA FORM1 ; ENABLE SOUND ORI 1 OUT CTRL1 VOICE2: MOV A, M INX H CPI 255 JZ END CPI 129 ; CONTINUE NOTE? JZ VOICE3 CPI 128 ; STOP NOTE? JNZ VOICE2A LDA FORM2 OUT CTRL2 JMP VOICE3 VOICE2A: LXI D, FREQU ADD A ADD E MOV E, A LDA FORM2 OUT CTRL2 XCHG MOV A, M OUT FREQL2 INX H MOV A, M OUT FREQH2 XCHG LDA FORM2 ; ENABLE SOUND ORI 1 OUT CTRL2 VOICE3: MOV A, M INX H CPI 255 JZ END CPI 129 ; CONTINUE NOTE? JZ LOOP CPI 128 ; STOP NOTE? JNZ VOICE3A LDA FORM3 OUT CTRL3 JMP LOOP VOICE3A: LXI D, FREQU ADD A ADD E MOV E, A LDA FORM3 OUT CTRL3 XCHG MOV A, M OUT FREQL3 INX H MOV A, M OUT FREQH3 XCHG LDA FORM3 ; ENABLE SOUND ORI 1 OUT CTRL3 JMP LOOP END: MVI A, 0 OUT MODEVOL DI MVI A, 0 STA 0FFH JMP 0F000H PUTFIFO: MVI D, FIFO LDA FIFOIN MOV E, A PUTFIFOL: MOV A, M ORA A JZ PUTFIFOX XCHG MOV M, A XCHG INX H INR E MOV A, E STA FIFOIN JMP PUTFIFOL PUTFIFOX: INX H RET LEV0: LDA CURLEV PUSH PSW MVI A, 0FH ; CURRENT IRQ INVERTED STA CURLEV OUT INTER ; SET IRQ LEVEL, DISABLE IRQ IN RTCISR ; RESET INTERRUPT FLAG LDA USEC ; INCREMENT AT 100HZ INR A STA USEC LDA TEMPO OUT 0FFH LDA TYPECOUNT ; DECREMENT AND RESET COUNT DCR A ORA A JNZ LEV0A MVI A, TYPEWAIT LEV0A: STA TYPECOUNT CPI TYPEWAIT JNZ LEV0X LDA FIFOIN ; DETERMINE IF THERE'S ANYTHING MOV B, A ; IN THE FIFO LDA FIFOOUT CMP B JZ LEV0X ; TRUE IF THERE'S NOTHING MVI H, FIFO LDA FIFOOUT MOV L, A INR A STA FIFOOUT MOV A, M OUT 082H ; DON'T NEED TO CHECK FLAGS LEV0X: POP PSW ; END OF INTERRUPT STA CURLEV ORI 10H ; ENABLE INTERRUPTS ON BOARD OUT INTER ; SET 8214 POP PSW POP B POP D POP H EI RET LEV1: LDA CURLEV PUSH PSW MVI A, 0EH STA CURLEV OUT INTER IN TTY0D ; CLEAR USART IF A KEY IS PRESSED IN TTY1D POP PSW ; END OF INTERRUPT STA CURLEV ORI 10H ; ENABLE INTERRUPTS ON BOARD OUT INTER ; SET 8214 POP PSW EI RET ROTATE: DB 1 CURLEV: DB 0 USEC: DB 0 TYPECOUNT: DB 0 TEMPO: DB 0 FIFOIN: DB 0 FIFOOUT: DB 0 FORM1: DB 0 FORM2: DB 0 FORM3: DB 0 ORG 0500H ; SO WE'RE ON A PAGE BOUNDRY FREQU: DW 274, 291, 308, 326, 346, 366, 388, 411, 435, 461, 489, 518 DW 549, 581, 616, 652, 691, 732, 776, 822, 871, 923, 978, 1036 DW 1097, 1163, 1232, 1305, 1383, 1465, 1552, 1644, 1742, 1845, 1955, 2071 DW 2195, 2325, 2463, 2610, 2765, 2930, 3104, 3288, 3484, 3691, 3910, 4143 DW 4389, 4650, 4927, 5220, 5530, 5859, 6207, 6577, 6968, 7382, 7821, 8286 DW 8779, 9301, 9854, 10440, 11060, 11718, 12415, 13153, 13935, 14764, 15642, 16572 DW 17557, 18601, 19709, 20879, 22121, 23436, 24830, 26306, 27871, 29528, 31234, 33144 DW 35115, 37203, 39415, 41795, 44242, 46873, 49660, 52613, 55741, 59056, 62567