Java untuk Playstation 2 - apakah mungkin?

gambar

Pendahuluan


Dengan proyek ini saya ingin menjawab satu pertanyaan: apakah mungkin untuk menulis Java API untuk Playstation 2 dan membuat demo grafis di atasnya. Saya tidak ingin mengungkapkan spoiler, tetapi jawabannya adalah ya.

Beberapa tahun yang lalu, saya memulai proyek Java Grinder yang menerima file Java .class yang dikompilasi dan benar-benar berfungsi sebagai disassembler. Tetapi alih-alih membongkar menjadi kode assembler Java, itu membongkar menjadi kode sumber assembler untuk prosesor nyata. Jika file kelas membutuhkan file kelas lain, maka mereka juga dibaca dan diproses. Semua panggilan metode API ditulis ke output, baik sebagai kode assembler bawaan, atau sebagai panggilan ke fungsi pra-tertulis yang melakukan tugas yang dimaksud.

Karena Java Grinder ditulis dalam bahasa C ++, berorientasi objek, abstrak, polimorfik, dan banyak lagi profil HR favorit lainnya, untuk mengembangkannya, terutama diperlukan untuk membuat kelas Playstation2, memperluas kelas R5900 baru, memperluas kelas Generator utama.

Hasilnya, proyek itu ternyata lebih besar dari yang saya harapkan. Sistemnya sendiri cukup sederhana, tetapi saya masih harus banyak belajar, dan menemukan informasi yang berkualitas tidak begitu sederhana. Bahkan, untuk pertama kalinya dalam proyek ini, saya mengambil pemrograman 3D nyata. Di posting lain, saya sudah berbicara tentang apa yang saya pelajari di halaman Pemrograman Playstation 2 saya.

Di bawah ini adalah video dan penjelasan rinci tentang proses pengembangan.

Video



Saya merekam demo pada PS2 slim dengan menghubungkan kabel audio dan video ke DVD burner. Saya agak khawatir bahwa PS2 memiliki semacam perlindungan Macrovision yang akan merusak sinyal video, tetapi entah dimatikan atau perekam DVD mengabaikannya. Video dimulai dengan demonstrasi Playstation 2 nyata, yang menjalankan demo. Konsol terhubung ke konverter sinyal ke VGA, terhubung ke layar LCD, membuktikan bahwa demo berjalan pada mesin nyata. Kemudian saya menambahkan perekatan dengan video nyata yang direkam langsung dari PS2 dalam perekam DVD.

YouTube: https://youtu.be/AjM069oKUGs

Proyek serupa di mikekohn.net


Java Grinder:Playstation 2 Java ,
Sega Genesis Java ,
Apple IIgs Java ,
TI99 / 4A Java ,
C64 Java ,
dsPIC Mandelbrots ,
Atari 2600 Jawa ,
chipKIT Java ,
Java Grinder ,
naken_asm

Demo


Mengingat demo Sega Genesis Java , saya sedikit menyesal bahwa saya tidak membuatnya lebih menarik. Maka lebih menarik bagi saya untuk menunjukkan kemampuan Java API. Ketika saya memulai proyek ini, saya memutuskan untuk melakukan sesuatu yang lebih serius. Sayangnya, saya sekali lagi sangat lelah dalam proses mempelajari sistem dan membuat API sehingga saya tidak memiliki kekuatan yang cukup untuk demo besar.

  • 3 Billion Devices Logo: Ini adalah 3 miliar perangkat beresolusi rendah yang menjalankan logo Java yang dibuat oleh Joe Davisson untuk demo Commodore 64 Java-nya .
  • Logo: Saya menggambar mereka dengan spidol dan memindai mereka (dengan pengecualian logo Java).
  • Bintang: Saya benar-benar menyalin kode dari demo Sega Genesis Java dan memodifikasinya agar berfungsi dengan Playstation 2 API. Teks di sini juga ditulis dengan spidol dan dipindai.
  • Mandelbrot fractals: mereka ditunjukkan menggunakan unit vektor 0, yang menghitung fraktal, dan unit vektor 1 melakukan perhitungan 3D. MIPS mengontrol apa yang dilakukan kedua perangkat vektor.
  • Kubus: Saya menggambar kubus ini di Wings3d dan menulis kode C untuk mengkonversi file STL ke array yang dapat digunakan Java Grinder . Saya menambahkan warna secara manual.
  • Cincin kotak: hanya upaya untuk menggambar banyak objek bergerak di layar. Mungkin perlu menambahkan lebih banyak objek sebelum sistem mulai melambat.

