Appunti per Scuola e Università
humanisticheUmanistiche
Appunti e tesine di tutte le materie per gli studenti delle scuole medie riguardanti le materie umanistiche: dall'italiano alla storia riguardanti le materie umanistiche: dall'italiano alla storia 
sceintificheScientifiche
Appunti, analisi, compresione per le scuole medie suddivisi per materie scientifiche, per ognuna troverai appunti, dispense, esercitazioni, tesi e riassunti in download.
tecnicheTecniche
Gli appunti, le tesine e riassunti di tecnica amministrativa, ingegneria tecnico, costruzione. Tutti gli appunti di AppuntiMania.com gratis!
Appunti
tecniche
AeronauticaAgricoltura agrariaArchitetturaAutomobileCostruzione
Demografia urbanisticaElettronica elettricitaForensicsIngegneria tecnicoVela


AppuntiMania.com » Tecniche » Appunti di Elettronica elettricita » Tesina del corso di calcolatori elettronici 2 sulla microprogrammazione e la macroprogrammazione del processore mic-1"

Tesina del corso di calcolatori elettronici 2 sulla microprogrammazione e la macroprogrammazione del processore mic-1"




Visite: 1420Gradito:apreciate stela [ Grande appunti ]
Leggi anche appunti:

Telecommutatore di polarita' per un motore a due velocita'


TELECOMMUTATORE DI POLARITA' PER UN MOTORE A DUE VELOCITA' ELENCO MATERIALE FUNZIONAMENTO

Comparatore con isteresi


Comparatore con isteresi Nei rivelatori di zero e nei comparatori già visti

Convertitore D/A a resistori pesati - Realizzazione di un convertitore D/A e verifica del suo funzionamento


OGGETTO DELL'ESERCITAZIONE Convertitore D/A a resistori pesati SCOPO Realizzazione
immagine di categoria

Scarica gratis Tesina del corso di calcolatori elettronici 2 sulla microprogrammazione e la macroprogrammazione del processore mic-1

TESINA DEL CORSO DI CALCOLATORI ELETTRONICI 2 SULLA MICROPROGRAMMAZIONE E LA MACROPROGRAMMAZIONE DEL PROCESSORE MIC-1"





PROGRAMMA DI ESEMPIO

Per testare la IJVM si è approntato un semplice programma di test che legge da tastiera due numeri e ne stampa il prodotto , il quoziente ed il resto.

Il codice del programma main è :


.constant

OBJREF 0x40 // needed for method invokation

CO 0x4F //CODICE ASCII 'O'

CP 0x50 //CODICE ASCII 'P'

C1 0x31 //CODICE ASCII '1'

C2 0x32 //CODICE ASCII '2'

C= 0x3D //CODICE ASCII '='

CQ 0x51 //CODICE ASCII 'Q'

CU 0x55 //CODICE ASCII 'U'

CZ 0x5A //CODICE ASCII 'Z'

CR 0x52 //CODICE ASCII 'R'

CE 0x45 //CODICE ASCII 'E'

CS 0x53 //CODICE ASCII 'S'

CC. 0x2E //CODICE ASCII '.'

CLF 0X0A //LINE FEED

.end-constant



.main



.var

NUM1                                                  //VARIABILE LOCALE PRIMO NUMERO //LETTO

NUM2                                                  //VARIABILE LOCALE SECONDO NUMERO //LETTO

PROD //VARIABILE LOCALE PROTOTTO

QUOZIENTE //VARIABILE LOCALE QUOZIENTE

RESTO //VARIABILE LOCALE RESTO

DIVIDENDO                                        //VARIABILE LOCALE DIVIDENDO

DIVISORE                                            //VARIABILE LOCALE DIVISORE

.end-var


//PROGRAMMA CHE STAMPA IL PRODOTTO , IL QUOZIENTE ED IL RESTO DI DUE NUMERI A 2 //CIFRE LETTI DA TASTIERA

CICLO:            LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM1 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

//STAMPA SPAZIO BIANCO

LDC_W CLF //STAMPA A CAPO

OUT

LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM2 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

LDC_W CLF //STAMPA A CAPO

OUT

//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

LDC_W OBJREF //PUSH DI OBJREF

ILOAD NUM1 //PUSH PRIMO OPERANDO

ILOAD NUM2 //PUSH SECONDO OPERANDO

INVOKEVIRTUAL IMUL //EFFETTUA MOLTIPLICAZIONE

ISTORE PROD //SALVA PRODOTTO



ILOAD NUM1

ISTORE DIVIDENDO

ILOAD NUM2

ISTORE DIVISORE




//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

IDIV:                           BIPUSH 0x00

ISTORE QUOZIENTE //QUOZIENTE = 0

ILOAD DIVIDENDO

ISTORE RESTO //RESTO = DIVIDENDO

IDIV1: ILOAD DIVIDENDO //PUSH DIVIDENDOENDO

IFEQ FINE //SE DIV=0 SALTA A DIVZERO //ALTRIMENTI.

ILOAD DIVISORE //PUSH DIVISORE

IFEQ HALT1

TESTSEGNO: ILOAD RESTO

ILOAD DIVISORE

ISUB

IFLT FINE

SOTTRAI: ILOAD RESTO

ILOAD DIVISORE

ISUB

ISTORE RESTO //RESTO=RESTO-DIVISORE

INCREMENTA:                       IINC QUOZIENTE 0x01 //QUOZIENTE=QUOZIENTE+1

GOTO TESTSEGNO //RIPETE ITERAZIONE

HALT1:                       HALT //DIVISIONE PER ZERO

FINE:             ILOAD QUOZIENTE //PUSH QUOZIENTE (X IDIV)

ILOAD RESTO //PUSH RESTO (X IDIV)



ISTORE RESTO //SALVA RESTO

ISTORE QUOZIENTE //SALVA QUOZIENTE



//STAMPA DEL PRODOTTO , DEL QUOZIENTE E DEL RESTO

LDC_W OBJREF //PUSH DI OBJREF

ILOAD PROD //PUSH PRIMO OPERANDO

ILOAD QUOZIENTE //PUSH SECONDO OPERANDO

ILOAD RESTO //PUSH SECONDO OPERANDO

INVOKEVIRTUAL STAMPA_TUTTO //CHIAMATA METODO STAMPA DEI //RISULTATI



GOTO CICLO //RIPETE ALL'INFINITO

.end-main



Esso si occupa di stampare le scritte di richiesta di immissione dei due operandi , invoca i metodi per la conversione da ASCII/BCD a binario , esegue poi la moltiplicazione , calcola il quoziente ed il resto ed infine invoca il metodo per la stampa dei risultati.

Il codice del metodo per la lettura di un operando è:



//LEGGE DUE CARATTERI E RESTITUISCE IL NUMERO CONVERTITO IN BINARIO SULLO STACK

.method LEGGI()




.var

CAR1 //VARIABILE LOCALE PRIMO CARATTERE LETTO

CAR2 //VARIABILE LOCALE SECONDO CARATTERE LETTO

TEMP //VARIABILE DI APPOGGIO PER CONVERSIONE IN DECIMALE

.end-var



START:                       IN //LEGGE 1° CARATTERE DAL BUFFER

DUP //DUPLICA SULLO STACK

IFEQ CLEAR //SE NO CARATTERI SALTA A CLEAR

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

SECONDO:          IN //LEGGE SECONDO CARATTERE DAL BUFFER

DUP //LO DUPLICA SULLO STACK

IFEQ CLEAR2 //SE NIENTE CARATTERI SALTA A CLEAR2

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO

ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO DECINA

ILOAD CAR1 //PUSH DI CAR1

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB                 //AGGIUSTAMENTO DA ASCII A //DECIMALE

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO UNITA'

ILOAD CAR2 //PUSH DI CAR2

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB                 //AGGIUSTAMENTO DA ASCII A //DECIMALE

ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR2'

