All MicroEvals
Tóm tắt chính xác tài liệu RP2A03 / CPU NES, Cycle Reference...
Create MicroEval
Header image for Tóm tắt chính xác tài liệu RP2A03 / CPU NES, Cycle Reference...

Tóm tắt chính xác tài liệu RP2A03 / CPU NES, Cycle Reference...

Prompt

Tóm tắt chính xác tài liệu RP2A03 / CPU NES, Cycle Reference và kỹ thuật đếm chu kỳ - Bản chuẩn ~14950 ký tự: 1. Tổng quan 2A03: RP2A03 (gọi tắt 2A03) là chip CPU NES hệ NTSC do Ricoh sản xuất, tích hợp trên một die: lõi MOS 6502 đã cắt bỏ decimal mode (cờ D vô tác dụng, SED/CLD thành NOP 2c), APU 5 kênh, mạch đọc tay cầm và DMA OAM. Hệ PAL dùng RP2A07, logic tương thích 100% nhưng khác tần số, tần số audio điều chỉnh cho 50Hz và đã sửa bug DMA treo bus của 2A03. Famiclone/Dendy dùng NOAC UA6527P+UA6538 với divisor 15 để tương thích. Đặc điểm lõi 6502: mọi chu kỳ bus đều là read hoặc write, không có idle cycle. Illegal opcodes hoạt động giống hệt giữa 2A03 và 2A07. 2. Bản đồ thanh ghi CPU $4000-$4017: Khác PPU/mapper chỉ giải mã một phần, thanh ghi CPU được giải mã hoàn toàn (fully decoded) nên vùng $4018-$401F và $4020-$FFFF trống hoàn toàn cho Game Pak. Mapper có thể đặt thanh ghi ghi ở $4018-$401F an toàn nhưng không nên đặt thanh ghi đọc vì xung đột bus khi DMA (open bus). 22 thanh ghi: $4000 SQ1_VOL: bit7-6 duty (12.5/25/50/75%), bit5 halt/loop, bit4 constant, bit3-0 volume. $4001 SQ1_SWEEP: bit7 enable, bit6-4 period, bit3 negate, bit2-0 shift. $4002 SQ1_LO: 8 bit thấp period Pulse1. $4003 SQ1_HI: bit7-3 length load, bit2-0 period cao. $4004-$4007 SQ2 tương tự Pulse1. $4008 TRI_LINEAR: bit7 control, bit6-0 linear counter. $4009 unused. $400A TRI_LO, $400B TRI_HI: period 11-bit + length. $400C NOISE_VOL, $400D unused, $400E NOISE_LO (loop/period), $400F NOISE_HI (length). $4010 DMC_FREQ: bit7 IRQ, bit6 loop, bit3-0 freq index. $4011 DMC_RAW: DAC 7-bit. $4012 DMC_START: addr = $C000+$40*$xx. $4013 DMC_LEN: len = $10*$xx+1 byte =128*$xx+8 samples. $4014 OAMDMA: ghi $xx copy 256 byte $xx00-$xxFF vào OAM qua $2004, tốn 513 cycles (+1 nếu bắt đầu ở odd get cycle thành 514). $4015 SND_CHN: ghi enable bit4 DMC bit3 Noise bit2 Tri bit1 P2 bit0 P1; đọc status bit7 DMC IRQ bit6 Frame IRQ bit4-0 channel active. $4016 JOY1: ghi strobe, đọc data tay 1 (shift 8 bit A,B,Select,Start,Up,Down,Left,Right). $4017 JOY2: ghi Frame Counter (bit7 IRQ inhibit, bit6 mode 4-step/5-step), đọc data tay 2. $4018-$401A là APU test (CPU Test Mode, chỉ mở khi test), $401C-$401F là tàn dư IRQ timer 16-bit chưa hoàn thiện, luôn vô hiệu. Đọc vùng này trả open bus. 3. Tần số Master và khác biệt NTSC/PAL/Dendy: Master =6fsc. fsc NTSC 3579545.45Hz (315/88MHz), Master 21.477272MHz; fsc PAL 4433618.75Hz, Master 26.601712MHz. Divisor d: NTSC 12, PAL 16, Dendy 15. CPU=6fsc/d: NTSC 1.789773MHz (559ns), PAL 1.662607MHz (601ns), Dendy 1.773448MHz (564ns). Nintendo giữ chia 16 cho PAL do Johnson counter chẵn, Dendy chọn 15 để tương thích game đếm chu kỳ như VRC4/MMC3, Balloon Fight. Bảng PPU/CPU: Master clocks per dot: NTSC 4, PAL/Dendy 5. Dots per CPU: NTSC 3, PAL 3.2, Dendy 3. Cycles/scanline 341 dots: NTSC 113 2/3, PAL 106 9/16, Dendy 113 2/3. HBlank 85 dots: NTSC 28 1/3, PAL 26 9/16. Picture: NTSC 240 (visible 224), PAL 239 (visible 268). Post-render: NTSC 1, PAL 1, Dendy 51. VBlank sau NMI: NTSC 20 lines (~2273c), PAL 70 (7459c). Chỉ ghi OAM: NTSC trong VBlank/forced blanking, PAL chỉ 24 lines đầu sau NMI (2557c). Tổng dots/frame: NTSC 89341.5 (341*261+340.5, pre-render ngắn 0.5 dot ở frame lẻ), PAL 106392 (341312). Cycles/frame: NTSC 29780.5 (89341.5/3) nếu render bật ở line 20, không thì 29780 2/3, PAL 33247.5 (106392/3.2), Dendy 35464 (106392/3). Frame rate: NTSC 60.0988Hz, PAL 50.007Hz. Border: NTSC đen $0E, PAL màu $3F00. Emphasis PPUMASK: NTSC Blue D7 Green D6 Red D5, PAL hoán đổi Red D6 Green D5. Emulator nên chạy NTSC ở 21441960Hz = (341262-0.5)460 để khóa 60fps. 4. Instruction Timings: Quy tắc nhớ: - Tối thiểu 2c/lệnh. - Mỗi byte fetch +1c. - Mỗi byte memory access +1c. - Indexed vượt trang +1c. - RMW +1c do dummy write. - Push +1c, Pop +2c (pre-increment SP). RTS +1c increment PC. Ví dụ: SEC 2c1b, AND #imm 2c2b, LDA zp 3c2b, STA abs 4c3b, LDA abs,X 4/5c3b, STA abs,X 5c luôn worst, ASL zp 5c2b, LDA (ind),Y 5/6c2b, STA (ind),Y 6c, PHA 3c1b, RTS 6c1b. Giả định: không page wrap khi branch (wrap +1c mỗi vòng), không NMI/IRQ xen vào, DMA có thể steal cycle phải bù. 5. Short Delays và Clockslide: Không có lệnh 1c nên delay lẻ phải ghép: 2c: NOP EA 1b. 3c: JMP *+3 4C 3b không relocatable; BCC *+2 cần biết Carry; BIT/LDA/LDX/LDY zp 2b clobber; IGN zp 04/34 NOP đọc zp không chính thức. 4c: NOPx2. 5c: CLC+BCC 18 90 00 clobber C, CLV+BVC clobber V. 6c: NOPx3. 7c: PHP 08 +PLP 28 2b ghi stack hiệu quả, PLA+PHA clobber A nhưng giữ stack khi IRQ. 8c: NOPx4. 9c: NOP+PHP+PLP. 10c: PHP+CMP+PLP. 12c: JSR @rts12 20 xx xx +RTS 60 (cần addr chứa $60) ghi 2 byte stack, hoặc ROL $36,X+ROR $36,X clobber ZN. Clockslide tạo delay 1c/byte bất kể entry chẵn/lẻ bằng giải mã chồng. Ví dụ CMP #$C9: dãy C9 C9 C9 C9 C5 EA từ byte0 là CMP #$C9+CMP #$C9+CMP $EA =6b7c, lệch 1 byte thành CMP #$C9+CMP #$C5+NOP =5b6c. Điều khiển entry bằng JMP indirect hoặc RTS Trick (push entry-1 rồi RTS). Thay $C9 bằng $89/$80 và $C5 bằng $04/$44/$64 để tạo clockslide trong suốt không hỏng cờ. 6. Delay Code tham số hóa Inline: - 2-3c r+2: bne. - 4-5c r+4: ora #0/cmp/cpx rồi bne. - 4-5c X+4: dex bpl. - 5-7c A+5 0≤A≤2: beq lsr bne / cmp #1 bcc bne / dex bmi bne. - 6-9c A+6 0≤A≤3: beq lsr beq bcs. - 7-10c A+7: lsr beq bpl bcs. - 8-11c X+8: dex bmi dex bmi bne. - 9-14c A-242 (251-255,C0): adc #3 bcc lsr beq lsr bcs core 5c. - 10-14c X+10: cpx #3 bcc bne dex bmi bne. - 11-19c A+11: lsr bcs adc #255 beq bcc lsr beq bcc bne. - 12-23c A+12: lsr bcs lsr bcc bcs beq lsr bcs +delay_n5 (inc $00 5c). - 15-270c A+15 0-255: sec sbc #5 bcs loop bóc 5c/vòng +core 9-14c, bản inline của delay_a_27. - 16-271c A+16: cmp #9 bcc sbc #9 bcs loop bóc 9c +core A+7. - 5-65285c 256X+5: txa beq nop tya ldy #48 dey48 bne tay dex jmp (clobber A) hoặc giữ A bằng cpx pha. - 18-218103813c 13*(65536Y+256A+X)+18: iny nop nop cpx #1 dex sbc #0 bcs dey bne rts, vòng 3 cấp Y-A-X mỗi vòng 13c. 7. Callable Functions (đã tính JSR6+RTS6=12c): - A+25c clobber A,ZNV,C: cmp #7 bcs sbc #7 loop, lsr bcs beq lsr beq bcc bne rts, bóc 7c/vòng, entry không đầu hàm nên chỉ dùng như hàm. - A+27c: sec sbc #5 bcs +core 9-14c, bọc inline 15-270c, entry đầu hàm nên nối tiếp được. - 256*A+X+33c: cmp #1 bcs sbc #1 pha lda #(256-27-16) jsr delay_a_27 pla txa. - 256*A+16c: cmp #0 bne rts pha tya ldy #46 loop 246+346 nop tay pla sec sbc #1 jmp, 251c/256. - 256*X+16c: tương tự clobber X,Y giữ A, bản gọn ldy #50 nếu được clobber Y. - 256*X+A+30c: cpx #0 beq delay_a25 pha lda #... jsr delay_a25 pla dex jmp, có bản ghép trực tiếp. - 851968Y+3328A+13X+30c: iny nop nop cpx #1 dex sbc #0 bcs dey bne rts, bọc inline 13... 8. Fixed Cycle Delay 2-50c tối ưu: Phân loại mode: implied 1b2c TAX/NOP, push 1b3c PHA, pop 1b4c PLA, return 1b6c RTS, imm 2b2c CMP, branch 2b2-4c BCC 3c taken 2c not (+1 cross không dùng), zp 2b3c LDA, zp RMW 2b5c INC, zp indexed 2b4c/6c, ind indexed 2b6c/8c SLO ($ptr,X) rẻ nhất 8c2b khi X=0, absolute jump 3b3c JMP, abs RMW 3b6c INC $4018, abs indexed RMW 3b7c INC $4018,X. Ví dụ chọn lọc: 2c EA, 3c C5 C5 CMP/BIT/LDA hoặc 4C JMP, 4c NOPx2, 5c 18 90 00 CLC+BCC, 6c NOPx3, 7c 08 28 PHP+PLP, 8c NOPx4, 15c PHP+TSX+PLP+TXS, 21c LDX #4 DEX BNE, 24c LDA #$0A BPL, 27c BIT <$2C+LDX #253 INX BNE, 50c LDA #$E9 ROL BCC với NOP xen. Dùng macro CA65 branch_check (assert >*== >dest) với bccnw/bcsnw/beqnw... để đảm bảo branch không cross page tại compile time. 9. Emulator một file C: Struct rp2a03_t {A,X,Y,S,P,PC; uint64_t cycles; ram[2048]; io[32]; oam[256]; joy[2],strobe,shift[2]; bool nmi,irq;} Bảng opcode 256 {len,cycles,mode,exec();}. Hàm read/write xử lý mirror $0000-$1FFF, PPU $2000-$3FFF, I/O $4000-$4017, test $4018-$401F ignore, cart $4020-$FFFF callback. step() fetch-decode-execute chính xác cycle với page cross +1, RMW dummy write, branch Taken3 Not2, DMA OAM 513/514 và DMC steal 4c, frame counter 4/5-step. Tham số hóa divisor 12/16/15 và dots per cpu 3/3.2 để chạy NTSC/PAL/Dendy, run_frame() đúng 29780.5c. Dùng delay routines và clockslide để verify với blargg cpu_timing/ppu_timing. Biên dịch gcc -std=c99 -o nes rp2a03_single.c chạy ngay, đủ cho raster split và PCM qua $4011. Viết nó thành 1 file C DUY NHẤT để emu RP2A03

Response not available

Drag to resize
Drag to resize