Musik


Untuk demo, saya membuat dan merekam tiga lagu, tetapi sebagai hasilnya saya hanya menggunakan dua lagu. Komposisi pertama sebenarnya adalah melodi yang saya tulis untuk proyek lain yang diterbitkan di situs web saya ( proyek akseptor koin ) sekitar setahun yang lalu ... awalnya hanya ada satu bagian. Setelah proyek selesai, saya pikir akan menarik untuk menempatkan solo gitar di atasnya, dan setelah merekam, saya membayangkan bahwa musik ini diputar sementara bintang-bintang terbang dalam demo. Saya berhasil menggunakannya hanya setelah beberapa bulan. Gitar dalam komposisi adalah Fender Strat I bergigi .

Saya mencatat komposisi kedua hanya sehari sebelum publikasi artikel. Gitar solo terdengar agak ... mabuk karena dimainkan pada gitar yang saya ubah menjadi fretless . Saya tidak pandai memainkannya, dan nada tinggi memudar dengan sangat cepat, tetapi slide terdengar cukup keren. Bagian ritmik dimainkan pada kit calon Yngwie saya (Squier Strat yang bergigi murah, overdrive DOD YJM308 dan Mini-Marshall ditenagai oleh baterai 9-volt).

Saya memprogram drum untuk kedua komposisi menggunakan program Drums ++ yang ditulis lama. Ia menerima input file teks yang direkam dalam bahasa saya sendiri, dan mengubahnya menjadi file .mid, yang saya impor ke Apple Garage Band, setelah itu Anda dapat merekam track base dan gitar. File sumber fretless.dpp dan shoebox.dpp ada di folder aset repositori demo saya.

Musik diputar oleh Playstation 2 SPU2, dan berkat R5900, ia dapat melakukan pekerjaan lain. Karena kurangnya dokumentasi yang baik, saya hampir menyelesaikan demo tanpa musik sama sekali. Lebih lanjut tentang ini di bawah ini.

Berikut adalah dua lagu dalam format MP3:


Pengembangan


Proyek ini telah dikembangkan sejak lama. Saya mulai menambahkan instruksi Mesin Emosi R5900 ke assembler MIPS di naken_asm , kemudian masuk untuk instruksi floating point dan instruksi unit makro / mikro vektor. Membuat jeda besar untuk bekerja pada proyek-proyek lain, saya mempelajari semua aspek lain yang diperlukan untuk demo ini, dan melanjutkan untuk menambahkan dukungan mereka ke Java Grinder . Jika seseorang tertarik pada detail level rendah, maka saya membuat halaman di mana saya mencoba mendokumentasikan semua informasi yang dikumpulkan: Pemrograman Playstation 2 .

Saya terutama diprogram menggunakan emulator PCXS2 . Cukup nyaman, karena di dalamnya saya bisa memeriksa register dan sejenisnya di layar. Tapi jelas tidak sefleksibel dan sesederhana MAME saat mengembangkan Sega Genesis . Misalnya, dalam MAME lebih mudah untuk memeriksa memori, dan RAM, dan register video / audio untuk memastikan Java Grinder berfungsi dengan baik.

Ketika bekerja dengan kode untuk Sega, saya membuat satu kesalahan - saya tidak mengujinya di mesin sampai demo ditulis. Setidaknya ada tiga keanehan dalam kode Sega yang diabaikan oleh emulator, tetapi mereka tidak menyukai mesin asli. Kali ini, setelah menulis masing-masing bagian dari kode, saya mengujinya pada mesin nyata, sehingga setelah demo selesai bekerja pada peralatan nyata dan emulator. Saya kembali menemukan hal-hal yang bekerja di emulator, tetapi tidak memulai pada PS2 nyata. Saya juga menemukan bahwa itu bekerja pada Playstation 2 nyata, tetapi itu tidak berfungsi dengan baik di emulator.