ILOAD CAR2 //PUSH DI CAR2

ISTORE TEMP //TEMP=UNITA'

LDC_W OBJREF //PUSH DI OBJREF

ILOAD CAR1 //PUSH DI DECINA

BIPUSH 0X0A //PUSH DI 10

INVOKEVIRTUAL IMUL //EFFETTUA MOLTIPLICAZIONE

ILOAD TEMP //PUSH DELLE UNITA'

IADD //CALCOLA DECINE + UNITA'

IRETURN //RITORNA

CLEAR2: POP //TOGLIE LO 0 DALLO STACK

GOTO SECONDO //E RICOMINCIA

CLEAR:                       POP //TOGLIE LO 0 DALLO STACK

GOTO START //E RICOMINCIA

.end-method



Per prima cosa il metodo legge decine ed unità , successivamente sottrae al codice ASCII di ciascuna cifra la costante 0x30 che è il codice ASCII di "0" ottenendo le due cifre. Fatto ciò il numero digitato viene calcolato sommando le unità alle decine moltiplicate per dieci ed infine viene restituito il numero così convertito.

Invece il metodo che calcola il prodotto è :


.method IMUL(OP1,OP2) //I DUE PARAMETRI SONO I DUE OPERANDI


.var

PRODOTTO //VARIABILE LOCALE QUOZIENTE

RESTO //VARIABILE LOCALE RESTO

.end-var




BIPUSH 0x00

ISTORE PRODOTTO //PRODOTTO=0

TEST: ILOAD OP1 //PUSH DI OP1

IFEQ FINE //SE OP1=0 VAI A FINE //ALTRIMENTI.

ILOAD OP2

ILOAD PRODOTTO

IADD

ISTORE PRODOTTO //PRODOTTO=PRODOTTO+OP2

IINC OP1 -1 //OP1=OP1-1

GOTO TEST

FINE: ILOAD PRODOTTO //PUSH PRODOTTO

IRETURN //RITORNA

.end-method



Esso si basa sull'algoritmo delle addizioni successive con la variante del controllo sull'operando usato come indice .

Infatti si effettua il test preliminare per controllare se esso sia nullo nullo , se questo non venisse fatto .

Infine il metodo per la stampa dei risultati è :




.method STAMPA_TUTTO(P1,P2,P3) //P1=PRODOTTO,P2=QUOZIENTE,P3=RESTO

LDC_W CP //STAMPA 'PRO='

OUT

LDC_W CR

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P1 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT


LDC_W CQ //STAMPA 'QUO='

OUT

LDC_W CU

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P2 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT



LDC_W CR //STAMPA 'RES='

OUT

LDC_W CE

OUT

LDC_W CS

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P3 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN

.end-method





.method STAMPA(P) //CONVERTE IN ASCII E STAMPA P


.var

DECINE //VAR. DI APPOGGIO PER CALCOLO DECINE

UNITA //VAR. DI APPOGGIO PER CALCOLO UNITA

CENTINAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

MIGLIAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

IDCHIAMANTE //VAR. DI APPOGGIO IDENTIFICATIVA 'DEL CHIAMANTE'

DIVIDENDO

DIVISORE

QUOZIENTE

RESTO

.end-var






//CONVERSIONE COL METODO DELLE DIVISIONI SUCCESSIVE PER 10

BIPUSH 0x00

ISTORE UNITA //AZZERA UNITA

BIPUSH 0x00

ISTORE DECINE //AZZERA DECINE

BIPUSH 0x00

ISTORE CENTINAIA //AZZERA CENTINAIA

BIPUSH 0x00

ISTORE MIGLIAIA //AZZERA MIGLIAIA


//RICAVO UNITA'

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10

// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x01

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE1: NOP

// ** ** ** ** ** ** ** ** ** ** **

ISTORE UNITA //RESTO DELLA DIVISIONE=UNITA'

ISTORE P //P = QUOZIENTE


//RICAVO DECINE

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10


// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x02

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE2: NOP

// ** ** ** ** ** ** ** ** ** ** **


ISTORE DECINE //RESTO DELLA DIVISIONE=DECINE

ISTORE P //P = QUOZIENTE


//RICAVO CENTINAIA E MIGLIAIA

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10


// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x03

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE3: NOP

// ** ** ** ** ** ** ** ** ** ** **

ISTORE CENTINAIA //RESTO DIVISIONE = CENTINAIA

ISTORE MIGLIAIA //MIGLIAIA = QUOZIENTE



//STAMPA CODICE ASCII MIGLIAIA

ILOAD MIGLIAIA //PUSH MIGLIAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA



//STAMPA CODICE ASCII CENTINAIA

ILOAD CENTINAIA //PUSH CENTINAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA


//STAMPA CODICE ASCII DECINE

ILOAD DECINE //PUSH DECINE

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA


//STAMPA CODICE ASCII UNITA

ILOAD UNITA //PUSH UNITA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN




//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

IDIV:                           BIPUSH 0x00

ISTORE QUOZIENTE //QUOZIENTE = 0

ILOAD DIVIDENDO

ISTORE RESTO //RESTO = DIVIDENDO

IDIV1: ILOAD DIVIDENDO //PUSH DIVIDENDOENDO

IFEQ FINE //SE DIVIDENDOENDO ZERO SALTA A //DIVZERO ALTRIMENTI.

ILOAD DIVISORE //PUSH DIVISORE

IFEQ HALT1

TESTSEGNO: ILOAD RESTO

ILOAD DIVISORE

ISUB

IFLT FINE

SOTTRAI: ILOAD RESTO

ILOAD DIVISORE

ISUB

ISTORE RESTO //RESTO=RESTO-DIVISORE

INCREMENTA:                       IINC QUOZIENTE 0x01 //QUOZIENTE=QUOZIENTE+1

GOTO TESTSEGNO //RIPETE ITERAZIONE

HALT1:                       HALT //DIVISIONE PER ZERO

FINE: ILOAD QUOZIENTE //PUSH QUOZIENTE (X //COMPATIBILITA' ISTRUZIONE IDIV)

ILOAD RESTO //PUSH RESTO (X COMPATIBILITA' //ISTRUZIONE IDIV)

RITORNO: ILOAD IDCHIAMANTE

BIPUSH 0x01

IF_ICMPEQ IDCHIAMANTE1 //SE IDCHIAMANTE=1 SALTA A //IDCHIAMANTE1

ILOAD IDCHIAMANTE

BIPUSH 0x02

IF_ICMPEQ IDCHIAMANTE2 //SE IDCHIAMANTE=1 SALTA A //IDCHIAMANTE2

ILOAD IDCHIAMANTE

BIPUSH 0x03

IF_ICMPEQ IDCHIAMANTE3 //SE IDCHIAMANTE=1 SALTA A //IDCHIAMANTE3






.end-method




Per poter stampare i risultati bisogna convertire in BCD ciascuno di essi ( prodotto , quoziente e resto ) e per far ciò si usa il metodo delle divisioni successive per dieci e leggendo i resti al contrario si ricavano centinaia , decine ed unità .

Le migliaia sono pari invece al quoziente dell'ultima divisione.

Successivamente si somma a ciascuna cifra la costante 0x30 ( che è il codice ASCII di "0" ) per ottenere il codice ASCII della relativa cifra e finalmente è possibile stampare ciascun numero a video.



AGGIUNTA DELLA MOLTIPLICAZIONE

Per dotare l'ISA della MIC-1 dell'operazione di moltiplicazione si è usato l'algoritmo delle somme successive di seguito riportato :





SI

Prodotto     =

Prodotto + op2

 
NO





Si è deciso di chiamare la nuova istruzione IMUL e di assegnarle il codice operativo 0x78 , quindi le microistruzioni che implementano l'algoritmo appena visto sono :




