3.Khái quát về máy PlayStation
PlayStation (một số dịch phẩm Việt văn gọi là “trạm chơi” ) là tên của một loại máy chơi game, cũng là thương hiệu đã cầu chứng của hãng Sony. Những thông tin chung chung về hệ máy này thì người đọc có thể tự tìm hiểu qua Google chấm com, còn ở đây chỉ nói những nét khái quát từ khía cạnh kỹ thuật (liên quan đến hack dịch game) của nó.
Hai đặc điểm lớn nhất của PSX so với các thế hệ máy chơi game trước đó như Famicom, Super Famicom (Nintendō), Mega Drive (Sega),… là khả năng lưu trữ lớn do sử dụng công nghệ ổ đĩa CD-ROM/XA với khả năng lưu trữ dữ liệu (khác) và âm thanh trên cùng một đĩa, thay vì sử dụng cardtridge. Khả năng diễn toán của PSX lớn hơn nhiều vì sử dụng bộ vi xử lý
32 bit (sẽ đề cập bên dưới) nên đưa tới hiệu quả hình ảnh, âm thanh tốt hơn các hệ máy trước đó.
Vào cuối thập niên 80, công nghệ CD-ROM đã xuất hiện trên thị trường, nhưng ứng dụng còn chậm chạp, thì đến thập niên 90 của thế kỷ trước, Sony đã có một bước đi đúng với công nghệ này khi cho ra đời máy PSX. Xét từ khía cạnh lưu trữ dữ liệu, nếu máy Famicom và Super Famicom sử dụng cardtridge để lưu trữ hết các file cần thiết của game vào “một cục”, với dung lượng hết sức hạn chế (cao nhất là 48
Megabit đối với Super Famicom), thì công nghệ CD cho phép lưu trữ dữ liệu lên đến 660
Megabyte, và các file cần thiết để chạy game không bị dồn chung “một cục” mà được lưu trữ riêng biệt trên các sector. Dĩ nhiên trong thực tế, nhiều nhà sản xuất dùng giải thuật nén, mã hóa nên khi mở CD-ROM ra thì chỉ thấy 01 file duy nhất. Và cũng hiếm có game nào trên PSX sử dụng hết 660 Mb của đĩa. Chính vì từng file riêng biệt nên game PSX luôn tồn tại một thành phần quan trọng, gọi là “Table of Contents” (tạm dịch là mục lục nội dung) hay gọi tắt là TOC. Đây là thành phần ghi (đăng ký) nơi bắt đầu của các file nội dung. Nắm rõ thành phần này là một yếu tố quan trọng trong việc hack dịch game PSX, vì ta sẽ cần đến, thay đổi, đăng ký lại TOC trong trường hợp muốn mở rộng thêm dung lượng của bản dịch.
Đặc điểm thứ hai của PSX là khả năng diễn toán lớn. Sở dĩ được như vậy vì máy PSX sử dụng bộ vi xử lý R3000A 32 bit, ngôn ngữ lập trình MIPS với khả năng thực hiện hàng triệu lệnh mỗi giây. Tương đồng với PSX còn có máy Nintendō 64 (N64) với bộ vi xử lý R4000i, với khả năng diễn toán tốt hơn và nhiều lệnh hơn PSX một tí.
Ta hay nghe cụm từ “hệ điều hành 32 bit”, “hệ điều hành 64 bit”, Windows 32 bit,… Thực chất, đó chính là sức chứa của các Register của bộ vi xử lý. Có thể nói Register là hạch tâm của CPU. Đó là một phần của bộ vi xử lý, một vùng để lưu trữ bất cứ loại dữ liệu nào, bao gồm cả lệnh thực thi. Register là khu vực có thể viết (ghi) tự do giống như Ram, và có cấu tạo cho phép ghi nhanh chóng vì thường xuyên được sử dụng đến.
Bản thân từ “Regist” có nghĩa là “lưu trữ”, và “Register” mang nghĩa là thứ, đồ để lưu trữ thứ gì đó. Trong ngôn ngữ Assembly thì khi nói đến “lưu trữ thứ gì đó”, thì đó là lưu trữ giá trị.
Register của máy PSX có sức chứa 32 bit, có nghĩa là nó có khả năng lưu trữ, diễn toán dữ liệu trong phạm vi từ $00000000 cho đến $FFFFFFFF.
Ta cũng thường nghe cụm từ “đồ họa 8 bit”, hay “âm thanh 8 bit” khi nói đến hình ảnh và âm thanh của máy Famicom, hay “có vẻ giống” Famicom. Sở dĩ gọi như vậy là vì máy Famicom sử dụng Register chỉ có sức chứa 8 bit, nên chỉ có khả năng diễn toán trong phạm vi từ $00 cho đến $FF, hay 256 byte về độ rộng. Chính vì vậy nên hình ảnh và âm thanh của Famicom bị mất đi rất nhiều so với mong muốn của nhà lập trình. Còn máy Super Famicom sử dụng bộ vi sử lý 650C816 với Register 16 bit, gấp đôi so với Famicom nên hình ảnh và âm thanh trung thực, chi tiết hơn Famicom rất nhiều, nhưng kém hơn PSX với Register 32 bit.
Ngoài ra, cũng cần biết thêm PSX có Ram chính lên đến 2Mb và 1Mb cho Vram (Video ram). Hình ảnh hiển thị của PSX là 4:3, thích hợp với Tivi thời đó, với màn hình gần như là hình vuông, so với tỷ lệ 16:9 của màn hình Tivi bây giờ (thời điểm 2015). Độ phân giải của PSX thường là 256x240, 364x240, 320x240, 640x480. Độ phân giải tùy thuộc vào từng game, hệ màu của game. Nhìn chung ít có game nào lên đến 640x480 như Bloody Roar, còn đa phần game NTSC đều có độ phân giải 320x240, bao gồm cả FF9.
4.Ngôn ngữ Assembly
Assembly, viết tắt là Asm, dịch Việt văn là “hợp ngữ” hay đôi khi còn gọi nôm na là “ngôn ngữ máy”, là loại ngôn ngữ cấp thấp (bậc thấp) mà máy tính (không phải “máy vi tính”) có thể hiểu được và thực thi. Ngôn ngữ bậc cao (cấp cao) là ngôn ngữ mà con người có thể hiểu được dễ dàng, như Pascal, C,… Nhưng máy tính không thể hiểu được những loại ngôn ngữ này, vì vậy nên cần phải dịch code viết từ các loại ngôn ngữ cấp cao này sang ngôn ngữ cấp thấp để máy tính có thể thực hiện. Mỗi loại máy tính đều có cấu trúc khác nhau, nên chúng sử dụng ngôn ngữ Asm khác nhau. Chẳng hạn Famicom dùng ngôn ngữ 650C, Super Famicom dùng 650C816, PSX dùng MIPS,…
Thực chất, máy tính là loại thiết bị ngu đần gần nhất quả Đất. Nó không thể hiểu bất cứ thứ gì khác ngoài con số “0” và con số “1”, tương đương với hai trạng thái “tắt” và “mở” của bóng đèn. Do vậy, để yêu cầu tên đầy tớ ngu đần này làm việc thì ông chủ (con người) rất khổ sở. Thay vì nói
“Phát cho tao tiếng bíp” thì người chủ phải nói “0100010011100011000110”,
thay vì nói “tăng độ sáng cho màn hình lên mức 2” thì phải nói “1101101010100010101000101010101”, vân vân.
Nhưng nếu chủ mà nói chỉ toàn “0” và “1” như vậy thì chắc thà đập đầu vào tường, cắn lưỡi tự sát còn sướng hơn. Hai người nước khác nhau, không hiểu tiếng của nhau còn có thể ra hiệu, chỉ trỏ, dùng ánh mắt để truyền đạt cho nhau hiểu. Nhưng máy tính thì không có tay chân, mắt mũi lưỡi mồm, hay bất cứ thứ gì khác ngoài “0” và “1” trong bộ não lợn của nó.
Chính vì khổ còn hơn con chó như vậy nên người chủ mới cần đến người hùng Assembly, biệt danh là Asm. Thực chất anh chàng này làm nghề phiên dịch, vì có thể hiểu được cả tiếng người lẫn tiếng của thằng đần máy tính.
Chẳng hạn, đối với máy tính thì “100010” nghĩa là “nói to lên”, thì Asm sẽ dùng các chữ cái NTL để giúp con người hiểu được, “100100001010111” nghĩa là “cho mày nghỉ ngơi” thì Asm dùng các chữ cái CMN để diễn đạt cho người hiểu, “1100100101” nghĩa là “cút mẹ mày đi!” thì Asm dùng các chữ CMM.
Do đó, nếu người chủ muốn yêu cầu với máy tính “nói to lên”, rồi “cho mày nghỉ ngơi”, sau đó là “cút mẹ mày đi!” thì sẽ nhờ Asm bằng cách nói
NTL
CMN
CMM
Thì lúc này Asm sẽ dịch sang ngôn ngữ của máy là
100010
100100001010111
1100100101
để máy tính thực hiện tuần tự các mệnh lệnh của ông chủ.
Chính vì vậy nên có thể nói, Asm điều khiển tất cả mọi thứ mà máy tính thực hiện. Có bao giờ bạn đọc tự hỏi bên trong file .EXE là thứ gì? Nó là Asm.
Để giúp người đọc hình dung một cách cụ thể hơn về Asm, dưới đây là một đoạn mã trong game Mario trên máy Super Famicom với ngôn ngữ 65816. Phần bên tay trái, màu đỏ là lệnh, bên tay mặt, màu đen là comment (giải thích).
Dcb “INIT” Routine mở đầu
LDA#$00 Tải giá trị “0” vào Register A
STA $0DBF Ghi giá trị trong Register A vào vị trí $0DBF trong Ram
LDA#$00 Tải giá trị “0” vào Register A
STA$0FB3 Ghi giá trị của Register A (đang là 0) vào vị trí $0FB3
RTL Trở về Routine chính
Đoạn chương trình này cho thấy, giá trị ban đầu tại vị trí $0DBF trong Ram là 0, và địa chỉ này quản lý số đồng tiền của Mario. Tương tự, giá trị ban đầu của địa chỉ $0FB3 là 0, và địa chỉ này quản lý số mạng bonus của Mario. Như vậy, qua đoạn này ta thấy ban đầu Mario được cấp cho 0 đồng cắc và 0 mạng bonus.
Dcb “MAIN” Routine chính
INC$0DBF Tăng giá trị tại $0DBF lên 1 đơn vị
LDA$0DBF Tải giá trị tại $0DBF vào Register A
CMP#$64 So sánh giá trị trong Register A với 100
BEQ LABEL Nếu so sánh bên trên có kết quả bằng (=) thì nhảy sang Routine LABEL
LDA$0DBF Tải giá trị tại $0DBF vào Register A
BEQ LABEL2 Nếu so sánh bên trên có kết quả bằng (=) thì nhảy sang Routine LABEL2
RTL
Qua đoạn này ta thấy, số đồng cắc được tăng lên 1, và đến khi đạt giá trị 100 thì máy sẽ nhảy sang Routine LABEL và LABEL2.
LABEL
LDA#$00 Tải giá trị 0 vào Register A
STA $0DBF Ghi trá trị của Register A (đang là 0) và $0DBF
RTL
Qua Routine này, ta thấy giá trị tại $0DBF, địa chỉ quản lý số đồng cắc, bị chuyển về 0.
LABEL 2
INC$0FB3 Tăng giá trị tại địa chỉ $0FB3 lên 1 đơn vị
RTL
Qua Routine này, ta thấy số mạng bonus của Mario được tăng thêm 1.
Như vậy, qua cả 4 Routine là INIT, MAIN và LABEL và LABEL2 thì hiểu được ban đầu Mario có 0 đồng cắc. Mỗi khi Mario “ăn” thì số cắc tăng thêm 1, cho đến khi đạt 100 cắc thì số này chuyển về 0, và Mario được thêm 1 mạng bonus. Cho nên, nếu muốn hack sao cho Mario chỉ cần “ăn” 3 cắc là được thưởng 1 mạng thì chỉ cần sửa dòng
CMP#$64 thành CMP#$03 là được.
※
Trong ví dụ trên, LDA#$00 là cách viết theo lối phiên dịch của Asm, còn thực ra máy tính (bộ vi xử lý) sẽ hiểu là $A9 $00. Hay theo hệ nhị phân là 10101001 và 0. Trong đó $A9 được gọi là opcode (gọi tắt của operation code) còn $00 là tham số của opcode $A9. Tham số này được gọi bằng thuật ngữ operand. Bản thân opcode chỉ là con số, nên rất khó nhớ. Vì thế người ta thay bằng 3 chữ cái LDA (Load Accumulator) cho dễ nhớ, và những chữ cái đại diện cho opcode như vậy được gọi Mnemonic (nghĩa là hỗ trợ cho bộ nhớ).
※
Mỗi hệ máy khác nhau dùng mỗi kiểu ngôn ngữ Asm khác nhau. Bản thân các ngôn ngữ này cũng khác nhau như tiếng Việt khác tiếng Anh, khác tiếng Đức. Mỗi loại có những đặc điểm riêng mà chỉ có học mới biết. Nhưng khi đã nắm được một ngôn ngữ rồi thì việc học ngôn ngữ khác cũng khá dễ dàng. Giống như khi đã học được tiếng Phạn thì việc học tiếng La Tinh cũng khá nhẹ nhàng.
5.Debugger
Debugger bản thân nó là một phần mềm giả lập kèm theo chức năng Debug. Nó cho phép người dùng theo dõi giả lập (máy) đang thực thi những lệnh nào, Routine nào, và chuẩn bị làm những gì tiếp theo. Debugger cũng có ích trong việc theo dõi Vram, biết được những gì đang hiển thị trên màn hình, chúng được upload lên Vram từ đâu.
Có nhiều loại Debugger cho cùng một hệ máy, và mỗi loại có cách sử dụng khác nhau nhưng tựu trung đều dựa trên nền tảng Asm. Vậy nên để hiểu được Debugger thì cần phải nắm rõ Asm của hệ máy đó.
Sử dụng Debugger là một vũ khí lợi hại trong việc hack game. Cách sử dụng Debugger cũng như tìm chúng ở đâu, người đọc có thể hỏi Google chấm com.
No$psx là một trong số nhiều Debugger cho PSX.
6.Ngôn ngữ MIPS
MIPS là ngôn ngữ Asm của máy PSX. Hiện tại vẫn chưa có tài liệu hoàn chỉnh cho ngôn ngữ này, nhưng vì bộ vi xử lý của PSX cùng hệ với bộ vi xử lý của N64 nên có thể tìm đọc tài liệu Asm của N64 để hiểu được MIPS. Phần này chỉ giới thiệu những nét khái quát nhất về MIPS.
Đầu tiên, để máy thực hiện việc gì đó thì cần phải có chỉ thị, hay lệnh. Lệnh là thứ mà máy dùng để xử lý các giá trị được chứa trong các Register. Như đã nói trên, Register của PSX là 32 bit nên các giá trị này được phép dao động trong khoảng từ 0x00000000 cho tới 0xFFFFFFFF. PSX có tất cả 32 Register, trong đó có 29 Register được sử dụng tự do (từ đây về sau, Register X được viết tắt là rX) vì r0 luôn là 0, r29 lưu trữ offset của Stack pointer và r31 lưu trữ offset đặc biệt.
Mọi chỉ thị, hay lệnh trong MIPS đều là 32 bit, trong đó phần
opcode chiếm 6 bit. Phần opcode này, hay
mnemonic nếu viết theo lối phiên dịch cho người đọc, cho biết rõ tính chất của câu lệnh. Chẳng hạn, trong lệnh “quét nhà 5 phút” thì phần “quét nhà” là tính chất của lệnh, hay opcode, mnemonic, còn “5 phút” là tham số của lệnh, hay
operand.
Nếu ngôn ngữ 65816 có các mnemonic được viết hoa toàn bộ thì các mnemonic trong MIPS đều viết thường.
Phần opcode luôn được đọc đầu tiên, sau đó mới đến phần còn lại của lệnh (tham số). Nhưng vì MIPS dùng lối sắp xếp dữ liệu theo trật tự Little endian nên bộ vi xử lý sẽ đọc một chuỗi liên tiếp 4 byte (hay còn gọi là 1 word) từ byte cuối cùng cho đến byte đầu tiên.
Ví dụ, dưới đây là một đoạn các lệnh trong Ram
00 01 02
03 04 05 06
07 08 09 0A
0B 0C 0D 0E
0F
Khi gặp đoạn dữ liệu này, con chip sẽ đọc
Word1=
03 02 01 00
Word2=
07 06 05 04
Word3=
0B 0A 09 08
Word4=
0F 0E 0D 0C
Trong đó phần bôi vàng là opcode.
Qua đây cũng cần ghi nhớ, PSX đọc giá trị với trật tự đảo ngược theo lối Little endian. Đây cũng là đặc điểm chung của tất cả các máy console mà tôi biết.
MIPS có 3 kiểu lệnh chính, đó là kiểu lệnh J, kiểu lệnh I và kiểu lệnh R. Ở đây giới thiệu sơ qua về lệnh J, hay Jump. Lệnh này cho phép game đọc (nhảy đến) phần khác của code. Các lệnh J đều có đặc điểm là lệnh nằm ngay sau lệnh nhảy sẽ được thực thi ngay sau bản thân lệnh nhảy, rồi mới tới lệnh tại vị trí nhảy đến. Trong các lệnh nhảy, phần opcode 6 bit được đọc trước tiên, sau đó mới đến phần địa chỉ thuộc 26 bit còn lại. Giá trị của 26 bit được nhân với 4 để xác định offset của Ram cần nhảy đến.
Chẳng hạn, có mnemonic j (nhảy đến địa chỉ xác định) với opcode là $08.
Ví dụ dưới đây là một lệnh nhảy
01 02 03 08 là j 0x030201*4 = j 0xC0804
Qua đây cũng cần ghi nhớ, giá trị chia hết cho 4 là một đặc điểm của PSX.
Hai kiểu lệnh còn lại là I (Immediate) và R (Register). Kiểu lệnh I cho phép máy biên tập một Register với một giá trị xác định bởi con số 16 bit. Kiểu lệnh I liên quan đến Load, phân nhánh, điều kiện... Còn kiểu lệnh R cho phép máy biên tập các Register với giá trị được lưu trữ trong Register khác. Kiểu lệnh này liên quan nhiều đến cộng trừ nhân chia, shift byte...
Trên đây là những nét khái quát chung về ngôn ngữ Asm cũng như MIPS Asm. Đây là những kỹ năng lợi hại phục vụ cho việc hack game, dịch game. Người đọc quan tâm có thể tìm hiểu sâu hơn tại Google chấm com.
(còn)