Fitur API


  • Unit Vector 0 memiliki metode untuk memuat / menjalankan kode dan memuat / membongkar data.
  • Unit Vektor 1 melakukan rotasi dan proyeksi 3D.
  • Tekstur menggunakan format 16- atau 24-bit (transparansi ditunjukkan dalam warna hitam).
  • Tekstur dalam format 16-bit dapat dikodekan RLE.
  • Kode untuk menggambar titik, garis, segitiga, dengan dan tanpa tekstur.
  • Kabut dan naungan oleh Guro.
  • Metode untuk mengakses generator nomor acak.
  • Menggunakan dua konteks (mengganti halaman)
  • Masukkan data biner besar ke dalam kode assembler terkompilasi.
  • Memutar musik.

API


Bagian utama API diatur dalam kelas Playstation2 . Awalnya, saya akan memberinya kebebasan besar - kemampuan untuk mengatur mode video dan sejenisnya, tapi kemudian saya pikir mungkin lebih baik untuk menyembunyikan semua kesulitan ini. Pada dasarnya, itu hanya mengatur tampilan 640x448 interlaced. Seperti proyek Java Grinder lainnya, saya pada dasarnya menambahkan metode / fitur yang diperlukan.

Ada satu set kelas yang saya beri nama membosankan Draw3D . Pada intinya, mereka mendefinisikan semua jenis primitif yang dapat dihasilkan Graphics Synthesizer dengan dukungan untuk tekstur 16-, 24- dan 32-bit. Saya berpikir untuk menambahkan tekstur 8-bit, tetapi memutuskan untuk belum melakukannya. Draw3D menyediakan rotasi 3D, proyeksi, transfer perangkat keras DMA, tekstur, dll. Anda mungkin akan bertanya mengapa saya tidak membuatnya berdasarkan OpenGL, tetapi saya belum pernah bekerja dengan OpenGL sebelumnya. Sekali waktu saya terlibat dalam pemrograman ps2dev sederhana, tetapi tidak ada yang serius di sana dan saya hampir tidak ingat proyek itu, jadi saya ulangi - kita dapat berasumsi bahwa ini adalah pertama kalinya saya melakukan sesuatu yang serius dalam 3D.

Ada contoh menggunakan semua hal ini, tidak hanya di demo, tetapi juga di folder sampel .
Hampir semua kesulitan disembunyikan di API. Pengembang tidak perlu khawatir tentang menghapus cache, tentang komputasi 3D, dll. Namun, pengembalian untuk ini adalah penurunan fleksibilitas. Oleh karena itu, jika, misalnya, tekstur diubah oleh prosesor, tetapi hanya 64 piksel pertama yang berubah, maka Anda hanya perlu menghapus satu baris cache 64-byte, tetapi Java Grinder menghapus seluruh gambar. Ini menandai objek, oleh karena itu mereka dibersihkan hanya jika perlu, tetapi membersihkan seluruh fragmen memori. Dengan probabilitas tinggi ketika mengubah 64 byte, seluruh gambar juga berubah.

Unit Vektor 0 (VU0)


Pengguna Java Grinder bebas menggunakan VU0. Saya menggunakan bagian demo yang disebut "Dua Unit Vektor, Satu MIPS" untuk membuat fraktal Mandelbrot. Kode dapat dioptimalkan dengan lebih baik, misalnya, sebagian besar instruksi unit floating point vektor memiliki waktu berjalan 1 dan latensi 4. Sejauh yang saya mengerti, ini berarti bahwa jika register adalah target untuk instruksi, maka dapat dieksekusi dalam 1 siklus, tetapi untuk agar hasilnya tersedia, diperlukan 4 siklus. Jika register ini digunakan, maka unit vektor akan tetap menganggur sampai siap. Oleh karena itu, idenya adalah Anda perlu mengatur instruksi sehingga Anda dapat menjalankan setiap instruksi dalam 1 siklus tanpa downtime. Ketika saya membuat fraktal Mandelbrot di Playstation 3 tahun lalu, saya mengoptimalkan kode ini sambil secara bersamaan menghitung 8 piksel (2 register SIMD), sambil memperhatikan peningkatan kecepatan yang besar. Dalam kasus saat ini, saya mencoba membuat kode lebih mudah dibaca, jadi saya tidak repot dengan optimasinya.