.label imul1 0x78// *****AGGIUNTO CODICE OPERATIVO DI MOLTIPLICAZIONE







//EFFETTUA LA MOLTIPLICAZIONE DELLE DUE PRIME WORD DELLO STACK E FA IL PUSH DEL //PRODOTTO

//DI CUI UNA E' GIA' NEL REGISTRO TOS E LA SECONDA E' DA PRELEVARE

//SI USA L'ALGORITMO DELLE SOMME RIPETUTE

//UN OPERANDO E' IN TOS (CHE CONTIENE L'OPERANDO DA USARE COME INDICE DEL CICLO //ITERATIVO A CONTEGGIO)

//E L'ALTRO E' IN MDR

//NEL REGISTRO H C'E' LA SOMMA PARZIALE CHE ALLA FINE PRODUCE IL PRODOTTO





imul1 Z=TOS;if(Z) goto imul7 ; else goto imul2 //TEST DELL'INDICE , SE //NULLO IL PRODOTTO VALE //ZERO ALTRIMENTI


imul2 MAR=SP=SP-1;rd //LEGGE SECONDO OPERANDO DALLO STACK E DECREMENTA //SP , ORA IL 2° OPERANDO E' IN MDR


imul3               H=0 //AZZERA SOMMA PARZIALE


imul4               H=H+MDR //INCREMENTA PRODOTTO PARZIALE


imul5               TOS=TOS-1;if(Z) goto imul6 ; else goto imul4 //SE INDICE NON NULLO //RIPETE SOMMA , //ALTRIMENTI PRODOTTO //FINITO


imul6               MDR=TOS=H;wr;goto Main1 //PUSH SULLO STACK DEL RISULTATO , AGGIORNO //TOS E SALTO ALLA MICROROUTINE DI FETCH


imul7               MDR=0;wr;goto Main1 //SE TOS = 0 ALLORA PRODOTTO = 0 E SALTO ALA //MICROROUTINE DI FETCH






Per comprendere l'utilizzo della nuova istruzione considero il seguente frammento di codice d'esempio:


(1) ILOAD NUM1


(2) ILOAD NUM2


(3) IMUL


L'evoluzione dello stack dopo l'istruzione (1) è la seguente:


NUM1

VAR2

VAR1

SP

LV


Dopo quella (2) invece:


NUM2

NUM1

VAR2

VAR1

SP


LV


Ed infine dopo quella (3) :

NUM1 * NUM2

VAR2

VAR1


SP

LV


Quindi bisogna fare il pop sullo stack dei due operandi , l'istruzione preleva i due operandi dallo stack facendone il pop , calcola il prodotto ed alla fine fa il push del prodotto sullo stack.


AGGIUNTA DELLA DIVISIONE

Invece per dotare l'ISA della MIC-1 dell'operazione di divisione si è usato l'algoritmo delle sottrazioni successive arricchito del controllo preliminare sulla nullità del dividendo e del divisore (eventualità quest'ultima, che provoca il blocco della MIC-1) riportato di seguito :






SI

NO

SI


NO

SI

resto =  resto - divisore

 
NO

quoziente = quoziente + 1

 




la nuova istruzione che effettua la divisione è stata chiamata IDIV e le è stato assegnato il codice operativo 0xE0.

Si riportano per comodità di comprensione le microistruzioni che implementano l'algoritmo appena descritto mediante il diagramma di flusso:


// ** ** ** ** ** ** ** ** ** ** ********//CONVENZIONE USATA PER I REGISTRI INTERNI

// H = DIVISORE

// TOS = DIVIDENDO

// MDR = QUOZIENTE

// OPC = RESTO

// PUSH DEL QUOZIENTE E POI DEL RESTO

// CONTEMPLA I CASI DI DIVIDENDO NULLO , DIVISORE NULLO E DIVIDENDO<DIVISORE

// VIENE USATO L'ALGORITMO DELLE SOTTRAZIONI SUCCESSIVE CON LA VARIANTE

// DEL CONTROLLO PRELIMINARE DEI TRE CASI PARTICOLARI MENZIONATI PRIMA.



idiv1 Z=TOS;if(Z) goto divzero ; else goto idiv2 //TEST DEL //DIVIDENDO(DIVIDENDO E' GIA' IN TOS) , SE NULLO IL QUOZIENTE VALE ZERO //ALTRIMENTI

idiv2 MAR=SP=SP-1;rd //LEGGE SECONDO OPERANDO DALLO STACK E DECREMENTA SP

idivwait OPC=TOS //RESTO=DIVIDENDO

testdivis Z=MDR;if(Z) goto halt1 ; else goto idiv3 //SE DIVISORE=0 HALT //PROCESSORE , ALTRIMENTI.

idiv3 H=MDR //ORA IL 2°OPERANDO(DIVISORE)E' IN MDRidiv3

idiv4 MDR=0 //AZZERA QUOZIENTE

test N=OPC-H;if(N) goto fine ; else goto resto //SE RESTO-DIVISORE<0 //( RESTO<DIVISORE) FINE DIVISIONE ALTRIMNTI PROS. ISTR.

resto OPC=OPC-H //RESTO=RESTO-DIVISORE

incquoz MDR=MDR+1;goto test //QUOZIENTE=QUOZIENTE+1 E RIPETE SOTTRAZIONE

fine wr //PUSH DEL QUOZIENTE

fine1 SP=MAR=SP+1 //INCREMENTO SP

fine2 MDR=TOS=OPC;wr;goto Main1 //PUSH DEL RESTO E SALTO ALA MICROROUTINE //DI FETCH

divzero MAR=SP=SP-1 //DECREMENTA SP PER POSIZIONARSI ALLA LOCAZIONE DEL //DIVISORE

divzero1 MDR=TOS=0;wr //QUOZIENTE=0

divzero2 MAR=SP=SP+1;goto Main1 //INCREMENTA SP PER POSIZIONARSI ALLA //LOCAZIONE DEL DIVIDENDO(GIA'=0)E







Per esempio considero il codice seguente :



(1) ILOAD DIVISORE


(2) ILOAD DIVIDENDO


(3) IDIV



lo stack dopo l'istruzione (1) è nel seguente stato :


DIVISORE

VAR2

VAR1

SP

LV



Dopo quella (2) invece:


DIVIDENDO

DIVISORE

VAR2

VAR1

SP


LV



Ed infine dopo quella (3) :


RESTO

QUOZIENTE

VAR2

VAR1

SP


LV



Quindi bisogna fare il pop sullo stack del divisore e poi del dividendo , l'istruzione preleva i due operandi dallo stack facendone il pop , calcola il quoziente ed il resto ed alla fine fa il push prima del quoziente e poi del resto sullo stack .



PROGRAMMA FINALE SENZA ISTRUZIONI

IDIV E IMUL


Segue il programma di test completo senza le istruzioni IDIV ed IMUL :





.constant

OBJREF 0x40 // needed for method invokation - see S.C.O. //chapter 4

CO 0x4F //CODICE ASCII 'O'

CP 0x50 //CODICE ASCII 'P'

C1 0x31 //CODICE ASCII '1'

C2 0x32 //CODICE ASCII '2'

C= 0x3D //CODICE ASCII '='

CQ 0x51 //CODICE ASCII 'Q'

CU 0x55 //CODICE ASCII 'U'

CZ 0x5A //CODICE ASCII 'Z'

CR 0x52 //CODICE ASCII 'R'

CE 0x45 //CODICE ASCII 'E'

CS 0x53 //CODICE ASCII 'S'

CC. 0x2E //CODICE ASCII '.'

CLF 0X0A //LINE FEED

.end-constant



.main



.var

NUM1                                                  //VARIABILE LOCALE PRIMO NUMERO //LETTO

NUM2                                                  //VARIABILE LOCALE SECONDO NUMERO //LETTO

PROD //VARIABILE LOCALE PROTOTTO

