|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 OUT &H40,&H20:::::::OUT &H40,0 20 GOTO 10 |
Main:
di
ld e,7
ld ix,NoteTable
.loop:
call Play
inc ix
inc ix
dec e
jr nz,.loop
jr Main
Play:
ld b,100 ;おとのながさ(てきとう)
.loop:
ld l,(ix+0) ;19
ld h,(ix+1) ;19
ld a,$20 ;7 $80=88mk2BEEP
out ($40),a ;11
.wait1:
dec hl ;6 -+
ld a,l ;4 |
or h ;4 |
jp nz,.wait1 ;10-+ * n
inc hl ;6
ld a,0 ;7
ld l,(ix+0) ;19
ld h,(ix+1) ;19
ld a,0 ;7
out ($40),a ;11
.wait2:
dec hl ;6 -+
ld a,l ;4 |
or h ;4 |
jp nz,.wait2 ;10-+ * n
djnz .loop ;13
ret ;=138+(24*n*2)
NoteTable:
dw ((3993600 / 261) - 138) / 48 ;o4c
dw ((3993600 / 293) - 138) / 48 ;o4d
dw ((3993600 / 329) - 138) / 48 ;o4e
dw ((3993600 / 349) - 138) / 48 ;o4f
dw ((3993600 / 391) - 138) / 48 ;o4g
dw ((3993600 / 440) - 138) / 48 ;o4a
dw ((3993600 / 493) - 138) / 48 ;o4b
|
| N88-BASIC での割り込みテーブル | ||||
|---|---|---|---|---|
| Lv.0 | $F300-$F301 | RXRDY | RS-232C 受信割り込み | ↑ 高 低 ↓ |
| Lv.1 | $F302-$F303 | VRTC | 画面終了割り込み 1/60 秒 | |
| Lv.2 | $F304-$F305 | CLOCK | リアルタイムクロック 1/600 秒 | |
| Lv.3 | $F306-$F307 | INT4 | ユーザー割り込み (音源) | |
| Lv.4 | $F308-$F309 | INT3 | ユーザー割り込み (音源) | |
| Lv.5 | $F30A-$F30B | INT2 | ユーザー割り込み | |
| Lv.6 | $F30C-$F30D | FDINT1 | FDD 用リザーブ | |
| Lv.7 | $F30E-$F30F | FDINT0 | FDD 用リザーブ | |
| I/O ポート $E4 【入力・出力】 | ||
|---|---|---|
| bit | 3 | 0=割り込みレベルを参照して割り込みを発生させる 1=優先順位による割り込み |
| bit | 2-0 | 割り込みレベル 0-7 |
| I/O ポート $E6 【出力】 | ||
|---|---|---|
| bit | 2 | USART 割り込みマスク 0=禁止 1=許可 |
| bit | 1 | VRTC 割り込みマスク 0=禁止 1=許可 |
| bit | 0 | リアルタイムクロック割り込みマスク 0=禁止 1=許可 |
| I/O ポート $32 【入力・出力】 | ||
|---|---|---|
| bit | 7 | 音源割り込みマスク 0=割り込み許可 1=割り込み不可 |
| bit | 6 | グラフィックVRAMアクセスモード 0=独立アクセスモード 1=ALUアクセスモード |
| bit | 5 | カラーモード 0=デジタルモード 1=アナログモード |
| bit | 4 | 高速RAM/メインRAMバンク選択 0=高速テキストRAM選択 1=メインRAM選択 |
| bit | 3 | 画面出力モード 00=テレビ/ビデオモード 01=なし 10=アナログRGBモード 11=オプションモード |
| bit | 2 | |
| bit | 1 | 内部EROM選択 00=内部EROMバンク0選択 01=内部EROMバンク1選択 02=内部EROMバンク2選択 03=内部EROMバンク3選択 |
| bit | 0 | |
| I/O ポート $AA 【出力】 | ||
|---|---|---|
| bit | 7 | 音源割り込みマスク 0=割り込み許可 1=割り込み不可 |
| bit | 6-0 | |
|
・FM 音源タイマー B が満期
->FM 音源レジスタ $27 のタイマー B オーバーフロー受け付けフラグが ON
->FM 音源 OPNA レジスタ $29 のタイマー B 使用可能フラグが有効
->FM 音源 OPNA レジスタ $10 のタイマー B マスクフラグが降りている
-> I/O ポート $32 の音源割り込みマスク「許可」
-> I/O ポート $E4 の割り込みレベルの条件を満たしている
-> Z80 の状態が割り込み許可 (EI)
-> 割り込み発生!
・1/600秒カウンタ満期
-> I/O ポート$E6 の割り込みマスク「許可」
-> I/O ポート $E4 の割り込みレベルの条件を満たしている
-> Z80 の状態が割り込み許可 (EI)
-> 割り込み発生!
|
Sount_Interrupt:
di
push af ;FM 音源割り込みでここに来たので FM 音源ドライバの処理を行う
push bc
push de
push hl
push ix
ld d,$27 ;FM 音源コントロールポート
ld e,%00101010 ;FM 音源タイマー B を再セット
call WriteOPN
ld a,7 ;割り込みレベル再設定
out ($E4),a
call Sound_Driver ;音源ドライバ処理
pop ix
pop hl
pop de
pop bc
pop af
ei
ret
|
IntSound:
in a,($44)
rrca
jr c,.timera
rrca
jr nc,.exit
.timerb:
ld d,$27 ;mode. timer-ctrl
ld e,%00101111 ;[ResetB]
call WriteOPN
ここに Timer-B の処理を書く
jr IntSound ;必ず両方のフラグの処理を消化する
.timera:
ld d,$27 ;mode. timer-ctrl
ld e,%00011111 ;[ResetA]
call WriteOPN
ここに Timer-A の処理を書く
jr IntSound ;必ず両方のフラグの処理を消化する
.exit:
ld a,5
out ($E4),a
ei
ret
|
Check_N88ROM:
ld a,%00111001 ;N88-BASIC, ROM&RAM
out ($31),a
ld a,($79D7)
cp $32
jr c,.PC8801 ;1.0-1.1 初代
jr z,.PC8801A ;1.2 A
cp $33
jr z,.PC8801mk2 ;1.3 mk2
cp $34
jr z,.PC8801mk2SRTR ;1.4 SR/TR
cp $38
jr c,.PC8801FRMR ;1.5-1.7 FR/MR
jr z,.PC8801FHMH ;1.8 FH/MH
ld a,($79D8)
cp $0D
jr z,.PC8801FAMAVAx ;1.9 VA/FA/MA/VA2/VA3
cp $31
jr z,.PC8801FEMA2 ;1.91 FE/MA2
cp $32
jr z,.PC98DO ;1.92 DO
cp $33
jr z,.PC8801FE2MC ;1.93 FE2/MC
cp $34
jr z,.PC98DOP ;1.94 DO+
jr .PC8801unknown ;不明
以下個別の処理(略)
|
Check_Mode:
in a,($31) ;bit76:10=V1S 11=V1H 01=V2
rlca
ld hl," 2"
jr nc,.mode
rlca
ld hl,"H1"
jr c,.mode
ld hl,"S1"
.mode:
in a,($6E) ;bit7:0=8MHz 1=4MHz (FH以降)
rlca
ld a,"4"
jr c,.spd
ld a,"8"
.spd:
ld (SPEED),a
ld (MODE+1),hl
ret
SPEED:
db "4MHz",0
MODE:
db "V2S Mode",0
|
Check_MC:
in a,($40)
and %00000010
ld hl,$01C0 ;15KHz
jr nz,.skip1
ld hl,$0100 ;24KHz
.skip1:
ld bc,0
call WaitVblank
.loop:
ld ix,($0000)
inc bc
in a,($40)
and $20
jr nz,.loop ;vblank の間ループを続ける
sbc hl,bc ; bc>hl なら 8MHz-H モードと見なす
ld hl,"H-"
jr c,.skip2
ld hl,"S-"
.skip2:
ret
WaitVblank:
in a,($40)
and $20
jr nz,WaitVblank ;bit5 一旦ディスプレイサイクルになるまで待つ
.wait:
in a,($40)
and $20 ;bit5 ディスプレイサイクル → Vblank になったら ret
jr z,.wait
ret
|
Check_ExtRAM:
ld a,%00111011
out ($31),a ;64KRAM 選択
ld a,%00010001
out ($E2),a
ld b,0
ld hl,$AA00
.loop1:
ld a,b
out ($E3),a
ld ($0000),hl ;適当に埋める
dec l
djnz .loop1 ;降順
xor a
out ($E2),a
ld hl,$8801
ld ($0000),hl ;メインRAMに書き込み
ld a,%00010001
out ($E2),a
ld bc,0
.loop2:
ld a,b
out ($E3),a
ld hl,($0000)
ld a,h
cp $88
jr z,.skip
cp $AA
jr nz,.skip
ld a,l
cp b
jr nz,.skip
inc c
.skip:
inc b
jp nz,.loop2 ;昇順
xor a
out ($E2),a
out ($E3),a
ld a,c ;バンク数で返る。32K*バンク数byteのメモリがあるはず。
ld (Machine_ExtRAM),a
ret
|
| 例 | 内蔵 | 拡張 | INT3 | INT4 | 割込制御 | FM1 | FM2 | FM3 | FM4 | JOYSTICK |
|---|---|---|---|---|---|---|---|---|---|---|
| PC-8001mk2 +PC-8801-11 | なし | OPN | 80側 | 88側 | $AA | $A8,$A9 | ? | |||
| PC-8001mk2 +PC-8801-23 | なし | OPNA | 拡張 | $AA | $A8,$A9 | $AC,$AD | ? | |||
| PC-8001mk2SR | OPN | 内蔵 | $33.bit1 | $44,$45 | ? | |||||
| PC-8001mk2SR +PC-8801-11 | OPN | OPN | 内蔵 | 88側 | $33,$AA | $44,$45 | $A8,$A9 | ? | ||
| PC-8001mk2SR +PC-8801-23 | OPN | OPNA | 内蔵 | 拡張 | $33,$AA | $44,$45 | $A8,$A9 | $AC,$AD | ? | |
| PC-8801 +PC-8801-11 | なし | OPN | 88側 | 80側 | $AA | $A8,$A9 | ? | |||
| PC-8801 +PC-8801-23 | なし | OPNA | 拡張 | $AA | $A8,$A9 | $AC,$AD | ? | |||
| PC-8801mk2SR | OPN | 内蔵 | $32 | $44,$45 | 内蔵 | |||||
| PC-8801mk2SR +PC-8801-11 | OPN | OPN | 内蔵 | 80側 | $32,$AA | $44,$45 | $A8,$A9 | ? | ||
| PC-8801mk2SR +PC-8801-23 | OPN | OPNA | 両方 | $32,$AA | $44,$45 | $A8,$A9 | $AC,$AD | ? | ||
| PC-8801FA | OPNA | 内蔵 | $32 | $44,$45 | $46,$47 | 内蔵 | ||||
| PC-8801FA +PC-8801-11 | OPNA | OPN | 内蔵 | 80側 | $32,$AA | $44,$45 | $46,$47 | $A8, $A9 | ? | |
| PC-8801FA +PC-8801-23 | OPNA | OPNA | 両方 | $32,$AA | $44,$45 | $46,$47 | $A8,$A9 | $AC,$AD | ? | |
| PC-8801xH +PC-8801-24 | OPN | OPNA | 拡張 | $32 | × | $44,$45 | $46,$47 | ? | ||
| PC-8801FE +PC-8801-25 | OPN | OPNA | 拡張 | $32 | × | $44,$45 | $46,$47 | 内蔵 | ||
| PC-8801xH +Re:BitrhFM | OPN | OPNA | 拡張 | $32 | × | $44,$45 | $46,$47 | ? |
10 new cmd 20 cmd play"@13v15c" |
10 'fm(opn) sound test 20 DEFINT A-Z:CH=0:OCT=3:FRQ=&H26A 'o4c 30 READ AL,FB 40 REG=&HB0+CH:DAT=FB*8+AL:GOSUB 460 50 OP=0:GOSUB 360:OP=2:GOSUB 360:OP=1:GOSUB 360:OP=3:GOSUB 360 60 ' 70 REG=&HA4+CH:DAT=((OCT*2048+FRQ) AND &HFF00)/256:GOSUB 460 80 REG=&HA0+CH:DAT=((OCT*2048+FRQ) AND &HFF):GOSUB 460 90 REG=&H28:DAT=&HF0+CH:GOSUB 460 100 PRINT"PUSH SPACE TO KEYOFF" 110 IF INP(9)<>191 THEN 110 120 REG=&H28:DAT=CH:GOSUB 460 130 END 360 'write fm parameter to (op) 370 READ AR,DR,SR,RR,SL,TL,KS,ML,DT,SSG 380 REG=&H30+CH+OP*4:DAT=DT*16+ML:GOSUB 460 390 REG=&H40+CH+OP*4:DAT=TL:GOSUB 460 400 REG=&H50+CH+OP*4:DAT=KS*64+AR:GOSUB 460 410 REG=&H60+CH+OP*4:DAT=DR:GOSUB 460 420 REG=&H70+CH+OP*4:DAT=SR:GOSUB 460 430 REG=&H80+CH+OP*4:DAT=SL*16+RR:GOSUB 460 440 REG=&H90+CH+OP*4:DAT=SSG:GOSUB 460 450 RETURN 460 'write fm register 470 OUT &H44,REG 480 OUT &H45,DAT 490 RETURN 500 ' AL FB 510 DATA 2, 7 520 ' AR DR SR RR SL TL KS ML DT SSG-EG 530 DATA 31,12, 4,10, 1,32, 0,12, 0, 0 540 DATA 31, 2, 4, 6,15,57, 3,15, 1, 0 550 DATA 31,12, 4, 6, 0,30, 0, 1, 0, 0 560 DATA 31, 5, 7, 7, 2, 0, 2, 3, 5, 0 |
| I/O ポート $44 【入力】 | ||
|---|---|---|
| bit | 7 | 1=データをレジスタにセット中 |
| bit | 1 | 1=OPN タイマー B がオーバーフローした |
| bit | 0 | 1=OPN タイマー A がオーバーフローした |
| I/O ポート $44 【出力】 | ||
|---|---|---|
| bit | 7-6 | OPN レジスタ指定 |
| I/O ポート $45 【入出力】 | ||
|---|---|---|
| bit | 7-6 | OPN データ入出力 |
WriteOPN:
in a,($44)
rlca
jr c,WriteOPN
ld a,d
out ($44),a
ld a,(ix+0) ;dummy
ld a,e
out ($45),a
ret
|
| OPN レジスタ $27 【出力】 | ||
|---|---|---|
| bit | 7-6 | 00=通常モード 01=効果音モード 10=音声合成モード |
| bit | 5 | 1=フラグB リセット |
| bit | 4 | 1=フラグA リセット |
| bit | 3 | 1=タイマーB のオーバーフロー時にフラグB を 1 にする。0=オーバーフローを無視 |
| bit | 2 | 1=タイマーA のオーバーフロー時にフラグA を 1 にする。0=オーバーフローを無視 |
| bit | 1 | 1=タイマーB 始動 0=停止 |
| bit | 0 | 1=タイマーA 始動 0=停止 |
| OPN レジスタ $2F 【出力】 | ||
|---|---|---|
| bit | 7-0 | FM 音源の分周比 1/2 SSG 音源の分周比 1/1 OPN への最大入力クロック 1.4MHz |
| OPN レジスタ $2D 【出力】 | ||
|---|---|---|
| bit | 7-0 | FM 音源の分周比 1/6 SSG 音源の分周比 1/4 OPN への最大入力クロック 4.2MHz |
| OPN レジスタ $2D,$2E 【出力】 | ||
|---|---|---|
| bit | 7-0 | FM 音源の分周比 1/3 SSG 音源の分周比 1/2 OPN への最大入力クロック 2.1MHz |
PadInit: ;初回に一度呼ぶ
ld a,7
out ($44),a
in a,($45)
and %00111111 ;PSG I/O Port A/B 共に入力にする
out ($45),a
ret
PadRead:
ld a,$0E
out ($44),a
in a,($45)
cpl ;....RLDU
and $0F ;押したところが 1 になる
ld (Pad),a
ld a,$0F
out ($44),a
in a,($45)
cpl
and %00000011 ;ボタン0=bit0 ボタン1=bit1
ld (Button),a
ret
|
| 80mk2/88mk2 の汎用 I/O ポート【入出力】 | 88SR の汎用 I/O ポート【入出力】 | ||||
|---|---|---|---|---|---|
| pin1 | UIP2 | IN $30.bit7 | JIP1 | IN OPN($0E).bit0 | |
| pin2 | UIP1 | IN $30.bit6 | JIP2 | IN OPN($0E).bit1 | |
| pin3 | UOP1 | OUT $30.bit6 | JIP3 | IN OPN($0E).bit2 | |
| pin4 | UOP2 | OUT $30.bit7 | JIP4 | IN OPN($0E).bit3 | |
| pin5 | GND | - | +5V | - | |
| pin6 | UOP3 | OUT $10.bit7 | JIOP1 | IN/OUT OPN($0F).bit0 | |
| pin7 | GND | - | JIOP2 | IN/OUT OPN($0F).bit1 | |
| pin8 | UINT2 | 負論理 | JOP1 | OUT $40.bit6 | |
| pin9 | +5V | - | GND | - | |
ld c,$44
call .sub
ret nc ;c=$44 側に OPNA がある
ld c,$A8
call .sub
ret nc ;c=$A8 側に OPNA がある
jp notexist ;OPNA が存在しない
.sub:
ld a,$FF
out (c),a
inc c
in a,(c)
dec c
cp 1
ret z ;存在したら cf=0
scf
ret ;存在しなければ cf=1
|
| I/O ポート $46 【入力】 | ||
|---|---|---|
| bit | 7 | [BUSY]1=データをレジスタにセット中 |
| bit | 6 | 未使用 |
| bit | 5 | [PCMBSY] 1=ADPCM録音・再生中 |
| bit | 4 | [ZERO] 1=ADPCM録音中に無音状態になった |
| bit | 3 | [BRDY] 1=ADPCM録音・再生またはメモリへの格納が 1byte 完了した |
| bit | 2 | [EOS] 1=ADPCM録音・再生が終端アドレスに達した、またはPCM再生周期になった |
| bit | 1 | [FLAGB]1=OPNA タイマー B がオーバーフローした |
| bit | 0 | [FLAGA]1=OPNA タイマー A がオーバーフローした |
| I/O ポート $46 【出力】 | ||
|---|---|---|
| bit | 7-6 | OPNA レジスタ指定 |
| I/O ポート $47 【入出力】 | ||
|---|---|---|
| bit | 7-6 | OPNA データ入出力 |
| OPNA レジスタ $29 【出力】 | ||
|---|---|---|
| bit | 7 | 1=FM4-6, ADPCM を使用可能にする |
| bit | 4 | 1=ADPCM録音中に無音状態になった時に[ZERO]フラグを立て割り込みをかける |
| bit | 3 | 1=ADPCM録音・再生またはメモリへの格納が 1byte 完了したときに[BRDY]フラグを立て割り込みをかける |
| bit | 2 | 1=ADPCM録音・再生が終端アドレスに達した、またはPCM再生周期になった時に[EOS]フラグを立て割り込みをかける |
| bit | 1 | 1=OPNA タイマー B がオーバーフローしたときに[FLAGB]を立て割り込みをかける |
| bit | 0 | 1=OPNA タイマー A がオーバーフローしたときに[FLAGA]を立て割り込みをかける |
| OPNA レジスタ $10 【出力】 | ||
|---|---|---|
| bit | 7 | 1=全フラグを 0 にする。bit4-0 の設定は無視 |
| bit | 4 | 1=[ZERO]を常に 0 にマスクする |
| bit | 3 | 1=[BRDY]を常に 0 にマスクする |
| bit | 2 | 1=[EOS]を常に 0 にマスクする |
| bit | 1 | 1=[FLAGB]を常に 0 にマスクする |
| bit | 0 | 1=[FLAGA]を常に 0 にマスクする |
WriteOPNA:
in a,($44)
rlca
jr c,WriteOPNA
ld a,d
out ($44),a
nop ;dummy
ld a,e
out ($45),a
ret
|
ADPCM_Init: ;初回に一度だけ呼び出せばよい
ld c,$46
ld de,$1000 ;フラグコントロール どのフラグもマスクしない
call WriteFM2
ld de,$1080 ;フラグコントロール 全てのステータスフラグを0に
call WriteFM2
ld de,$0102 ;x8 DRAM
call WriteFM2
ld de,$04FF ;ストップアドレス下位 $04
call WriteFM2
ld de,$051F ;ストップアドレス上位 $05
call WriteFM2
ld de,$0CFF ;リミットアドレス下位 $FF
call WriteFM2
ld de,$0D1F ;リミットアドレス上位 $1F
jp WriteFM2
ADPCM_READ2:
ld c,$46
ld de,$0020 ;$00 メモリアクセス許可
call WriteFM2
ld hl,(ADPCM_START)
ld d,$02
ld e,l ;$02 スタートアドレス下位
call WriteFM2
ld d,$03
ld e,h ;$03 スタートアドレス上位
call WriteFM2
ex de,hl
ld hl,(ADPCM_END)
or a
sbc hl,de ;Length=End-Start+1
inc l ;+1はdec hlと相殺
inc h
ex de,hl
ld a,$08
out (c),a
inc c
in a,(c)
in a,(c) ;2回分空読みする
ld hl,(ADPCM_ADR) ;書き込み先
.loop:
ld b,32
inir ;BRDY を見る必要なし. フラグのリセットも必要なし.
dec e
jp nz,.loop
dec d
jp nz,.loop
dec c
ld de,$0001 ;$00 コントロール1 リセット
jp WriteFM2
|