VU0 hanya berisi 4 KB memori data, dan Anda tidak akan menulis seluruh gambar fraktal di sana, jadi MIPS mengirimkan koordinat hanya 1/8 gambar pada satu waktu.

Keanehan yang saya temui ketika bekerja dengan VU0: Saya awalnya menjalankan kode VU0 menggunakan instruksi dan menggunakan VIF0_STAT untuk memverifikasi penyelesaian eksekusi mereka. Tampaknya VIF0_STAT tidak berfungsi jika Anda tidak memulai VU0 dengan paket VIF. Ini diperbaiki di emulator, tetapi kesalahannya masih di perangkat keras nyata. Akibatnya, saya menemukan bahwa vcallms dan menggunakan cfc2 di register 29 berfungsi di kedua kasus.

Sepertinya saya bahwa set instruksi unit vektor tidak memiliki instruksi perbandingan paralel yang ditemukan pada Intel X86_64, Playstation 3, dan bahkan set instruksi MIPS R5900 Emotion Engine. Fraktal mandelbrot harus secara iteratif menghitung rumus sampai hasilnya lebih unggul, jadi dengan serangkaian instruksi yang berbeda, saya hanya akan melakukan perbandingan paralel yang akan membuat masker untuk semua biner 1 atau 0. Topeng dapat digunakan untuk menghentikan kenaikan penghitung warna. Untuk Playstation 2, saya harus mendapatkan formula yang sangat aneh, yang cukup dekat dengan rumus fraktal. Saya mendokumentasikan ini dalam kode sumber mandelbrot_vu0.asm sesuai dengan komentar Python.

Saya merasa keren di perangkat unit vektor konsol Playstation 2 yang sangat bagus bahwa saya belum pernah melihat set instruksi SIMD lain di mana semua instruksi FPU dapat memiliki atribut .xyzw memberi tahu instruksi mana dari empat angka floating-point yang dimilikinya. mempengaruhi. Artinya, jika saya membutuhkan hasil instruksi untuk mempengaruhi hanya komponen-x dari vektor, maka saya hanya akan menambahkan .x di akhir instruksi. Hal lain yang menarik adalah bahwa itu adalah satu set instruksi VLIW, yaitu, dalam setiap siklus, dua instruksi dieksekusi secara bersamaan. Sebenarnya, modul ini lebih seperti DSP daripada prosesor tujuan umum.

Unit Vektor 1 (VU1)


VU1 dicadangkan oleh Java Grinder untuk melakukan rotasi, gerakan, dan proyeksi 3D. Objek Draw3D diteruskan ke VU1 menggunakan metode draw (), yang menggunakan assembler unit vektor untuk mengonversi titik dan mentransfernya ke Graphics Synthesizer. Kode assembler di VU1 bisa jauh lebih baik dioptimalkan untuk kecepatan, tetapi cocok untuk tujuan saya, jadi saya memutuskan untuk membiarkan kode mudah dibaca (tidak dioptimalkan).

Untuk mempelajari rumus proyeksi dan belokan, saya menggunakan Wikipedia: proyeksi dan belokan .

Kode transformasi 3D juga ada di repositori naken_asm sebagai file .asm: rotasi_vu1.asm sederhana.

MIPS R5900


Saya tidak terlalu suka set instruksi MIPS sampai saya mulai mengerjakan proyek ini. Bahkan, cukup mudah untuk bekerja dengan CPU ini. Versi Emotion Engine CPU ini memiliki fitur yang sangat nyaman. Paling khusus, register adalah 128 bit, tetapi pada kenyataannya mereka hanya digunakan untuk memuat / penyimpanan dan SIMD. Pada kenyataannya, ini adalah register 128-bit, 64-bit ALU dan pointer 32-bit.

Dimungkinkan juga untuk memperkenalkan optimasi ke dalam kode MIPS utama, tetapi saya tidak melakukan ini untuk menjaga keterbacaan kode atau karena kurangnya waktu. Sebagai contoh, CPU MIPS menganggur untuk satu siklus jika register instruksi target digunakan segera setelah pengaturannya. Perilaku ini bisa diperbaiki.

Hacks Java