QUOZIENTE //VARIABILE LOCALE QUOZIENTE

RESTO //VARIABILE LOCALE RESTO

DIVIDENDO                                        //VARIABILE LOCALE DIVIDENDO

DIVISORE                              //VARIABILE LOCALE DIVISORE

.end-var

//PROGRAMMA CHE STAMPA IL PRODOTTO , IL QUOZIENTE ED IL RESTO DI DUE NUMERI A 2 CIFRE LETTI DA TASTIERA

CICLO:            LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM1 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

//STAMPA SPAZIO BIANCO

LDC_W CLF //STAMPA A CAPO

OUT

LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM2 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

LDC_W CLF //STAMPA A CAPO

OUT

//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

LDC_W OBJREF //PUSH DI OBJREF

ILOAD NUM1 //PUSH PRIMO OPERANDO

ILOAD NUM2 //PUSH SECONDO OPERANDO

INVOKEVIRTUAL IMUL //EFFETTUA MOLTIPLICAZIONE

ISTORE PROD //SALVA PRODOTTO



ILOAD NUM1

ISTORE DIVIDENDO

ILOAD NUM2

ISTORE DIVISORE




//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

IDIV:                           BIPUSH 0x00

ISTORE QUOZIENTE //QUOZIENTE = 0

ILOAD DIVIDENDO

ISTORE RESTO //RESTO = DIVIDENDO

IDIV1: ILOAD DIVIDENDO //PUSH DIVIDENDOENDO

IFEQ FINE //SE DIVIDENDOENDO ZERO SALTA A //DIVZERO ALTRIMENTI.

ILOAD DIVISORE //PUSH DIVISORE

IFEQ HALT1

TESTSEGNO: ILOAD RESTO

ILOAD DIVISORE

ISUB

IFLT FINE

SOTTRAI: ILOAD RESTO

ILOAD DIVISORE

ISUB

ISTORE RESTO //RESTO=RESTO-DIVISORE

INCREMENTA:                       IINC QUOZIENTE 0x01 //QUOZIENTE=QUOZIENTE+1

GOTO TESTSEGNO //RIPETE ITERAZIONE

HALT1:                       HALT //DIVISIONE PER ZERO

FINE: ILOAD QUOZIENTE //PUSH QUOZIENTE (X //COMPATIBILITA' ISTRUZIONE IDIV)

ILOAD RESTO //PUSH RESTO (X COMPATIBILITA' //ISTRUZIONE IDIV)



ISTORE RESTO //SALVA RESTO

ISTORE QUOZIENTE //SALVA QUOZIENTE



//STAMPA DEL PRODOTTO , DEL QUOZIENTE E DEL RESTO

LDC_W OBJREF //PUSH DI OBJREF

ILOAD PROD //PUSH PRIMO OPERANDO //(PARAMETRO1)

ILOAD QUOZIENTE //PUSH SECONDO OPERANDO //(PARAMETRO2)

ILOAD RESTO //PUSH SECONDO OPERANDO //(PARAMETRO2)

INVOKEVIRTUAL STAMPA_TUTTO //CHIAMATA METODO STAMPA DEI //RISULTATI



GOTO CICLO //RIPETE ALL'INFINITO

.end-main


//LEGGE DUE CARATTERI E RESTITUISCE IL NUMERO CONVERTITO IN BINARIO SULLO STACK

.method LEGGI()




.var

CAR1 //VARIABILE LOCALE PRIMO CARATTERE LETTO

CAR2 //VARIABILE LOCALE SECONDO CARATTERE LETTO

TEMP //VARIABILE DI APPOGGIO PER CONVERSIONE IN DECIMALE

.end-var



START:                       IN //LEGGE PRIMO CARATTERE DAL //BUFFER

DUP //DUPLICA SULLO STACK

IFEQ CLEAR //SE NIENTE CARATTERI SALTA A //CLEAR

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA VARIABILE LOCALE 'CAR1'

SECONDO:          IN //LEGGE SECONDO CARATTERE DAL //BUFFER

DUP //LO DUPLICA SULLO STACK

IFEQ CLEAR2 //SE NIENTE CARATTERI SALTA A //CLEAR2

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO

ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO DECINA

ILOAD CAR1 //PUSH DI CAR1

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB                 //AGGIUSTAMENTO DA ASCII A //DECIMALE

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO UNITA'

ILOAD CAR2 //PUSH DI CAR2

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB                 //AGGIUSTAMENTO DA ASCII A //DECIMALE

ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR2'

ILOAD CAR2 //PUSH DI CAR2

ISTORE TEMP //TEMP=UNITA'

LDC_W OBJREF //PUSH DI OBJREF

ILOAD CAR1 //PUSH DI DECINA

BIPUSH 0X0A //PUSH DI 10

INVOKEVIRTUAL IMUL //EFFETTUA MOLTIPLICAZIONE ILOAD TEMP //PUSH DELLE UNITA'

IADD //CALCOLA DECINE + UNITA'

IRETURN //RITORNA

CLEAR2: POP //TOGLIE LO 0 DALLO STACK

GOTO SECONDO //E RICOMINCIA

CLEAR:                       POP //TOGLIE LO 0 DALLO STACK

GOTO START //E RICOMINCIA

.end-method





.method IMUL(OP1,OP2) //I DUE PARAMETRI SONO I DUE OPERANDI


.var

PRODOTTO //VARIABILE LOCALE QUOZIENTE

RESTO //VARIABILE LOCALE RESTO

.end-var




BIPUSH 0x00

ISTORE PRODOTTO //PRODOTTO=0

TEST: ILOAD OP1 //PUSH DI OP1

IFEQ FINE //SE OP1=0 VAI A FINE //ALTRIMENTI.

ILOAD OP2

ILOAD PRODOTTO

IADD

ISTORE PRODOTTO //PRODOTTO=PRODOTTO+OP2 IINC OP1 -1 //OP1=OP1-1

GOTO TEST

FINE: ILOAD PRODOTTO //PUSH PRODOTTO

IRETURN //RITORNA

.end-method




.method STAMPA_TUTTO(P1,P2,P3) //P1=PRODOTTO,P2=QUOZIENTE,P3=RESTO

LDC_W CP //STAMPA 'PRO='

OUT

LDC_W CR

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P1 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT


LDC_W CQ //STAMPA 'QUO='

OUT

LDC_W CU

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P2 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT



LDC_W CR //STAMPA 'RES='

OUT

LDC_W CE

OUT

LDC_W CS

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P3 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN

.end-method





.method STAMPA(P) //CONVERTE IN ASCII E STAMPA P


.var

DECINE //VAR. DI APPOGGIO PER CALCOLO DECINE

UNITA //VAR. DI APPOGGIO PER CALCOLO UNITA

CENTINAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

MIGLIAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

IDCHIAMANTE //VAR. DI APPOGGIO IDENTIFICATIVA 'DEL CHIAMANTE'

DIVIDENDO

DIVISORE

QUOZIENTE

RESTO

.end-var






//CONVERSIONE COL METODO DELLE DIVISIONI SUCCESSIVE PER 10

BIPUSH 0x00

ISTORE UNITA //AZZERA UNITA

BIPUSH 0x00

ISTORE DECINE //AZZERA DECINE

BIPUSH 0x00

ISTORE CENTINAIA //AZZERA CENTINAIA

BIPUSH 0x00

ISTORE MIGLIAIA //AZZERA MIGLIAIA


//RICAVO UNITA'

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10

// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO

ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x01

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE1: NOP

// ** ** ** ** ** ** ** ** ** ** **

ISTORE UNITA //RESTO DELLA DIVISIONE=UNITA'

ISTORE P //P = QUOZIENTE


//RICAVO DECINE

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10


// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO

ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x02

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE2: NOP

// ** ** ** ** ** ** ** ** ** ** **


ISTORE DECINE //RESTO DELLA DIVISIONE=DECINE

