−Goroh氏のドキュメントに加筆しています。 8000 PRG page number at $8000-$BFFF (page_size=index_size=16k) 9000,a000,b000 ch1,ch2,ch3 Sound Control 1 bit CChessss C = Duty Cycle (Positive vs. Negative) 00 = 87.5% 01 = 75.0% 10 = 50.0% 11 = 25.0% h = Hold Note 0 = Don't hold note 1 = Hold note e = Envelope Select 0 = Envelope Vary 1 = Envelope Fixed s = Playback Rate #00 Not Output *4000と、ほぼ同じ *基本波形は、4000よりreverbをかけないと、本物のように聞こえない *ch1/ch2:Square wave *ch3:Triangle wave *ch3は、Dyty Cycleは無効。Hold Note/Envelope Selectは有効 9001,a001,b001 ch1,ch2,ch3 Sound Control 1 bit ffffffff f = Frequency Value Data (lower 8-bits) 9002,a002,b002 ch1,ch2,ch3 Sound Control 3 bit tttttddd d = Frequency Value Data (upper 3-bits) t = Active Time Length(???) *Active Time Lengthは、4003と同じではない。  Famtasiaでは、無視している。 *ch3は、その外のレジスタより、1.5キー分周波数が低下する if(no==2){ Psg[no].Freq<<=1; Psg[no].Freq=Psg[no].Freq*21/24; // 1.5キー周波数落ちる } 9003 Unknown b003 Mirror Setting Bmmmmmmm B: SRAM enable/disable 1:enable 0:disable mmmmmmm: Mirroring #08 HHHH #20 VHVH #24 VVHH #28 VVVV #2C HHHH c000 PRG page number at $C000-$DFFF (page_size=index_size=8k) d000 CHR page number at $0000-$03FF (page_size=index_size=1k) d001 CHR page number at $0400-$07FF (page_size=index_size=1k) d002 CHR page number at $0800-$0BFF (page_size=index_size=1k) d003 CHR page number at $0C00-$0FFF (page_size=index_size=1k) e000 CHR page number at $1000-$13FF (page_size=index_size=1k) e001 CHR page number at $1400-$17FF (page_size=index_size=1k) e002 CHR page number at $1800-$1BFF (page_size=index_size=1k) e003 CHR page number at $1C00-$1FFF (page_size=index_size=1k) f000 IRQ scanline(本当はclock) counter (#$100-i)*#$72 clock wait. f001 IRQ enable/disable f002 IRQ enable/disable ------AB A 0:IRQ disable 1:IRQ enable B 0:f001 is IRQ disable 1:f001 is IRQ enable *IRQ関連は、下記ソースを参照してください。 void _fastcall TVRC6::CPUWrite(WORD adr, BYTE data) { int i; if(iVRC6Type==1){ // PA1/PA0反転(#26) adr=adr&0xfffc | ((adr&1)<<1) | ((adr&2)>>1); } switch(adr&0xf003){ case 0x8000: // 8000 PRG page number at $8000-$BFFF (page_size=index_size=16k) data <<= 1; data &= uPROMBank-1; iPrgBank1=data; PROMBank[0]=bPROM[iPrgBank1]; PROMBank[1]=bPROM[iPrgBank1+1]; break; case 0x9000://PSG1-1 SoundParam00(0,data); break; case 0xa000://PSG2-1 SoundParam00(1,data); break; case 0xb000://PSG3-1 SoundParam00(2,data); break; case 0x9001://PSG1-2 SoundParam20(0,data); break; case 0xa001://PSG2-2 SoundParam20(1,data); break; case 0xb001://PSG3-2 SoundParam20(2,data); break; case 0x9002://PSG1-3 Psg[0].param[3]=data; SoundStart(0); break; case 0xa002://PSG2-3 Psg[1].param[3]=data; SoundStart(1); break; case 0xb002://PSG3-3 Psg[2].param[3]=data; SoundStart(2); break; case 0x9003://PSG reset? break; case 0xb003:// Mirroring /*Bmmmmmmm B: SRAM enable/disable 1:enable 0:disable mmmmmmm: Mirroring #08 HHHH #20 VHVH #24 VVHH #28 VVVV #2C HHHH */ if(data!=cVScroll) Disp_draw(DRAW_PART); cVScroll=data; switch(cVScroll&0x7f){ case 0x08: case 0x2c:// 0x2400固定Mirroring PPU_BG_style_set(4); break; case 0x20:// Hスクロール PPU_BG_style_set(1); break; case 0x04:// for Esper Dream2 case 0x24:// Vスクロール PPU_BG_style_set(2); break; case 0x28:// 0x2000固定スクロール PPU_BG_style_set(0); break; default: Dialog_Box(strtbl.GetString(IDS_E_UNKNOWN_WRITE),data,adr); break; } break; case 0xc000: // PRG page number at $C000-$DFFF (page_size=index_size=8k) data &= uPROMBank-1; iPrgBank2=data; PROMBank[2]=bPROM[iPrgBank2]; break; case 0xd000: // CHR page number at $0000-$03FF (page_size=index_size=1k) case 0xd001: // CHR page number at $0400-$07FF (page_size=index_size=1k) case 0xd002: // CHR page number at $0800-$0BFF (page_size=index_size=1k) case 0xd003: // CHR page number at $0C00-$0FFF (page_size=index_size=1k) case 0xe000: // CHR page number at $1000-$13FF (page_size=index_size=1k) case 0xe001: // CHR page number at $1400-$17FF (page_size=index_size=1k) case 0xe002: // CHR page number at $1800-$1BFF (page_size=index_size=1k) case 0xe003: // CHR page number at $1C00-$1FFF (page_size=index_size=1k) Disp_draw(DRAW_PART); data &= uCROMBank-1; i=(adr&0x3) | ((adr&0x2000)?4:0); iCharBank[i]=data; CROMBank[i]=bCROM[iCharBank[i]]; CharBank[i]=bChar[iCharBank[i]]; break; case 0xf000: // IRQ scanline(本当はclock) counter (#$100-i)*#$72 clock wait. cIRQCnt=data; break; case 0xf001: // IRQ enable/disable // ??????AB // A: 1:IRQ Enable 0:Disable // B: 1:$f002 IRQ reset Enable? 0:Disable cIRQCtrl1=data; if(cIRQCtrl1&0x2){ dwIRQTiming=Cycle_timev+(0x100-(int)cIRQCnt)*0x72; INT_timer=dwIRQTiming; } if(cIRQCtrl1==0){ dwIRQTiming=0; INT_timer=0; } break; case 0xf002: // IRQカウンタリセット // ???????? // IRQ Counter reset cIRQCtrl2=data; if(cIRQCtrl1&0x1){ INT_timer=dwIRQTiming; } break; default: Dialog_Box(strtbl.GetString(IDS_E_UNKNOWN_WRITE),data,adr); break; } } // IRQ発生時に呼ばれる void _fastcall TVRC6::ProcIRQPend(void) { INT_timer=0; // IRQタイミングをリセット // f002リセット時に使用される割込みタイミング dwIRQTiming=Cycle_timev+(0x100-(int)cIRQCnt)*0x72; }