Java Grinder sendiri juga memiliki ... keanehan, tetapi ada sesuatu yang hilang, terutama karena saya awalnya bertujuan pada MSP430 dan sebagian besar merupakan percobaan. Salah satu elemen yang hilang adalah ketidakmampuan untuk mengalokasikan memori untuk objek. Saya menambahkan fitur ini di Playstation 2 untuk membuat instance banyak objek, terutama menggunakan Draw3D API. Saya tidak menulis pengalokasi memori atau pengumpul sampah, jadi semua panggilan baru dilakukan di stack. Saya berpikir untuk mengimplementasikan sesuatu seperti pengalokasi memori yang dinamis, tetapi pada akhirnya saya memutuskan untuk tidak mempersulitnya. Saya juga menambahkan dukungan tambahan Playstation 2 untuk angka floating point (mengambang) (sebagian dukungan ini masih dalam kode Epiphany / Parallella). Beberapa hal lain, seperti tipe panjang dan ganda, masih belum didukung.

Mungkin hal yang paling menyebalkan yang saya lakukan adalah terkait dengan pembatasan mengerikan dari file kelas Java. Metode Java tidak boleh lebih besar dari 64K jika saya ingat dengan benar. Mungkin ini normal, tetapi masalah muncul ketika ada array statis di file kelas dan tidak membuang ke file kelas sebagai data biner. Itu ditempatkan di file kelas sebagai instruksi assembler Java dalam initializer statis untuk membuat array. Saya mencoba untuk menyimpan gambar ke file kelas sebagai array byte statis [], tetapi beberapa di antaranya tidak cocok, jadi saya menambahkan metode ke file kelas Memory Java Grinder :

byte[] Memory.preloadByteArray(String filename); 

Itu tidak mengunduh file ini saat runtime, tetapi mengunduhnya saat membangun menggunakan direktif .binfile naken_asm . Gambar disalin ke biner keluaran selama perakitan.

Dengan semua ini dalam pikiran, saya sangat berharap bahwa James Gosling tidak akan pernah tersandung pada proyek saya.

Gambar


Draw3D API dapat menggunakan tekstur 16-, 24- dan 32-bit. Pixel tekstur dapat diatur piksel demi piksel atau dengan memuat menggunakan array byte []. Saya juga menambahkan kemampuan untuk RLE-kompres gambar dalam format {length, lo16, hi16}, di mana lo16 dan hi16 adalah warna 16-bit dalam format endian kecil, yang disalin ke waktu "panjang" tekstur.

Alat-alatnya


Ketika bekerja pada Sega untuk membuat alat untuk membuat gambar, musik, dan sejenisnya, saya menggunakan bahasa Google Go, hanya untuk belajar bahasa baru. Kali ini saya mencoba Rust. Alat pertama mengkonversi binari ke kode sumber Java, dan yang kedua mengubah BMP ke format biner, yang dapat dimuat ke dalam tekstur, termasuk dalam format RLE. Akibatnya, saya menulisnya dengan Python, kalau-kalau ada yang mau bergabung dengan saya membuat demo.

Suara


Setelah menemukan cara kerja perangkat grafik dan vektor, langkah terakhir adalah suara. Saya pikir itu akan menjadi bagian yang paling mudah, terutama setelah mempelajari PDF dengan deskripsi Sony SPU2. Betapa salahnya saya. Bagian dari sistem ini sangat buruk didokumentasikan.

Hal pertama yang saya temukan adalah bahwa SPU2 (unit pemrosesan suara) terhubung ke IOP (prosesor I / O, alias prosesor Playstation 1). CPU Playstation 2 terhubung ke IOP ini melalui sesuatu yang disebut SIF. PDF Sony hanya menyebutkan SIF DMA, tetapi tidak mengatakan apa-apa tentang penggunaannya.

Akibatnya, saya menolak untuk menggunakan SIF, tetapi memutuskan untuk menambahkan tautan ke naken_asm sehingga saya bisa menggunakan kernel.a dari PS2DEV SDK. Linker diterima, tetapi gagal.

Pada tahap ini, saya sudah memutuskan bahwa saya tidak bisa mendapatkan suara untuk bekerja, dan saya hanya ingin menyelesaikan demo tanpa itu. Tapi itu menyiksaku, jadi aku memutuskan untuk melihat kode sumber berbagai emulator Playstation 2 untuk memahami cara kerja SIF. Akhirnya, saya menemukan cara untuk langsung mengakses memori dari kode MIPS R3000 di IOP dan menjalankannya (ada contoh di folder sampel repositori naken_asm). Saya berhasil membuat suara bekerja di emulator.

