SUBLEQ

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca

SUBLEQ o subtract and branch if less equal (Sottrai e salta se minore o uguale a zero) è una istruzione che permette l'implementazione di un OISC, un calcolatore con una sola istruzione, e che quindi si programma senza microcodice (essendo sottintesa l'unica possibile istruzione).

Sintassi[modifica | modifica wikitesto]

subleq a, b, c   ; Mem[b] = Mem[b] - Mem[a]
                 ; if (Mem[b] ≤ 0) goto c

L'istruzione richiede 3 operatori, tutti indirizzi di memoria: il contenuto del primo viene sottratto al contenuto del secondo, e se il risultato è minore o uguale a zero, setta il program counter al terzo (effettua un JUMP). Ipoteticamente, si considera un array di memoria infinito, anche se per sviluppare un emulatore occorrono dei limiti. Il listato in codice macchina è dato nella forma

16 -1 3 
15 0 6 
15 10 9 
29 16 -1 
...

Le istruzioni sono codificate tramite numeri interi, positivi o negativi. Un particolare significato riveste l'indirizzo -1: l'istruzione data prima

16 -1 3

significherebbe sottrarre il contenuto della 16ª cella dalla cella -1, ovviamente inesistente: questa istruzione viene interpretata come l'invio della 16ª cella all'output e prosegue alla 3ª istruzione. Similmente l'istruzione

-1 16 3

legge dallo standard input un carattere e ne immette il valore nella cella 16. Il salto ad un valore negativo, qualunque esso sia, termina il programma. Un emulatore in C è del tipo

int Mem[MAX_ADDR]; /* MAX_ADDR = Dimensione massima della memoria */
int a,b,c;
int main (int argc, char* argv[])
{ 
  int program_counter = 0;

  leggi_memoria(Mem); /* carica il codice macchina */ 
  
  while ((program_counter >= 0) && (program_counter < MAX_ADDR))
  {
    a =  Mem[program_counter];
    b =  Mem[program_counter + 1];
    c =  Mem[program_counter + 2];

    /* casi particolari */
    if ( a == -1 ) /* leggi valore */
    { 
       leggi_valore(Mem + program_counter + 1);
       program_counter=c;
    }
    else
    if ( b == -1 ) /* stampa valore */
    { 
       stampa_valore(Mem[a]);
       program_counter=c;
    }
    else  /* effettua subleq a, b, c*/
    Mem[b] = Mem[b] - Mem[a];
    if ( Mem[b] <= 0 ) 
    { 
       program_counter=c; /* valore negativo, salta */
    } 
    else /* vai all'istruzione successiva*/
    { 
       program_counter=program_counter + 3;
    } 
  }
  return 0;
}

Nel codice sopra mancano le procedure di stampa, input e lettura.

Hello World![modifica | modifica wikitesto]

Il classico programma che stampa "Hello World!":

ciclo: 
  ciao (-1)                  ; Stampa il primo carattere
  m1   ciclo                 ; Incrementa il puntatore (ciclo è una [[label]])
  m1   fine+1                ; Incrementa il puntatore per il controllo 
fine:   
Z ciao (-1)                  ; Se il carattere è zero, fermati 	
Z Z ciclo                    ; Vai a ciclo

; Dati
m1: -1                       ; per incrementare, sottraggo -1  
ciao: "Hello, World!\n" Z: 0 ; Stringa da scrivere

Istruzioni derivate[modifica | modifica wikitesto]

Vediamo come si simulano le istruzioni in pseudo-assembler. Per effettuare un JMP assoluto si usa

Z Z addr   ; Mem [Z] si suppone pari a zero
           ; 0-0=0 e dunque salta all'indirizzo addr

Per simulare un'addizione (ADD A B) si ricorre al seguente codice

; Effettua Mem[b]=Mem[b]+Mem[a]
; Mem [Z] si suppone pari a zero
A Z    ; Mem [Z] = -Mem[a]
Z B    ; Mem [B] = Mem [B] - (-Mem[a])
Z Z    ; resetta Mem [Z]

Omettere il terzo operatore significa saltare comunque all'istruzione successiva. Per simulare una MOV A B, basta azzerare preventivamente B, e sommare.

; Effettua Mem[b] = Mem[a]
; Mem [Z] si suppone pari a zero
B B    ; Mem [B] = 0
A Z    ; Mem [Z] = -Mem[a]
Z B    ; Mem [B] = - (-Mem[a])
Z Z    ; resetta Mem [Z]

Per effettuare una moltiplicazione, occorre sommarre n volte:

Z Z loop
; costanti
Z:0 m1:-1 one:1

; variabili
A:5      ; primo numero
B:9      ; secondo numero
ACC:0    ; Accumulatore

loop:
; aggiunge A ad accumulatore     
A Z         
Z ACC       
Z Z         
one B end  ; dec B, se 0 fine
Z Z loop
end:
Z Z (-1)

Una divisione viene invece effettuata per sottrazioni successive:

; Divisione con resto
; B: B / A
; Il resto viene poi copiato in A

Z   Z   start
; costanti
Z:0 m1:-1 one:1

; Variabili
A: 10 B: 64       ;divisore  e dividendo
C:0

start:
  B Z             ;copia B in C
  Z C
  Z Z
  B B             ;azzera B
  
  loop:  
    A  C   end    ; C -= A, se C < =0 fine
    m1 B          ; B += 1
    Z  Z   loop

  end: 
  C Z resto_nullo ; se C = 0 non somma     
  C C             ; risistema Z= -C, azzera C
  Z C             ; C - Z
  Z Z             ; Z = 0
  A Z             ; C += A
  Z C
  Z Z

resto_nullo:
  B B             ; B=R 
  R Z
  Z B
  Z Z
  
  A A             ; A=C(resto)
  C Z
  Z A
  Z Z

stop:
  Z Z (-1)       ; STOP

Istruzioni con uno stack, tipo push e pop, sono possibili, usando un doppio riferimento indiretto[1].

Note[modifica | modifica wikitesto]

Collegamenti esterni[modifica | modifica wikitesto]

  • SUBLEQ sul sito di Oleg Mazonka, con assembler, interprete e compilatore da pseudo-C
  • SUBLEQ URISC/OISC su Tech Thinkering