1;
2; Copyright (c) 2018 Yosuke Sugahara. All rights reserved.
3;
4; Redistribution and use in source and binary forms, with or without
5; modification, are permitted provided that the following conditions
6; are met:
7; 1. Redistributions of source code must retain the above copyright
8;    notice, this list of conditions and the following disclaimer.
9; 2. Redistributions in binary form must reproduce the above copyright
10;    notice, this list of conditions and the following disclaimer in the
11;    documentation and/or other materials provided with the distribution.
12;
13; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23; SUCH DAMAGE.
24;
25;
26; LUNA XP multiplexed device firmware
27;
28; used language:
29;  zasm 4.1
30;  http://k1.spdns.de/Develop/Projects/zasm
31;
32; XP memory map
33;
34; type : SH, PR, IN, NC
35;     SH: host shared memory, 64kB, PA 00000 - 0FFFF
36;     PR: private memory, 32kB, PA 28000-2FFFF
37;     IN: HD647180 internal 512 bytes memory
38;     NC: not connected (00 or FF or image readable, maybe)
39;
40; start end type desc
41;  0000 00FF SH RESET/RST etc.
42;  0100 01FF SH shared variables
43;  0200 0FFF SH resident program
44;  1000 7FFF SH PAM/PCM buffer 28K
45;  8000 8FFF SH PSG buffer 4K
46;  9000 9FFF SH LPR buffer 4K
47;  A000 DFFF SH FDC buffer 16K
48;  E000 EFFF PR program/stack
49;  F000 FDFF NC bus error (00 or FF)
50;  FE00 FFDF IN PAM player
51;  FFE0 FFFF IN interrupt vector
52;
53; shared variable area
54;  0100    XPBUS
55;  0110    TIME
56;  0120    PAM
57;  0130    PCM
58;  0140    PSG
59;  0150    SPK
60;  0160    LPR
61;  0170    FDC
62;  0180    SIO0
63;  0190    SIO1
64; device ID = bit 7-4
65;
66; XP internal device usage
67;  PRT0  device dispatcher/TIME
68;  PRT1  PCM
69;  PT2   unused
70;  ASCI0 SIO0
71;  ASCI1 SIO1	������������������������������������������?
72;
73; READY-CMD-RESULT-RUN ���������������
74; XP ������
75; READY
76;   ������������������������������������������ != 0
77;   ������������������������ 0
78; CMD
79;   ���������������������������������������������
80;   ��������������������� 0
81;   XP ���������������������������������������READY=0 CMD=0 ������������XP ��� 0 ���������
82; RESULT
83;   ���������������������������
84;   RESULT=x READY=1 ������������������������
85;   ��������������������������������������������� 0 ������������������
86; RUN
87;   ������������������������ != 0
88;   ������������������������������ 0
89;   ������������������RESULT=x RUN=0 READY=1 ������������������������
90;
91; ���������������������
92;  READY ������������
93;  CMD ���������������������������
94;  READY ������������
95;  RUN ������������
96;  CMD ������������
97;  ������
98;  RESULT ���������
99;  RUN ������������
100;  READY ������������
101;
102; ���������������
103; ���������������������������
104;  while (READY == 0);	// ������������������
105;  RESULT=0;		// ���������������
106;  CMD=x;		// ������������������
107;  while (RESULT == 0);	// ������������������
108;  if (RESULT==ERROR) error();	// ���������������
109;
110
111;
112; XPBUS
113;  +0.b READY
114;  +1.b CMD
115;  +2.b RESULT
116;  +3.b RUN
117;
118;  +4.b STAT_RESET
119;        ������������������������������ 0������������������
120;        ��������������������������������������� +1
121;        ������������������������������ 1 ���������������������
122;  +5.3 align
123;  +8.w PRT0_TIMER
124;        ==256(1200Hz)
125;  +A.w INTR1_DEV
126;        bitmap of INTR1 device ID
127;  +C.w INTR5_DEV
128;        bitmap of INTR5 device ID
129;
130; TIME
131;  +0.b READY
132;  +1.b CMD
133;  +2.b RESULT
134;  +3.b RUN
135;
136;  +4.w TIMECOUNTER
137;
138; PAM
139;  +0.b READY
140;  +1.b CMD
141;  +2.b RESULT
142;  +3.b RUN
143;
144;  +4.b ENC
145;        ���������������������������������������������
146;  +5.b REPT
147;        REPT ���������
148;  +6.w CYCLE_CLK
149;        ���������������������
150;        ���������������������������
151;  +8.b REPT_CLK
152;        1 REPT ������������������������������
153;        ���������������������������
154;  +9.b REPT_MAX
155;        REPT ������������������������������
156;        ���������������������������
157;
158;  +E.w STAT_PTR
159;
160; PCM
161;  +0.b READY
162;  +1.b CMD
163;  +2.b RESULT
164;  +3.b RUN
165;  +4.b ENC
166;  +6.w PRT1_TIMER
167;        PCM >=10(30.72kHz,200clk)
168;
169;  +E.w STAT_PTR
170;
171; PSG
172;  +0.b READY
173;  +1.b CMD
174;  +2.b RESULT
175;  +3.b RUN
176;
177; SPK
178;  +0.b READY
179;  +1.b CMD
180;  +2.b RESULT
181;  +3.b RUN
182;
183;  +4.b VOL
184;        PSG ���������������������������������
185;  +6.w FREQ
186;        PSG FREQ ������������������
187;  +8.w TIME
188;        1200Hz ������������������������
189;  +A.w REMAIN
190;        ������������������������������
191;
192; LPR
193;  TBD.
194; FDC
195;  TBD.
196;
197; SIO0
198;  +0.b READY
199;  +1.b CMD
200;  +2.b RESULT
201;  +3.b RUN
202;				; ���������������������������������������������������
203;				; ���������������������
204;  +4.b TXCMD
205;  +5.b TXSTAT
206;  +6.b TX
207;  +A.b RXCMD
208;  +B.b RXSTAT
209;  +C.b RX
210;
211; SIO1
212;  +0.b READY
213;  +1.b CMD
214;  +2.b RESULT
215;  +3.b RUN
216;				; ���������������������������������������������������
217;				; ���������������������
218;  +4.b TXCMD
219;  +5.b TXSTAT
220;  +6.b TX
221;  +A.b RXCMD
222;  +B.b RXSTAT
223;  +C.b RX
224
225	.Z180
226
227; ######## device ID
228
229#define DEVID_XPBUS	0
230#define DEVID_TIME	1
231#define DEVID_PAM	2
232#define DEVID_PCM	3
233#define DEVID_PSG	4
234#define DEVID_SPK	5
235#define DEVID_LPR	6
236#define DEVID_FDC	7
237#define DEVID_SIO0	8
238#define DEVID_SIO1	9
239; ######## define
240
241#define PAM_CMD_START	1
242#define PAM_CMD_QUERY	2
243
244#define PAM_ENC_PAM2A	1
245#define PAM_ENC_PAM2B	2
246#define PAM_ENC_PAM3A	3
247#define PAM_ENC_PAM3B	4
248#define PAM_ENC_PAM1P	5
249
250#define PCM_CMD_START	1
251
252#define PCM_ENC_PCM1	1
253#define PCM_ENC_PCM2	2
254#define PCM_ENC_PCM3	3
255
256#define SPK_CMD_START	1
257#define SPK_CMD_STOP	2
258#define SPK_CMD_KEEP	3
259
260
261; #### RESULT
262#define XPLX_R_OK		1
263#define XPLX_R_ERROR_PARAM	254
264#define XPLX_R_UNKNOWN_CMD	255
265
266
267; ######## switch
268; 0 = USE STAT_PTR for userland test mode
269; 1 = USE HOSTINTR for kernel (normal)
270#define USE_INTR	1
271
272; ######## constants
273; xp to host level 1 interrupt port
274HOSTINTR1	.EQU	0B0H
275; xp to host level 5 interrupt port
276HOSTINTR5	.EQU	0A0H
277
278; PAM use HOSTINTR5
279PAM_HOSTINTR	.EQU	HOSTINTR5
280; PCM use HOSTINTR5
281PCM_HOSTINTR	.EQU	HOSTINTR5
282
283; I/O PORT
284TMDR0L	.EQU	0CH
285TMDR0H	.EQU	0DH
286RLDR0L	.EQU	0EH
287RLDR0H	.EQU	0FH
288TCR	.EQU	10H
289TMDR1L	.EQU	14H
290TMDR1H	.EQU	15H
291RLDR1L	.EQU	16H
292RLDR1H	.EQU	17H
293
294PSG_ADR	.EQU	83H		; PSG address (out)
295PSG_DAT	.EQU	82H		; data output
296PSG_IN	.EQU	83H		; data input (in)
297
298INITIAL_SP:	.EQU	01000H
299PRIVATE_SP:	.EQU	0F000H
300
301; ######## macros
302
303ADD_HL_A:	.MACRO
304	ADD	A,L
305	LD	L,A
306	JR	NC,$ + 3
307	INC	H
308	.ENDM
309
310WAIT3	.MACRO
311	NOP
312	.ENDM
313
314WAIT4	.MACRO
315	LD	A,A
316	.ENDM
317
318WAIT6	.MACRO
319	NOP
320	NOP
321	.ENDM
322
323WAIT7	.MACRO
324	LD	A,A			; 4+3=7
325	NOP
326	.ENDM
327
328WAIT8	.MACRO
329	LD	A,A			; 4*2=8
330	LD	A,A
331	.ENDM
332
333WAIT9	.MACRO
334	NOP				; 3*3=9
335	NOP
336	NOP
337	.ENDM
338
339WAIT10	.MACRO
340	LD	A,A			; 4+3*2=10
341	NOP
342	NOP
343	.ENDM
344
345WAIT11	.MACRO
346	LD	A,A			; 4*2+3=11
347	LD	A,A
348	NOP
349	.ENDM
350
351WAIT12	.MACRO
352	LD	A,A			; 4*3=12
353	LD	A,A
354	LD	A,A
355	.ENDM
356
357WAIT13	.MACRO
358	LD	A,A			; 4+3*3=13
359	NOP
360	NOP
361	NOP
362	.ENDM
363
364WAIT16	.MACRO
365	LD	A,A
366	LD	A,A
367	LD	A,A
368	LD	A,A
369	.ENDM
370
371WAIT17	.MACRO
372	LD	A,A			; 4*2+3*3=17
373	LD	A,A
374	NOP
375	NOP
376	NOP
377	.ENDM
378
379WAIT19	.MACRO
380	LD	A,A			; 4*4+3=19
381	LD	A,A
382	LD	A,A
383	LD	A,A
384	NOP
385	.ENDM
386
387; ######## RESET/RST
388	.ORG	0000H
389RESET:
390	JP	ENTRY
391
392	.ORG	0038H
393INT0:
394	JP	INTR_INT0
395
396	.ORG	0066H
397NMI:
398	RETN
399
400	.ORG	0080H
401DEBUG0::	.DB	0
402DEBUG1::	.DB	0
403DEBUG2::	.DB	0
404DEBUG3::	.DB	0
405DEBUG4::	.DB	0
406DEBUG5::	.DB	0
407DEBUG6::	.DB	0
408DEBUG7::	.DB	0
409DEBUG8::	.DB	0
410DEBUG9::	.DB	0
411DEBUG10::	.DB	0
412
413	.ORG	00FCH
414XPLX_MAGIC::			; MAGIC
415	.DB	"XPLX"
416
417; ######## shared variables
418; XPBUS
419	.ORG	0100H
420XPLX_VAR_BASE::
421XPBUS_READY::
422	.DB	0
423XPBUS_CMD::
424	.DB	0
425XPBUS_RESULT::
426	.DB	0
427XPBUS_RUN::
428	.DB	0
429
430XPBUS_STAT_RESET::		; reset count
431	.DB	0
432	.DB	0,0,0		; reserved
433
434XPBUS_PRT0_TIMER::		; PRT0 TIMER TLDR (devices dispatch)
435	.DW	256
436XPBUS_INTR1_DEV::		; HOSTINTR1 device
437	.DW	0
438XPBUS_INTR5_DEV::		; HOSTINTR5 device
439	.DW	0
440
441; TIME
442	.ORG	0110H
443TIME_READY::
444	.DB	0
445TIME_CMD::
446	.DB	0
447TIME_RESULT::
448	.DB	0
449TIME_RUN::
450	.DB	0
451TIME_TIMECOUNTER::		; timecounter (TBD.)
452	.DW	0
453
454; PAM
455	.ORG	0120H
456PAM_READY::
457	.DB	0
458PAM_CMD::
459	.DB	0
460PAM_RESULT::
461	.DB	0
462PAM_RUN::
463	.DB	0
464
465PAM_ENC::
466	.DB	0
467PAM_REPT::
468	.DB	0
469PAM_CYCLE_CLK::
470	.DW	0
471PAM_REPT_CLK::
472	.DB	0
473PAM_REPT_MAX::
474	.DB	0
475
476	.DB	0,0,0,0		; reserved
477PAM_STAT_PTR::
478	.DW	0
479
480; PCM
481	.ORG	0130H
482PCM_READY::
483	.DB	0
484PCM_CMD::
485	.DB	0
486PCM_RESULT::
487	.DB	0
488PCM_RUN::
489	.DB	0
490
491PCM_ENC::
492	.DB	0
493	.DB	0		; reserved
494PCM_PRT1_TIMER::			; PRT1 TIMER TLDR (PCM)
495	.DW	0
496
497	.DB	0,0,0,0,0,0	; reserved
498PCM_STAT_PTR::
499	.DW	0
500
501; PSG
502	.ORG	0140H
503PSG_READY::
504	.DB	0
505PSG_CMD::
506	.DB	0
507PSG_RESULT::
508	.DB	0
509PSG_RUN::
510	.DB	0
511
512; SPK
513	.ORG	0150H
514SPK_READY::
515	.DB	0
516SPK_CMD::
517	.DB	0
518SPK_RESULT::
519	.DB	0
520SPK_RUN::
521	.DB	0
522
523SPK_VOL::
524	.DB	0
525	.DB	0		; reserved
526SPK_FREQ::
527	.DW	0
528SPK_TIME::
529	.DW	0
530SPK_REMAIN::
531	.DW	0
532
533; LPR
534	.ORG	0160H
535LPR_READY::
536	.DB	0
537LPR_CMD::
538	.DB	0
539LPR_RESULT::
540	.DB	0
541LPR_RUN::
542	.DB	0
543	; TBD.
544
545LPR_CMD_START	.EQU	1
546
547; FDC
548	.ORG	0170H
549FDC_READY::
550	.DB	0
551FDC_CMD::
552	.DB	0
553FDC_RESULT::
554	.DB	0
555FDC_RUN::
556	.DB	0
557; TBD.
558
559FDC_CMD_START	.EQU	1
560
561; SIO0
562	.ORG	0180H
563SIO0_READY::
564	.DB	0
565SIO0_CMD::
566	.DB	0
567SIO0_RESULT::
568	.DB	0
569SIO0_RUN::
570	.DB	0
571
572SIO0_TXCMD::
573	.DB	0
574SIO0_TXSTAT::
575	.DB	0
576SIO0_TX::
577	.DB	0
578	.DS	3
579SIO0_RXCMD::
580	.DB	0
581SIO0_RXSTAT::
582	.DB	0
583SIO0_RX::
584	.DB	0
585
586; SIO1
587	.ORG	0190H
588SIO1_READY::
589	.DB	0
590SIO1_CMD::
591	.DB	0
592SIO1_RESULT::
593	.DB	0
594SIO1_RUN::
595	.DB	0
596
597SIO1_TXCMD::
598	.DB	0
599SIO1_TXSTAT::
600	.DB	0
601SIO1_TX::
602	.DB	0
603	.DS	3
604SIO1_RXCMD::
605	.DB	0
606SIO1_RXSTAT::
607	.DB	0
608SIO1_RX::
609	.DB	0
610
611
612; ######## Bootstrap program
613	.ORG	0200H
614ENTRY:
615	DI
616	LD	SP,INITIAL_SP
617
618				; inc reset count
619	LD	HL, XPBUS_STAT_RESET
620	INC	(HL)
621
622				; initial devices
623				; READY=0
624	XOR	A
625	LD	(XPBUS_READY),A
626	LD	(TIME_READY),A
627	LD	(PAM_READY),A
628	LD	(PCM_READY),A
629	LD	(PSG_READY),A
630	LD	(SPK_READY),A
631	LD	(LPR_READY),A
632	LD	(FDC_READY),A
633	LD	(SIO0_READY),A
634	LD	(SIO1_READY),A
635
636	LD	A,1
637	LD	(DEBUG0),A
638
639				; init XP internal devices
640				; internal I/O address = 00H - 3FH
641	LD	A,00H		; IOA7[7]=0 IOSTP[5]=0
642ICR	.EQU	3FH
643	OUT0	(ICR),A
644
645				; memory wait = 0
646				; I/O wait = 3
647				; no DMA
648	LD	A,20H		; MWI[76]=0 IWI[54]=2(3wait) DMS[32]=0 DIM[10]=0
649DCNTL	.EQU	32H
650	OUT0	(DCNTL),A
651				; disable refresh
652	LD	A,03H		; REFE[7]=0 REFW[6]=0 CYC[10]=3(80state)
653RCR	.EQU	36H
654	OUT0	(RCR),A
655
656	LD	A,2
657	LD	(DEBUG0),A
658
659				; prepare memory map
660				; MMU
661CBR	.EQU	38H
662BBR	.EQU	39H
663CBAR	.EQU	3AH
664				; Common0: VA=0000H -> PA=00000H SH
665				; Bank   : VA=E000H -> PA=28000H PR
666				; Common1: VA=F000H -> PA=FF000H IN
667	LD	A,0FEH
668	OUT0	(CBAR),A
669	LD	A,0F0H
670	OUT0	(CBR),A
671	LD	A,1AH
672	OUT0	(BBR),A
673
674	LD	A,3
675	LD	(DEBUG0),A
676
677				; internal RAM addressing
678				; for no-wait access
679				; PA=FxxxxH ���������������������������������������������
680				; PA=0xxxxH ���������������������������������
681				; ������������������������������������
682				; built-in RAM VA=FE00H PA=FFE00H
683	LD	A,0F0H
684RMCR	.EQU	51H
685	OUT0	(RMCR),A
686				; disable external interrupt
687				; TODO: if use "Host to XP" interrupt, change here
688	LD	A,00H		; TRAP[7]=0 ITE2[2]=0 ITE1[1]=0 ITE0[0]=0
689ITC	.EQU	34H
690	OUT0	(ITC),A
691				; Interrupt Vector Low = E
692				; I = FFH
693				; Interrupt Vector Address = FFE0H
694	LD	A,0E0H
695IL	.EQU	33H
696	OUT0	(IL),A
697	LD	A,0FFH
698	LD	I,A
699				; interrupt mode 1
700	IM	1
701
702	LD	A,4
703	LD	(DEBUG0),A
704
705	CALL	INIT_PSG
706
707	; TODO
708	; INIT FDC
709	; INIT LPR
710	; INIT SIO
711
712				; INIT PRT0,1
713				; TIE1[5]=TIE0[4]=0
714				; TOC1[3]=TOC0[2]=0
715				; TDE1[1]=TDE0[0]=0
716	LD	A,00H
717	OUT0	(TCR),A
718				; prepare PRT0
719	LD	HL,(XPBUS_PRT0_TIMER)
720	OUT0	(RLDR0L),L
721	OUT0	(TMDR0L),L
722	OUT0	(RLDR0H),H
723	OUT0	(TMDR0H),H
724				; TIE0, TID0 ON
725				; TIE0[4]=1 TDE0[0]=1
726	LD	A,11H
727	OUT0	(TCR),A
728
729				; copy to private memory
730	LD	HL,PROG_ORG
731	LD	DE,PRIVATE_RAM
732	LD	BC,PROG_ORG_LEN
733	LDIR
734				; interrupt vector copy to internal memory
735	LD	HL,VECTOR_ORG
736	LD	DE,VECTOR
737	LD	BC,VECTOR_ORG_LEN
738	LDIR
739
740	LD	A,5
741	LD	(DEBUG0),A
742				; jump to XPBUS
743	JP	XPBUS
744
745; initialize PSG registers
746; break all regs
747INIT_PSG:
748				; init PSG
749				; PSG R0-R6 All 00H
750	LD	A,0
751	LD	B,7
752	LD	C,PSG_DAT
753	LD	D,0
754PSG_CLEAR_06:
755	OUT	(PSG_ADR),A
756	OUT	(C),D
757	INC	A
758	DJNZ	PSG_CLEAR_06
759				; PSG mixer
760				; tone = off, noise = off
761				; IOA, IOB = output
762	LD	A,7
763	LD	D,0FFH
764	OUT	(PSG_ADR),A
765	OUT	(C),D
766				; PSG volume and envelope
767				; PSG R8-R15 all 0
768	LD	A,8
769	LD	B,8
770	LD	D,0
771PSG_CLEAR_8F:
772	OUT	(PSG_ADR),A
773	OUT	(C),D
774	INC	A
775	DJNZ	PSG_CLEAR_8F
776				; TODO: PSG I/O Port
777	RET
778
779; ######## buffers
780	.PHASE	1000H
781PAM_BUF::
782PCM_BUF::
783	.DEPHASE
784	.PHASE 08000H
785PAM_BUF_LEN::	.EQU	$-PAM_BUF
786PCM_BUF_LEN::	.EQU	$-PCM_BUF
787PSG_BUF::
788	.DEPHASE
789	.PHASE 09000H
790PSG_BUF_LEN::	.EQU	$-PSG_BUF
791LPR_BUF::
792	.DEPHASE
793	.PHASE 0A000H
794LPR_BUF_LEN::	.EQU	$-LPR_BUF
795FDC_BUF::
796	.DEPHASE
797
798; ######## private memory program
799	.PHASE 0E000H
800FDC_BUF_LEN::	.EQU	$-FDC_BUF
801
802PROG_ORG:	.EQU	$$
803PRIVATE_RAM:
804
805XPBUS:
806	LD	A,6
807	LD	(DEBUG0),A
808
809	LD	SP,PRIVATE_SP
810
811				; devices READY=1
812	LD	A,1
813	LD	(XPBUS_READY),A
814	LD	(TIME_READY),A
815	LD	(PAM_READY),A
816	LD	(PCM_READY),A
817	LD	(PSG_READY),A
818	LD	(SPK_READY),A
819	LD	(LPR_READY),A
820	LD	(FDC_READY),A
821	LD	(SIO0_READY),A
822	LD	(SIO1_READY),A
823
824				; wait for PRT0
825	EI
826XPBUS_LOOP:
827	HALT
828	JR	XPBUS_LOOP
829
830INTR_PRT0:
831; #### Periodic devices
832; 1200Hz
833; ������������������������������ DISPATCH ������������������
834; o. A ���������������������������������
835; o. AF, HL ������������������������
836; o. EI ���������������������������������������
837; o. EI ������������������������������������
838; o. ������������������ PCM ���������
839; o. PAM ���������0.83 msec ������������������������������������
840
841	PUSH	AF
842	PUSH	HL
843
844	LD	A,7
845	LD	(DEBUG0),A
846				; reset PRT0 interrupt
847	IN0	F,(TCR)
848	IN0	F,(TMDR0L)
849				; first EI, for PRT1
850	EI
851
852TIMECOUNTER_INCR:
853				; timecounter
854	LD	HL,(TIME_TIMECOUNTER)
855	INC	HL
856	LD	(TIME_TIMECOUNTER),HL
857
858; #### XPBUS devices dispatcher
859
860DEVICES_DISPATCH:
861	LD	A,(XPBUS_CMD)
862	OR	A
863	CALL	NZ,XPBUS_DISPATCH
864
865	LD	A,(PAM_CMD)
866	OR	A
867	CALL	NZ,PAM_DISPATCH
868
869	LD	A,(PCM_CMD)
870	OR	A
871	CALL	NZ,PCM_DISPATCH
872
873	LD	A,(PSG_CMD)
874	OR	A
875	CALL	NZ,PSG_DISPATCH
876
877	LD	A,(SPK_CMD)
878	OR	A
879	CALL	NZ,SPK_DISPATCH
880
881	LD	A,(LPR_CMD)
882	OR	A
883	CALL	NZ,LPR_DISPATCH
884
885	LD	A,(FDC_CMD)
886	OR	A
887	CALL	NZ,FDC_DISPATCH
888
889	LD	A,(SIO0_CMD)
890	OR	A
891	CALL	NZ,SIO0_DISPATCH
892
893	LD	A,(SIO1_CMD)
894	OR	A
895	CALL	NZ,SIO1_DISPATCH
896
897	LD	A,8
898	LD	(DEBUG0),A
899
900	POP	HL
901	POP	AF
902	RETI
903
904; #### XPBUS
905
906XPBUS_DISPATCH:
907	; not implemented
908	XOR	A
909	LD	(XPBUS_CMD),A
910	LD	A,XPLX_R_UNKNOWN_CMD
911	LD	(XPBUS_RESULT),A
912	RET
913
914; #### TIME
915
916TIME_DISPATCH:
917	; not implemented
918	XOR	A
919	LD	(TIME_CMD),A
920	LD	A,XPLX_R_UNKNOWN_CMD
921	LD	(TIME_RESULT),A
922	RET
923
924; #### PAM ���������
925
926; #### PCM driver core
927
928; PCM ���������������������������������������������������
929; ���������������������������������������������������������������������������������
930
931; #### PCM play start
932PCM_DISPATCH:
933	CP	PCM_CMD_START
934	JR	Z,PCM_START
935
936	LD	A,XPLX_R_UNKNOWN_CMD
937PCM_ERROR:
938	LD	(PCM_RESULT),A
939	RET
940
941PCM_START:
942				; if READY==0 return
943	LD	A,(PCM_READY)
944	OR	A
945	RET	Z
946				; check ENC
947	LD	A,(PCM_ENC)
948	DEC	A
949	JR	Z,PCM_START_OK	; PCM1 = 1
950	DEC	A
951	JR	Z,PCM_START_OK	; PCM2 = 2
952	DEC	A
953	JR	Z,PCM_START_OK	; PCM3 = 3
954
955	LD	A,XPLX_R_ERROR_PARAM
956	JR	PCM_ERROR
957
958PCM_START_OK:
959				; A = 0
960	LD	(PCM_READY),A
961	LD	(PCM_CMD),A
962
963
964				; prepare vector
965	DI
966				; set PRT1 vector
967	LD	HL,PCM_INTR
968	LD	(VEC_PRT1),HL
969				; prepare register
970	EXX
971
972	CALL	INIT_PSG
973
974				; make interrupt handler
975	LD	A,(PCM_ENC)
976	DEC	A
977	JR	Z,PCM_SET_PCM1
978	DEC	A
979	JR	Z,PCM_SET_PCM2
980PCM_SET_PCM3:
981	LD	HL,PCM3
982	JR	PCM_SET
983PCM_SET_PCM2:
984	LD	HL,PCM2
985	JR	PCM_SET
986PCM_SET_PCM1:
987	LD	HL,PCM1
988PCM_SET:
989	LD	(PCM_INTR_JMP),HL
990
991	LD	HL,PCM_BUF
992	LD	BC,0800H + PSG_ADR
993	LD	DE,0709H
994
995	EXX
996
997				; TIE1, TDE1 OFF
998	IN0	A,(TCR)
999	AND	0DDH		; TIE1[5]=0 TDE1[1]=0
1000	OUT0	(TCR),A
1001				; prepare PRT1
1002	LD	HL,(PCM_PRT1_TIMER)
1003	OUT0	(RLDR1L),L
1004	OUT0	(RLDR1H),H
1005	OUT0	(TMDR1L),L
1006	OUT0	(TMDR1H),H
1007				; TIE1, TID1 ON
1008	OR	22H		; TIE1[5]=1 TDE1[5]=1
1009	OUT0	(TCR),A
1010
1011	EI
1012
1013	LD	A,1
1014	LD	(PCM_RUN),A
1015
1016	RET
1017
1018
1019
1020; #### PCM interrupt handler
1021
1022PCM_INTR:
1023				; PRT1 interrupt
1024	EX	AF,AF
1025	EXX
1026				; interrupt acknowledge
1027				; reset PRT1 Interrupt
1028	IN0	F,(TCR)
1029	IN0	F,(TMDR1L)
1030
1031				; ���������������������������������������
1032PCM_INTR_JMP:	.EQU	$+1
1033	JP	PCM1
1034
1035PCM_INTR_NEXT:
1036	RLCA
1037	JR	C,PCM_RELOAD
1038				; inc ptr after reload check
1039	INC	HL
1040	RLCA
1041	JR	C,PCM_STAT
1042	RLCA
1043	JR	NC,PCM_NORMAL
1044
1045; PCM RESET attention
1046; in: HL = EXIT address
1047PCM_RESET:
1048				; PRT1 intr stop
1049	IN0	A,(TCR)
1050				; TIE1,TDE1 OFF
1051	AND	0DDH		; TIE1[5]=0 TDE1[1]=0
1052	OUT0	(TCR),A
1053				; PLAY STOP
1054	XOR	A
1055	LD	(PCM_RUN),A
1056	LD	A,XPLX_R_OK
1057	LD	(PCM_RESULT),A
1058	LD	(PCM_READY),A
1059
1060	JR	PCM_EXIT
1061
1062; PCM common code
1063
1064PCM_RELOAD:
1065	LD	HL,PCM_BUF
1066PCM_STAT:
1067#if USE_INTR
1068	OUT	(PCM_HOSTINTR),A
1069#else
1070	LD	(PCM_STAT_PTR),HL
1071#endif
1072PCM_NORMAL:
1073PCM_EXIT:
1074	EXX
1075	EX	AF,AF
1076	EI
1077	RETI
1078
1079; #### PCM core code
1080
1081PCM1:
1082				; PSG REG=8
1083	OUT	(C),B
1084				; read attention or CH0
1085	LD	A,(HL)
1086	OUT	(PSG_DAT),A
1087	JP	PCM_INTR_NEXT
1088
1089PCM2:
1090	LD	D,(HL)
1091	INC	HL
1092	LD	A,(HL)
1093
1094	OUT	(C),B
1095	OUT0	(PSG_DAT),D
1096	OUT	(C),E
1097	OUT	(PSG_DAT),A
1098	JP	PCM_INTR_NEXT
1099
1100PCM3:
1101	LD	E,(HL)
1102	INC	HL
1103	LD	D,(HL)
1104	INC	HL
1105	LD	A,(HL)
1106
1107	PUSH	HL
1108	LD	HL,090AH
1109	OUT	(C),B
1110	OUT0	(PSG_DAT),E
1111	OUT	(C),H
1112	OUT0	(PSG_DAT),D
1113	OUT	(C),L
1114	OUT	(PSG_DAT),A
1115	POP	HL
1116	JP	PCM_INTR_NEXT
1117
1118; #### SPK
1119SPK_DISPATCH:
1120	CP	SPK_CMD_START
1121	JR	Z,SPK_START
1122	CP	SPK_CMD_STOP
1123	JR	Z,SPK_STOP
1124	CP	SPK_CMD_KEEP
1125	JR	Z,SPK_KEEP
1126
1127	LD	A,XPLX_R_UNKNOWN_CMD
1128	LD	(SPK_RESULT),A
1129	RET
1130
1131SPK_START:
1132	LD	A,(SPK_READY)
1133	OR	A
1134	RET	Z
1135
1136	XOR	A
1137	LD	(SPK_READY),A
1138				; next to CMD_KEEP
1139	LD	A,SPK_CMD_KEEP
1140	LD	(SPK_CMD),A
1141	LD	A,1
1142	LD	(SPK_RUN),A
1143
1144				; set REMAIN
1145	LD	HL,(SPK_TIME)
1146	LD	(SPK_REMAIN),HL
1147
1148	DI
1149				; PSG CH3 FREQ
1150	LD	HL,(SPK_FREQ)
1151	LD	A,4
1152	OUT0	(PSG_ADR),A
1153	OUT0	(PSG_DAT),L
1154	LD	A,5
1155	OUT0	(PSG_ADR),A
1156	OUT0	(PSG_DAT),H
1157				; PSG CH3 VOL
1158	LD	A,10
1159	OUT	(PSG_ADR),A
1160	LD	A,(SPK_VOL)
1161	OUT	(PSG_DAT),A
1162				; save PSG R7
1163	LD	A,7
1164	OUT0	(PSG_ADR),A
1165	IN	A,(PSG_IN)
1166	LD	(SPK_PSGR7),A
1167				; PSG CH3 TONE ON
1168	AND	0FBH
1169	OUT	(PSG_DAT),A
1170
1171	JR	SPK_EXIT
1172
1173SPK_STOP:
1174	LD	A,(SPK_READY)
1175	OR	A
1176	RET	Z
1177
1178SPK_STOP_CORE:
1179	XOR	A
1180	LD	(SPK_READY),A
1181	LD	(SPK_CMD),A
1182
1183	DI
1184				; restore PSG R7
1185	LD	A,7
1186	OUT	(PSG_ADR),A
1187	LD	A,(SPK_PSGR7)
1188	OUT	(PSG_DAT),A
1189				; PSG CH3 VOL=0
1190	LD	A,10
1191	OUT	(PSG_ADR),A
1192	XOR	A
1193	OUT	(PSG_DAT),A
1194
1195	LD	(SPK_RUN),A
1196
1197	JR	SPK_EXIT
1198
1199SPK_KEEP:
1200				; REMAIN == 0, then stop
1201	LD	HL,(SPK_REMAIN)
1202	LD	A,H
1203	OR	L
1204	JR	Z,SPK_STOP_CORE
1205
1206	DEC	HL
1207	LD	(SPK_REMAIN),HL
1208
1209SPK_EXIT:
1210	EI
1211	LD	A,XPLX_R_OK
1212	LD	(SPK_RESULT),A
1213	LD	(SPK_READY),A
1214	RET
1215
1216SPK_PSGR7:
1217	.DB	0
1218
1219; ######## PSG
1220PSG_DISPATCH:
1221	; not implemented
1222	XOR	A
1223	LD	(PSG_CMD),A
1224	LD	A,XPLX_R_UNKNOWN_CMD
1225	LD	(PSG_RESULT),A
1226	RET
1227; ######## LPR
1228LPR_DISPATCH:
1229	; not implemented
1230	XOR	A
1231	LD	(LPR_CMD),A
1232	LD	A,XPLX_R_UNKNOWN_CMD
1233	LD	(LPR_RESULT),A
1234	RET
1235; ######## FDC
1236FDC_DISPATCH:
1237	; not implemented
1238	XOR	A
1239	LD	(FDC_CMD),A
1240	LD	A,XPLX_R_UNKNOWN_CMD
1241	LD	(FDC_RESULT),A
1242	RET
1243
1244; ######## SIO
1245SIO0_DISPATCH:
1246	; not implemented
1247	XOR	A
1248	LD	(SIO0_CMD),A
1249	LD	A,XPLX_R_UNKNOWN_CMD
1250	LD	(SIO0_RESULT),A
1251	RET
1252
1253SIO1_DISPATCH:
1254	; not implemented
1255	XOR	A
1256	LD	(SIO1_CMD),A
1257	LD	A,XPLX_R_UNKNOWN_CMD
1258	LD	(SIO1_RESULT),A
1259	RET
1260
1261INTR_INT0:
1262INTR_ASCI0:
1263INTR_ASCI1:
1264				; TBD
1265	EI
1266	RETI
1267
1268; #### PAM play start
1269
1270PAM_DISPATCH:
1271	CP	PAM_CMD_START
1272	JR	Z,PAM_START
1273	CP	PAM_CMD_QUERY
1274	JR	Z,PAM_QUERY
1275
1276	XOR	A
1277	LD	(PAM_CMD),A
1278	LD	A,XPLX_R_UNKNOWN_CMD
1279	LD	(PAM_RESULT),A
1280	RET
1281
1282; PAM ENC -> PAM Driver MAP address
1283; OUT: HL = MAP address
1284; if error, direct return to main routine
1285PAM_ENC_MAP:
1286	LD	A,(PAM_ENC)
1287	OR	A
1288	JR	Z,PAM_ERROR_ENC
1289	DEC	A
1290
1291	CP	PAM_DRIVER_MAP_LEN / 16		; 16 bytes / entry
1292	JP	NC,PAM_ERROR_ENC
1293
1294	ADD	A,A		; A *= 16
1295	ADD	A,A
1296	ADD	A,A
1297	ADD	A,A
1298
1299	LD	HL,PAM_DRIVER_MAP
1300	ADD_HL_A
1301	RET
1302
1303PAM_ERROR_ENC:
1304	POP	HL		; discard caller PC
1305PAM_ERROR_PARAM:
1306	LD	A,XPLX_R_ERROR_PARAM
1307	LD	(PAM_RESULT),A
1308	RET			; return to main
1309
1310PAM_QUERY:
1311	CALL	PAM_ENC_MAP	; get ENC to MAP
1312
1313	LD	A,(PAM_READY)
1314	OR	A
1315	RET	Z
1316
1317	XOR	A
1318	LD	(PAM_READY),A
1319	LD	(PAM_CMD),A
1320
1321	PUSH	BC
1322	PUSH	DE
1323
1324	LD	BC,12		; MAP offset 12 = CYCLE_CLK
1325	ADD	HL,BC
1326
1327				; CYCLE_CLK, REPT_CLK, REPT_MAX
1328	LD	DE,PAM_CYCLE_CLK
1329	LD	BC,4
1330	LDIR
1331
1332	POP	DE
1333	POP	BC
1334
1335	LD	A,XPLX_R_OK
1336	LD	(PAM_RESULT),A
1337	LD	(PAM_READY),A
1338	RET
1339
1340
1341PAM_START:
1342	CALL	PAM_ENC_MAP	; get ENC to MAP
1343
1344	LD	A,15
1345	ADD_HL_A		; HL points REPT_MAX
1346
1347	LD	A,(PAM_REPT)
1348	CP	(HL)
1349	JR	Z,PAM_START_OK	; == OK
1350	JR	C,PAM_START_OK	; < OK
1351	JR	PAM_ERROR_PARAM
1352
1353PAM_START_OK:
1354	LD	A,(PAM_READY)
1355	OR	A
1356	RET	Z
1357
1358	XOR	A
1359	LD	(PAM_READY),A
1360	LD	(PAM_CMD),A
1361
1362				; never normal return
1363				; PAM never EI
1364	DI
1365	CALL	INIT_PSG
1366
1367	CALL	PAM_ENC_MAP	; re- get ENC to MAP
1368
1369				; copy to internal RAM
1370	LD	DE,PAM_DRIVER
1371
1372	LD	SP,HL		; SP = top of Map entry
1373	POP	HL		; HEAD
1374	POP	BC		; HEAD_LEN
1375	LDIR
1376
1377	LD	A,(PAM_REPT)
1378	INC	A		; DEC is not change CY
1379
1380
1381PAM_REPT_LOOP:
1382	POP	HL		; REPT
1383	POP	BC		; REPT_LEN
1384
1385	DEC	A		; DEC is not change CY
1386	JR	Z,PAM_REPT_END
1387
1388	LDIR
1389
1390	DEC	SP
1391	DEC	SP
1392	DEC	SP
1393	DEC	SP
1394	JR	PAM_REPT_LOOP
1395PAM_REPT_END:
1396
1397	POP	HL		; TAIL
1398	POP	BC		; TAIL_LEN
1399	LDIR
1400
1401				; buffer pointer
1402	LD	HL,PAM_BUF
1403#if USE_INTR
1404#else
1405	LD	(PAM_STAT_PTR),HL
1406#endif
1407				; prefetch
1408	LD	SP,HL			; 4
1409	POP	DE
1410
1411; I/O WAIT 3 -> 2
1412; PSG ��� address / write ������ ��� 300ns ������������
1413; 1.8432 clock ��������������������� 1 wait ������������������������������������
1414; 2 wait ������������������ out ��������� 12 clock ������������
1415; ��������������������������� POP ��� 9+3=12 clock ���������������
1416; ���������������������������������������������������2 wait ������������������
1417; ������ PSG ��� read ��� 400ns ������������������2 wait ���������������������
1418; ������ HOSTINTR ������ I/O ������ out ��� wait ������������������������������
1419; ���������������������HOSTINTR ������������������������������������������
1420; ������������������������������������������������������������������������������������������
1421; ���������������������
1422	LD	A,10H		; IWI[54]=1(2wait)
1423	OUT0	(DCNTL),A
1424
1425	LD	A,1
1426	LD	(PAM_RUN),A
1427
1428	LD	A,8
1429	OUT	(PSG_ADR),A
1430	LD	C,PSG_DAT
1431
1432	JP	PAM_DRIVER
1433
1434PAM_RESET:
1435				; XPBUS ������������������
1436	LD	SP,PRIVATE_SP
1437
1438; I/O WAIT 2 -> 3
1439	LD	A,20H		; IWI[54]=2(3wait)
1440	OUT0	(DCNTL),A
1441
1442	CALL	INIT_PSG
1443
1444	XOR	A
1445	LD	(PAM_RUN),A
1446
1447	LD	A,XPLX_R_OK
1448	LD	(PAM_RESULT),A
1449	LD	(PAM_READY),A
1450
1451	JP	XPBUS
1452
1453PAM_DRIVER_MAP:
1454				; 16 bytes / entry
1455	DW	PAM2A_HEAD_ORG
1456	DW	PAM2A_HEAD_LEN
1457	DW	PAM2A_REPT_ORG
1458	DW	PAM2A_REPT_LEN
1459	DW	PAM2A_TAIL_ORG
1460	DW	PAM2A_TAIL_LEN
1461	DW	204		;CYCLE_CLK
1462	DB	36		;REPT_CLK
1463	DB	37		;REPT_MAX
1464
1465	DW	PAM2B_HEAD_ORG
1466	DW	PAM2B_HEAD_LEN
1467	DW	PAM2B_REPT_ORG
1468	DW	PAM2B_REPT_LEN
1469	DW	PAM2B_TAIL_ORG
1470	DW	PAM2B_TAIL_LEN
1471	DW	152		;CYCLE_CLK
1472	DB	24		;REPT_CLK
1473	DB	57		;REPT_MAX
1474
1475	DW	PAM3A_HEAD_ORG
1476	DW	PAM3A_HEAD_LEN
1477	DW	PAM3A_REPT_ORG
1478	DW	PAM3A_REPT_LEN
1479	DW	PAM3A_TAIL_ORG
1480	DW	PAM3A_TAIL_LEN
1481	DW	298		;CYCLE_CLK
1482	DB	51		;REPT_CLK
1483	DB	24		;REPT_MAX
1484
1485	DW	PAM3B_HEAD_ORG
1486	DW	PAM3B_HEAD_LEN
1487	DW	PAM3B_REPT_ORG
1488	DW	PAM3B_REPT_LEN
1489	DW	PAM3B_TAIL_ORG
1490	DW	PAM3B_TAIL_LEN
1491	DW	136		;CYCLE_CLK
1492	DB	36		;REPT_CLK
1493	DB	38		;REPT_MAX
1494
1495
1496
1497PAM_DRIVER_MAP_LEN:	.EQU	$-PAM_DRIVER_MAP
1498
1499	.DEPHASE
1500
1501
1502
1503; ######## PAM drivers
1504	.PHASE 0FE00H
1505				; all PAM drivers have same address=0FE00H
1506PAM_DRIVER:
1507	.DEPHASE
1508
1509; #### PAM2A
1510
1511	.PHASE 0FE00H
1512PAM2A_HEAD_ORG:	.EQU	$$
1513PAM2A_HEAD:
1514PAM2A:
1515				; PAM2A
1516				; 12+0:12+12 = 1:2 PAM
1517				; PAM 36clk 170.667kHz
1518				; output PAM wave = normal 5 + antinoise 1
1519
1520				; 1 PAM cycle = 204 clk
1521
1522				; 6.144E6 / (204 + 36*n)
1523
1524				; sampling freqs:
1525				;  0: 30118
1526				; 37:  4000
1527
1528				; no STAT for first time
1529	JP	PAM2A_LOOP
1530
1531PAM2A_RELOAD:
1532	OUT	(C),E
1533	OUT	(C),D
1534	LD	SP,PAM_BUF		;9
1535	WAIT3
1536
1537PAM2A_STAT:
1538#if USE_INTR
1539	OUT	(C),E
1540	OUT	(C),D
1541	OUT	(PAM_HOSTINTR),A		;10+2
1542#else
1543				; STAT_PTR ������������������������������������������
1544	OUT	(C),E
1545	OUT	(C),D
1546	LD	(PAM_STAT_PTR),SP		;19+3
1547#endif
1548
1549PAM2A_NORMAL:
1550	OUT	(C),E
1551	OUT	(C),D
1552				; prefetch
1553	POP	DE			;9+3
1554
1555	OUT	(C),L
1556	OUT	(C),H
1557				; ������������������������������������
1558				; ������ wait 12 ������ PAM ������������������
1559				; ������������������������������
1560PAM2A_LOOP:
1561				; prefetched DE
1562	OUT	(C),E
1563	OUT	(C),D
1564				; HL = DE for save current sample
1565	LD	L,E			;4
1566	LD	H,D			;4
1567				; A = attention
1568	LD	A,E			;4
1569
1570PAM2A_HEAD_LEN:	.EQU	$-PAM2A_HEAD
1571
1572PAM2A_REPT_ORG:	.EQU	$$
1573PAM2A_REPT:
1574	OUT	(C),E
1575	OUT	(C),D
1576	WAIT12
1577PAM2A_REPT_LEN:	.EQU	$-PAM2A_REPT
1578
1579PAM2A_TAIL_ORG:	.EQU	$$
1580PAM2A_TAIL:
1581				; ���������������������������������������������������
1582				; ������������������"������"���������������������
1583				; "���������"������������������������
1584	OUT	(C),E
1585	OUT	(C),D
1586	RLCA
1587				; attention bit
1588				; bit7=1, reload
1589				; must be JP
1590	JP	C,PAM2A_RELOAD		; jump=9 no=6
1591
1592	WAIT3
1593	OUT	(C),E
1594	OUT	(C),D
1595	RLCA				; 3
1596				; bit6=1, stat
1597				; must be JP
1598	JP	C,PAM2A_STAT		; jump=9 no=6
1599
1600	WAIT3
1601	OUT	(C),E
1602	OUT	(C),D
1603	RLCA				; 3
1604				; bit5=0, normal
1605				; must be JP
1606	JP	NC,PAM2A_NORMAL		; jump=9 no=6
1607				; attention=001, reset
1608	JP	PAM_RESET
1609PAM2A_TAIL_LEN:	.EQU	$-PAM2A_TAIL
1610
1611				; cycle
1612				; 5 * (12*3) + 12*2 = 204
1613
1614	.DEPHASE
1615
1616; #### PAM2B
1617
1618	.PHASE 0FE00H
1619				; all PAM drivers have same address=0FE00H
1620PAM2B_HEAD_ORG:	.EQU	$$
1621PAM2B_HEAD:
1622PAM2B:
1623				; PAM2B
1624				; averaged 1:1 PAM
1625				; wait (4,7), (3,9), (9,12), (12,0)
1626				; phase wait 28:28
1627				; clk  35, 36, 45, 36
1628				; PAM 176, 171, 137, 171 kHz
1629				; output PAM wave = 4
1630
1631				; 1 PAM cycle = 152 clk
1632
1633				; 6.144E6 / (152 + 24*n)
1634
1635				; sampling freqs:
1636				;  0: 40421
1637				; 57:  4042
1638
1639				; no STAT for first time
1640	JP	PAM2B_LOOP
1641
1642PAM2B_RELOAD:
1643	OUT	(C),E
1644	LD	SP,PAM_BUF		;9
1645
1646PAM2B_STAT:
1647#if USE_INTR
1648	OUT	(C),D
1649	OUT	(PAM_HOSTINTR),A		;10+2
1650#else
1651				; STAT_PTR ������������������������������������������
1652	OUT	(C),D
1653	LD	(PAM_STAT_PTR),SP		;19+3
1654#endif
1655
1656PAM2B_NORMAL:
1657	OUT	(C),E
1658				; prefetch
1659	POP	DE			;9+3
1660	OUT	(C),B
1661PAM2B_LOOP:
1662				; prefetched DE
1663	OUT	(C),E
1664				; A = attention
1665	LD	A,E			;4
1666	OUT	(C),D
1667				; B = save D
1668	LD	B,D			;4
1669	WAIT3
1670
1671PAM2B_HEAD_LEN:	.EQU	$-PAM2B_HEAD
1672
1673PAM2B_REPT_ORG:	.EQU	$$
1674PAM2B_REPT:
1675	OUT	(C),E
1676	OUT	(C),D
1677PAM2B_REPT_LEN:	.EQU	$-PAM2B_REPT
1678
1679PAM2B_TAIL_ORG:	.EQU	$$
1680PAM2B_TAIL:
1681				; ���������������������������������������������������
1682				; ������������������"������"���������������������
1683				; "���������"������������������������
1684	OUT	(C),E
1685	RLCA				;3
1686	OUT	(C),D
1687				; attention bit
1688				; bit7=1, reload
1689				; must be JP
1690	JP	C,PAM2B_RELOAD		; jump=9 no=6
1691
1692	RLCA				; 3
1693	OUT	(C),E
1694				; bit6=1, stat
1695				; must be JP
1696	JP	C,PAM2B_STAT		; jump=9 no=6
1697
1698	RLCA				; 3
1699	OUT	(C),D
1700	WAIT3
1701				; bit5=0, normal
1702				; must be JP
1703	JP	NC,PAM2B_NORMAL		; jump=9 no=6
1704				; attention=001, reset
1705	JP	PAM_RESET
1706PAM2B_TAIL_LEN:	.EQU	$-PAM2B_TAIL
1707
1708				; cycle
1709				; 4 * 12*2 + (4+7 + 3+9 + 9+12 + 12+0) = 152
1710
1711	.DEPHASE
1712
1713; #### PAM3A
1714
1715	.PHASE 0FE00H
1716PAM3A_HEAD_ORG:	.EQU	$$
1717PAM3A_HEAD:
1718PAM3A:
1719				; PAM3A
1720				; 12+0:12+3:12+12 = 4:5:8 PAM
1721				; PAM 51clk 120.471kHz
1722				; output PAM wave = normal 5 + antinoise 1
1723
1724				; 1 PAM cycle = 298 clk
1725
1726				; 6.144E6 / (298 + 51*n)
1727
1728				; sampling freqs:
1729				; 0: 20617
1730				; 24: 4037
1731
1732				; prefetch
1733	POP	AF
1734	LD	B,A
1735				; no STAT for first time
1736	JP	PAM3A_LOOP
1737
1738PAM3A_RELOAD:
1739	OUT	(C),L
1740	OUT	(C),H
1741	WAIT3
1742	OUT	(C),B
1743	LD	SP,PAM_BUF		;9
1744	WAIT3
1745
1746PAM3A_STAT:
1747#if USE_INTR
1748	OUT	(C),L
1749	OUT	(C),H
1750	WAIT3
1751	OUT	(C),B
1752	OUT	(PAM_HOSTINTR),A		;10+2
1753#else
1754				; STAT_PTR ������������������������������������������
1755	OUT	(C),L
1756	OUT	(C),H
1757	WAIT3
1758	OUT	(C),B
1759	LD	(PAM_STAT_PTR),SP		;19+3
1760#endif
1761
1762PAM3A_NORMAL:
1763	OUT	(C),L
1764	OUT	(C),H
1765	WAIT3
1766	OUT	(C),B
1767				; prefetch
1768	POP	DE			;9+3
1769
1770	OUT	(C),L
1771	OUT	(C),H
1772	WAIT3
1773	OUT	(C),B
1774				; prefetch
1775	POP	AF			;9+3
1776
1777	OUT	(C),L
1778	OUT	(C),H
1779	WAIT3
1780	OUT	(C),B
1781				; ������������������������������������
1782				; ������ wait 12 ������ PAM ������������������
1783				; ���������������������������4clk������������������
1784	LD	B,A			;4
1785PAM3A_LOOP:
1786				; prefetched DE, A=B
1787
1788PAM3A_HEAD_LEN:	.EQU	$-PAM3A_HEAD
1789
1790PAM3A_REPT_ORG:	.EQU	$$
1791PAM3A_REPT:
1792	OUT	(C),E
1793	OUT	(C),D
1794	WAIT3
1795	OUT	(C),B
1796	WAIT12
1797PAM3A_REPT_LEN:	.EQU	$-PAM3A_REPT
1798
1799PAM3A_TAIL_ORG:	.EQU	$$
1800PAM3A_TAIL:
1801				; ���������������������������������������������������
1802				; ������������������"������"���������������������
1803				; "���������"������������������������
1804	OUT	(C),E
1805	OUT	(C),D
1806	EX	DE,HL			;3
1807	OUT	(C),B
1808	RLCA
1809				; attention bit
1810				; bit7=1, reload
1811				; must be JP
1812	JP	C,PAM3A_RELOAD		; jump=9 no=6
1813
1814	WAIT3
1815	OUT	(C),L
1816	OUT	(C),H
1817	WAIT3
1818	OUT	(C),B
1819	RLCA				; 3
1820				; bit6=1, stat
1821				; must be JP
1822	JP	C,PAM3A_STAT		; jump=9 no=6
1823
1824	WAIT3
1825	OUT	(C),L
1826	OUT	(C),H
1827	WAIT3
1828	OUT	(C),B
1829	RLCA				; 3
1830				; bit5=0, normal
1831				; must be JP
1832	JP	NC,PAM3A_NORMAL		; jump=9 no=6
1833				; attention=001, reset
1834	JP	PAM_RESET
1835PAM3A_TAIL_LEN:	.EQU	$-PAM3A_TAIL
1836
1837				; cycle
1838				; 5 * (12*3+3+12) + (12*3+3+4) = 298
1839
1840	.DEPHASE
1841
1842; #### PAM3B
1843
1844	.PHASE 0FE00H
1845PAM3B_HEAD_ORG:	.EQU	$$
1846PAM3B_HEAD:
1847PAM3B:
1848				; PAM3B
1849				; approx 1:1:1
1850				; wait (9,9,12), (12,12,10)
1851				; phase wait 21:21:22
1852				; clk 66, 70
1853				; PAM 93, 88 kHz
1854				; output PAM wave = 2
1855
1856				; 1 PAM cycle = 136 clk
1857
1858				; 6.144E6 / (136 + 36*n)
1859
1860				; sampling freqs:
1861				; 0: 45176
1862				; 38: 4085
1863
1864				; prefetch
1865	POP	AF
1866	LD	B,A
1867	RLCA
1868				; no STAT for first time
1869	JP	PAM3B_LOOP
1870
1871PAM3B_RELOAD:
1872	OUT	(C),D
1873	LD	SP,PAM_BUF		;9
1874
1875PAM3B_STAT:
1876#if USE_INTR
1877	OUT	(C),B
1878	OUT	(PAM_HOSTINTR),A		;10+2
1879#else
1880				; STAT_PTR ������������������������������������������
1881	OUT	(C),B
1882	LD	(PAM_STAT_PTR),SP		;19+3
1883#endif
1884
1885PAM3B_NORMAL:
1886	OUT	(C),E
1887				; prefetch
1888	POP	HL			;9+3
1889
1890	OUT	(C),D
1891				; prefetch
1892	POP	AF			;9+3
1893
1894	OUT	(C),B
1895	EX	DE,HL			;3
1896	LD	B,A			;4
1897	RLCA				;3
1898PAM3B_LOOP:
1899				; prefetched DE,B A=RLCA-ed flag
1900
1901PAM3B_HEAD_LEN:	.EQU	$-PAM3B_HEAD
1902
1903PAM3B_REPT_ORG:	.EQU	$$
1904PAM3B_REPT:
1905	OUT	(C),E
1906	OUT	(C),D
1907	OUT	(C),B
1908PAM3B_REPT_LEN:	.EQU	$-PAM3B_REPT
1909
1910PAM3B_TAIL_ORG:	.EQU	$$
1911PAM3B_TAIL:
1912				; ���������������������������������������������������
1913				; ������������������"������"���������������������
1914				; "���������"������������������������
1915	OUT	(C),E
1916				; attention bit
1917				; bit7=1, reload
1918				; must be JP
1919	JP	C,PAM3B_RELOAD		; jump=9 no=6
1920
1921	RLCA				; 3
1922	OUT	(C),D
1923				; bit6=1, stat
1924				; must be JP
1925	JP	C,PAM3B_STAT		; jump=9 no=6
1926
1927	RLCA				; 3
1928	OUT	(C),B
1929	WAIT3
1930				; bit5=0, normal
1931				; must be JP
1932	JP	NC,PAM3B_NORMAL		; jump=9 no=6
1933				; attention=001, reset
1934	JP	PAM_RESET
1935PAM3B_TAIL_LEN:	.EQU	$-PAM3B_TAIL
1936
1937
1938	.DEPHASE
1939
1940; #### PAM1P
1941
1942	.PHASE	0FE00H
1943PAM1P_HEAD_ORG:	.EQU	$$
1944PAM1P_HEAD:
1945PAM1P:
1946				; PAM1P
1947				; PAM1P ���������������PCM������
1948				; ���������������PAM���������������������������
1949				; Polyphase PCM
1950
1951				; 1 cycle = 87 clk
1952				; 6.144E6 / (87 + 3*n)
1953
1954				; sampling freqs:
1955				; 0: 70621
1956				; 255: 7420
1957
1958	LD	HL,PAM_BUF		;9
1959
1960	LD	C,PSG_ADR
1961				; initial CH0
1962	LD	A,8
1963	OUT	(PSG_ADR),A
1964				; rotated next CH
1965	LD	B,9
1966	LD	DE,080AH
1967
1968				; no STAT for first time
1969	JP	PAM1P_LOOP
1970
1971PAM1P_RELOAD:
1972	LD	HL,PAM_BUF		;9
1973
1974PAM1P_STAT:
1975#if USE_INTR
1976	OUT	(PAM_HOSTINTR),A		;10+2
1977#else
1978				; STAT_PTR ������������������������������������������
1979	LD	(PAM_STAT_PTR),HL		;16+3
1980#endif
1981
1982PAM1P_NORMAL:
1983				; rotate B,E,D
1984	LD	A,B			;4
1985	LD	B,E			;4
1986	LD	E,D			;4
1987	LD	D,A			;4
1988	OUT	(C),B			;10+2
1989
1990PAM1P_LOOP:
1991
1992	LD	A,(HL)			;6+3
1993	INC	HL			;4
1994
1995	OUT	(PSG_DAT),A			;10+2
1996
1997PAM1P_HEAD_LEN:	.EQU	$-PAM1P_HEAD
1998
1999PAM1P_REPT_ORG:	.EQU	$$
2000PAM1P_REPT:
2001	WAIT3
2002PAM1P_REPT_LEN:	.EQU	$-PAM1P_REPT
2003
2004PAM1P_TAIL_ORG:	.EQU	$$
2005PAM1P_TAIL:
2006				; ���������������������������������������������������
2007				; ������������������"������"���������������������
2008				; "���������"������������������������
2009	RLCA				;3
2010				; attention bit
2011				; bit7=1, reload
2012				; must be JP
2013	JP	C,PAM1P_RELOAD		; jump=9 no=6
2014
2015	RLCA				; 3
2016				; bit6=1, stat
2017				; must be JP
2018	JP	C,PAM1P_STAT		; jump=9 no=6
2019
2020	RLCA				; 3
2021	WAIT3
2022				; bit5=0, normal
2023				; must be JP
2024	JP	NC,PAM1P_NORMAL		; jump=9 no=6
2025				; attention=001, reset
2026	JP	PAM_RESET
2027PAM1P_TAIL_LEN:	.EQU	$-PAM1P_TAIL
2028
2029				; cycle
2030				; 63 + 12 + 12 = 87
2031
2032	.DEPHASE
2033
2034PROG_ORG_LEN:	.EQU	$$-PROG_ORG
2035
2036; #### interrupt vector
2037	.PHASE	0FFE0H
2038VECTOR_ORG:	.EQU	$$
2039VECTOR:
2040
2041VEC_INT1:
2042	DW	INTR_IGN
2043VEC_INT2:
2044	DW	INTR_IGN
2045VEC_PRT0:
2046	DW	INTR_PRT0
2047VEC_PRT1:
2048	DW	INTR_IGN
2049VEC_DMAC0:
2050	DW	INTR_IGN
2051VEC_DMAC1:
2052	DW	INTR_IGN
2053VEC_SIO:
2054	DW	INTR_IGN
2055VEC_ASCI0:
2056	DW	INTR_ASCI0
2057VEC_ASCI1:
2058	DW	INTR_ASCI1
2059VEC_PT2IN:
2060	DW	INTR_IGN
2061VEC_PT2OUT:
2062	DW	INTR_IGN
2063VEC_PT2OVF:
2064	DW	INTR_IGN
2065			; ���������������������������������������������
2066			; ������������������������������������������������
2067INTR_IGN:
2068	EI
2069	RETI
2070
2071VECTOR_ORG_LEN:	.EQU	$$-VECTOR_ORG
2072
2073	.DEPHASE
2074XPLX_FIRMWARE_LEN::	.EQU	$
2075