ISTORE P //P = QUOZIENTE


//RICAVO CENTINAIA E MIGLIAIA

ILOAD P //PUSH DEL PRODOTTO

BIPUSH 0x0A //PUSH DI 10


// ** ** ** ** ******* DA SOSTITUIRE CON IDIV

ISTORE DIVISORE //POP DIVIDENDO E SALVATAGGIO ISTORE DIVIDENDO //POP DIVISORE E SALVATAGGIO

BIPUSH 0x03

ISTORE IDCHIAMANTE //CARICA IDENTIFICATIVO CHIAMANTE

GOTO IDIV

IDCHIAMANTE3: NOP

// ** ** ** ** ** ** ** ** ** ** **


ISTORE CENTINAIA //RESTO DELLA DIVISIONE = //CENTINAIA

ISTORE MIGLIAIA //MIGLIAIA = QUOZIENTE



//STAMPA CODICE ASCII MIGLIAIA

ILOAD MIGLIAIA //PUSH MIGLIAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA



//STAMPA CODICE ASCII CENTINAIA

ILOAD CENTINAIA //PUSH CENTINAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA

//STAMPA CODICE ASCII DECINE

ILOAD DECINE //PUSH DECINE

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA


//STAMPA CODICE ASCII UNITA

ILOAD UNITA //PUSH UNITA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN




//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

IDIV:                           BIPUSH 0x00

ISTORE QUOZIENTE //QUOZIENTE = 0

ILOAD DIVIDENDO

ISTORE RESTO //RESTO = DIVIDENDO

IDIV1: ILOAD DIVIDENDO //PUSH DIVIDENDOENDO

IFEQ FINE //SE DIVIDENDOENDO ZERO SALTA A //DIVZERO ALTRIMENTI.

ILOAD DIVISORE //PUSH DIVISORE

IFEQ HALT1

TESTSEGNO: ILOAD RESTO

ILOAD DIVISORE

ISUB

IFLT FINE

SOTTRAI: ILOAD RESTO

ILOAD DIVISORE

ISUB

ISTORE RESTO //RESTO=RESTO-DIVISORE

INCREMENTA:                       IINC QUOZIENTE 0x01 //QUOZIENTE=QUOZIENTE+1

GOTO TESTSEGNO //RIPETE ITERAZIONE

HALT1:                       HALT //DIVISIONE PER ZERO

FINE: ILOAD QUOZIENTE //PUSH QUOZIENTE (X //COMPATIBILITA' ISTRUZIONE IDIV)

ILOAD RESTO //PUSH RESTO (X COMPATIBILITA' //ISTRUZIONE IDIV)

RITORNO: ILOAD IDCHIAMANTE

BIPUSH 0x01

IF_ICMPEQ IDCHIAMANTE1 //SE IDCHIAMANTE=1 SALTA A IDCHIAMANTE1

ILOAD IDCHIAMANTE

BIPUSH 0x02

IF_ICMPEQ IDCHIAMANTE2 //SE IDCHIAMANTE=1 SALTA A //IDCHIAMANTE2

ILOAD IDCHIAMANTE

BIPUSH 0x03

IF_ICMPEQ IDCHIAMANTE3 //SE IDCHIAMANTE=1 SALTA A IDCHIAMANTE3




.end-method


PROGRAMMA FINALE CON ISTRUZIONI

IDIV E IMUL

Si riporta di seguito la variante del programma visto all'inizio che adopera le due nuove istruzioni aggiunte all'ISA del processore in luogo dei metodi di moltiplicazione e di divisione :


.constant

OBJREF 0x40 // needed for method invokation - see S.C.O. //chapter 4

CO 0x4F //CODICE ASCII 'O'

CP 0x50 //CODICE ASCII 'P'

C1 0x31 //CODICE ASCII '1'

C2 0x32 //CODICE ASCII '2'

C= 0x3D //CODICE ASCII '='

CQ 0x51 //CODICE ASCII 'Q'

CU 0x55 //CODICE ASCII 'U'

CZ 0x5A //CODICE ASCII 'Z'

CR 0x52 //CODICE ASCII 'R'

CE 0x45 //CODICE ASCII 'E'

CS 0x53 //CODICE ASCII 'S'

CC. 0x2E //CODICE ASCII '.'

CLF 0X0A //LINE FEED

.end-constant



.main



.var

NUM1                                                  //VARIABILE LOCALE PRIMO NUMERO //LETTO

NUM2                                                  //VARIABILE LOCALE SECONDO NUMERO //LETTO

PROD //VARIABILE LOCALE PROTOTTO

QUOZIENTE //VARIABILE LOCALE QUOZIENTE

RESTO //VARIABILE LOCALE RESTO

DIVIDENDO                                        //VARIABILE LOCALE DIVIDENDO

DIVISORE                                            //VARIABILE LOCALE DIVISORE

.end-var

//PROGRAMMA CHE STAMPA IL PRODOTTO , IL QUOZIENTE ED IL RESTO DI DUE NUMERI A 2 //CIFRE LETTI DA TASTIERA

CICLO:            LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM1 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

//STAMPA SPAZIO BIANCO

LDC_W CLF //STAMPA A CAPO

OUT

LDC_W CO //STAMPA SCRITTA 'OP='

OUT

LDC_W CP

OUT

LDC_W C=

OUT

//LETTURA PRIMO OPERANDO A DUE CIFRE ED ECO SU SCHERMO

LDC_W OBJREF //PUSH DI OBJREF

INVOKEVIRTUAL LEGGI //INVOCO METODO LETTURA PRIMO //OPERANDO E CONVERSIONE

ISTORE NUM2 //SALVA NUMERO CONVERTITO NELLA //VARIABILE LOCALE 'NUM1'

LDC_W CLF //STAMPA A CAPO

OUT

//CALCOLO DEL PRODOTTO DEI DUE NUMERI LETTI E CONVERTITI

LDC_W OBJREF //PUSH DI OBJREF

ILOAD NUM1 //PUSH PRIMO OPERANDO

ILOAD NUM2 //PUSH SECONDO OPERANDO

IMUL //EFFETTUA MOLTIPLICAZIONE

ISTORE PROD //SALVA PRODOTTO



ILOAD NUM2

ILOAD NUM1


IDIV


ISTORE RESTO //SALVA RESTO

ISTORE QUOZIENTE //SALVA QUOZIENTE



//STAMPA DEL PRODOTTO , DEL QUOZIENTE E DEL RESTO

LDC_W OBJREF //PUSH DI OBJREF

ILOAD PROD //PUSH PRIMO OPERANDO //(PARAMETRO1)

ILOAD QUOZIENTE //PUSH SECONDO OPERANDO //(PARAMETRO2)

ILOAD RESTO //PUSH SECONDO OPERANDO //(PARAMETRO2)

INVOKEVIRTUAL STAMPA_TUTTO //CHIAMATA METODO STAMPA DEI //RISULTATI



GOTO CICLO //RIPETE ALL'INFINITO

.end-main


//LEGGE DUE CARATTERI E RESTITUISCE IL NUMERO CONVERTITO IN BINARIO SULLO STACK

.method LEGGI()




.var

CAR1 //VARIABILE LOCALE PRIMO CARATTERE LETTO

CAR2 //VARIABILE LOCALE SECONDO CARATTERE LETTO

TEMP //VARIABILE DI APPOGGIO PER CONVERSIONE IN DECIMALE

.end-var



START:                       IN //LEGGE PRIMO CARATTERE DAL //BUFFER

DUP //DUPLICA SULLO STACK

IFEQ CLEAR //SE NIENTE CARATTERI SALTA A //CLEAR

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

SECONDO:          IN //LEGGE SECONDO CARATTERE DAL //BUFFER

DUP //LO DUPLICA SULLO STACK

IFEQ CLEAR2 //SE NIENTE CARATTERI SALTA A //CLEAR2

DUP //DUPLICA STACK

OUT //ECHO CARATTERE DIGITATO ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO DECINA

ILOAD CAR1 //PUSH DI CAR1

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB                 //AGGIUSTAMENTO DA ASCII A //DECIMALE

ISTORE CAR1 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR1'

//CONVERTO UNITA'

ILOAD CAR2 //PUSH DI CAR2

BIPUSH 0X30 //PUSH DI 0x30='0'

ISUB //AGGIUSTAMENTO DA ASCII A DECIMALE

ISTORE CAR2 //SALVA CARATTERE LETTO NELLA //VARIABILE LOCALE 'CAR2'

ILOAD CAR2 //PUSH DI CAR2

ISTORE TEMP //TEMP=UNITA'

LDC_W OBJREF //PUSH DI OBJREF

ILOAD CAR1 //PUSH DI DECINA

BIPUSH 0X0A //PUSH DI 10

IMUL //EFFETTUA MOLTIPLICAZIONE ILOAD TEMP //PUSH DELLE UNITA'

IADD //CALCOLA DECINE + UNITA'

IRETURN //RITORNA

CLEAR2: POP //TOGLIE LO 0 DALLO STACK

GOTO SECONDO //E RICOMINCIA

CLEAR:                       POP //TOGLIE LO 0 DALLO STACK

GOTO START //E RICOMINCIA

.end-method





.method STAMPA_TUTTO(P1,P2,P3) //P1=PRODOTTO,P2=QUOZIENTE,P3=RESTO

LDC_W CP //STAMPA 'PRO='

OUT

LDC_W CR

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P1 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT

LDC_W CQ //STAMPA 'QUO='

OUT

LDC_W CU

OUT

LDC_W CO

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P2 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT



LDC_W CR //STAMPA 'RES='

OUT

LDC_W CE

OUT

LDC_W CS

OUT

LDC_W C=

OUT

LDC_W OBJREF //PUSH DI OBJREF

ILOAD P3 //PUSH DEL PRIMO NUMERO DA //CONVERTIRE

INVOKEVIRTUAL STAMPA //INVOCA METODO

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN

.end-method





.method STAMPA(P) //CONVERTE IN ASCII E STAMPA P


.var

DECINE //VAR. DI APPOGGIO PER CALCOLO DECINE

UNITA //VAR. DI APPOGGIO PER CALCOLO UNITA

CENTINAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

MIGLIAIA //VAR. DI APPOGGIO PER CALCOLO CENTINAIA

IDCHIAMANTE //VAR. DI APPOGGIO IDENTIFICATIVA 'DEL CHIAMANTE'

DIVIDENDO

DIVISORE

QUOZIENTE

RESTO

.end-var






//CONVERSIONE COL METODO DELLE DIVISIONI SUCCESSIVE PER 10

BIPUSH 0x00

ISTORE UNITA //AZZERA UNITA

BIPUSH 0x00

ISTORE DECINE //AZZERA DECINE

BIPUSH 0x00

ISTORE CENTINAIA //AZZERA CENTINAIA

BIPUSH 0x00

ISTORE MIGLIAIA //AZZERA MIGLIAIA


//RICAVO UNITA'

BIPUSH 0x0A //PUSH DI 10

ILOAD P //PUSH DEL PRODOTTO


IDIV


ISTORE UNITA //RESTO DELLA DIVISIONE=UNITA'

ISTORE P //P = QUOZIENTE


//RICAVO DECINE

BIPUSH 0x0A //PUSH DI 10

ILOAD P //PUSH DEL PRODOTTO


IDIV


ISTORE DECINE //RESTO DELLA DIVISIONE=DECINE

ISTORE P //P = QUOZIENTE


//RICAVO CENTINAIA E MIGLIAIA

BIPUSH 0x0A //PUSH DI 10

ILOAD P //PUSH DEL PRODOTTO

IDIV


ISTORE CENTINAIA //RESTO DELLA DIVISIONE = //CENTINAIA

ISTORE MIGLIAIA //MIGLIAIA = QUOZIENTE



//STAMPA CODICE ASCII MIGLIAIA

ILOAD MIGLIAIA //PUSH MIGLIAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA



//STAMPA CODICE ASCII CENTINAIA

ILOAD CENTINAIA //PUSH CENTINAIA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA


//STAMPA CODICE ASCII DECINE

ILOAD DECINE //PUSH DECINE

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA


//STAMPA CODICE ASCII UNITA

ILOAD UNITA //PUSH UNITA

BIPUSH 0X30 //PUSH CODICE ASCII DI '0'

IADD //TRASFORMA CIFRA DECIMALE IN //CORRISPONDENTE CODICE ASCII

OUT //STAMPA

LDC_W CLF //STAMPA A CAPO

OUT

IRETURN




.end-method




MICROPROGRAMMA FINALE DELA MIC-1


Ecco il microprogramma completo della MIC-1 arricchito delle istruzioni IMUL ed IDIV :


// note that this is nearly identical to the example

// given in Tanenbaum. Note:


// 1) SlashSlash-style ('//') comment characters have been added.


// 2) 'nop' has been added as a pseudo-instruction to indicate that

// nothing should be done except goto the next instruction. It

// is a do-nothing sub-instruction that allows us to have MAL

// statements without a label.


// 3) instructions are 'anchored' to locations in the control

// store as defined below with the '.label' pseudo-instruction


// 4) a default instruction may be specified using the '.default'

// pseudo-instruction. This instruction is placed in all

// unused locations of the control store by the mic1 MAL assembler.



// labeled statements are 'anchored' at the specified control store address

.label nop1 0x00

.label bipush1 0x10

.label ldc_w1 0x13

.label iload1 0x15

.label wide_iload1 0x115

.label istore1 0x36

.label wide_istore1 0x136

.label pop1 0x57

.label dup1 0x59

.label swap1 0x5F

.label iadd1 0x60

.label isub1 0x64

.label iand1 0x7E

.label iinc1 0x84

.label ifeq1 0x99

.label iflt1 0x9B

.label if_icmpeq1 0x9F

.label goto1 0xA7

.label ireturn1 0xAC

.label ior1 0xB0

.label invokevirtual1 0xB6

.label wide1 0xC4

.label halt1 0xFF

.label err1 0xFE

.label out1 0xFD

.label in1 0xFC

.label imul1 0x78 // ******** AGGIUNTO CODICE OPERATIVO //DI MOLTIPLICAZIONE

.label idiv1 0xE0 // ******** AGGIUNTO CODICE OPERATIVO //DI DIVISIONE


// default instruction to place in any unused addresses of the control store

.default goto err1


Main1 PC = PC + 1; fetch; goto (MBR) // MBR holds opcode; get next byte; dispatch


nop1 goto Main1 // Do nothing


iadd1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

iadd2 H = TOS // H = top of stack

iadd3 MDR = TOS = MDR + H; wr; goto Main1 // Add top two words; write to top of //stack


isub1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

isub2 H = TOS // H = top of stack

isub3 MDR = TOS = MDR - H; wr; goto Main1 // Do subtraction; write to top of //stack


iand1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

iand2 H = TOS // H = top of stack

iand3 MDR = TOS = MDR AND H; wr; goto Main1 // Do AND; write to new top of //stack


ior1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

ior2 H = TOS // H = top of stack

ior3 MDR = TOS = MDR OR H; wr; goto Main1 // Do OR; write to new top of //stack


dup1 MAR = SP = SP + 1 // Increment SP and copy to MAR

dup2 MDR = TOS; wr; goto Main1 // Write new stack word


pop1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

pop2 // Wait for new TOS to be read from memory

pop3 TOS = MDR; goto Main1 // Copy new word to TOS


swap1 MAR = SP - 1; rd // Set MAR to SP - 1; read 2nd word from stack

