Latar Belakang
Saya suka chip 6502 8-bit lama saya. Bahkan menyenangkan untuk menyelesaikan beberapa tantangan di sini di PPCG dalam kode mesin 6502. Tetapi beberapa hal yang seharusnya sederhana (seperti, membaca data atau output ke stdout) tidak perlu rumit untuk dilakukan dalam kode mesin. Jadi ada ide kasar di pikiran saya: Ciptakan mesin virtual 8-bit saya sendiri yang terinspirasi oleh 6502, tetapi dengan desain yang dimodifikasi agar lebih dapat digunakan untuk tantangan. Mulai menerapkan sesuatu, saya menyadari ini mungkin tantangan yang bagus jika desain VM dikurangi seminimal mungkin :)
Tugas
Menerapkan mesin virtual 8-bit yang sesuai dengan spesifikasi berikut. Ini adalah kode-golf , sehingga implementasi dengan byte paling sedikit menang.
Memasukkan
Implementasi Anda harus mengambil input berikut:
Byte tunggal yang tidak ditandatangani
pc, ini adalah penghitung program awal (alamat di memori tempat VM memulai eksekusi,0berbasis)Daftar byte dengan panjang
256entri maksimum , ini adalah RAM untuk mesin virtual (dengan konten awalnya)
Anda dapat mengambil input ini dalam format apa pun yang masuk akal.
Keluaran
Daftar byte yang merupakan isi terakhir RAM setelah VM berakhir (lihat di bawah). Anda dapat berasumsi bahwa Anda hanya mendapatkan input yang pada akhirnya akan berakhir. Format apa pun yang masuk akal diizinkan.
CPU virtual
CPU virtual memiliki
- penghitung program 8-bit,
- register akumulator 8-bit disebut
Adan - register indeks 8-bit disebut
X.
Ada tiga bendera status:
Z- bendera nol ditetapkan setelah beberapa operasi menghasilkan0N- Bendera negatif ditetapkan setelah beberapa operasi menghasilkan angka negatif (iow sedikit 7 dari hasil ditetapkan)C- flag carry diatur dengan penambahan dan pergeseran untuk bit "hilang" dari hasilnya
Setelah mulai, semua bendera dibersihkan, penghitung program diatur ke nilai yang diberikan dan isi dari Adan Xtidak ditentukan.
Nilai 8-bit mewakili keduanya
- sebuah unsigned integer dalam kisaran
[0..255] - a ditandatangani integer, komplemen 2, dalam kisaran
[-128..127]
tergantung pada konteksnya. Jika suatu operasi over atau underflow, nilainya membungkus (dan dalam hal penambahan, flag carry dipengaruhi).
Penghentian
Mesin virtual berakhir ketika
- Sebuah
HLTinstruksi tercapai - Alamat memori yang tidak ada diakses
- Penghitung program berjalan di luar memori (perhatikan itu tidak membungkus bahkan jika VM diberikan 256 byte penuh memori)
Mode adressing
- implisit - instruksi tidak memiliki argumen, operan tersirat
- segera - operan adalah byte langsung setelah instruksi
- relatif - (hanya untuk percabangan) byte setelah instruksi ditandatangani (komplemen 2's) dan menentukan offset untuk ditambahkan ke penghitung program jika cabang diambil.
0adalah lokasi instruksi berikut - absolut - byte setelah instruksi adalah alamat operan
- diindeks - byte setelah instruksi plus
X(register) adalah alamat operan
Instruksi
Setiap instruksi terdiri dari opcode (satu byte) dan, dalam mode pengalamatan segera , relatif , absolut dan diindeks byte argumen kedua. Ketika CPU virtual menjalankan instruksi, itu menambah penghitung program yang sesuai (oleh 1atau2 ).
Semua opcode yang ditampilkan di sini adalah dalam hex.
LDA- muat operan keA- Opcode: langsung:,
00absolut02:, diindeks:04 - Flags:
Z,N
- Opcode: langsung:,
STA- simpanAke dalam operan- Opcode: langsung:,
08absolut0a:, diindeks:0c
- Opcode: langsung:,
LDX- muat operan keX- Opcode: langsung:,
10absolut12:, diindeks:14 - Flags:
Z,N
- Opcode: langsung:,
STX- simpanXke dalam operan- Opcode: langsung:,
18absolut1a:, diindeks:1c
- Opcode: langsung:,
AND- bitwise dan ofAdan operan keA- Opcode: langsung:,
30absolut32:, diindeks:34 - Flags:
Z,N
- Opcode: langsung:,
ORA- bitwise atau dariAdan operan keA- Opcode: langsung:,
38absolut3a:, diindeks:3c - Flags:
Z,N
- Opcode: langsung:,
EOR- bitwise xor (eksklusif atau) dariAdan operan keA- Opcode: langsung:,
40absolut42:, diindeks:44 - Flags:
Z,N
- Opcode: langsung:,
LSR- Pergeseran logis ke kanan, geser semua bit operan satu tempat ke kanan, bit 0 pergi untuk dibawa- Opcode: langsung:,
48absolut4a:, diindeks:4c - Flags:
Z,N,C
- Opcode: langsung:,
ASL- Aritmatika bergeser ke kiri, menggeser semua bit operan satu tempat ke kiri, bit 7 pergi untuk membawa- Opcode: langsung:,
50absolut52:, diindeks:54 - Flags:
Z,N,C
- Opcode: langsung:,
ROR- Putar ke kanan, geser semua bit operan satu tempat ke kanan, carry pergi ke bit 7, bit 0 pergi ke carry- Opcode: langsung:,
58absolut5a:, diindeks:5c - Flags:
Z,N,C
- Opcode: langsung:,
ROL- Putar ke kiri, geser semua bit operan satu tempat ke kiri, bawa pergi ke bit 0, bit 7 pergi untuk membawa- Opcode: langsung:,
60absolut62:, diindeks:64 - Flags:
Z,N,C
- Opcode: langsung:,
ADC- tambahkan dengan carry, operan plus carry ditambahkan keA, carry diset pada overflow- Opcode: langsung:,
68absolut6a:, diindeks:6c - Flags:
Z,N,C
- Opcode: langsung:,
INC- operan kenaikan satu- Opcode: langsung:,
78absolut7a:, diindeks:7c - Flags:
Z,N
- Opcode: langsung:,
DEC- operan decrement oleh satu- Opcode: langsung:,
80absolut82:, diindeks:84 - Flags:
Z,N
- Opcode: langsung:,
CMP- bandingkanAdengan operan dengan mengurangi operan dariA, lupakan hasil. Carry dibersihkan saat underflow, atur sebaliknya- Opcode: langsung:,
88absolut8a:, diindeks:8c - Flags:
Z,N,C
- Opcode: langsung:,
CPX- bandingkanX- sama sepertiCMPuntukX- Opcode: langsung:,
90absolut92:, diindeks:94 - Flags:
Z,N,C
- Opcode: langsung:,
HLT-- mengakhiri- Opcode: tersirat:
c0
- Opcode: tersirat:
INX- selisihXsatu- Opcode: tersirat:
c8 - Flags:
Z,N
- Opcode: tersirat:
DEX- penguranganXsatu per satu- Opcode: tersirat:
c9 - Flags:
Z,N
- Opcode: tersirat:
SEC- atur flag carry- Opcode: tersirat:
d0 - Bendera:
C
- Opcode: tersirat:
CLC- Membawa bendera yang jelas- Opcode: tersirat:
d1 - Bendera:
C
- Opcode: tersirat:
BRA- cabang selalu- Opcode: relatif:
f2
- Opcode: relatif:
BNE- Cabang jikaZbendera dibersihkan- Opcode: relatif:
f4
- Opcode: relatif:
BEQ- cabang jikaZflag diatur- Opcode: relatif:
f6
- Opcode: relatif:
BPL- Cabang jikaNbendera dibersihkan- Opcode: relatif:
f8
- Opcode: relatif:
BMI- cabang jikaNflag diatur- Opcode: relatif:
fa
- Opcode: relatif:
BCC- Cabang jikaCbendera dibersihkan- Opcode: relatif:
fc
- Opcode: relatif:
BCS- cabang jikaCflag diatur- Opcode: relatif:
fe
- Opcode: relatif:
Opcode
Perilaku VM tidak terdefinisi jika ada opcode ditemukan yang tidak memetakan ke instruksi yang valid dari daftar di atas.
Sesuai permintaan Jonathan Allan , Anda dapat memilih set opcodes Anda sendiri alih-alih opcode yang diperlihatkan di bagian Instruksi . Jika Anda melakukannya, Anda harus melakukannya menambahkan pemetaan penuh ke opcodes yang digunakan di atas dalam jawaban Anda.
Pemetaan harus berupa file hex berpasangan <official opcode> <your opcode>, misalnya jika Anda mengganti dua opcode:
f4 f5
10 11
Baris baru tidak masalah di sini.
Test case (opcodes resmi)
// some increments and decrements
pc: 0
ram: 10 10 7a 01 c9 f4 fb
output: 10 20 7a 01 c9 f4 fb
// a 16bit addition
pc: 4
ram: e0 08 2a 02 02 00 6a 02 0a 00 02 01 6a 03 0a 01
output: 0a 0b 2a 02 02 00 6a 02 0a 00 02 01 6a 03 0a 01
// a 16bit multiplication
pc: 4
ram: 5e 01 28 00 10 10 4a 01 5a 00 fc 0d 02 02 d1 6a 21 0a 21 02 03 6a 22 0a 22 52
02 62 03 c9 f8 e6 c0 00 00
output: 00 00 00 00 10 10 4a 01 5a 00 fc 0d 02 02 d1 6a 21 0a 21 02 03 6a 22 0a 22 52
02 62 03 c9 f8 e6 c0 b0 36
Saya mungkin menambahkan lebih banyak testcases nanti.
Referensi dan pengujian
Untuk membantu dengan eksperimen sendiri, berikut ini beberapa implementasi referensi (yang sama sekali tidak golf) - ia dapat menampilkan informasi penelusuran (termasuk instruksi yang dibongkar) kestderr dan mengonversi opcode saat berjalan.
Cara yang disarankan untuk mendapatkan sumber:
git clone https://github.com/zirias/gvm --branch challenge --single-branch --recurse-submodules
Atau checkout cabang challengedan lakukan agit submodule update --init --recursive setelah kloning, untuk mendapatkan sistem build kustom saya.
Bangun alat dengan GNU make (ketik saja make, atau gmakejika di sistem Anda, make default bukan GNU make).
Penggunaan :gvm [-s startpc] [-h] [-t] [-c convfile] [-d] [-x] <initial_ram
-s startpc- penghitung program awal, default ke0-h- input dalam hex (jika tidak biner)-t- lacak eksekusi kestderr-c convfile- Mengonversi opcodes sesuai dengan pemetaan yang diberikan diconvfile-d- dump memori yang dihasilkan sebagai data biner-x- dump memori yang dihasilkan sebagai hexinitial_ram- Konten RAM awal, baik hex atau biner
Perhatikan bahwa fitur konversi akan gagal pada program yang memodifikasi opcodes saat menjalankan.
Penafian: Aturan dan spesifikasi di atas adalah otoritatif untuk tantangan, bukan alat ini. Ini terutama berlaku untuk fitur konversi opcode. Jika menurut Anda alat yang disajikan di sini memiliki bug yang terkait dengan spesifikasi, silakan laporkan dalam komentar :)
BRA("cabang selalu") tidak memperkenalkan cabang dalam aliran kontrol, bukankah seharusnya disebut JMP?
BRAada dalam desain chip kemudian (6502 tidak memiliki instruksi seperti itu) seperti 65C02 dan MC 68000. JMPada juga. Perbedaannya adalah yang BRAmenggunakan pengalamatan relatif dan JMPmenggunakan pengalamatan absolut. Jadi, saya hanya mengikuti desain ini - memang, itu tidak terdengar masuk akal;)