SUBLEQ
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
modificasubleq 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!
modificaIl 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
modificaVediamo 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
modificaCollegamenti esterni
modifica- SUBLEQ Archiviato il 29 giugno 2017 in Internet Archive. sul sito di Oleg Mazonka, con assembler, interprete e compilatore da pseudo-C
- SUBLEQ URISC/OISC su Tech Thinkering