Dec 22, 2023
Un linguaggio assembly letterato
Una recente edizione di The Chip Letter [di Babbage] discute l'oscurità del linguaggio assembly. Sottolinea, e penso correttamente, che il linguaggio assembly viene più spesso letto che scritto, ma quasi
Una recente edizione di The Chip Letter [di Babbage] discute l'oscurità del linguaggio assembly. Sottolinea, e penso correttamente, che il linguaggio assembly è più spesso letto che scritto, ma quasi tutti sono ostacolati dall'oscurità rimasta dai giorni in cui le schede perforate avevano 80 colonne e un simbolo di sei lettere era tutto ciò che potevi gestire. nello spazio di memoria limitato del computer. Ad esempio, senza cercarlo, cosa fa l'istruzione ARM FJCVTZS? Il nome completo dell'istruzione è Converti Javascript in virgola mobile in arrotondamento a virgola fissa con segno. Non molto utile.
Ma mi è venuto in mente che nulla ti impedisce di scrivere un assembler competente che sia reso più facile da leggere. Innanzitutto, la maggior parte dei compilatori C accetterà una sorta di istruzione asm e probabilmente potresti gestirla con la costruzione di stringhe e le macro in fase di compilazione. Tuttavia, penso che ci sia una possibilità migliore.
Dato che a volte sviluppo nuove architetture di CPU, ho un cross assembler universale che, onestamente, è un brutto hack, ma funziona abbastanza bene. Ne ho già parlato in precedenza, ma se non vuoi leggere l'intero post a riguardo, utilizza alcuni semplici trucchi per convertire formati di linguaggio assembly dall'aspetto standard in codice C che viene poi compilato. L'esecuzione del programma risultante produce il linguaggio macchina desiderato nel formato di file desiderato. È molto semplice da configurare e nel mezzo c'è un simpatico programma C che emette codice macchina. Non è molto più leggibile dell'assembly grezzo, ma non dovresti vederlo. Ma cosa succederebbe se iniziassimo il processo da lì e rendessimo leggibile il formato?
Al centro del sistema c'è un programma C che risiede in soloasm.c. Gestisce le opzioni della riga di comando e la generazione di file di output. Chiama una funzione esterna, genasm, con un singolo argomento intero. Quando l'argomento è impostato su 1, indica che l'assembler è al primo passaggio e devi solo compilare i valori dell'etichetta con numeri reali. Se il passaggio è 2, significa effettivamente compilare l'array che contiene il codice.
Tale array è definito nell'istruzione __solo_info (soloasm.h). Include la dimensione della memoria, un puntatore al codice, la dimensione della parola del processore, gli indirizzi iniziale e finale e un flag di errore. Normalmente, il sistema converte l'input del linguaggio assembly in una serie di chiamate di funzione che scrive all'interno della funzione genasm. Ma in questo caso, voglio riutilizzare soloasm.c per creare un linguaggio assembly competente.
Ho scritto tutto questo molto tempo fa, ma volevo che la creazione di assembly letterati fosse più semplice, quindi ho deciso di eseguire una conversione a C++ con poco sforzo. Ciò consente, ad esempio, di utilizzare belle strutture dati per la tabella dei simboli. Tuttavia, non ho utilizzato tutte le funzionalità C++ che potevo avere, semplicemente nell'interesse del tempo.
La classe base è ragionevolmente indipendente dal processore e, come esempio, ho fornito un assemblatore RCA 1802 competente. Solo una prova di concetto, quindi probabilmente potrei nominare le istruzioni in modo un po' più coerente, e c'è molto spazio per altri miglioramenti, ma fa capire il mio punto.
Ecco un estratto di un programma di luci lampeggianti scritto per il 1802 utilizzando la sintassi assembler standard:
Ora ecco esattamente lo stesso scritto per l'assemblatore letterato:
Bene, è vero, ci sono commenti e simboli, ma comunque. Puoi scaricare entrambi i file se vuoi confrontarli. Puoi anche trovare l'intero progetto online.
L'idea è semplice. Ogni funzione popola semplicemente un array con il byte o i byte necessari. Certo, il 1802 è piuttosto semplice. Sarebbe più difficile farlo per un processore moderno con molte istruzioni e modalità complesse. Ma non impossibile.
Puoi fare molte cose per semplificarti la vita, sia durante la programmazione che durante l'impostazione delle istruzioni. Ad esempio, se volessi 100 istruzioni NOP, potresti scrivere:
for (int i = 0 ; i < 100 ; i++) NOP();
D'altra parte, NOP ha un argomento facoltativo che lo farà per te. Puoi utilizzare liberamente il compilatore C++ e il preprocessore delle macro per semplificarti la vita. Ad esempio, un'attività comune sul 1802 è inserire un valore costante come un'etichetta in un registro. Il file lit1802.h ha una macro per semplificare questa operazione: