ESERCIZIO 1 Il set di istruzioni del DLX viene esteso con le seguenti due istruzioni FOR Ri, Rx, Ry NEXT Ri, IMM Che verranno sempre utilizzate in coppia come mostrato nel seguente frammento di codice ADDI FOR LW SW NEXT
R4, R0, 4 R1, R0, R4 R4, 1000H(R1) 2000H(R1), R4 R1, 4
Queste due nuove istruzioni devono comportarsi come segue: FOR Ri, Rx, Ry Ri Rx e R29 Rx (indici per il ciclo for) R30 Ry (il significato di Ry è spiegato nell’istruzione NEXT. Si suppone che valga la relazione Rx < Ry e che Rx ≥ 0) R31 PC + 4 (indirizzo dell’istruzione successiva all’istruzione FOR) NEXT Ri, IMM Ri Ri + IMM (IMM è un operando immediato senza segno) R29 R29 + 1 Confronta il valore di R29 aggiornato col valore di R30. Se (R29 ≥ R30) allora l’esecuzione del programma continua con l’istruzione che segue l’istruzione NEXT. Se (R29 < R30) allora la prossima istruzione da eseguire sarà l’istruzione successiva all’istruzione FOR (l’indirizzo di tale istruzione si trova già in R31). NB: Si suppone inoltre che le istruzioni presenti tra un’istruzione FOR e la corrispondente NEXT non modifichino i registri Ri, R29, R30 e R31. Si indichi una possibile codifica binaria nel linguaggio macchina del DLX delle due nuove istruzioni. Per l’istruzione FOR serve il formato con tre registri, cioè il formato R. FOR
Rx
Ry
Ri
Op. code
Per l’istruzione NEXT serve un formato che abbia l’operando immediato, cioè il formato I. NEXT
Ri
R29
IMMEDIATE
Con riferimento all’implementazione sequenziale del DLX, si disegni il diagramma degli stati delle istruzioni FOR e NEXT. FOR IR M[PC] A Rx (c’è Rx) B Ry (c’è Ry) (incremento contatore) PC PC + 4* C A
Ri C Ri Rx R29 C C B R29 Rx R30 C C PC R30 Ry R31 C R31 PC + 4* NEXT IR M[PC] A Ri B R29 PC PC + 4 C A + (0)16 ## IR15…0 Ri Ri + IMM Ri C C B + 1 R29 R29 + 1 R29 C A R29 B R30
((R29
≥
C A – B A R31 R30) per C maggiore o uguale a zero, salta a dopo la NEXT)
PC A Se (R29 < R30) allora la prossima istruzione da eseguire sarà l’istruzione successiva all’istruzione FOR (l’indirizzo di tale istruzione si trova già in R31) Considerando il frammento di codice riportato all’inizio del testo, si mostri con un esempio quale risultato si ottiene dall’esecuzione di detto codice. ADDI FOR
R4, R0, 4 R1, R0, R4
LW SW NEXT
R4, 1000H(R1) 2000H(R1), R4 R1, 4
Si inizializza R4 a 4 Viene invocata la FOR con parametri R1, R0, R4. 0 viene messo in Ri. 0 viene messo in R29. R4 (= 4) viene messo in R30. In R31 viene messo l’indirizzo dell’istruzione successiva al FOR. In R4 viene messo M[R1+1000H] Viene caricato in M[R1+2000H] il valore appena spostato. Viene invocata la NEXT con parametri R1 e 4. R1 viene incrementato di 4. In R29 viene aggiunto 1 (quindi si va a 0+1 = 1).
Si confronta R29 con R30: se sono uguali, o se R29 è maggiore, si salta a dopo NEXT. Altrimenti si ricomincia dalla LW. Vengono in pratica all’indirizzo 2000H.
spostate
4
word
(4
x
4
byte)
dall’indirizzo
1000H
Si indichi il numero di periodi di clock necessari ad eseguire le istruzioni nell’ipotesi che la memoria richieda 2 stati di wait per ogni accesso. FOR = 7 + wait = 9 NEXT = (taken) 8 + wait = 10 (not-taken) 7 + wait = 9 Nelle ipotesi del punto 4, supponendo una frequenza di clock di 100 Mhz, quale valore occorre assegnare ad N affinché l’esecuzione del frammento di codice che segue avvenga in un tempo il più prossimo possibile a 20 nsec. ADDI FOR NEXT
R3, R0, N R1, R0, R3 R1, 1
ESERCIZIO 1 Come si potrebbe codificare l’istruzione utilizzando uno dei tre formati che ci mette a disposizione il DLX? Non è difficile accorgersi che, nella nuova istruzione, fanno la loro comparsa 3 registri: Rx, Ry, Rz. Dunque, l’unica codifica possibile è quella di tipo R: LBUR
Ry
Rz
Rx
LBUR
L’istruzione che abbiamo definito trasferisce in Rx il dato di tipo unsigned-byte situato all’indirizzo di memoria ottenuto sommando i registri Ry e Rz. FETCH:
IR M[PC]
DECODE:
PC PC + 4 A RS1 (che sarebbe Ry) B RS2 (che sarebbe Rz)
MEMORY:
MAR A + B
WRITE BACK:
stati di wait
MDR M[MAR]
accesso in memoria (wait)
C MDR0..7 ## (0)24
si inserisce tutto in C
RD C
Vengono utilizzati 6 + altri 2 aggiuntivi dovuti agli accessi alla memoria Nell’ipotesi di voler aggiungere all’indirizzo di memoria usato dall’istruzione LBUR anche una costante con segno (cioè accedere alla cella M[Ry + Rz + IMMEDIATE]) e si indichi come dev’essere modificata la codifica precedente. Quale ulteriore accorgimento dovrebbe essere adottato nella codifica per rendere la LBUR distinguibile senza ambiguità dalle altre istruzioni codificate nello stesso formato. LBUR
Ry
Rz
Rx
IMMEDIATE
Ad IMMEDIATE vengono riservati 11 bit, quindi può essere codificato con un range di [-1024, 1023]. Per poter distinguere questa codifica dalle altre senza generare confusione, l’unico campo che può essere modificato è quello del codice operativo LBUR. Si deve infatti modificare affinché sia diverso da quello di tutte le altre istruzioni di tipo R. ESERCIZIO 2 Si consideri la seguente sequenza di istruzioni del DLX
CICLO:
ADDI LBU LB SB ADDI
R1, R0, 400H R2, 0(R1) R3, 0(R2) 0(R1), R3 R1, R1, 1
SLTI R2, R1, 500H BNEZ R2, CICLO Si indichi il numero totale di cicli di bus relativo rispettivamente al “fetch” e all’esecuzione delle istruzioni. Anzitutto esaminiamo il codice:
CICLO:
ADDI LBU LB SB ADDI SLTI
R1, R0, 400H R2, 0(R1) R3, 0(R2) 0(R1), R3 R1, R1, 1 R2, R1, 500H
BNEZ R2, CICLO
R1 viene a messo 400H (cioè 1024) Viene messo in R2 il contenuto di M[R1] Viene messo in R3 il contenuto di M[R2] Viene messo in R1 il contenuto di M[R3] R1 viene incrementato di 1 Se R1 è < 500H (cioè 1280) allora R2 viene messo a 1, altrimenti a 0 Se R2 è diverso da zero ciclo
Dunque questo mini-programmino assembler mette 400H In R1 in R2 in R3 Poi R1 viene incrementato di uno e si controlla se è minore di 500H: in tal caso si ricomincia da CICLO. Si esegue dunque il blocco CICLO (di 6 istruzioni) 1280 – 1024 = 256 volte; per questo motivo la fase di fetch viene invocata 1 (per la prima ADDI) + 256 ⋅ 6 = 1537 volte. Questo numero è pari a quello delle volte in cui dev’essere invocato il ciclo di BUS relativo al Fetch (1 volta/istruzione). Per quanto riguarda l’esecuzione delle istruzioni, solo le prime 3 (in rosso) prevedono l’accesso alla memoria: quindi il numero totale di accessi è di 256 ⋅ 3 = 768. Si consideri la struttura sequenziale del DLX ed, ipotizzando che tutti gli accessi in memoria siano completati in 2 clock, si calcolino il numero totale di cicli di clock necessario all’esecuzione della sequenza ed il CPI-medio. Vengono fatte: 256 + 1 256 ⋅ 2 256 256 255 1
ALU (6 clock ciascuna) LOAD (6+2 clock ciascuna) STORE (5+2 clock ciascuna) SET (5 clock ciascuna) BRANCH (not-taken) (3+2 clock ciascuna) BRANCH (taken) (4 clock)
Il numero totale di periodi di clock è quindi 10501. Il CPI medio, di conseguenza, risulta pari a 10501/1537 = 6,83
ESERCIZIO 1 Si supponga di voler estendere il set di istruzioni del DLX con l’istruzione: BNEQ++ (Rx), (Ry), IMMEDIATE Dove gli operandi Rx, Ry rappresentano due registri generali ed IMMEDIATE è una costante signed a 16 bit. L’istruzione confronta la word situata in memoria all’indirizzo Rx con la word situata in memoria all’indirizzo Ry: se i valori risultano diversi somma la costante IMMEDIATE al valore corrente del PC. Inoltre, indipendentemente dall’esito del confronto, l’istruzione incrementa il registro Ry (sommando il valore +4). Una possibile descrizione RTL delle operazioni svolte dalla nuova istruzione è data da If (M[Rx] ≠ M[Ry) Ry Ry + 4
PC PC + IMMEDIATE
then
Si mostri come potrebbe essere codificata la nuova istruzione utilizzando il più idoneo fra i 3 formati delle istruzioni DLX. Il formato più idoneo è quello di tipo I, perché abbiamo a disposizione lo spazio per due registri e per l’operando immediato. BNEQ++
Rx
Ry
IMMEDIATE
Con riferimento al datapath del DLX sequenziale visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch ed alla decodifica. Accesso in memoria
1) FETCH
IR M[PC]
2) DECODE
PC PC + 4 A RS1 (Rx) B RS2 (Ry)
3) MEMORY
MAR B (Ry)
4)
MDR M[MAR] C MAR + 4
Accesso in memoria Approfittiamone per farlo (bisogna effettuare questa operazione in ogni caso)
5)
TEMP MDR RS2 C
Ry (com’era all’inizio) è in TEMP, mentre l’Ry aggiornato viene deposto in B
6)
MAR A
Ora è necessario andare a prendere l’altro registro per effettuare il confronto
7)
MDR M[MAR]
L’accesso (solito) in memoria
8)
MDR != TEMP
Ora possiamo effettuare il confronto
(le solite due fasi)
SE è TRUE 9a)
PC PC + (IR15)16 ## (IR15..0) Aggiorniamo il PC con l’immediato (16 bit)
SE è FALSE --)
Si torna daccapo
Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 2 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. CASO Branch-TAKEN (risposta TRUE al punto 8) CPI = 6 + 2 (IF) + 2 (MEM1) + 2 (MEM2) = 12 CASO Branch-NOT-TAKEN (risposta FALSE al punto 8) CPI = [caso precedente] – 1 = 11 Utilizzando la nuova istruzione BNEQ++ si scriva un frammento di codice assembler DLX che, dato un vettore V1 di 10 word (32 bit) memorizzato a partire dell’indirizzo 200H ed una variabile alfa memorizzata all’indirizzo 4000H, ritorna nel registro R1 il numero di elementi di V1 che risultano uguali ad alfa e memorizza in ordine crescente in un secondo vettore (V2, adiacente al primo in memoria) gli indirizzi di tali elementi. ADD R1, R0, R0 ADDI R2, R0, 200H ADDI R3, R0, 228H
ADDI R4, R0, 4000H LOOP:
BNEQ++ (R4), (R2), SKIP ADDI R1, R1, 1 SUBI R5, R2, 4 SW
SKIP:
0(R3), R5
ADDI R3, R3, 4 SEQI R5, R2, 228H BEQZ R5, LOOP
Inizializziamo R1: è il contatore degli elementi uguali ad alfa Inizializziamo R2 a 200H (dove inizia V1) Inizializziamo R3 a 228H (distante 40 celle da 8 bit da 200H, ovvero le celle dove contenere le 10 word). Qui inizia il secondo vettore, che è adiacente al primo. Mettiamo in R4 l’indirizzo della variabile alfa Se V[i] è diverso da alfa, vai a SKIP Aggiungiamo 1 ad R1: abbiamo trovato una word uguale ad alfa Mettiamo, in R5, R2 – 4; esso è l’indice di V1 aggiornato Memorizziamo nel secondo vettore (R3 ne è l’indice) l’indirizzo di V1 aggiornato. Incrementiamo l’indice di V2 (sempre R3) Se R2 è uguale a 228H, allora metti R5 a 1 R5 è uguale a zero? Vuol dire che non abbiamo finito di scorrere il vettore: si ritorna a loop.
Sempre con riferimento al DLX sequenziale si calcoli il CPI medio del codice scritto al punto precedente nell’ipotesi che il numero di elementi di V1 che risultano uguali ad alfa sia pari all’ultima cifra del proprio numero di matricola. Per l’istruzione BNEQ++ si utilizzi il CPI precedentemente calcolato e per le altre istruzioni i valori visti a lezione e deducibili dai diagrammi degli stati del controllo (si mantenga l’ipotesi che ogni accesso alla memoria richieda 2 clock). IPOTESI: Numero di elementi di V1 uguali ad alfa = 7 [ultima cifra del numero di matricola].
Dividiamo il codice in tre fasi: 1) INIZIALIZZAZIONE (4 istruzioni) Si tratta di 4 ALU 4 + 2 (wait)
24 clock
2) UGUALE AD ALFA (5 istruzioni) Ci sono 3 ALU 4 + 2 (wait) C’è una STORE 3 + 2 + 2 (wait) La BNEQ++ TAKEN NOT-TAKEN
18 clock 7 clock 12 clock 11 clock
3) FINALE / DIVERSO DA ALFA (2 istruzioni) C’è la SET 4 + 2 (wait) 6 clock Infine, la BRANCH TAKEN 5 clock NOT-TAKEN 4 clock L’inizializzazione si fa una volta sola. Poi, se si verifica che l’elemento del vettore è uguale ad alfa allora si fanno sia la fase 2 (con la BNEQ++ “Not-taken”) che la fase 3. Altrimenti si fa solo la BNEQ++ “Taken” e la 3. La BRANCH finale si fa sempre not-taken tranne l’ultima volta. Per 7 volte ci troviamo nella prima situazione, per 3 volte nella seconda. Numero totale di clock: 24 + (3 x [12+6+5+4]) + (7 x [11 + 7 + 18 + 6 + 5]) – 1 = 433 (il -1 è per l’ultima branch, che è not-taken). Numero totale di operazioni: 4 + (3 x 3) + (7 x 7) = 62 CPI MEDIO = 433/62 = 6,78
ESERCIZIO 1 Si supponga di voler estendere il set di istruzioni del DLX con l’istruzione: BNEQ++ (Rx), (Ry), IMMEDIATE Dove gli operandi Rx, Ry rappresentano due registri generali ed IMMEDIATE è una costante signed a 16 bit. L’istruzione confronta la word situata in memoria all’indirizzo Rx con la word situata in memoria all’indirizzo Ry: se i valori risultano diversi somma la costante IMMEDIATE al valore corrente del PC. Inoltre, indipendentemente dall’esito del confronto, l’istruzione incrementa il registro Ry (sommando il valore +4). Una possibile descrizione RTL delle operazioni svolte dalla nuova istruzione è data da If (M[Rx] ≠ M[Ry) Ry Ry + 4
PC PC + IMMEDIATE
then
Si mostri come potrebbe essere codificata la nuova istruzione utilizzando il più idoneo fra i 3 formati delle istruzioni DLX. Il formato più idoneo è quello di tipo I, perché abbiamo a disposizione lo spazio per due registri e per l’operando immediato. BNEQ++
Rx
Ry
IMMEDIATE
Con riferimento al datapath del DLX sequenziale visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch ed alla decodifica. Accesso in memoria
1) FETCH
IR M[PC]
2) DECODE
PC PC + 4 A RS1 (Rx) B RS2 (Ry)
3) MEMORY
MAR B (Ry)
4)
MDR M[MAR] C MAR + 4
Accesso in memoria Approfittiamone per farlo (bisogna effettuare questa operazione in ogni caso)
5)
TEMP MDR RS2 C
Ry (com’era all’inizio) è in TEMP, mentre l’Ry aggiornato viene deposto in B
6)
MAR A
Ora è necessario andare a prendere l’altro registro per effettuare il confronto
7)
MDR M[MAR]
L’accesso (solito) in memoria
8)
MDR != TEMP
Ora possiamo effettuare il confronto
(le solite due fasi)
SE è TRUE 9a)
PC PC + (IR15)16 ## (IR15..0) Aggiorniamo il PC con l’immediato (16 bit)
SE è FALSE --)
Si torna daccapo
Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 2 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. CASO Branch-TAKEN (risposta TRUE al punto 8) CPI = 6 + 2 (IF) + 2 (MEM1) + 2 (MEM2) = 12 CASO Branch-NOT-TAKEN (risposta FALSE al punto 8) CPI = [caso precedente] – 1 = 11 Utilizzando la nuova istruzione BNEQ++ si scriva un frammento di codice assembler DLX che, dato un vettore V1 di 10 word (32 bit) memorizzato a partire dell’indirizzo 200H ed una variabile alfa memorizzata all’indirizzo 4000H, ritorna nel registro R1 il numero di elementi di V1 che risultano uguali ad alfa e memorizza in ordine crescente in un secondo vettore (V2, adiacente al primo in memoria) gli indirizzi di tali elementi. ADD R1, R0, R0 ADDI R2, R0, 200H ADDI R3, R0, 228H
ADDI R4, R0, 4000H LOOP:
BNEQ++ (R4), (R2), SKIP ADDI R1, R1, 1 SUBI R5, R2, 4 SW
SKIP:
0(R3), R5
ADDI R3, R3, 4 SEQI R5, R2, 228H BEQZ R5, LOOP
Inizializziamo R1: è il contatore degli elementi uguali ad alfa Inizializziamo R2 a 200H (dove inizia V1) Inizializziamo R3 a 228H (distante 40 celle da 8 bit da 200H, ovvero le celle dove contenere le 10 word). Qui inizia il secondo vettore, che è adiacente al primo. Mettiamo in R4 l’indirizzo della variabile alfa Se V[i] è diverso da alfa, vai a SKIP Aggiungiamo 1 ad R1: abbiamo trovato una word uguale ad alfa Mettiamo, in R5, R2 – 4; esso è l’indice di V1 aggiornato Memorizziamo nel secondo vettore (R3 ne è l’indice) l’indirizzo di V1 aggiornato. Incrementiamo l’indice di V2 (sempre R3) Se R2 è uguale a 228H, allora metti R5 a 1 R5 è uguale a zero? Vuol dire che non abbiamo finito di scorrere il vettore: si ritorna a loop.
Sempre con riferimento al DLX sequenziale si calcoli il CPI medio del codice scritto al punto precedente nell’ipotesi che il numero di elementi di V1 che risultano uguali ad alfa sia pari all’ultima cifra del proprio numero di matricola. Per l’istruzione BNEQ++ si utilizzi il CPI precedentemente calcolato e per le altre istruzioni i valori visti a lezione e deducibili dai diagrammi degli stati del controllo (si mantenga l’ipotesi che ogni accesso alla memoria richieda 2 clock). IPOTESI: Numero di elementi di V1 uguali ad alfa = 7 [ultima cifra del numero di matricola].
Dividiamo il codice in tre fasi: 1) INIZIALIZZAZIONE (4 istruzioni) Si tratta di 4 ALU 4 + 2 (wait)
24 clock
2) UGUALE AD ALFA (5 istruzioni) Ci sono 3 ALU 4 + 2 (wait) C’è una STORE 3 + 2 + 2 (wait) La BNEQ++ TAKEN NOT-TAKEN
18 clock 7 clock 12 clock 11 clock
3) FINALE / DIVERSO DA ALFA (2 istruzioni) C’è la SET 4 + 2 (wait) 6 clock Infine, la BRANCH TAKEN 5 clock NOT-TAKEN 4 clock L’inizializzazione si fa una volta sola. Poi, se si verifica che l’elemento del vettore è uguale ad alfa allora si fanno sia la fase 2 (con la BNEQ++ “Not-taken”) che la fase 3. Altrimenti si fa solo la BNEQ++ “Taken” e la 3. La BRANCH finale si fa sempre not-taken tranne l’ultima volta. Per 7 volte ci troviamo nella prima situazione, per 3 volte nella seconda. Numero totale di clock: 24 + (3 x [12+6+5+4]) + (7 x [11 + 7 + 18 + 6 + 5]) – 1 = 433 (il -1 è per l’ultima branch, che è not-taken). Numero totale di operazioni: 4 + (3 x 3) + (7 x 7) = 62 CPI MEDIO = 433/62 = 6,78
ESERCIZIO 1 Si supponga di voler estendere il set di istruzioni del DLX con l’istruzione: SCANVW
Rx, Ry, Rz
Dove gli operandi Rx, Ry, Rz, rappresentano tre registri generali. L’istruzione confronta la word situata in memoria all’indirizzo Rx con il valore di Ry: se i valori risultano uguali il registro Rz viene posto a 1, viceversa viene posto a 0. Effettuato il confronto, l’istruzione incrementa il registro Rx (sommando il valore +4). Una possibile descrizione RTL delle operazioni svolta dalla nuova istruzione è data da: if (M[Rx] = Ry) then Rz 1 else Rz 0 Rx Rx + 4 Si mostri come potrebbe essere codificata la nuova istruzione utilizzando il più idoneo fra i tre formati delle istruzioni del DLX. Senza troppo scervellarci: ci sono tre registri, dunque la codifica appropriata è quella di tipo R. SCANWV Rx,Ry,Rz Ry Rx Rz … Con riferimento al datapath del DLX sequenziale (cioè non-pipelined) visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch e alla decodifica. FETCH
IR M[PC]
DECODE
A RS1 (Ry) B RS2 (Rx) PC PC + 4
SI
(stati di wait)
MAR B
(mettiamo in MAR l’indirizzo del registro da confrontare)
MDR M[MAR]
(stati di wait)
MDR == A ?
(confronto: e qui discriminiamo)
C 1 C B + 4 RD C
NO
C 0
(dobbiamo incrementare Rx)
RS2 C Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 3 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione delle istruzioni. CPI = 6 + 3 (FETCH) + 3 (MEMORY) = 12 Utilizzando la nuova istruzione SCANVW si scriva un frammento di codice assmebler DLX che, dato un vettore di 256 word (32 bit) memorizzato a partire dall’indirizzo 0000 0400H, ritorna nel registro R1 l’indirizzo di memoria del primo elemento del vettore che risulta uguale a 100 (se nessun elemento del vettore è uguale a 100 in R1 deve essere ritornato il valore 0).
Inizializziamo la variabile R2 (indirizzo del vettore)
ADDI
R2, R0, 0400H
Valore confrontando
ADDI
R3, R0, 100
Contatore delle iterazioni
ADDI
R4, R0, 256
Usiamo l’istruzione SCANVW
SCANWV
R3, R2, R1
Se l’elemento è uguale a = R3 allora salta alla label FOUND
BNEZ
R1, FOUND
Decremento del contatore delle iterazioni
SUBI
R4, R4, 1
Se il contatore delle iterazioni è diverso da 0, salta a NEXT
BNEZ
R4, NEXT
Se arriviamo qui significa che nessun elemento del vettore è R3, quindi azzeriamo R2
ADDI
R2, R0, 4
Se abbiamo trovato un elemento = 100 allora R1 = indirizzo di tale elemento. Altrimenti R1 = 0
SUBI
R1, R2, 4
(NEXT)
(FOUND)
Quindi: R2 400H R3 100 R4 256 M[400H] è = 100 ? Se sì R1 1 Altrimenti R1 0 In ogni caso R2 404H
(NEXT)
R1 è diverso da 0 (abbiamo trovato un valore = 100)? Se sì, salta a FOUND Altrimenti prosegui. R4 255 R4 è diverso da 0 (abbiamo finito)? Se no, torna a NEXT. Altrimenti, prosegui. Nessun elemento del vettore è = 3. Dunque R2 4 Abbiamo trovato un elemento = 100 R1 404H – 4H = 400H
(FOUND)
Sempre con riferimento al DLX sequenziale (cioè non-pipelined), si calcoli il CPI medio del codice scritto al punto precedente nell’ipotesi che l’unico elemento del vettore che risulta uguale a 100 sia il decimo (cioè quello di indice 9). Per l’istruzione SCANVW si utilizzi il CPI precedentemente calcolato e per le altre istruzioni i valori visti a lezione e deducibili dai diagrammi degli stati del controllo (si mantenga l’ipotesi che ogni accesso alla memoria richieda 3 clock). L’inizializzazione consiste in 3 ALU L’unico elemento = 100 è il decimo, inizializzazione vengono eseguiti 9 da SCANVW alla BNEZ-R4 (con BNEZ-R1
(4 + 3 = 7 clock ciascuna). quindi dopo queste prime tre istruzioni di loop costituiti dalle istruzioni che vanno not-taken e BNEZ-R4 taken). La decima volta
si fa invece dalla SCANVW alla successiva BNEZ-R1 (taken), quindi si salta alla FOUND. QUINDI 9 volte: SCANVW BNEZ-R1 (n.t.) SUBI BNEZ-R4 (t.)
12 clock 5 clock 7 clock 6 clock
1 volta: SCANVW BNEZ-R1 (t.) FOUND (SUBI)
12 clock 6 clock 7 clock
NUMERO TOTALE DI ISTRUZIONI: 3 (init) + 4 x 9 + 2 x 1 + 1 = 42 NUMERO TOTALE DI CLOCK: 13 x 7 (ALU) + 10 x 12 (SCANVW) + 10 x 6 (BRANCH TAKEN) + 9 x 5 (B. NOT TAKEN) = 316 CPI medio: 316 / 42 = 7,5 circa
ESERCIZIO 1 Si supponga di voler estendere il Set di Istruzioni del DLX con la seguente istruzione NEG IMMEDIATE(Rx) Dove Rx è un registro generale ed IMMEDIATE è una costante di 16 bit con segno. L’istruzione deve eseguire il cambiamento del segno della word (32 bit) situata all’indirizzo di memoria Rx + IMMEDIATE. Si mostri come potrebbe essere codificata la nuova istruzione utilizzando uno dei 3 formati delle istruzioni DLX. C’è soltanto un registro sufficiente la codifica I: NEG
di
cui
tenere
Rx
conto
(Rx),
indifferente
dunque
è
largamente
IMMEDIATE (16 bit)
Con riferimento al datapath del DLX sequenziale (cioè non-pipelined) visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch ed alla decodifica. IR M[PC]
(stati di wait)
A RS1 (Rx) B RS2 (nulla) PC PC + 4 MAR A + (IR15)16 ## IR15..0
(sommiamo A all’operando immediato)
MDR M[MAR]
(stati di wait)
MDR 0 – MDR
(creiamo in questo modo il complemento a due)
M[MAR] MDR
(stati di wait, depositiamo il nuovo valore dove stava prima)
Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 2 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. CPI: 3 + 2 (fetch) + 2 (primo accesso in memoria) + 2 (secondo accesso) = 9 ESERCIZIO 2 Si consideri il codice della seguente procedura in Assembler DLX. PROC: LOOP:
SUBUI SW NEG ADDI SUBI BNEZ LW ADDUI JR
R30, R30, 4 0(R30), R31 0(R1) R1, R1, 4 R2, R2, 1 R2, LOOP R31, 0(R30) R30, R30, 4 R31
Che fa uso dell’istruzione NEG definite nell’esercizio precedente.
Si spieghi procedura.
in
modo
preciso
e
sintetico
qual
è
l’operazione
svolta
Si sottrae 4 dal registro R30 Si deposita R31 in R30
R30 R30 - 4 R30 R31
Viene cambiato di segno di ciò che c’è nel registro R1
( LOOP) R1 -R1 R1 R1 + 4 R2 R2 - 1
Viene aggiunto 4 ad R1 (si cerca la prossima word) Viene sottratto 1 da R2 R2 è uguale a zero? Se sì torna a LOOP, sennò prosegui. Viene messo in R31 ciò che viene preso in R30 Si aggiunge 4 ad R30 Si salta ad R31
dalla
R31 R30 R30 R30 + 4 Salta
Cosa fa questo benedetto programmino? All’interno del loop (eseguito R2 volte) cambia segno a ciò che c’è nel registro R1 poi, a scalare, negli altri elementi del vettore che parte – appunto – da R1. Si consideri la struttura sequenziale del DLX. Ipotizzando che tutti gli accessi in memoria siano completati in 2 clock e che prima di trasferire il controllo alla procedura il registro R2 sia stato posto al valore 1000, si calcolino il numero totale di cicli di clock necessario per l’esecuzione della procedura ed il relativo CPImedio. Se R2 è stato posto a 1000 significa che il LOOP (testo in verde) verrà eseguito 1000 volte. Il numero totale di istruzioni è dunque: 2 (inizializzazione) + 4 x 1000 (loop) + 3 (fine) = 4005 ISTRUZIONI TIPO DI ISTRUZIONE
QUANTE E QUANDO
CLOCK
Load Store Alu Jump Branch (taken) Branch (not-taken) Neg
1 (fine) 1 (init) 1 (init) + 2000 (loop) + 1 (fine) 1 (fine) 999 (loop) 1 (loop) 1000 (loop)
8 7 6 4 5 4 9
TOTALE = 8 + 7 + 6 x 2002 + 4 + 5 x 999 + 4 + 9 x 1000 = 20630 CPI medio = 26030 / 4005 = 6,5 Si mostri come dovrebbe essere modificato il codice della procedura al fine di garantire che essa non alteri il contesto del chiamante (cioè non modifichi alcun registro ad eccezione di quelli eventualmente utilizzati per restituire dei risultati). Cosa bisogna fare? Prima di entrare nel loop è necessario salvare i valori dei registri R1 ed R2, perché durante la procedura questi verranno modificati. Poi, all’uscita dal loop, dovranno essere ripristinati. Dobbiamo quindi introdurre una SW preceduta da una SUBUI (all’inizio) e una LW seguita da una ADDUI (alla fine), in più.
PROC:
LOOP:
SUBUI SW SUBUI SW NEG ADDI SUBI BNEZ LW ADDUI LW ADDUI JR
R30, R30, 4 0(R30), R31 R30, R30, 4 0(R30), R2 0(R1) R1, R1, 4 R2, R2, 1 R2, LOOP R31, 0(R30) R30, R30, 4 R31, 0(R30) R30, R30, 4 R31
ESERCIZIO 1 Si supponga di voler estendere il Set di Istruzioni del DLX con la seguente istruzione: ADDM IMMEDIATE(Rx), Ry Dove Rx, Ry sono due registri generali e IMMEDIATE è una costante a 16 bit con segno. L’istruzione deve eseguire la somma fra la word (32 bit) situata all’indirizzo di memoria Rx + IMMEDIATE ed il registro Ry e poi scrivere il risultato nuovamente all’indirizzo di memoria Rx + IMMEDIATE (cioè, in notazione RTL, eseguire l’operazione: M[Rx + IMMEDIATE] M[Rx + IMMEDIATE] + Ry Si mostri come potrebbe essere codificata la nuova istruzione utilizzando uno dei tre formati delle istruzioni DLX. Usiamo, in virtù della presenza dei due registri, il formato I. ADDM
Rx
Ry
IMMEDIATE (16 bit)
Con riferimento al datapath del DLX sequenziale (non-pipelined) visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch ed alla decodifica. IR M[PC]
(fase di FETCH, stati di wait)
A RS1 (Rx) B RS2 (Ry) PC PC + 4
(fase di DECODE)
MAR A + (IR15)16 ## IR15..0
(aggiungiamo l’IMMEDIATE)
MDR M[MAR]
(stati di wait)
MDR MDR + B
(aggiungiamo Ry)
M[MAR] MDR
(stati di wait)
Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 3 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. Numero di clock: 3 + 3 (fetch) + 3 (memory 1) + 3 (memory 2) = 12 ESERCIZIO 2 Si consideri la seguente sequenza di istruzioni DLX
CICLO:
ADDI LW LW ADD SW ADDI SLTI BNEZ
R1, R0, R0 R2, V1(R1) R3, V2(R1) R2, R2, R3 V1(R1), R2 R1, R1, 4 R2, R1, 1000H R2, CICLO
Dove V1 e V2 sono due costanti che rappresentano gli indirizzi di base (cioè l’indirizzo del primo elemento) di due vettori di word (32 bit).
Cosa fa questo codice? ADDI R1, R0, R0 CICLO: LW R2, V1(R1) LW R3, V2(R1) ADD R2, R2, R3 SW V1(R1), R2 ADDI R1, R1, 4 SLTI R2, R1, 1000H BNEZ R2, CICLO
Inizializziamo R1 a 0 Si carica in R2 il valore in V1[R1] Si carica in R3 il valore in V2[R1] Si somma: R2 R2 + R3 Si mette R2 in V1[R1] Togli 4 da R1 Se R1 < 1000H allora R2 1 (0 altrimenti) Se R2 non è uguale a zero, vai a CICLO
Il programma scorre due vettori (V1 e V2), somma fra loro gli elementi V1[i]+V2[i], poi si pone il risultato in posizione V1[i]. Si compie questa operazione 400H = 1024 volte. Si consideri la struttura sequenziale del DLX ed, ipotizzando che tutti gli accessi in memoria siano completati in 3 clock, si calcolino il numero totale di cicli di clock necessario per l’esecuzione della sequenza ed il CPI medio. TIPO DI ISTRUZIONE ALU LOAD STORE SET BRANCH (taken) BRANCH (not-taken)
QUANTE E QUANDO 1 (init.) + 1024 x 2 (ciclo) 1024 x 2 (ciclo) 1024 x 1 (ciclo) 1024 x 1 (ciclo) 1023 x 1 (ciclo) 1 (ciclo)
CLOCK 7 10 9 8 6 5
N° DI ISTRUZIONI ESEGUITE IN TOTALE: 1 + (1024 x 7) = 7169 N° CLOCK IN TOTALE: 2049 x 7 + 2048 x 10 + 1024 x 9 + 1024 x 8 + 6 x 1023 + 5 = 58374 CPI medio = 58374 / 7169 = 8,14 Si riscriva la precedente sequenza di istruzioni impiegando l’istruzione ADDM IMMEDIATE(Rx), Ry definita nell’Esercizio 1 al fine di sommare gli elementi corrispondenti dei due lettori V1 e V2. ADDI R1, R0, R0 CICLO: LW R2, V1(R1) ADDM V1(R1), R2 ADDI R1, R1, 4 SLTI R2, R1, 1000H BNEZ R2, CICLO
Inizializziamo R1 a 0 Si carica in R2 il valore in V1[R1] 1 istruzione al posto di tre Togli 4 da R1 Se R1 < 1000H allora R2 1 (0 altrimenti) Se R2 non è uguale a zero, vai a CICLO
Sempre considerando la struttura sequenziale del DLX ed ipotizzando che tutti gli accessi in memoria siano completati in 3 clock, si calcolino per la nuova sequenza il numero totale di cicli di clock necessario per l’esecuzione ed il CPI medio. TIPO DI ISTRUZIONE ALU LOAD ADDM SET BRANCH (taken) BRANCH (not-taken)
QUANTE E QUANDO 1 (init.) + 1024 x 1 (ciclo) 1024 x 1 (ciclo) 1024 x 1 (ciclo) 1024 x 1 (ciclo) 1023 x 1 (ciclo) 1 (ciclo)
CLOCK 7 10 12 8 6 5
N° DI ISTRUZIONI ESEGUITE IN TOTALE: 1 + (1024 x 5) = 5121 N° CLOCK IN TOTALE: 1025 x 7 + 1024 x 10 + 1024 x 12 + 1024 x 8 + 6 x 1023 + 5 = 44038
CPI medio = 44038 / 5121 = 8,59 Come si nota, il CPI medio si è alzato. Tuttavia, ciò non significa che il nuovo codice sia più lento: abbiamo infatti un risparmio totale di 14336 cicli di clock. Considerando sia la struttura sequenziale sia quella “pipelined”, si discutano vantaggi e svantaggi dell’eventuale introduzione nell’ISA DLX della nuova istruzione ADDM IMMEDIATE(Rx), Ry. Semplicemente, non possiamo eseguire tale programma sulla pipeline a 5 stadi del DLX: la nuova istruzione è di tipo CISC.
ESERCIZIO 1 Si scriva in Assembler DLX una procedura che calcola il massimo di un vettore di unsigned word (32 bit). La procedura deve ricevere come parametri di ingresso l’indirizzo del vettore sul registro R1 e la dimensione del vettore (cioè il numero dei suoi elementi) sul registro R2. La procedura deve restituire il massimo del vettore sul registro R3. PROC:
ADD
R3, R0, R0
LOOP:
LW SGTU
R4, 0(R1) R5, R4, R3
BEQZ ADD ADDI
R5, SKIP R3, R4, R0 R1, R1, 4
SUBI BNEZ JR
R2, R2, 1 R2, LOOP R31
SKIP:
Inizializziamo R3: qua dentro ci finirà il massimo appena lo troveremo all’interno del vettore. Carichiamo ciò che c’è in R1 su R4. Se R4 > R3 allora R5 = 1 (se, cioè, abbiamo trovato un massimo, altrimenti R5 = 0. Non abbiamo trovato un nuovo massimo. Salta. Aggiornamento di R3 col nuovo massimo. Si prosegue nel vettore (nota l’operando immediato 4, dovuto all’elaborazione di word). Decrementiamo il contatore. Se non abbiamo finito, ricominciamo da LOOP. Se abbiamo finito, ritorniamo al programma chiamante.
Si scriva il codice Assembler DLX necessario ad invocare la procedura scritta al punto precedente in maniera tale che essa calcoli il massimo di un vettore di 10 elementi allocato all’indirizzo 8000H. Dobbiamo mettere in R1 l’indirizzo 8000H Dobbiamo mettere il contatore a 10 Chiamiamo la procedura
ADDUI ADDI JAL
R1, R0, 8000H R2, R0, 10 PROC
Si faccia riferimento alla struttura pipelined del DLX (con presenza di Forwarding Unit e Register File che ritorna il nuovo valore in caso lettura e scrittura simultanee sullo stesso registro) e si assuma che i “branch” siano gestiti con politica “predict-not-taken”. Nell’ipotesi che la procedura scritta sia invocata su un vettore di 10 elementi tutti nulli, si calcoli il CPI medio relativo all’esecuzione della procedura utilizzando la formula CPI medio = 1 + s Dimensione del vettore 10 elementi Tutti gli elementi sono nulli quindi la BEQZ è sempre taken, mentre la politica adottata è quella di not-taken. Numero di istruzioni: 6 (in rosso) x 2 + 2 = 62. Ora esaminiamo gli stalli: ISTRUZIONE STALLI LW R4, 0(R1) Uno stallo solo, per ritardare la fase di execute della SGTU. BEQZ R5, SKIP Siamo nel caso predict not-taken. Siccome, in realtà, la branch è sempre taken dobbiamo introdurre ogni volta 3 stati di stallo. BNEZ R2, LOOP Nelle prima 9 operazioni è taken. Quando abbiamo terminato il nostro processo, invece, essa diventa not-taken. JR R31 Nella jump si fanno sempre 3 stalli Numero di stalli = 10 + 30 + 27 + 3 = 70 Stalli / istruzione = 70 / 62 = circa 1.13 CPI medio = 1 + 1.13 = 2.13
TOTALE STALLI 10 3 x 10 = 30
3 x 9 = 27
3
ESERCIZIO 1 Si supponga di voler estendere il set di istruzioni del DLX con l’istruzione CMPS Rx, Ry, Rz Dove gli operandi Rx, Ry, Rz rappresentano tre registri generali. L’istruzione CMPS (CoMPareString) confronta il dato di tipo unsigned byte situato in memoria all’indirizzo Rx con il dato dello stesso tipo situato in memoria agli indirizzi Ry: se i due dati risultano uguali il registro Rz viene posto a 1, altrimenti viene posto a 0. Una possibile descrizione RTL delle operazioni svolte dalla nuova istruzione è data da: if(M[Rx] = M[Ry]) then Rz 1 else Rz 0 Si mostri come potrebbe essere codificata la nuova istruzione utilizzando il più idoneo fra i formati delle istruzioni del DLX. Ci sono tre registri, dunque siamo obbligati ad usare il formato R CMPS Rx, Ry, Rz Rx Ry Rz Non importanti Rx Primo registro sorgente Ry Secondo registro sorgente Rz Registro destinazione Con riferimento al datapath del DLX sequenziale visto a lezione, si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch ed alla decodifica. IR M[PC] A RS1 B RS2 PC PC + 4
(cioè Rx) (cioè Ry)
MAR A MDR M[MAR] TEMP (0)24 ## MDR0..7
Abbiamo messo in TEMP (dobbiamo infatti caricare l’altro valore e dobbiamo disporre di MAR e MDR liberi) ciò che c’è in M[Rx] (è un byte, quindi 8 bit).
MAR B MDR M[MAR] TEMP == (0)24 ## MDR0..7
In temp c’è il valore di M[Rx], in MDR quello di M[Ry] Sono uguali?
Sì No
Mettiamo o 1 oppure 0 in Rz
C 1 C 0
RD C Nell’ipotesi che tutti gli accessi alla memoria possano essere completati in 2 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. In fucsia le fasi in cui dobbiamo accedere alla memoria.
CLOCK TOTALI: 7 + 2 x 3 = 13 Utilizzando la nuova istruzione CMPS si scriva un frammento di codice assembler DLX che confronta due stringe di 100 caratteri, memorizzate rispettivamente agli indirizzi 1000H e 2000H, e ritorna nel registro R3 il risultato del confronto (R3 = 1 se le stringe sono uguali, R3 = 0 se le stringhe sono diverse). ADDI ADDI ADDI LOOP: CMPS BEQZ ADDI ADDI SUBI BNEZ SKIP: …
R1, R2, R4, R1, R3, R1, R2, R4, R4,
R0, 1000H R0, 2000H R0, 100 R2, R3 SKIP R1, 1 R2, 1 R4, 1 LOOP
Indirizzo del primo vettore Indirizzo del secondo vettore Contatore dei caratteri Confronta gli elementi Al primo elemento diverso, si salta a SKIP Incremento del puntatore della prima stringa Incremento del puntatore della seconda stringa Decremento del contatore Controllo del prossimo elemento
Sempre con riferimento al DLX sequenziale (cioè non-pipelined), si calcoli il CPImedio del codice scritto al punto precedente nell’ipotesi che le due stringhe siano uguali. Per l’istruzione CMPS si utilizzi il CPI precedentemente calcolato e per le altre istruzioni i valori visti a lezione e deducibili dai diagrammi degli stati del controllo (si mantenga l’ipotesi che ogni accesso alla memoria richieda 2 clock). ISTRUZIONE ALU BRANCH (taken) BRANCH (not-taken) CMPS
QUANDO Nell’inizializzazione (3 ALU); nel loop (300 ALU) 99 volte la BNEZ R4, LOOP 100 volte la BEQZ R3, SKIP Perché tutti gli elementi sono uguali 1 volta la BNEZ R4, LOOP Per quando avremo finito il confronto 100 volte nel loop
CLOCK 303 x 6 = 1818 99 x 5 = 495 101 x 4 = 404 100 x 13 = 1300
CLOCK TOTALI = 1818 + 495 + 404 + 1300 = 4017 N° ISTRUZIONI TOTALI = 303 + 99 + 101 + 100 = 603 CPI MEDIO = 4017 / 603 = circa 6.66 ESERCIZIO 2 Con riferimento al datapath del DLX sequenziale (cioè non-pipelined) visto a lezione, si consideri la micro-operazione: MAR A Si specifichi quelli sono i segnali di controllo che devono essere attivati dal Controller per far sì che il Datapath esegua la micro-operazione precedente. Si disegnino le forme d’onda dei segnali di controllo nell’ipotesi che il datapath esegua nel clock i la micro-operazione precedente e nel clock i+1 la micro-operazione C A + MAR
ESERCIZIO 1 Si supponga di voler estendere il set di istruzioni del DLX con l’istruzione SWAP_RM Rx, IMMEDIATE (Ry) Dove Rx, Ry rappresentano due registri generali ed IMMEDIATE una costante signed a 16 bit. La nuova istruzione scambia fra loro il contenuto del registro Rx e della word situata in memoria all’indirizzo (Ry + IMMEDIATE). Si mostri come potrebbe essere codificata la nuova istruzione utilizzando il più idoneo fra i tre formati delle istruzioni del DLX. Il formato più idoneo è quello di tipo I SWAP_RM Rx
Ry
IMMEDIATE
Con riferimento al datapath del DLX sequenziale visto a lezione si disegni il diagramma degli stati che controlla l’esecuzione della nuova istruzione inserendo anche gli stati necessari al fetch e alla decodifica. IR M[PC] A RS1 B RS2 PC PC + 4
STATI DI WAIT (cioè Rx) (cioè Ry)
MAR B + (IR15)16 ## IR15.0 MDR M[MAR] C MDR
Ora in C abbiamo M[Ry+Immediate] STATI DI WAIT
MDR A RS1 C
Mettiamo in MDR il registro Rx Mettiamo Ry in Rx
M[MAR] MDR
Mettiamo in M[Ry+Immediate] Rx STATI DI WAIT
Nell’ipotesi che tutti gli accesi alla memoria possano essere completati in 2 clock, si calcoli il numero di cicli di clock (CPI) necessari per l’esecuzione dell’istruzione. CPI = 4 + 3 x 2 = 10 Clock Si scriva la sequenza di istruzioni appartenenti all’ISA DLX studiato a lezione che consente di eseguire un’operazione il più possibile simile a quella svolta dalla SWAP_RM Rx, IMMEDIATE(Ry). In cosa differiscono le due operazioni? ADD LW SW
Rx, Rx, R0 Rx, IMMEDIATE(Ry) IMMEDIATE(Ry), Rz
Salvataggio di Rx in Rz Trasferimento di memoria da M[Ry+IMMEDIATE] a Rx Trasferimento da Rz a memoria
Le due istruzioni differiscono per l’uso del registro Rz, che resta modificato al termine della sequenza. ESERCIZIO 2 Si scriva il codice assembler DLX necessario all’esecuzione operazione descritta in un linguaggio di alto livello
della
seguente
For (i = 0; i < 100, i++) V1[i] = V2[V1[i]] Dove V1 e V2 sono due vettori di all’indirizzo 400H ed all’indirizzo 0. ADDI ADDI LOOP: LBU LBU SW ADDI SUBI BNEZ
R1, R3, R2, R2,
R0, 400H R0, 100 0(R1) 0(R2)
0(R1), R2 R1, R1, 1 R3, R3, 1 R3, LOOP
unsigned-byte
allocati
rispettivamente
Indice del vettore V1 Contatore delle iterazioni R2 è ora l’indice del vettore V1, cioè V1[i] Ora mettiamo in R2 il contenuto riferito dall’indice trovato precedentemente Mettiamo ora tutto nel primo vettore Incremento dell’indice di V1 Decremento del contatore iterazioni Se non abbiamo ancora finito, continuiamo a looppare
Con riferimento al DLX sequenziale si calcoli il CPI medio relativo all’esecuzione del codice scritto al punto precedente nell’ipotesi che ogni accesso alla memoria richieda 4 cicli di clock. Calcolo del CPI MEDIO: ISTRUZIONE QUANDO ALU 2 (inizializzazione) + 2 x 100 (ciclo) LOAD 2 x 100 (ciclo) STORE 100 (ciclo) BRANCH (taken) 99 (ciclo) BRANCH (not-taken) 1 (ciclo) CLOCK TOTALI = 1616 + 2400 + 1100 + 693 + 6 = 5815 N° ISTRUZIONI TOTALI = 202 + 200 + 100 + 99 + 1 = 602 CPI MEDIO = 5815 / 602 = 9.66 circa
CLOCK 8 x 202 = 12 x 200 = 11 x 100 = 7 x 99 = 6 x 1 =
1616 2400 1100 693 6