swap2 MAR = SP // Set MAR to top word

swap3 H = MDR; wr // Save TOS in H; write 2nd word to top of stack

swap4 MDR = TOS // Copy old TOS to MDR

swap5 MAR = SP - 1; wr // Set MAR to SP - 1; write as 2nd word on stack

swap6 TOS = H; goto Main1 // Update TOS


bipush1 SP = MAR = SP + 1 // MBR = the byte to push onto stack

bipush2 PC = PC + 1; fetch // Increment PC, fetch next opcode

bipush3 MDR = TOS = MBR; wr; goto Main1 // Sign-extend constant and push on stack



iload1 H = LV // MBR contains index; copy LV to H

iload2 MAR = MBRU + H; rd // MAR = address of local variable to push

iload3 MAR = SP = SP + 1 // SP points to new top of stack; prepare write

iload4 PC = PC + 1; fetch; wr // Inc PC; get next opcode; write top of stack

iload5 TOS = MDR; goto Main1 // Update TOS


istore1 H = LV // MBR contains index; Copy LV to H

istore2 MAR = MBRU + H // MAR = address of local variable to store into

istore3 MDR = TOS; wr // Copy TOS to MDR; write word

istore4 SP = MAR = SP - 1; rd // Read in next-to-top word on stack

istore5 PC = PC + 1; fetch // Increment PC; fetch next opcode

istore6 TOS = MDR; goto Main1 // Update TOS

wide1 PC = PC + 1; fetch; goto (MBR OR 0x100) // Multiway branch with high bit set


wide_iload1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd

wide_iload2 H = MBRU << 8 // H = 1st index byte shifted left 8 bits

wide_iload3 H = MBRU OR H // H = 16-bit index of local variable

wide_iload4 MAR = LV + H; rd; goto iload3 // MAR = address of local variable to push


wide_istore1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd

wide_istore2 H = MBRU << 8 // H = 1st index byte shifted left 8 bits

wide_istore3 H = MBRU OR H // H = 16-bit index of local variable

wide_istore4 MAR = LV + H; goto istore3 // MAR = address of local variable to store into


ldc_w1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd

ldc_w2 H = MBRU << 8 // H = 1st index byte << 8

ldc_w3 H = MBRU OR H // H = 16-bit index into constant pool

ldc_w4 MAR = H + CPP; rd; goto iload3 // MAR = address of constant in pool


iinc1 H = LV // MBR contains index; Copy LV to H

iinc2 MAR = MBRU + H; rd // Copy LV + index to MAR; Read variable

iinc3 PC = PC + 1; fetch // Fetch constant

iinc4 H = MDR // Copy variable to H

iinc5 PC = PC + 1; fetch // Fetch next opcode

iinc6 MDR = MBR + H; wr; goto Main1 // Put sum in MDR; update variable


goto1 OPC = PC - 1 // Save address of opcode.

goto2 PC = PC + 1; fetch // MBR = 1st byte of offset; fetch 2nd byte

goto3 H = MBR << 8 // Shift and save signed first byte in H

goto4 H = MBRU OR H // H = 16-bit branch offset

goto5 PC = OPC + H; fetch // Add offset to OPC

goto6 goto Main1 // Wait for fetch of next opcode


iflt1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack

iflt2 OPC = TOS // Save TOS in OPC temporarily

iflt3 TOS = MDR // Put new top of stack in TOS

iflt4 N = OPC; if (N) goto T; else goto F // Branch on N bit


ifeq1 MAR = SP = SP - 1; rd // Read in next-to-top word of stack

ifeq2 OPC = TOS // Save TOS in OPC temporarily

ifeq3 TOS = MDR // Put new top of stack in TOS

ifeq4 Z = OPC; if (Z) goto T; else goto F // Branch on Z bit


if_icmpeq1 MAR = SP = SP - 1; rd // Read in next-to-top word of stack

if_icmpeq2 MAR = SP = SP - 1 // Set MAR to read in new top-of-stack

if_icmpeq3 H = MDR; rd // Copy second stack word to H

if_icmpeq4 OPC = TOS // Save TOS in OPC temporarily

if_icmpeq5 TOS = MDR // Put new top of stack in TOS

if_icmpeq6 Z = OPC - H; if (Z) goto T; else goto F // If top 2 words are equal, goto T, else goto F


T OPC = PC - 1; fetch; goto goto2 // Same as goto1; needed for target address


F PC = PC + 1 // Skip first offset byte

F2 PC = PC + 1; fetch // PC now points to next opcode

F3 goto Main1 // Wait for fetch of opcode







//EFFETTUA LA MOLTIPLICAZIONE DELLE DUE PRIME WORD DELLO STACK E FA IL PUSH DEL //PRODOTTO

//DI CUI UNA E' GIA' NEL REGISTRO TOS E LA SECONDA E' DA PRELEVARE

//SI USA L'ALGORITMO DELLE SOMME RIPETUTE

//UN OPERANDO E' IN TOS (CHE CONTIENE L'OPERANDO DA USARE COME INDICE DEL CICLO //ITERATIVO A CONTEGGIO)

//E L'ALTRO E' IN MDR

//NEL REGISTRO H C'E' LA SOMMA PARZIALE CHE ALLA FINE PRODUCE IL PRODOTTO





imul1 Z=TOS;if(Z) goto imul7 ; else goto imul2 //TEST DELL'INDICE , SE //NULLO IL PRODOTTO VALE ZERO ALTRIMENTI

imul2 MAR=SP=SP-1;rd //LEGGE SECONDO OPERANDO DALLO STACK E DECREMENTA SP , ORA IL 2° OPERANDO E' IN MDR

imul3               H=0 //AZZERA SOMMA PARZIALE

imul4               H=H+MDR //INCREMENTA PRODOTTO PARZIALE

imul5               TOS=TOS-1;if(Z) goto imul6 ; else goto imul4 //SE INDICE NON NULLO //RIPETE SOMMA , ALTRIMENTI PRODOTTO FINITO

imul6               MDR=TOS=H;wr;goto Main1 //PUSH SULLO STACK DEL RISULTATO , AGGIORNO //TOS E SALTO ALLA MICROROUTINE DI FETCH

imul7               MDR=0;wr;goto Main1 //SE TOS = 0 ALLORA PRODOTTO = 0 E SALTO ALA //MICROROUTINE DI FETCH










//CONVENZIONE USATA PER I REGISTRI INTERNI

// H = DIVISORE

// TOS = DIVIDENDO

// MDR = QUOZIENTE

// OPC = RESTO

// PUSH DEL QUOZIENTE E POI DEL RESTO

// CONTEMPLA I CASI DI DIVIDENDO NULLO , DIVISORE NULLO E DIVIDENDO<DIVISORE

// VIENE USATO L'ALGORITMO DELLE SOTTRAZIONI SUCCESSIVE CON LA VARIANTE

// DEL CONTROLLO PRELIMINARE DEI TRE CASI PARTICOLARI MENZIONATI PRIMA.



idiv1 Z=TOS;if(Z) goto divzero ; else goto idiv2 //TEST DEL //DIVIDENDO(DIVIDENDO E' GIA' IN TOS) , SE NULLO IL QUOZIENTE VALE ZERO //ALTRIMENTI

idiv2 MAR=SP=SP-1;rd //LEGGE SECONDO OPERANDO DALLO STACK E DECREMENTA SP idivwait OPC=TOS //RESTO=DIVIDENDO

testdivis Z=MDR;if(Z) goto halt1 ; else goto idiv3 //SE DIVISORE=0 HALT //PROCESSORE , ALTRIMENTI.

idiv3 H=MDR //ORA IL 2°OPERANDO(DIVISORE)E' IN MDRidiv3

idiv4 MDR=0 //AZZERA QUOZIENTE

