Setelah beberapa saat, saya menjadi akrab dengan sistem benteng sod32 yang ditulis oleh Lennart Benschop . Sistem benteng ini memiliki mesin virtual yang ditulis dalam C, dan citra biner yang dimuat ke dalam mesin virtual tidak bergantung pada urutan byte dalam sistem host kata. sod32 memiliki 32 primitif, ini dia:
NOOP
( --- )
Do nothing
SWAP
( x1 x2 --- x2 x1 )
Swap the two top items on the stack.
ROT
( x1 x2 x3 --- x2 x3 x1 )
Rotate the three top items on the stack.
0=
( x --- f)
f is true if and only if x is 0.
NEGATE
( n1 --- -n1)
Negate top number on the stack.
UM*
( u1 u2 --- ud )
Multiply two unsigned numbers, giving double result.
C@
( c-addr --- c)
Fetch character c at c-addr.
@
( a-addr --- x)
Fetch cell x at a-addr.
+
( w1 w2 --- w3)
Add the top two numbers on the stack.
AND
( x1 x2 --- x3)
Bitwise and of the top two cells on the stack.
OR
( x1 x2 --- x3)
Bitwise or of the top two cells on the stack.
XOR
( x1 x2 --- x3)
Bitwise exclusive or of the top two cells on the stack.
U<
( u1 u2 ---- f)
f is true if and only if unsigned number u1 is less than u2.
<
( n1 n2 --- f)
f is true if and only if signed number n1 is less than n2.
LSHIFT
( x1 u --- x2)
Shift x1 left by u bits, zeros are added to the right.
RSHIFT
( x1 u --- x2)
Shift x1 right by u bits, zeros are added to the left.
UM/MOD
( ud u1 --- urem uquot)
Divide the unsigned double number ud by u1, giving unsigned quotient and remainder.
+CY
( n1 n2 cy1 --- n3 cy2)
Add n1 and n2 and the carry flag cy1 (must be 0 or 1) giving sum n3 and carry flag cy2. (n3 cy2 can be seen as a double number)
SCAN1
( x d --- u)
Scan x for the first 1 bit. u is the position of that bit (counted from the scan direction) and 32 if x=0. d is the scan direction, 0 is left-to-right, 1 is right-to-left.
SPECIAL
( x ---)
Any of a large number of special instructions, indicated by x.
DROP
( x ---)
Discard the top item on the stack.
>R
( x ---)
Push x on the return stack.
C!A
( c c-addr --- c-addr)
Store character c at c-addr, keep address.
!A
( x a-addr --- a-addr)
Store cell x at a-addr, keep address.
DUP
( x --- x x )
Duplicate the top cell on the stack.
OVER
( x1 x2 --- x1 x2 x1)
Copy the second cell of the stack.
R@
( --- x)
x is a copy of the top of the return stack.
R>
( --- x)
Pop the top of the return stack and place it on the stack.
0
( --- 0)
The constant number 0.
1
( --- 1)
The constant number 1.
4
( --- 4)
The constant number 4.
LIT
( --- lit)
Push literal on the stack (literal number is in-line).
Saya menyadari bahwa saya memiliki kesempatan untuk menemukan jawaban atas pertanyaan saya dan saya mulai mengubah primitif menjadi definisi tingkat tinggi. Saya ingin langsung menunjukkan bahwa semua kegiatan ini memiliki makna akademis semata. Hal ini tidak mungkin untuk menerapkan hasil yang diperoleh dalam praktek karena hilangnya kinerja. Saat saya bereksperimen, saya melacak ukuran biner sistem benteng dan runtime dari rangkaian pengujian John Hayes. Saya membangun gambar biner baru dengan perintah
echo 'S" extend-cross.4" INCLUDED '|./sod32 kernel.img
dan menjalankan tes seperti ini:
time ./sod32 kernel.img <<< $(echo -e 'S" tester.fr" INCLUDED\n12345\nBYE')
Pada tabel di bawah, Anda dapat melihat bagaimana setiap perubahan memengaruhi ukuran dan kinerja. Tautan dari kolom "ubah" mengarah ke komit yang sesuai di github.
| perubahan | ukuran kernel.img | tester waktu eksekusi.fr |
| sod32 asli | 10164 | 0m0.059s |
| lshift, rshift | 10312 | 0m0.071s |
| +, um *, um / mod | 11552 | 0m0.123s |
| c @, c! a | 11952 | 0m0.795s |
| 0 =, meniadakan <, u < | 12340 | 0m2.800s |
| penurunan | 12784 | 0m5.022s |
| tukar, busuk, ganti | 13436 | 0m5.860s |
| sp @, sp!, rp @, rp!, dup | 13680 | 0m8.696s |
| r @, r>,> r | 14160 | 0m15.463s |
| dan, atau, xor | 14336 | 0m21.198s |
| 0, 1, 4 | 15236 | 0m21.671s |
| 0branch | 15912 | 0m41.765s |
Akibatnya, ukuran citra biner sistem benteng meningkat dari 10164 menjadi 15912 (+ 57%), kinerja turun 708 kali (hampir 3 kali lipat). Mungkin kinerja dapat ditingkatkan dengan membuat profil kode dan mengoptimalkan kemacetan, tetapi saya yakin hasilnya masih akan sangat lambat dibandingkan dengan sod32 asli.
Dengan 32 primitif ditambah logika tambahan di interpreter internal, saya berakhir dengan 7: nop, nand,!, @, Um +, special, lit. Penerjemah internal mempertahankan logika untuk menjalankan definisi primitif dan tingkat tinggi (panggilan), serta logika untuk menyelesaikan definisi tingkat tinggi (berikutnya). Saya menemukan jawaban atas pertanyaan saya: sistem benteng dapat dibangun atas dasar 9 primitif (atau 8, jika nop tidak harus primitif). Saya bingung dengan fakta bahwa ada sebanyak 3 primitif untuk akses memori: @,! dan menyala, tapi saya belum menemukan cara menghindarinya. Saya bisa saja melewatkan sesuatu, jadi jika Anda tahu bagaimana Anda bisa menyingkirkan sejumlah besar primitif, silakan tulis di komentar.