TL; DR
Quale procedura viene seguita quando si selezionano i byte per rappresentare gli opcode? I byte per gli opcode sono scelti casualmente e sono mappati su mnemonici?
Recentemente ho appreso da questo ha risposto che il bytecode di solito consiste di istruzioni che avere un codice operativo, che consiste in un numero fisso di byte e operandi. In particolare questo frammento di maniaco del cricchetto risponde:
The bytecode itself is very often a very simple syntax. Where the first few bytes indicate what operation has to be performed and what operands are needed. The bytecode will be designed so that when reading byte per byte there is a unambiguous interpretation of the instructions.
Ho seguito questo consiglio e ho iniziato a progettare il mio set di istruzioni bytecode. Ma presto ho avuto un problema. Prima di porre la domanda , avevo provato a creare opcode usando metodi come :
# pseudo code
opcodes = {
'PUSH': convertToBytes(5),
'POP': convertToBytes(10),
'ADD': converToBytes(15),
etc...
}
Come puoi probabilmente sapere, nell'esempio precedente ho usato interi che erano multipli di cinque e li ho convertiti in forma di byte. Stavo cercando di creare un modo in cui potevo mappare ordinatamente i miei codici operativi, a qualcosa come numeri interi. Questo, naturalmente, non ha funzionato perché ogni singolo numero è diventato più grande, così ha fatto il numero di byte relativo a ciascun intero. Il che significava che i miei codici operativi sarebbero stati di lunghezza variabile.
Poi ho iniziato a chiedermi se stavo andando in questo modo nel modo sbagliato. Ho fatto qualche ricerca per vedere come altri linguaggi progettano gli opcode.
Ho trovato questa pagina web relativa ai codici operativi della CPU che dicevano:
The x86 CPU has a set of 8-16 bit codes that it recognizes and responds to. Each different code causes a different operation to take place inside the registers of the CPU or on the buses of the system board.
Here are three examples showing the bit patterns of three actual x86 opcodes, each followed by their one or more bytes of operands:
E continua a fare un esempio:
Bit Pattern ; operation performed by CPU
----------- -------------------------------------------------------
1. 10111000 ; MOVe the next two bytes into 16-bit register AX
2. 00000101 ; ...the LSB of the number (goes in AL)
3. 00000000 ; ...the MSB of the number (goes in AH)
1. 00000001 ; ADD to the BX register
2. 11000011 ; ...the contents of the AX register
1. 10001001 ; (2-byte opcode!) MOVe the contents of BX to
2. 00011110 ; ...the memory location pointed to
3. 00100000 ; ...by these last
4. 00000001 ; ...two bytes
Questo mi porta alla mia domanda: Quale procedura viene seguita quando si selezionano i byte per rappresentare gli opcode? . Come nell'esempio precedente, ogni istruzione consiste di un byte. Come, tuttavia, è stato lo schema specifico di un byte selezionato? . I byte per gli opcode sono scelti casualmente e sono mappati su mnemonici? ad esempio:
# pseudo code
opcodes = {
'PUSH': selectRandomByte(),
'POP': selectRandomByte(),
'ADD': selectRandomByte(),
etc...
}
Nota: mi permetta di chiarire: Quando dico opcode, mi riferisco agli opcode trovati in Virtual Machine bytecode , non alla CPU. Mi scuso se non era chiaro prima. L'esempio che ho fornito con i codici opzionali della CPU era solo a scopo illustrativo.
Fonti