Pada akhirnya, saya menemukan bahwa memori TIO (termasuk SPU2) terletak di ruang Mesin Emosi, jadi saya berusaha keras (dokumentasinya sangat kecil dan tidak ada satu pun emulator yang diimplementasikan sepenuhnya dengan benar, tetapi tidak masalah bagi mereka untuk bekerja ), Saya belajar bekerja dengan suara.

Perbandingan emulator dan besi


Saya menemukan beberapa perbedaan antara eksekusi pada mesin nyata dan dalam sebuah emulator.

  • Jika paket GIF menetapkan register PRIM kedua nilai IIP (metode shading), dan bit FIX semuanya 1, maka emulator memperhitungkan bit IIP dan melakukan shading Gouro, sementara peralatan nyata melakukan shading datar.
  • Jika paket GIF ditransmisikan melalui PATH3 (EE langsung ke GS), dan bendera EOP (akhir paket) tidak disetel, maka jika VU1 mencoba mengirim paket GIF melalui PATH 1 (VU1 ke GS), ini akan menyebabkan hang di perangkat keras nyata, tetapi akan bekerja di emulator.
  • Melewatkan membersihkan cache CPU sebelum transfer DMA tidak diperlukan, tetapi pada mesin nyata menyebabkan perilaku aneh.
  • Saat menempatkan SPU2 di ruang EE, emulator dapat dengan mudah merekam data audio dalam FIFO SPU2. Pada Playstation 2 yang sebenarnya, setelah merekam 32 kata, perlu untuk menulis ke register untuk memberikan perintah untuk menghapus FIFO. Juga, pada perangkat keras nyata, ketika mengatur transmisi / mulai alamat SPU2, mode transmisi harus diatur ke 0. Emulator tidak peduli jika mode memiliki nilai 0.
  • Menulis TIO dari EE ke register memori yang dialokasikan crash pada mesin nyata, meskipun itu dalam mode kernel. Emulator memungkinkan operasi seperti itu bekerja terlepas dari mode CPU saat ini.
  • Menggunakan saluran DMA SIF bekerja di emulator, tapi saya masih belum bisa membuatnya bekerja pada peralatan nyata. Saya mendapatkan kesalahan akses memori untuk register SIF DMA bahkan dalam mode kernel.
  • Emulator terlalu lambat untuk menjalankan demo ketika menghitung fraktal menggunakan VU0, sehingga suara tidak sinkron.

Untuk meringkas


Saya ingin menulis beberapa program untuk Playstation 2 hampir sejak saat pembelian. Sebenarnya, saya sudah memiliki kit Linux untuk PS2 untuk waktu yang lama (saya pikir itu sebabnya saya membeli Playstation 2), dan saya bahkan mencoba bekerja dengan perpustakaan PS2DEV di C, tetapi ini adalah pengalaman yang sangat berbeda dibandingkan dengan pemrograman dalam bahasa assembly secara langsung untuk besi.

Saya harus berterima kasih kepada Lukash karena menyimpan kode sumber assembler lama dan dokumen PS2. Tidak yakin apakah saya bisa memulai tanpa demo Duke 3 Star, yang membantu saya menginisialisasi peralatan. Saya juga berterima kasih kepada para pengembang emulator PCSX2 , yang sangat mempercepat proses debugging. Selain itu, saya tidak dapat menemukan suara jika saya tidak melihat kode sumber emulator dan tidak mengerti apa yang salah.

Dan terima kasih kepada Sony untuk komputer kecil yang cantik ini. Jika seseorang dari Sony membaca artikel ini, inilah tipnya: mengapa tidak menyusutkan ke ukuran Rapsberry Pi dan menjualnya sebagai papan untuk proyek hobi? :)

Bangun demo


git clone https://github.com/mikeakohn/playstation2_demo.git
git clone https://github.com/mikeakohn/java_grinder.git
git clone https://github.com/mikeakohn/naken_asm.git
cd naken_asm
./configure
make
cd ..
cd java_grinder
make java
make
cd ..
cd playstation2_demo
make

Source: https://habr.com/ru/post/id423751/


All Articles