Đi sâu vào kiến trúc CPU HuC6280 của PC Engine (TurboGrafx-16)
Bài viết phân tích chi tiết kiến trúc CPU HuC6280 của hệ máy PC Engine, một bộ vi xử lý 8-bit mạnh mẽ với tốc độ xung nhịp ấn tượng nhưng tập lệnh hạn chế so với các đối thủ 16-bit. Chúng ta sẽ cùng tìm hiểu về khả năng quản lý bộ nhớ, các lệnh chuyển khối dữ liệu mới và lý do tại sao phần cứng này lại thú vị đối với các lập trình viên phát triển trình giả lập.
Gần đây, tôi đã bắt đầu phát triển một trình giả lập (emulator) cho hệ máy PC Engine (còn được biết đến với tên TurboGrafx-16) và nhận thấy phần cứng của nó vô cùng thú vị. Được ra mắt lần đầu vào năm 1987, phần cứng của PC Engine nằm ở một vị thế khá khó xử giữa thế hệ máy chơi game thứ 3 (NES, Sega Master System) và thế hệ thứ 4 (Genesis/Mega Drive, SNES). Tuy nhiên, nhờ khả năng đồ họa vượt trội hẳn so với NES và SMS, nó thường được xếp chung vào nhóm thế hệ sau. Mặc dù bán khá chạy tại Nhật Bản, nhưng tại Bắc Mỹ, hệ máy này khó có thể cạnh tranh với Genesis và Super Nintendo, và thậm chí chưa từng được phát hành chính thức tại Châu Âu. Về mặt lịch sử, PC Engine đáng chú ý vì là hệ máy console đầu tiên hỗ trợ trò chơi trên đĩa CD thông qua phụ kiện CD-ROM2 (hay TurboGrafx-CD).
Bài viết này sẽ đi sâu vào tổng quan về CPU của PC Engine, một điểm thú vị bởi nó có tốc độ rất nhanh so với thời đại của mình nhưng lại có khả năng tập lệnh (instruction set) hạn chế hơn nhiều so với các đối thủ trực tiếp.
Một chiếc 6502 được tăng tốc
Mặc dù có tên gọi TurboGrafx-“16” tại Bắc Mỹ, hệ máy console này thực tế không hề sở hữu một CPU 16-bit! Điều này khác với trường hợp của chip 68000, nơi mọi người thường tranh cãi xem nó là 16-bit hay 32-bit; với PC Engine, đơn giản là không có yếu tố 16-bit nào trong CPU của nó cả. Nó có thanh ghi 8-bit, ALU 8-bit và đường dữ liệu 8-bit. Tuy nhiên, nó cố gắng bù đắp bằng tốc độ xử lý thô.
CPU này là một phần của gói thiết kế tùy chỉnh của Hudson có tên HuC6280, bao gồm cả CPU lõi và một số phần cứng khác như chip âm thanh PSG và bộ hẹn giờ phần cứng. Bản thân CPU dựa mạnh trên 65C02, phiên bản nâng cấp của WDC cho dòng CPU 8-bit huyền thoại 6502. Tập lệnh sẽ trông rất quen thuộc với bất kỳ ai có kinh nghiệm lập trình cho NES (6502 bỏ chế độ BCD) hoặc SNES (65C816, bản mở rộng 16-bit của 65C02), mặc dù nó cũng bổ sung một số lệnh độc quyền dành riêng cho HuC6280.
HuC6280 kế thừa hầu hết các lệnh mới của 65C02 và chế độ địa chỉ mới (gián tiếp trang zero), cùng với các bản sửa lỗi cho một số khía cạnh kỳ quặc của 6502, ví dụ như cách lệnh jmp ($xxFF) sẽ bao quanh trong cùng một trang 256-byte khi đọc địa chỉ nhảy. Ngoài ra, nó cũng không có hành vi opcode bất hợp pháp (illegal opcode) điên rồ như của 6502; CPU PC Engine có 22 opcode chưa sử dụng, nhưng tất cả chúng dường như hoạt động như các lệnh NOP cũ kỹ, thậm chí không có những lệnh NOP đa byte hài hước mà một số opcode bất hợp pháp của 6502 thực hiện.
CPU có thể chạy ở một trong hai tốc độ xung nhịp: “thấp” (~1,79 MHz, giống như NES) hoặc “cao” (~7,16 MHz). CPU luôn khởi động ở tốc độ thấp và các trò chơi có thể chuyển đổi giữa hai tốc độ này bằng các lệnh hướng dẫn CSL (Clock Speed Low) và CSH (Clock Speed High). Theo như tôi biết, không có bất kỳ nhược điểm nào khi chạy ở tốc độ cao 7,16 MHz, vì vậy các trò chơi thường thực hiện ngay lập tức một lệnh CSH và để CPU ở chế độ tốc độ cao.
7,16 MHz là một tốc độ rất nhanh đối với một CPU dựa trên 6502 vào cuối những năm 80 / đầu những năm 90! Tốc độ này gấp đôi tốc độ CPU của SNES, và thậm chí tốt hơn, CPU PC Engine hầu như không bị ảnh hưởng bởi độ trễ bộ nhớ như CPU SNES. Nó chịu một chu kỳ chờ mỗi khi truy cập một trong các cổng bộ xử lý video, nhưng nếu không thì không có độ trễ bộ nhớ nào trong PC Engine — tất cả các vùng ROM và RAM đều có thể phản hồi trong một chu kỳ đồng hồ 7,16 MHz. Trong thực tế, điều này làm cho CPU PC Engine thường nhanh hơn gấp hai lần CPU SNES... miễn là bạn không cần thực hiện bất kỳ phép tính hoặc logic nào trên các giá trị 16-bit.
Về tốc độ thô, PC Engine cũng so sánh khá thuận lợi với CPU 68000 chính 7,67 MHz của Genesis, mặc dù đó là một sự so sánh phức tạp hơn nhiều. 68000 thực hiện ít công việc hơn trên mỗi chu kỳ đồng hồ so với các CPU dựa trên 6502, nhưng nó bù đắp bằng số lượng lớn các thanh ghi 32-bit đa mục đích (đa mục đích ở đây là do sự phân chia thanh ghi dữ liệu/địa chỉ) và tập lệnh mạnh mẽ hơn nhiều. CPU nào sẽ hoạt động tốt hơn phụ thuộc vào mã và cách nó được viết.
Về việc đếm chu kỳ, đáng chú ý là nhiều lệnh HuC6280 mất từ 1 đến 2 chu kỳ lâu hơn so với lệnh tương đương trên 6502 hoặc 65816. Ví dụ, lệnh ADC với địa chỉ tuyệt đối mất 4 chu kỳ trên 6502 nhưng mất 5 chu kỳ trên HuC6280. Ngoài ra, đối với các lệnh mà 6502 có chu kỳ phạt tiềm năng khi vượt trang (ví dụ: các lệnh chỉ mục tuyệt đối), có vẻ như HuC6280 luôn chịu chu kỳ phạt ngay cả khi không có sự vượt trang nào. Điều này có lẽ được thực hiện để dễ dàng hỗ trợ tốc độ xung nhịp cao hơn, hoặc có thể是为了 tiết kiệm chi phí bằng cách chia sẻ nhiều mạch hơn giữa các lệnh khác nhau. Tuy nhiên, đó chỉ là phỏng đoán.
Quản lý bộ nhớ
Phần mềm chạy trên HuC6280 hoạt động trên địa chỉ bộ nhớ 16-bit, giống như phần mềm 6502, nhưng HuC6280 có một MMU tích hợp mở rộng không gian địa chỉ vật lý từ 16-bit lên 21-bit (phạm vi địa chỉ 2 MB). Nó cực kỳ đơn giản xét về khái niệm MMU: nó chia không gian địa chỉ logic 16-bit thành tám trang 8 KB, và mỗi trang có thanh ghi MPR (Memory Page Register) 8-bit riêng của nó, ánh xạ trực tiếp nó đến một trang vật lý 8 KB. Nó rất giống với các bộ mapper chuyển đổi ngân hàng bộ nhớ (memory-banking mappers) được thấy trong nhiều băng đĩa NES / Game Boy / Master System / Game Gear, chỉ khác là nó được tích hợp vào CPU, vì vậy các băng đĩa trò chơi không cần bao gồm phần cứng mapper của riêng mình (mặc dù một trò chơi vẫn làm điều đó do kích thước ROM khổng lồ của nó).
Bản dịch địa chỉ chỉ đơn giản là:
# logical_addr là địa chỉ 16-bit, trả về địa chỉ vật lý 21-bit
def translate_address(logical_addr):
logical_page = logical_addr >> 13
physical_page = MPR[logical_page]
return (physical_page << 13) | (logical_addr & 0x1FFF)
Theo quy ước, các trò chơi PC Engine dường như luôn ánh xạ trang 0 ($0000-$1FFF) vào trang I/O được ánh xạ bộ nhớ ($FF), trang 1 ($2000-$3FFF) vào trang RAM làm việc ($F8), và trang 7 ($E000-$FFFF) vào 8 KB đầu tiên của ROM băng đĩa (trang $00) trong khi tự do ánh xạ lại các trang 2-6 khi cần. Các trò chơi có thể tương tác với tám MPR bằng các lệnh hướng dẫn CPU TAMi (Transfer Accumulator to MPRi) và TMAi (Transfer MPRi to Accumulator).
Trang zero và ngăn xếp phần cứng của HuC6280 nằm tại $2000-$21FF, thay vì $0000-$01FF như trên 6502. Điều này có lẽ là do các trò chơi được mong đợi sử dụng trang $0000-$1FFF hoàn toàn cho I/O được ánh xạ bộ nhớ. Đúng là cái tên “zero page” hơi khó xử khi nó không thực sự nằm ở $0000, nhưng tôi đoán Hudson nghĩ rằng việc sử dụng cùng một thuật ngữ với 6502 sẽ có lợi hơn. Để so sánh, 65816 hỗ trợ di chuyển trang zero, và WDC đã đổi tên nó thành “direct page” như một phần của việc này.
Bản đồ bộ nhớ vật lý của hệ máy khá đơn giản, đơn giản hơn nhiều so với bản đồ bộ nhớ rắc rối của SNES:
| Pages | Mô tả |
|---|---|
| $00-$7F | Băng đĩa trò chơi HuCard hoặc System Card CD-ROM2 |
| $80-$F7 | Mở rộng (được sử dụng bởi phụ kiện CD-ROM2 để thêm RAM) |
| $F8 | 8 KB RAM làm việc |
| $F9-$FB | Mở rộng (được sử dụng bởi SuperGrafx để thêm RAM) |
| $FF | Thanh ghi và cổng I/O được ánh xạ bộ nhớ |
Điều này giới hạn kích thước băng trò chơi ở mức 1 MB, mặc dù Street Fighter II vượt qua giới hạn này bằng một mapper chuyển đổi ngân hàng để quản lý việc truy cập vào ROM khổng lồ 2,5 MB của nó (khổng lồ theo tiêu chuẩn PCE ít nhất). Phiên bản Genesis của Super Street Fighter II cũng tình cờ là trò chơi Genesis được cấp phép chính thức duy nhất có mapper chuyển đổi ngân hàng trong băng đĩa, vì vậy tôi đoán Capcom chỉ sẵn sàng sử dụng phần cứng tùy chỉnh để phát hành các bản port của trò chơi cờ hiệu arcade của họ với lượng ROM bất thường cao.
8 KB RAM làm việc không phải là nhiều! Nó nhiều hơn nhiều so với những gì bạn có được trên NES (2 KB), nhưng bằng với những gì bạn có trên Game Boy gốc và Sega Master System / Game Gear, và ít hơn nhiều so với những gì bạn có trên Genesis (64 KB) hoặc SNES (128 KB). Các bản sửa đổi khác nhau của phụ kiện CD-ROM2 tăng cường điều này bằng cách thêm từ 64 KB đến 2 MB RAM bổ sung, chưa tính đến RAM bộ đệm chip âm thanh. Mặc dù 64 KB thực sự không nhiều sau khi tính đến việc trò chơi CD-ROM2 cần tải mã và tài sản vào RAM rất lâu trước khi sử dụng chúng do độ trễ cực cao khi đọc từ đĩa, trong khi các trò chơi dựa trên HuCard có thể thực thi mã và đọc dữ liệu trực tiếp từ băng đĩa bất cứ lúc nào.
Một số thủ thuật mới
Trong số các lệnh mới, những cái nổi bật nhất là năm lệnh chuyển khối (block transfer): TAI, TDD, TIA, TII và TIN. Tất cả đều làm cùng một việc, sao chép hàng loạt từ một vị trí bộ nhớ này sang vị trí bộ nhớ khác, nhưng mỗi lệnh áp dụng các bước địa chỉ khác nhau cho địa chỉ nguồn và đích. Chúng hơi giống với các lệnh MVN và MVP của 65816 (Move Memory Negative/Positive), nhưng không giống như SNES, PC Engine không có bất kỳ phần cứng DMA nào có thể truy cập ROM băng đĩa hoặc RAM làm việc của CPU, vì vậy các lệnh này thực sự hữu ích trên PC Engine.
| Lệnh | Bước nguồn | Bước đích |
|---|---|---|
| TAI | Xen kẽ | Tăng |
| TDD | Giảm | Giảm |
| TIA | Tăng | Xen kẽ |
| TII | Tăng | Tăng |
| TIN | Tăng | Không (Cố định) |
Các lệnh chuyển khối của HuC6280
“Xen kẽ” (Alternate) thay đổi giữa tăng 1 và giảm 1 sau mỗi byte được sao chép, điều này rất hữu ích cho các bản sao hàng loạt vào và ra khỏi cổng dữ liệu 16-bit của bộ xử lý video.
Các lệnh này sao chép với tốc độ 1 byte mỗi 6 chu kỳ, cộng với chi phí 17 chu kỳ cho mỗi lệnh. Chi phí này không đáng kể nếu bạn sao chép lượng dữ liệu đủ lớn và 6 chu kỳ mỗi byte không cực nhanh nhưng nhanh hơn nhiều so với việc bạn sao chép bằng phần mềm. Một đơn vị DMA phần cứng chuyên dụng có lẽ sẽ nhanh hơn thế này, nhưng trên PC Engine, các lệnh này dường như là cách tốt nhất để sao chép lượng lớn dữ liệu vào VRAM hoặc RAM làm việc.
Một điều cần lưu ý là CPU không thể phản hồi các ngắt (interrupts) khi nó đang ở giữa quá trình chuyển khối. Bạn có thể sao chép lên đến 64 KB trong một lệnh chuyển khối duy nhất và CPU chỉ nhận được khoảng 120.000 chu kỳ mỗi khung hình ở chế độ 7,16 MHz, vì vậy bạn có thể dễ dàng vượt qua nhiều ngắt VBlank nếu bạn thực hiện chuyển khối đủ lớn. Điều này không sao nếu màn hình bị tắt trong quá trình chuyển cảnh màn hình hoặc tương tự, nhưng bạn có lẽ không muốn chạy chuyển khối nhiều khung hình trong quá trình chơi game.
Lệnh mới khác mà tôi nghĩ đáng chú ý là SET (Set T), lệnh này đặt cờ T mới, nhưng chỉ cho lệnh ngay sau nó. Khi được thực thi ngay trước một lệnh ADC, AND, EOR hoặc ORA, lệnh ADC/AND/EOR/ORA sẽ hoạt động trên một giá trị trang zero trong bộ nhớ thay vì hoạt động trên thanh ghi tích lũy, cụ thể là giá trị tại ZeroPage[X]. Điều này hữu ích để thao tác các giá trị trong trang zero mà không cần phải đi qua thanh ghi tích lũy.
Một vài lệnh mới rất đặc thù cho PC Engine: ST0, ST1 và ST2 mỗi lệnh ghi một toán hạng ngay lập tức trực tiếp vào một trong ba cổng VDC (Video Display Controller). Các lệnh này có thể hữu ích để tăng tốc độ mã một chút cập nhật các thanh ghi VDC khác nhau.
Ngoài ra, có một lệnh BSR mới (Branch to Subroutine), hoạt động gần giống hệt như JSR (Jump to Subroutine) ngoại trừ toán hạng là độ lệch tương đối PC thay vì địa chỉ tuyệt đối. Tôi nghĩ lợi ích chính của BSR so với JSR là mã sử dụng BSR không phụ thuộc vào ngân hàng bộ nhớ mà nó được ánh xạ vào, trong khi mã sử dụng JSR yêu cầu nó phải được ánh xạ vào một trang logic 8 KB cụ thể.
TST (Test Bits) giống như các lệnh TRB và TSB của 65C02 (Test and Reset/Set Bits) ngoại trừ việc nó không làm thay đổi giá trị bộ nhớ, chỉ kiểm tra các bit được chỉ định. Có các lệnh hoán đổi mới SAX, SAY và SXY để hoán đổi giá trị giữa hai thanh ghi. Và cuối cùng có các lệnh xóa mới CLA, CLX và CLY để nhanh chóng đưa một thanh ghi về 0 mà không sửa đổi các cờ CPU.
Kết thúc?
Tôi muốn theo dõi bài viết này với các bài viết về các phần khác của phần cứng PC Engine, nhưng chúng ta sẽ xem. Tôi nghĩ phần cứng video thú vị ở cách nó tương phản với phần cứng video của Genesis và SNES nên tôi có lẽ sẽ ít nhất viết một bài về điều đó.
Một số tài liệu tham khảo:
- The HuC6280 CPU: http://shu.emuunlim.com/download/pcedocs/pce_cpu.html
- HuC6280 opcode matrix: https://www.chrismcovell.com/PCEdev/HuC6280_opcodes.html
- TurboGrafx-16 Hardware Notes: https://www.romhacking.net/documents/302/
- PC Engine / TurboGrafx-16 Architecture: https://www.copetti.org/writings/consoles/pc-engine/
Bài viết liên quan

Công nghệ
Tổng hợp thị trường M&A an ninh mạng: 33 thương vụ được công bố trong tháng 4/2026
04 tháng 5, 2026

Công nghệ
Nintendo bất ngờ công bố Star Fox mới cho Switch 2: Bản làm lại hiện đại của huyền thoại không gian
06 tháng 5, 2026

Công nghệ
Nhà xuất bản cáo buộc Mark Zuckerberg cá nhân chỉ đạo vi phạm bản quyền để đào tạo AI Llama
05 tháng 5, 2026
