Personal computer/Linguaggio Macchina/DLX/Operazioni
Formato operazioni
modificaOgni OpCode è composto di 6 bit, ogni indirizzo di 5, mentre i restanti bit sono eventualmente per offset o altri tipi di input. Le tre grandi famiglie di comandi sono:
Formato I: Questo formato è quello utilizzato per ogni operazione con operatori immediati. Come si nota l'offset è di soli 16 bit, il che significa che non si può passare come argomento direttamente un dato a 32 bit, bensì bisogna suddividerlo in due passaggi con in mezzo uno shift di 16 posizioni (un esempio è l'istruzioni LHI)
Formato R: Questo è il formato delle operazioni fra registri. Gli 11 bit finali vengono utilizzati per rendere più specifiche alcune operazioni (ricordiamo che essendoci solo 6 bit per le operazioni, il numero massimo di queste è ).
Formato J: Quest'ultimo è il formato dei salti condizionati o meno.
Operazioni
modifica- Trasferimenti di dati
- LB, LBU, SB Carica un byte, carica un byte senza segno, memorizza un byte
- LH, LHU, SH Carica halfword, carica halfword senza segno, memorizza halfword
- LW, SW Load word, store word (a/da registri integer)
- LF, LD, SF, SD Load SP float, load DP float, store SP float, store DP float (SP - single precision, DP - double precision)
- MOVI2S, MOVS2I Move from/to GPR to/from a special register
- MOVF, MOVD Copy one floating-point register or a DP pair to another register or pair
- MOVFP2I, MOVI2FP Move 32 bits from/to FP tegister to/from integer registers
- Aritmetica/Logica
- ADD, ADDI, ADDU, ADDUI Add, add immediate (tutti gli immediati sono a 16 bit); signed and unsigned
- SUB, SUBI, SUBU, SUBUI Subtract, subtract immediate; signed and unsigned
- MULT, MULTU, DIV, DIVU Multiply and divide, signed and unsigned; Gli operandi devono essere registri Floating-point; Tutte le operazioni richiedono valori a 32 bit e danno come risultato valori a 32 bit.
- AND, ANDI And, And immediate
- OR, ORI, XOP, XOPI Or, or immediate, exclusive or, exclusive or immediate
- LHI Load high immediate - carica nella parte alta del registro il dato immediato
- SLL, SRL, SRA, SLLI, SRLI, SRAI Shifts: sia immediato(S__I) che variabile (S__); gli shift sono Shift Left Logical, Right Logical, Right Arithmetic
- S__, S__I, S__U Set condizionati: "__" può essere LT less than, GT greather than, LE less-equal, GE greater-equal, EQ equal, NE not equal
- Controllo
- BEQZ, BNEZ Branch GPR equal/not equal to zero; 16-bit offset from PC
- BFPT, BFPF Test comparison bit in the FP status register and branch; 16-bit offset from PC
- J, JR Jumps: 26-bit offset from PC(J) or target in register(JR)
- JAL, JALR Jump and link: save PC+4 to R31, target is PC-relative(JAL) ot a register(JALR)
- TRAP Transfer to operating system at a vectored address
- RFE Return to user code From an Exception; restore user code
- Virgola Mobile
- ADDD, ADDF Add DP, numeri SP
- SUBD, SUBF Subtract DP, numeri SP
- MULTD, MULTF Multiply DP, SP floating point
- DIVD, DIVF Divide DP, SP floating point
- CVTF2D, CVTF2I, CVTD2F,
- CVTD2I, CVTI2F, CVTI2D Istruzioni di Conversione: CVTx2y converte dal tipo x al tipo y, dove x e y sono I(Integer), D(Double precision), o F(Single precision). Entrambi gli operandi sono nel registro FP
- __D, __F confronti DP e SP: "__" può essere LT, GT, LE, GE, EQ, NE; impostare il bit di paragone nel registro FP.
Istruzioni aritmetiche e logiche
modificaSono istruzioni a tre operandi, il primo è il registro destinazione, gli altri due registri sorgente
Ad esempio ADD R1, R2, R3 eseguel l'operazione R1 = R2 + R3 ADDI R1, R0, 100 esegue R1 = 100 (R0 vale sempre 0 e non è modificabile) ADD R1, R2, R0 esegue R1 <- R2 (assegna ad R1 il valore di R2)
Le istruzioni di set condizionato ( S__ ) eseguono un confronto tra i due operando sorgente ed assegnano il valore 0 oppure 1 a seconda del risultato del contronto, per cui
SNE R1, R2, R3 assegnerà il valore 1 ad R1 se R2 ed R3 non sono uguali, in caso contrario assegnerà il valore 0
Le operazioni di confronto possono essere eseguite anche tra un registro e un operando immediato
SLTI R1, R2, 10 assegna 1 ad R1 se R2 è più piccolo di 10
o tra operandi senza segno (e non in complemento a due)
SGTU R1, R2, R3 assegna 1 ad R1 se R2 è più grande di R3
Istruzioni di trasferimento dati
modificaDato che il DLX è un Instruction Set R-R prima di utilizzare dei valori presenti in memoria deve copiarli in un registro interno alla CPU per questo motivo esistono operazioni di prelievo e scrittura di dati da e verso la memoria.
Sono istruzioni codificate nel formato I per cui richiedono tre operandi espliciti, nella forma destinazione, offset(registro). L'indirizzo di memoria a cui accedere sarà calcolato come la somma del valore in registro e dell' offset, ad esempio
LW R1, 100(R2) preleva una parola ( Load Word ) di trentadue bit dall'indirizzo di memoria 100 + R2 e la memorizza in R1, operazione che si può anche scrivere come R1 <-32 M[100+R2]
Analogamente SW R1, 20(R3) salverà nell'indirizzo di memoria 20 + R3 la parola (Store Word) contenuta nel registro R1
Istruzioni di trasferimento del controllo
modificaNel DLX queste istruzioni sono di tre tipi:
- Jump Effettua un salto, un trasferimento del controllo, incondizionato
- Jump And Link Trasferisce il controllo salvando l'indirizzo di ritorno nel registro R31 (si parla anche di chiamata a procedura)
- Branch Trasferisce il controllo soltanto dopo aver verificato una condizione ( salto condizionato )
Le istruzioni di Jump e Jump And Link possono essere sia di tipo I che J
Jump con istruzione di tipo I
J R3 Modifica il program counter con il valore del registro R3, PC <- R3
Jump And Link con instruzioni di tipo I
JALR R3 Salva l'indirizzo della prossima istruzione nel registro R31 e assegna al program counter il valore di R3, ovvero R31 <- (PC + 4) ; PC <- R3
Jump con istruzione di tipo J Le istruzioni di tipo J usano un solo operatore di offset da 26 bit
J alfa Salta all'operazione nell'indirizzo di memoria distante alfa dalla prossima istruzione da eseguire, PC <- (PC + 4) + alfa
Jump And Link con istruzione di tipo J
JAL alfa Si comporta come l'operazione di Jump, ma salvando l'indirizzo della prossima istruzione del registro R31, R31 <- (PC + 4); PC <- (PC + 4) + alfa
L'operazione di ritorno da una procedura è
JR R31 Assegna al program counter il valore che un'istruzione di Jump And Link ha memorizzato in R31, PC <- R31
Le operazioni di Branch invece possono essere soltanto di tipo I, l'OP code definisce il tipo di controllo da eseguire prima di effettuare il salto, il primo operatore è il registro su cui fare questo controllo, il secondo è l'offset di 16 bit relativo, come nei casi precedenti, ad program counter, per cui
BNEZ R3, alfa Salta all'istruzione nell'indirizzo di memoria (PC + 4) + l'offset alfa soltanto se R3 non è uguale a zero (Branch Not Equal to Zero), in altri termini if (R3 != 0) : PC <- (PC + 4) + alfa
Esempi di codice in assembler per una macchina R-R
modificaSomma degli elementi di un vettore A di 8 elementi
modificaSe si utilizzano i seguenti registri per
- R1 per la somma corrente
- R2 per l’indice
- R3 per il contatore delle iterazioni
Il codice si può scrivere
ADD R1, R0, R0 ; azzera la somma corrente ADD R2, R0, R0 ; R2 vale indice * 4 (4 e’ numero byte per word) ADDI R3, R0, 8 ; inizializza il contatore CICLO: LW R4, A(R2) ; indirizzo dell’operando in memoria calcolato a run time ADD R1, R1, R4 ; aggiorna somma corrente ADDI R2, R2, 4 ADDI R3, R3, -1 BNEZ R3, CICLO SW Z(R0), R1 ; Z e’ la variabile con il risultato
Ovviamente si può sostituire ADDI R3,R3,-1 con SUBI R3,R3,1
Creazione di uno Stack pointer che supporti l'annidamento
modificaAbbiamo visto che il DLX non supporta l'annidamento ( nesting ) delle chiamate a procedura poiché non ha un stack ed utilizza come unico registro di ritorno R31, con questo codice si può implementare via software uno stack pointer con il registro R30. R30 rappresenta l'indirizzo dell'ultima word di 32 bit (4 byte) inserita nello stack, per cui decresce man mano che lo stack si riempie e cresce man mano che si svuota.
Le prime due istruzioni vanno aggiunte prima delle istruzioni della procedura e servono per memorizzare il valore di R31 (indirizzo di ritorno dalla procedura) nello stack implementato grazie al registro R30
SUBI R30, R30, 4 ; Decrementa lo stack SW 0(R30), R31 ; Salva nell'indirizzo di memoria il valore di R31
... istruzioni della procedura ...
Al termine della procedura sono necessarie alcune righe aggiuntive per permettere il ritorno all'istruzione mappata nell'ultimo indirizzo di memoria dello stack pointer
LW R31, 0(R30) ; Preleva l'indirizzo a cui fare ritorno ADDI R30, R30, 4 ; Incrementa lo stack visto che sto uscendo dalla procedura JR R31
Gestione di word (32 bit)
modificaSupponiamo di voler copiare un vettore di 1K word (32 bit) memorizzato all’indirizzo 1000H in un vettore di identico formato memorizzato all’indirizzo 40001000H. Le istruzioni del DLX permettono operandi (immediati) al massimo di 16 bit per cui si usino le istruzioni
LHI Rx, IMMEDIATE (Load High Immediate), che carica nella parte alta (16 bit più significativi) del registro destinazione Rx una costante a 16 bit ed azzera la parte bassa (16 bit meno significativi) di tale registro
ORI Rx, IMMEDIATE (OR Immediate) scrive in Rx il valore IMMEDIATE senza estenderlo (corrispondere a scrivere soltanto i 16 bit meno significativi)
ADDI R1,R0,1000H ; Inizializza R1 per leggere il vettore dal suo ultimo elemento ( 1000H - 4 ) LHI R2,4000H ; Costruisci R2 come l'indirizzo di memoria su cui salvare il vettore ORI R2,R2,2000H ; che andrà da 40001000H a (40002000H -4 )essendo da 1K word LOOP: SUBI R1,R1,4 ; decrementa R1 LW R3,1000H(R1) ; carica la parola all'ultimo indirizzo del vettore SUBI R2,R2,4 ; decrementa anche R2 SW 0(R2),R3 ; Memorizza la parola nell'indirizzo di R2 BNEZ R1,LOOP ; Dopo 1K word il valore di R1 è decrementato fino ad arrivare a 0
Massimo di un vettore di unsigned-word (32 bit)
modificaSi scriva una procedura che ricevendo in ingresso i parametri R1 : registro con l'indirizzo del vettore R2 : dimensione del registro (numero di elementi) R3 : registro usato dalla procedura per memorizzare il valore massime del vettore di unsigned-word
PROC: ADD R3,R0,R0 ; inizializzazione del massimo corrente, per ora a 0 LOOP: LW R4,0(R1) ; lettura dalla memoria dell’i-esima word SGTU R5,R4,R3 ; confronto con il massimo corrente BEQZ R5,SKIP ; “skip” se word corrente è minore del massimo corrente ADD R3,R4,R0 ; aggiornamento del massimo corrente ( solo se BEQZ non effettua il salto di "skip") SKIP: ADDI R1,R1,4 ; incremento del puntatore alla word successiva ( 1 word = 4 byte ) SUBI R2,R2,1 ; decremento del contatore delle iterazioni BNEZ R2,LOOP ; verifica che ci siano altri elementi da processare JR R31 ; ritorno al programma chiamante