test N=OPC-H;if(N) goto fine ; else goto resto //SE RESTO-DIVISORE<0 //(RESTO<DIVISORE) FINE DIVISIONE ALTRIMNTI PROS. ISTR.

resto OPC=OPC-H //RESTO=RESTO-DIVISORE

incquoz MDR=MDR+1;goto test //QUOZIENTE=QUOZIENTE+1 E RIPETE SOTTRAZIONE

fine wr //PUSH DEL QUOZIENTE

fine1 SP=MAR=SP+1 //INCREMENTO SP

fine2 MDR=TOS=OPC;wr;goto Main1 //PUSH DEL RESTO E SALTO ALA MICROROUTINE //DI FETCH

divzero MAR=SP=SP-1 //DECREMENTA SP PER POSIZIONARSI ALLA LOCAZIONE DEL //DIVISORE

divzero1 MDR=TOS=0;wr //QUOZIENTE=0

divzero2 MAR=SP=SP+1;goto Main1 //INCREMENTA SP PER POSIZIONARSI ALLA

//LOCAZIONE DEL DIVIDENDO(GIA'=0)E









invokevirtual1 PC = PC + 1; fetch // MBR = index byte 1; inc. PC, get 2nd //byte

invokevirtual2 H = MBRU << 8 // Shift and save first byte in H

invokevirtual3 H = MBRU OR H // H = offset of method pointer from //CPP

invokevirtual4 MAR = CPP + H; rd // Get pointer to method from CPP area

invokevirtual5 OPC = PC + 1 // Save Return PC in OPC temporarily

invokevirtual6 PC = MDR; fetch // PC points to new method; get param //count

invokevirtual7 PC = PC + 1; fetch // Fetch 2nd byte of parameter count

invokevirtual8 H = MBRU << 8 // Shift and save first byte in H

invokevirtual9 H = MBRU OR H // H = number of parameters

invokevirtual10 PC = PC + 1; fetch // Fetch first byte of # locals

invokevirtual11 TOS = SP - H // TOS = address of OBJREF - 1

invokevirtual12 TOS = MAR = TOS + 1 // TOS = address of OBJREF (new LV)

invokevirtual13 PC = PC + 1; fetch // Fetch second byte of # locals

invokevirtual14 H = MBRU << 8 // Shift and save first byte in H

invokevirtual15 H = MBRU OR H // H = # locals

invokevirtual16 MDR = SP + H + 1; wr // Overwrite OBJREF with link pointer

invokevirtual17 MAR = SP = MDR; // Set SP, MAR to location to hold old //PC

invokevirtual18 MDR = OPC; wr // Save old PC above the local //variables

invokevirtual19 MAR = SP = SP + 1 // SP points to location to hold old LV

invokevirtual20 MDR = LV; wr // Save old LV above saved PC

invokevirtual21 PC = PC + 1; fetch // Fetch first opcode of new method.

invokevirtual22 LV = TOS; goto Main1 // Set LV to point to LV Frame



ireturn1 MAR = SP = LV; rd // Reset SP, MAR to get link pointer

ireturn2 // Wait for read

ireturn3 LV = MAR = MDR; rd // Set LV to link ptr; get old PC

ireturn4 MAR = LV + 1 // Set MAR to read old LV

ireturn5 PC = MDR; rd; fetch // Restore PC; fetch next opcode

ireturn6 MAR = SP // Set MAR to write TOS

ireturn7 LV = MDR // Restore LV

ireturn8 MDR = TOS; wr; goto Main1 // Save return value on original top of stack



halt1 goto halt1



err1 OPC=H=-1

OPC=H+OPC

MAR=H+OPC // compute IO address

OPC=H=1 // 1

OPC=H=H+OPC // 10

OPC=H=H+OPC // 100

OPC=H=H+OPC // 1000

OPC=H=H+OPC+1 // 10001

OPC=H=H+OPC // 100010

MDR=H+OPC+1;wr // 1000101 'E'

OPC=H=1 // 1

OPC=H=H+OPC // 10

OPC=H=H+OPC+1 // 101

OPC=H=H+OPC // 1010

OPC=H=H+OPC // 10100

OPC=H=H+OPC+1 // 101001

MDR=H+OPC;wr // 1010010 'R'

nop

MDR=H+OPC;wr // 1010010 'R'

OPC=H=1 // 1

OPC=H=H+OPC // 10

OPC=H=H+OPC // 100

OPC=H=H+OPC+1 // 1001

OPC=H=H+OPC+1 // 10011

OPC=H=H+OPC+1 // 100111

MDR=H+OPC+1;wr // 1001111 'O'

OPC=H=1 // 1

OPC=H=H+OPC // 10

OPC=H=H+OPC+1 // 101

OPC=H=H+OPC // 1010

OPC=H=H+OPC // 10100

OPC=H=H+OPC+1 // 101001

MDR=H+OPC;wr // 1010010 'R'

goto halt1


out1 OPC=H=-1

OPC=H+OPC

MAR=H+OPC // compute OUT address

MDR=TOS; wr // write to output

nop

MAR=SP=SP-1; rd // decrement stack pointer

nop

TOS=MDR; goto Main1


in1 OPC=H=-1

OPC=H+OPC

MAR=H+OPC;rd // compute IN address ; read from input

MAR=SP=SP+1 // increment SP; wait for read

TOS=MDR;wr ; goto Main1 // Write















FILE IJVM.CONF







// configuration file for IJVM Assembler

0x10 BIPUSH byte // Push byte onto stack

0x59 DUP // Copy top word on stack; push onto stack

0xA7 GOTO label // Unconditional jump

0x60 IADD // Pop two words from stack; push their sum

0x7E IAND // Pop two words from stack; push Boolean AND

0x99 IFEQ label // Pop word from stack; branch if it is zero

0x9B IFLT label // Pop word from stack; branch if it is less than zero

0x9F IF_ICMPEQ label // Pop two words from stack; branch if equal

0x84 IINC varnum const // Add a constant to a local variable

0x15 ILOAD varnum // Push local variable onto stack

0xB6 INVOKEVIRTUAL offset // Invoke a method

0xB0 IOR // Pop two words from stack; push Boolean OR

0xAC IRETURN // Return from method with integer value

0x36 ISTORE varnum // Pop word from stack; store in local variable

0x64 ISUB // Pop two words from stack; push their difference

0x13 LDC_W index // Push constant from constant pool onto stack

0x00 NOP // Do nothing

0x57 POP // Delete word on top of stack

0x5F SWAP // Swap the two top words on the stack

0xC4 WIDE // Prefix instruction; next instruction has 16-bit index

0xFF HALT // halt the simulator

0xFE ERR // print ERROR and halt

0xFD OUT // Pop a word from the stack and use the low order8-bits // as an ASCI character to display on screen

0xFC IN // Read a character from standard input and put it in // the low order 8-bits of a word pushed onto the stack

0x78 IMUL // MOLTIPLICA LE DUE TOP WORD DALLO STACK E FA IL PUSH // DEL PRODOTTO

0xE0 IDIV // DIVIDE LE DUE TOP WORD DALLO STACK E FA IL PUSH DEL // QUOZIENTE E DEL RESTO










Scarica gratis Tesina del corso di calcolatori elettronici 2 sulla microprogrammazione e la macroprogrammazione del processore mic-1
Appunti su:



Scarica 100% gratis e , tesine, riassunti



Registrati ora

Password dimenticata?
  • Appunti superiori
  • In questa sezione troverai sunti esame, dispense, appunti universitari, esercitazioni e tesi, suddivisi per le principali facoltà.
  • Università
  • Appunti, dispense, esercitazioni, riassunti direttamente dalla tua aula Universitaria
  • all'Informatica
  • Introduzione all'Informatica, Information and Comunication Tecnology, componenti del computer, software, hardware ...

Appunti Gestione Gestione
Tesine costruzione costruzione
Lezioni Ingegneria tecnico Ingegneria tecnico