Come eseguire il loop e codificare come binario?

Sep 02 2020

Sto cercando di ottenere un programma in esecuzione in LMC che converte qualsiasi valore numerico in binario.

Normalmente userei solo il metodo di divisione, ma non posso farlo poiché Little Man Computer non consente la divisione o la moltiplicazione. Il più lontano che ho ottenuto in questo è solo un semplice INP. In questa fase non so come avviare i loop in esso, o nemmeno come iniziare.

Come posso avviare i loop? E come posso fermarli? Avrei in qualche modo bisogno di un ciclo ripetuto che sottrae un valore fino a quando non raggiunge un 1 o uno 0. Ciò raggiungerà il mio obiettivo in quanto posso semplicemente inviarlo in output.

Ad esempio: inserisco 33 e nell'output viene restituito 100 001.

Sono un principiante assoluto. L'ho appena preso oggi, quindi mantenerlo semplice sarebbe molto apprezzato.

Risposte

trincot Sep 07 2020 at 19:31

Scrivi che per 33 l'output dovrebbe essere 100 001. Questo potrebbe non funzionare (a seconda del simulatore LMC), poiché il secondo valore potrebbe essere emesso senza gli zeri preinseriti, e quindi mostrerebbe 100 1. Questo può creare confusione in quanto assomiglia molto a quello che ti aspetteresti per l'input 9.

Suggerirei di emettere ogni cifra binaria come un numero separato : in questo modo ti assicuri che tutte le cifre siano visibili nell'output.

Un algoritmo per codificare un input n in questo modo potrebbe essere il seguente:

  1. Confronta n con 512. Se non è inferiore:

    un. Uscita 1 e sottrarre 512 da n , altrimenti:

    b. Uscita 0

  2. Raddoppia il valore di n , cioè aggiungi n a se stesso

  3. Ripeti quanto sopra altre 9 volte. Decrementa un contatore che inizia con 10 e ripeti fino a quando non imposta il flag negativo.

Come eseguire il loop

Quindi "avvia" un ciclo in modo statico: imposta il valore iniziale di un contatore in DATun'istruzione. Nell'algoritmo di cui sopra vogliamo che il contatore inizi a 10:

COUNTER DAT 10

Quindi, quando è necessario eseguire il ciclo, diminuisci il contatore:

LDA COUNTER
SUB ONE
STA COUNTER

E (come molti programmi LMC), hai bisogno di una costante ONEper questo:

ONE DAT 1

Infine, per sapere se il contatore non è andato sotto lo 0, puoi controllare il flag "negativo". Questo è un flag che può essere impostato da SUB, quando c'è un overflow negativo (ricorda che LMC non può davvero memorizzare valori negativi, quindi hai solo il flag come indicazione). L' BRPistruzione (branch se positiva) utilizzerà quel flag per decidere se saltare o meno:

BRP LOOP

LOOP dovrebbe essere l'etichetta del punto in cui è iniziato il codice del ciclo.

Implementazione

Si noti che in questo caso pratico, non è utile eseguire questo ciclo più di 10 volte, poiché l'input in LMC non può essere superiore a 999, che in binario richiede 10 cifre.

Ecco l'implementazione dell'algoritmo sopra descritto, con anche una precauzione che il contatore partirà dal suo valore iniziale anche quando il contatore del programma viene azzerato dopo una prima esecuzione:

#input:13
         INP
         STA NUM
         LDA NINE
LOOP     STA COUNTER
         LDA NUM
COMPARE  SUB POW_9
         BRP BIT1
BIT0     LDA ZERO
         OUT
         BRA DOUBLE
BIT1     STA NUM  ; Reduce number with 512
         LDA ONE
         OUT
DOUBLE   LDA NUM
         ADD NUM
         STA NUM
         LDA COUNTER
         SUB ONE
         BRP LOOP
ZERO     HLT
POW_9    DAT 512
ONE      DAT   1
NINE     DAT   9
NUM      DAT
COUNTER  DAT

<script src="https://cdn.jsdelivr.net/gh/trincot/[email protected]/lmc.js"></script>

Alternativa

Esistono diversi altri modi per eseguire questa operazione. Ad esempio, possiamo codificare le potenze di 2 di cui abbiamo bisogno per 10 cifre binarie: 1, 2, 4, ..., 512.

Quindi confrontare il valore di input con il maggiore di quelli (con 2 9 = 512). Se non è inferiore, emette 1 bit, altrimenti emette 0. Se 1, sottrarre quella potenza di 2 dal numero di ingresso. In entrambi i casi, passare alla potenza precedente di 2 (2 8 ) e ripetere questo processo. Ripeti finché non hai completato il lavoro per 2 0 .

Potresti provare a implementarlo senza un ciclo, ma avrai 10 volte lo stesso codice, con solo una potenza diversa di 2. Questa potrebbe anche essere una sfida da inserire nella memoria di LMC di 100 "caselle di posta" (funzionerebbe tuttavia, se si limita l'input a 64, quindi occorrono solo 6 cifre binarie).

Per implementarlo con un ciclo (meno codice), è possibile utilizzare una tecnica di indirizzamento indiretto. In LMC non ci sono istruzioni per l'indirizzamento indiretto, ma con il codice auto-modificante è possibile.

Supponiamo di avere l'elenco dei poteri implementati come segue:

POW_9   DAT 512
POW_8   DAT 256
; ... etc
POW_0   DAT 1

Quindi faresti un confronto dell'accumulatore con POW_9 tramite:

COMPARE SUB POW_9

L'etichetta ci consente di memorizzare un'istruzione diversa lì, in modo che la prossima volta che viene eseguita la esegua effettivamente:

COMPARE SUB POW_8

Ciò è possibile con la seguente manipolazione:

LDA COMPARE
ADD ONE
STA COMPARE

Questo è un po 'complicato perché il codice viene trattato come dati e questo modifica il codice. Notare come la modifica SUB POW_9funzioni effettivamente come se si facesse riferimento a un elemento in un array e si aumentasse l'indice in quell'array.

È necessario disporre di una condizione di arresto in modo da non rendere il riferimento al codice una potenza di 2 che non è DATnell'elenco. Per questo puoi confrontare il codice modificato con un pezzo di codice fisso (anche a SUB, ma che non viene mai eseguito) che fa riferimento alla potenza più bassa di 2.

Ecco un'implementazione di questa idea:

#input:13
         INP
         STA NUM
         LDA FIRST
LOOP     STA COMPARE ; self-modifying code!
         SUB LAST    ; Compare with "SUB ZERO"
         BRP ZERO  
         LDA NUM
COMPARE  SUB POW_9 ; Indirect addressing
         BRP BIT1
BIT0     LDA ZERO
         OUT
         BRA NEXT
BIT1     STA NUM  ; Reduce number with power
         LDA ONE
         OUT
NEXT     LDA COMPARE ; Change power of 2
         ADD ONE
         BRA LOOP
FIRST    SUB POW_9  ; Never executed
LAST     SUB ZERO   ; Never executed
POW_9    DAT 512
POW_8    DAT 256
POW_7    DAT 128
POW_6    DAT  64
POW_5    DAT  32
POW_4    DAT  16
POW_3    DAT   8
POW_2    DAT   4
POW_1    DAT   2
ONE      DAT   1
ZERO     HLT
NUM      DAT

<script src="https://cdn.jsdelivr.net/gh/trincot/[email protected]/lmc.js"></script>