| I/O ポート $88 【出力】 | ||
|---|---|---|
| bit | 7-6 | OPM レジスタ指定 |
| I/O ポート $89 【出力】 | ||
|---|---|---|
| bit | 7-6 | OPM データ出力 |
| I/O ポート $89 【入力】 | ||
|---|---|---|
| bit | 7 | 1=データをレジスタにセット中 |
| bit | 1 | 1=OPM タイマー B がオーバーフローした |
| bit | 0 | 1=OPM タイマー A がオーバーフローした |
10 'fm(opm) sound test 20 DEFINT A-Z:CH=0:OCT=3:LR=3:KC=0:KF=0 'o4c 30 READ AL,FB,WF,SY,SPD,PMD,AMD,PMS,AMS 40 REG=&H18:DAT=SPD:GOSUB 460 50 REG=&H19:DAT=&H80+PMD:GOSUB 460 60 REG=&H19:DAT=AMD:GOSUB 460 70 REG=&H1B:DAT=WF:GOSUB 460 80 REG=&H20+CH:DAT=LR*64+FB*8+AL:GOSUB 460 90 REG=&H38+CH:DAT=PMS*16+AMS:GOSUB 460 100 OP=0:GOSUB 370:OP=2:GOSUB 370:OP=1:GOSUB 370:OP=3:GOSUB 370 110 ' 120 REG=&H28+CH:DAT=OCT*16+KC:GOSUB 460 130 REG=&H30+CH:DAT=KF*4:GOSUB 460 140 REG=&H8:DAT=&H78+CH:GOSUB 460 150 PRINT"PUSH SPACE TO KEYOFF" 160 IF INP(9)<>191 THEN 160 170 REG=&H8:DAT=CH:GOSUB 460 180 END 370 'write fm parameter to (op) 380 READ AR,DR,SR,RR,SL,TL,KS,ML,DT1,DT2,AME 390 REG=&H40+CH+OP*8:DAT=DT1*16+ML:GOSUB 460 400 REG=&H60+CH+OP*8:DAT=TL:GOSUB 460 410 REG=&H80+CH+OP*8:DAT=KS*64+AR:GOSUB 460 420 REG=&HA0+CH+OP*8:DAT=AME*128+DR:GOSUB 460 430 REG=&HC0+CH+OP*8:DAT=DT2*64+SR:GOSUB 460 440 REG=&HE0+CH+OP*8:DAT=SL*16+RR:GOSUB 460 450 RETURN 460 'write fm register 470 OUT &H88,REG 480 OUT &H89,DAT 490 RETURN 500 ' AL FB WF SY SPD PMD AMD PMS AMS 510 DATA 2, 7, 2, 1,220, 0, 4, 1, 1 520 ' AR DR SR RR SL TL KS ML DT1 DT2 AME 530 DATA 31, 5, 7, 4, 9,37, 1, 1, 5, 0, 0 540 DATA 22, 0, 4, 5, 4,62, 1, 5, 2, 0, 0 550 DATA 29, 0, 4, 5, 4,77, 1, 1, 7, 0, 0 560 DATA 31, 7, 6, 5, 4, 0, 2, 1, 1, 0, 1 |
WriteOPM:
in a,($89)
rlca
jr c,WriteOPM
ld a,d
out ($88),a
ld a,(ix+0) ;dummy
ld a,e
out ($89),a
ret
|
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| I/O ポート $C2 【入出力】 | ||
|---|---|---|
| bit | 7-6 | MIDI 通信用 8251 データ入出力 |
| I/O ポート $C3 【入出力】 | ||
|---|---|---|
| bit | 7-6 | MIDI コントロール用 8251 コマンド出力・ステータス入力 |
10 'PC-8801-10 and GSX-8800 PSG Sound Test 20 CLK=3993600 30 CS=0:R=7:D=&H38:GOSUB 200:CS=1:R=7:D=&H38:GOSUB 200 40 CS=2:R=7:D=&H38:GOSUB 200:CS=3:R=7:D=&H38:GOSUB 200 50 CS=0:R=8:D=15:GOSUB 200:CS=1:R=8:D=15:GOSUB 200 60 CS=2:R=8:D=15:GOSUB 200:CS=3:R=8:D=15:GOSUB 200 100 CS=0:D=CLK/32/261:GOSUB 230 'o4c 110 CS=1:D=CLK/32/329:GOSUB 230 'o4e 120 CS=2:D=CLK/32/392:GOSUB 230 'o4g 130 CS=3:D=CLK/32/523:GOSUB 230 'o5c 140 PRINT"PUSH SPACE TO STOP" 150 IF INP(9)<>191 THEN 150 160 CS=0:R=8:D=0:GOSUB 200:CS=1:GOSUB 200 170 CS=2:GOSUB 200:CS=3:GOSUB 200 180 END 190 'write PSG 200 OUT &HA0+CS*2,R 210 OUT &HA1+CS*2,D 220 RETURN 230 'write frq 240 OUT &HA0+CS*2,0 250 OUT &HA1+CS*2,(D AND 255) 260 OUT &HA0+CS*2,1 270 OUT &HA1+CS*2,(D AND &HFF00) / 256 280 RETURN |
| I/O ポート $02 【PIT コントロール出力】 | ||
|---|---|---|
| bit | 7 | チャンネル 2 出力 1=ON 0=OFF |
| bit | 6 | チャンネル 1 出力 1=ON 0=OFF |
| bit | 5 | PCG ROM コピー |
| bit | 4 | PCG RAM ライト |
| bit | 3 | チャンネル 0 出力 1=ON 0=OFF |
| bit | 2 | RAM A10 |
| bit | 1 | RAM A9 |
| bit | 0 | RAM A8 |
| I/O ポート $0F 【PIT コントロール出力】 | ||
|---|---|---|
| bit | 7-6 | カウンタチャンネル指定 00=チャンネル 0 01=チャンネル 1 10=チャンネル 2 |
| bit | 5-4 | カウンタアクセスモード 11=16bit ロード(下位・上位の順) 10=上位 8bit のロード 01=下位 8bit のロード 00=カウント値ラッチ |
| bit | 3-1 | カウントモード 000=mode0:ターミナルカウント 001=mode1:プログラマブルワンショット 010=110=mode2:レートジェネレータ 011=111=mode3:方形波レートジェネレータ 100=mode4:ソフトウェアトリガストローブ 101=mode5:ハードウェアトリガストローブ |
| bit | 0 | PIT カウントモード 1=BCD 0=2進数 |
| I/O ポート $0C 【PIT チャンネル 0 出力】 | ||
|---|---|---|
| bit | 7-0 | チャンネル 0 カウント値 |
| I/O ポート $0D 【PIT チャンネル 1 出力】 | ||
|---|---|---|
| bit | 7-0 | チャンネル 1 カウント値 |
| I/O ポート $0E 【PIT チャンネル 2 出力】 | ||
|---|---|---|
| bit | 7-0 | チャンネル 2 カウント値 |
10 'PCG-8800 sound output test 20 OUT &H2,&HC8 'pcg sound on 30 CH=0:F=15301:GOSUB 100 '3993600 / 261Hz o4c 40 CH=1:F=12138:GOSUB 100 '3993600 / 329Hz o4e 50 CH=2:F=10187:GOSUB 100 '3993600 / 392Hz o4g 60 PRINT "hit space to stop" 70 IF INP(9)<>191 THEN 70 80 OUT &H2,0 'pcg sound off 90 END 100 ' 110 FL=F AND &HFF 120 FH=(F AND &HFF00) / 256 200 ' 210 OUT &HF,&H36+CH*64 220 OUT &HC+CH,FL 230 OUT &HC+CH,FH 240 RETURN |
ld a,$C8
out ($02),a ;PCG sound ch.0-2 on
ld a,%00110000 ;ch.0/16bit load/mode0/binary
out ($0F),a
ld hl,PCMDATA ;7800Hz 8bit PCM
ld de,PCMEND - PCMDATA
.loop:
ld a,(hl) ;7
inc hl ;6
add a,a ;4
out ($0C),a ;11
ld a,0 ;7
rla ;4
out ($0C),a ;11
ld b,33 ;7
ld b,33 ;7
djnz $ ;424 (13*32+8)
dec de ;6
ld a,d ;4
or e ;4
jp nz,.loop ;10 =512clk
xor a
out ($02),a
|
| I/O ポート $AC 【出力】 | ||
|---|---|---|
| bit | 7-6 | DCSG1 データ出力 |
| I/O ポート $AD,$AE 【出力】 | ||
|---|---|---|
| bit | 7-6 | クロックマスク / 解除 |
| I/O ポート $AF 【出力】 | ||
|---|---|---|
| bit | 7-6 | DCSG2 データ出力 |
10 ' ADDCOM Sound Unit SN76489 TEST 15 OUT &HAE,0 20 PT=&HAC:F=478:GOSUB 80 '3993600 / 32 / 261 o4c 30 PT=&HAF:F=318:GOSUB 80 '3993600 / 32 / 392 o4g 40 IF INP(9)<>191 THEN 40 50 PT=&HAC:D=&H80+CH*32+16+15:GOSUB 120 60 PT=&HAF:D=&H80+CH*32+16+15:GOSUB 120 70 END 80 CH=0:V=0:D=&H80+CH*32+16+V:GOSUB 120 90 CH=0:D=&H80+CH*32+(F AND 15):GOSUB 120 100 CH=0:D=(F AND &H3F0)/16:GOSUB 120 110 RETURN 120 DT=(D AND 1)*128 'invert bit7<->bit0 130 DT=DT+(D AND 2)*32 140 DT=DT+(D AND 4)*8 150 DT=DT+(D AND 8)*2 160 DT=DT+(D AND 16)/2 170 DT=DT+(D AND 32)/8 180 DT=DT+(D AND 64)/32 190 DT=DT+(D AND 128)/128 200 OUT PT,DT 210 RETURN |
| I/O ポート $90 【PPI ポート A 出力】 | ||
|---|---|---|
| bit | 7-0 | PSG レジスタ・データ |
| I/O ポート $92 【PPI ポート C 入出力】 | ||
|---|---|---|
| bit | 5-4 | レジスタ指定=11 データ書き込み=10 |
| bit | 7-0 | 全ビット 0 を書き込むと書き込み確定 |
| bit | 0 | 0,1 が定期的に読み出せる。 |
| I/O ポート $93 【PPI コントロール出力】 | ||
|---|---|---|
| bit | 7 | 1 |
| bit | 6-5 | PortA, PortC上位4bitのモード選択 00=mode0 01=mode1 10=11=mode2 |
| bit | 4 | PortA 0=出力 1=入力 |
| bit | 3 | PortC上位4bit 0=出力 1=入力 |
| bit | 2 | PortB, PortC下位4bitのモード選択 0=mode0 1=mode1 |
| bit | 1 | PortB 0=出力 1=入力 |
| bit | 0 | PortC下位4bit 0=出力 1=入力 |
10 'PCS-8081 20 CLK=3579545 30 OUT &H93,&H81:OUT &H97,&H81:OUT &H9B,&H81:OUT &H9F,&H81 40 FRQ=CLK/261 'o4c 100 CS=0:REG=7:DAT=&H38:GOSUB 500 110 CS=0:REG=0:DAT=FRQ AND 255:GOSUB 500 120 CS=0:REG=1:DAT=(FRQ AND &HFF00)/256:GOSUB 500 130 CS=0:REG=8:DAT=15:GOSUB 500 180 PRINT"PUSH SPACE TO STOP" 190 IF INP(9)<>&HBF THEN 190 200 REG=8:DAT=0:CS=0:GOSUB 500:CS=1:GOSUB 500 210 REG=8:DAT=0:CS=2:GOSUB 500:CS=3:GOSUB 500 400 END 500 'write PSG ChipSelect=0/1/2/3 510 OUT &H92+CS*4,&H30 520 OUT &H90+CS*4,REG 530 OUT &H92+CS*4,0 540 OUT &H92+CS*4,&H20 550 OUT &H90+CS*4,DAT 560 OUT &H92+CS*4,0 570 RETURN |
| I/O ポート $90 【PPI ポート A 出力】 | ||
|---|---|---|
| bit | 7-0 | PSG1 レジスタ・データ |
| I/O ポート $91 【PPI ポート B 出力】 | ||
|---|---|---|
| bit | 7-0 | PSG2 レジスタ・データ |
| I/O ポート $92 【PPI ポート C 入出力】 | ||
|---|---|---|
| bit | 7-6 | PSG2: レジスタ指定=11 データ書き込み=10 |
| bit | 5-4 | PSG1: レジスタ指定=11 データ書き込み=10 |
| bit | 7-0 | 全ビット 0 を書き込むと書き込み確定 |
| bit | 0 | 0,1 が定期的に読み出せる。 |
| I/O ポート $93 【PPI コントロール出力】 | ||
|---|---|---|
| bit | 7 | 1 |
| bit | 6-5 | PortA, PortC上位4bitのモード選択 00=mode0 01=mode1 10=11=mode2 |
| bit | 4 | PortA 0=出力 1=入力 |
| bit | 3 | PortC上位4bit 0=出力 1=入力 |
| bit | 2 | PortB, PortC下位4bitのモード選択 0=mode0 1=mode1 |
| bit | 1 | PortB 0=出力 1=入力 |
| bit | 0 | PortC下位4bit 0=出力 1=入力 |
10 'PCS-8007 20 CLK=3579545 30 OUT &H93,&H81:OUT &H97,&H81 40 FRQ=CLK/261 'o4c 100 CS=0:REG=7:DAT=&H38:GOSUB 500 110 CS=0:REG=0:DAT=FRQ AND 255:GOSUB 500 120 CS=0:REG=1:DAT=(FRQ AND &HFF00)/256:GOSUB 500 130 CS=0:REG=8:DAT=15:GOSUB 500 180 PRINT"PUSH SPACE TO STOP" 190 IF INP(9)<>&HBF THEN 190 200 CS=0:REG=8:DAT=0:GOSUB 500:CS=1:GOSUB 500 210 CS=2:REG=8:DAT=0:GOSUB 500:CS=3:GOSUB 500 400 END 500 'write PSG ChipSelect=0/1/2/3 510 OUT &H92+(CS AND 2)*2,&H30*4^(CS AND 1) 520 OUT &H90+(CS AND 2)*2+(CS AND 1),REG 530 OUT &H92+(CS AND 2)*2,0 540 OUT &H92+(CS AND 2)*2,&H20*4^(CS AND 1) 550 OUT &H90+(CS AND 2)*2+(CS AND 1),DAT 560 OUT &H92+(CS AND 2)*2,0 570 RETURN |
| I/O ポート $82 【出力】 | ||
|---|---|---|
| bit | 7-0 | PSG レジスタ指定 |
| I/O ポート $83 【出力】 | ||
|---|---|---|
| bit | 7-6 | PSG データ書き込み |
10 'PSG+CTC (I/O:1981.12) 20 CLK=3993600 30 FRQ=CLK/261 'o4c 100 CS=0:REG=7:DAT=&H38:GOSUB 500 110 CS=0:REG=0:DAT=FRQ AND 255:GOSUB 500 120 CS=0:REG=1:DAT=(FRQ AND &HFF00)/256:GOSUB 500 130 CS=0:REG=8:DAT=15:GOSUB 500 140 PRINT"PUSH SPACE TO STOP" 150 IF INP(9)<>&HBF THEN 190 160 CS=0:REG=8:DAT=0:GOSUB 500 400 END 500 'write PSG 510 OUT &H82,REG 520 OUT &H83,DAT 530 RETURN |
| I/O ポート $84 【CTC ch.0 出力】 | ||
|---|---|---|
| bit | 7 | 割り込みイネーブル 1:許可 0:禁止 |
| bit | 6 | モードの設定。 1:カウンタモード 0:タイマーモード |
| bit | 5 | プリスケールの選択。タイマモードにおいてのみ意味がある。 1:1/256 0:1/16 供給クロック 4MHz に対する分周比を指定する。 |
| bit | 4 | エッジの選択。無視して良い。 タイマモードの時は bit3 で使うトリガの方向(立ち上がり=1, 立ち下がり=0 を決める) カウンタモードの時は数えるパルスの方向を決める(立ち上がり=1, 立ち下がり=0) |
| bit | 3 | トリガの有無。タイマモードにおいてのみ意味がある。無視して良い。 |
| bit | 2 | タイムコンスタントの設定。bit2=1 で、次の 1byte がタイムコンスタントであることを示す。 |
| bit | 1 | リセット。bit1=1 で停止。もし bit2=1 ならタイムコンスタントが書き込まれた後、動作開始。 |
| bit | 0 | 常に 1 にする。ch.0 の場合は bit0=0 ならば割り込みベクタ設定 |
| I/O ポート $85 【CTC ch.1 出力】 | ||
|---|---|---|
| bit | 7-0 | ch.0 と同じ |
| I/O ポート $86 【CTC ch.2 出力】 | ||
|---|---|---|
| bit | 7-0 | ch.0 と同じ |
| I/O ポート $87 【CTC ch.3 出力】 | ||
|---|---|---|
| bit | 7-0 | ch.0 と同じ |
Table:
jr Main
dw Dummy
dw Dummy
dw IntCTC
dw Dummy
dw Dummy
dw Dummy
dw Dummy
Dummy:
ei
ret
Main:
di
im 2
ld a,Table >> 8
ld i,a
ld a,$FF
out ($E4),a
ld a,CTC_SETVECTOR + $00
out ($84),a
ld a,CTC_DISABLE | CTC_TIMER | CTC_PRESCALE256 | CTC_EDGE_UP | CTC_CONSTANT | CTC_RESET | CTC_SETCMD
out ($86),a
ld a,$41 ;3993600/256/65=240(Hz)
out ($86),a
ld a,CTC_ENABLE | CTC_COUNTER | CTC_PRESCALE16 | CTC_EDGE_UP | CTC_CONSTANT | CTC_RESET | CTC_SETCMD
out ($87),a
ld a,$F0 ;240Hz/240=1Hz
out ($87),a
ei
jr $
IntCTC:
push af
ld a,$FF
out ($E4),a
〜長いので略〜
pop af
ei
ret
|
| I/O ポート $87 【PPI コントロール出力】 | ||
|---|---|---|
| bit | 7 | 1 |
| bit | 6-5 | PortA, PortC上位4bitのモード選択 00=mode0 01=mode1 10=11=mode2 |
| bit | 4 | PortA 0=出力 1=入力 |
| bit | 3 | PortC上位4bit 0=出力 1=入力 |
| bit | 2 | PortB, PortC下位4bitのモード選択 0=mode0 1=mode1 |
| bit | 1 | PortB 0=出力 1=入力 |
| bit | 0 | PortC下位4bit 0=出力 1=入力 |
| I/O ポート $84 【PPI ポート A 出力】 | ||
|---|---|---|
| bit | 7-0 | PSG レジスタ・データ |
| I/O ポート $85 【PPI ポート B 出力】 | ||
|---|---|---|
| bit | 7-6 | PSG4: レジスタ指定=11 データ書き込み=10 解除=00 |
| bit | 5-4 | PSG3: レジスタ指定=11 データ書き込み=10 解除=00 |
| bit | 3-2 | PSG2: レジスタ指定=11 データ書き込み=10 解除=00 |
| bit | 1-0 | PSG1: レジスタ指定=11 データ書き込み=10 解除=00 |
10 '12ch Synth Unit (Oh!PC:1982.8) 20 OUT &H87,&H80 30 CLK=3993600/32 40 FRQ=CLK/261 'o4c 100 CS=0:REG=7:DAT=&H38:GOSUB 500 110 CS=0:REG=0:DAT=FRQ AND 255:GOSUB 500 120 CS=0:REG=1:DAT=(FRQ AND &HFF00)/256:GOSUB 500 130 CS=0:REG=8:DAT=15:GOSUB 500 180 PRINT"PUSH SPACE TO STOP" 190 IF INP(9)<>&HBF THEN 190 200 CS=0:REG=8:DAT=0:GOSUB 500 400 END 500 'write PSG ChipSelect=0/1/2/3 510 OUT &H84,REG 520 OUT &H85,&H3*(4^CS) 530 OUT &H85,0 540 OUT &H84,DAT 550 OUT &H85,&H2*(4^CS) 560 OUT &H85,0 570 RETURN |
| I/O ポート $D3 【PPI コントロール出力】 | ||
|---|---|---|
| bit | 7 | 1 |
| bit | 6-5 | PortA, PortC上位4bitのモード選択 00=mode0 01=mode1 10=11=mode2 |
| bit | 4 | PortA 0=出力 1=入力 |
| bit | 3 | PortC上位4bit 0=出力 1=入力 |
| bit | 2 | PortB, PortC下位4bitのモード選択 0=mode0 1=mode1 |
| bit | 1 | PortB 0=出力 1=入力 |
| bit | 0 | PortC下位4bit 0=出力 1=入力 |
| I/O ポート $D1 【PPI ポート B 出力】 | ||
|---|---|---|
| bit | 7-0 | 1bit PCM データ |
IO_PPI_PORTA equ $D0
IO_PPI_PORTB equ $D1
IO_PPI_PORTC equ $D2
IO_PPI_CTRL equ $D3
ld a,PPI_MODE0_ACH | PPI_OUT_A | PPI_OUT_CH | PPI_MODE0_BCL | PPI_OUT_B | PPI_OUT_CL
out (IO_PPI_CTRL),a
ld hl,PCMDATA
ld de,PCMEND - PCMDATA
ld c,IO_PPI_PORTB
.loop:
ld b,(hl) ;7
inc hl ;6
srl b
srl b
srl b ;b=0-31
ld a,$FF ;7
out (c),a ;12
ld a,32 ;7
sub b ;4
inc b ;4
djnz $
out (c),b ;12
ld b,a ;4
djnz $
dec de ;6
ld a,d ;4
or e ;4
jp nz,.loop ;10
|
|
||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 ' ASCII Music Addapter SN76489 TEST 20 PT=&H10 30 F=3579545/32/261 'o4c 40 CH=0:V=0 :D=&H80+CH*32+16+V:GOSUB 110 50 CH=0:D=&H80+CH*32+(F AND 15):GOSUB 110 60 CH=0:D=(F AND &H3F0)/16:GOSUB 110 70 PRINT"PUSH SPACE TO STOP" 80 IF INP(9)<>191 THEN 80 90 CH=0:D=&H80+CH*32+16+15:GOSUB 110 100 END 110 OUT &H40,0:OUT PT,D:OUT &H40,1:RETURN |
|
||||||
di
ld hl,PCMDATA
ld de,PCMEND - 1
ld c,$10
.loop:
outi ;16
ld b,33 ;7
djnz $ ;13/8 [13*32+8=424]
or a ;4
sbc hl,de ;15
add hl,de ;11
jp nz,.loop ;10
ei
|
|
|||||||||||||||||||||||||||
ld hl,PCMDATA
ld de,PCMEND - PCMDATA
.loop:
ld a,(hl)
rrca
rrca
rrca
and %00001110
bit 7,(hl)
jr z,.skip
inc a
.skip:
or %11010000 ;$D0 と or を取る
ex af,af'
.wait1:
in a,($40)
rrca ;port ready であれば待つ
jr nc,.wait1
.wait2:
in a,($40)
rrca ;port busy であれば待つ
jr c,.wait2
ex af,af'
out ($10),a
inc hl
dec de
ld a,d
or e
jp nz,.loop
xor a
out ($10),a
|
|
|||||||||
ld hl,PCMDATA ;8bit 8192Hz
ld de,PCMEND - PCMDATA
ld c,$10
.loop:
ld b,(hl) ;7
inc hl ;6
srl b
srl b
srl b ;b=0-31
ld a,$FF ;7
out (c),a ;12
ld a,32 ;7
sub b ;4
inc b ;4
djnz $
out (c),b ;12
ld b,a ;4
djnz $
dec de ;6
ld a,d ;4
or e ;4
jp nz,.loop ;10
jr Main
|