Vai al contenuto

Personal computer/Linguaggio Macchina/DLX/Operazioni

Wikibooks, manuali e libri di testo liberi.
Indice del libro

Formato operazioni

[modifica | modifica sorgente]

Ogni 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 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 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 Formato J: Quest'ultimo è il formato dei salti condizionati o meno.

  • 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

[modifica | modifica sorgente]

Sono 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

[modifica | modifica sorgente]

Dato 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

[modifica | modifica sorgente]

Nel 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

[modifica | modifica sorgente]

Somma degli elementi di un vettore A di 8 elementi

[modifica | modifica sorgente]

Se 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

[modifica | modifica sorgente]

Abbiamo 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)

[modifica | modifica sorgente]

Supponiamo 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)

[modifica | modifica sorgente]

Si 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