* * * *

Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

Trascinare un file nel programma
DB concetti fondamentali e ZeosLib
Recuperare codice HTML da pagina web
Mandare mail con Lazarus
Stabilire il sistema operativo
Esempio lista in pascal
File INI
Codice di attivazione
Realizzare programmi multilingua
Lavorare con le directory
Utilizzare Unità esterne
TTreeView
TTreeview e Menu
Generare controlli RUN-TIME
LazReport, PDF ed immagini
Intercettare tasti premuti
Ampliare Lazarus
Lazarus e la crittografia
System Tray con Lazarus
UIB: Unified Interbase
Il file: questo sconosciuto
Conferma di chiusura di un applicazione
Liste e puntatori
Overload di funzioni
Funzioni a parametri variabili
Proprietà
Conversione numerica
TImage su Form e Panel
Indy gestiore server FTP lato Client
PopUpMenu sotto Pulsante (TSpeedButton)
Direttiva $macro
Toolbar
Evidenziare voci TreeView
Visualizzare un file Html esterno
StatusBar - aggirare l'errore variabile duplicata
Da DataSource a Excel
Le permutazioni
Brute force
Indy 10 - Invio email con allegati
La gestione degli errori in Lazarus
Pascal Script
Linux + Zeos + Firebird
Dataset virtuale
Overload di operatori
Lavorare con file in formato JSON con Lazarus
Zeos ... dietro le quinte (prima parte)
Disporre le finestre in un blocco unico (come Delphi)
Aspetto retrò (Cmd Line)
Lazarus 1.0
Come interfacciare periferica twain
Ubuntu - aggiornare free pascal e lazarus
fpcup: installazioni parallele di lazarus e fpc
Free Pascal e Lazarus sul Raspberry Pi
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Creare un server multithread
guida all'installazione di fpc trunk da subversion in linux gentoo
Indice
DB concetti fondamentali e connessioni standard
Advanced Record Syntax
DB concetti fondamentali e DBGrid
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
Advanced Record Syntax: un esempio pratico
Superclasse form base per programmi gestionali (e non)
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Installare lazarus su mac osx sierra
immagine docker per lavorare con lazarus e free pascal
TDD o Test-Driven Development
Benvenuto! Effettua l'accesso oppure registrati.
Novembre 24, 2024, 10:41:54 am

Inserisci il nome utente, la password e la durata della sessione.

54 Visitatori, 1 Utente
 

Autore Topic: Emulatore di Chip 16  (Letto 11577 volte)

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Emulatore di Chip 16
« il: Gennaio 30, 2012, 11:25:18 am »
Ho notato che ultimamente il forum è un po' fermo. Per ravvivare l'interesse voglio proporvi un progetto affascinante (almeno per me). Si tratta di scrivere un emulatore di Chip16 :)
Non lasciatevi spaventare: il Chip16 è una console virtuale, ideata proprio per i principianti. Riporto dalla pagina ufficiale:
Citazione
What is Chip16?
 
 Chip16 is intended as a fairly easy to implement, well documented and community supported system which would aid beginners when writing their emulator.
 This would solve many CHIP8 inconsistencies as well as undocumented features sometimes (possibly) added by interpreter authors themselves.
 CHIP16 has a regular D-PAD controller with 4 buttons in contrast to CHIP8's somewhat messy 16 keys keyboard.

Parlavo di "console virtuale", in quanto non esiste fisicamente: sono state stabilite delle specifiche tecniche semplificate ma funzionanti, ed è stato inventato un set di OP codes in assembly che permettono di programmare la macchina virtuale. E' stato quindi sviluppato un assemblatore utilizzato da alcuni coraggiosi per scrivere delle demo direttamente in ASM ed è in sviluppo persino un compilatore Pascal.

La sfida che propongo è quella di provare a scrivere in pascal un software che emuli il Chip16. Potremo utilizzare questo topic per chiedere chiarimenti e per mostrare lo stato dei nostri lavori  :)

Il mio emulatore è a buon punto. Sto cercando di riorganizzare un po' il codice, che al momento risulta abbastanza incasinato...  ::) Per chi volesse dare un occhio al mio emulatore in esecuzione:
 http://www.youtube.com/watch?v=WvC7umlwzhA

Trovate maggiori informazioni e le specifiche tecniche qui:
http://forums.ngemu.com/showthread.php?t=145620
Consiglio di consultare anche il vecchio topic qui:
http://forums.ngemu.com/showthread.php?t=138170


Fatemi sapere cosa ne pensate  ;)

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3276
  • Karma: +12/-0
Re:Emulatore di Chip 16
« Risposta #1 il: Gennaio 30, 2012, 11:47:02 am »
Penso che sia veramente una cosa carina da fare. Dicci qualcosa di più al riguardo, cosa sarebbe da implementare sul tuo!
E quali potrebbero essere gli usi di un tale emulatore.  :)
Ieri è passato, domani è futuro, oggi è un dono...

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Re:Emulatore di Chip 16
« Risposta #2 il: Gennaio 30, 2012, 01:50:03 pm »
Sul mio, sto completando l'emulazione della parte audio. C'è da migliorare il debugger integrato, ma non è una priorità. Il resto sembrerebbe funzionare, salvo alcuni opcodes che sono stati aggiunti di recente alle specifiche, che non vengono sfruttati da nessuna ROM. Teoricamente dovrebbero funzionare, praticamente non posso ancora testarli  ;D

L'utilità di un emulatore è sempre relativa: ai fini pratici serve a far girare su una macchina del software creato per un'altra. Questo Chip16 può essere un buon punto di partenza per chi vuole imparare a programmare un emulatore e non vuole partire subito con qualcosa di più complesso.

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3276
  • Karma: +12/-0
Re:Emulatore di Chip 16
« Risposta #3 il: Gennaio 30, 2012, 02:03:11 pm »
Bhe dai, ora vediamo la partecipazione della gente al progetto!
Ieri è passato, domani è futuro, oggi è un dono...

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Re:Emulatore di Chip 16
« Risposta #4 il: Gennaio 30, 2012, 02:07:54 pm »
In ogni caso, chiarisco un punto che probabilmente dal mio primo post non si capisce bene: non sto invitando altri utenti ad aiutarmi a completare il mio emulatore, ma sto invitandoli a provare a scrivere ognuno il proprio, rendendomi disponibile per eventuali chiarimenti e consigli (nel mio piccolo, si intende: questo è il primo emulatore che scrivo, se si eccettua un emulatore di Chip8 che ho buttato giù quest'estate, che ho abbandonato per mancanza di interesse) ;)
Magari stasera proverò a buttare giù un paio di righe per spiegare come ho strutturato il mio emulatore :)

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3276
  • Karma: +12/-0
Re:Emulatore di Chip 16
« Risposta #5 il: Gennaio 30, 2012, 02:10:04 pm »
Capito. Bella idea!  :)
Ieri è passato, domani è futuro, oggi è un dono...

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Re:Emulatore di Chip 16
« Risposta #6 il: Gennaio 31, 2012, 10:28:09 am »
Oh, allora, vediamo di descrivere come è strutturato il mio emulatore :)

Per prima cosa, occorre dire che un emulatore riproduce via software ogni componente hardware di un computer/console. Io ho utlizzato una classe per la CPU e il core, una per la GPU e una per le ROM. Il chip16, come dicevo, è strutturato in maniera molto semplice, quindi non occorre altro.

Il core della console prevede 64KB ($FFFF) di memoria, che viene utilizzata sia per il codice che per la grafica (probabilmente in una prossima revisione verrà aggiunto un altro banco di 64KB da utilizzare soltanto per la grafica). Gli ultimi "chunks" di questi 64 kb sono usati per lo stack (512 bites a partire dalla locazione $FDF0) e per le porte I/O, cioè i pad (2 bytes per ogni pad; il pad1 a partire dalla locazione $FFF0 e il pad2 a partire dalla locazione $FFF2) di cui parlerò in seguito. Nell'emulatore la memoria è rappresentata da un array monodimensionale di byte:
Codice: [Seleziona]
fMemory: array [$0000..$FFFF] of byte;
E' qui che andremo a caricare i dati recuperati dalla ROM.

La CPU è lievemente più complicata. Ha una velocità di clock pari a 1Mhz ed utilizza un'architettura little endian.  E' dotata di una serie di registri: un Program Counter di 16 bit (PC) che tiene l'indirizzo dell'opcode correntemente eseguito; uno Stack Pointer di 16 bit (SP) che indica la posizione dell'ultimo slot dello stack utilizzato; 16 registri generici di 16 bit cadauno (R0-RF); un registro di 8 bit per i flag di sistema. Io ho provveduto ad implementare i registri in un record:
Codice: [Seleziona]
type
  TBit = 0..1;
  TRegisters = record
    PC: word;                   // Program Counter
    SP: word;                   // Stack pointer
    R: array [$0..$F] of word;  // Registers
    flag: array [0..7] of TBit;
  end;   
...
var
  fRegisters: TRegisters;

La parte più interessante della CPU è quella della gestione degli OpCodes. Essi sono il set di comandi che la CPU è in grado di interpretare; vengono eseguiti in un ciclo macchina. Ogni OpCode occupa 32 bit in memoria, ovvero 4 byte; gli 8 bit più a sinistra indicano l'opcode vero e proprio; gli altri bit sono invece i parametri che l'OpCode accetta. Ad esempio, l'OpCode per impostare il colore dello schermo al valore memorizzato nello slot 4 della palette è:

Codice: [Seleziona]
0C 00 04 00
Ovviamente ogni opcode ha dei valori mnemonici associati. Il comando qui sopra viene creato dall'assemblatore a partire dal codice asm:
Codice: [Seleziona]
BGC 4

Detta così sembrerebbe semplice. Il problema è che i valori a 8 bit dei parametri non vengono utilizzati sempre in maniera lineare. Ad esempio, un OpCode per disegnare sullo schermo è il seguente:

Codice: [Seleziona]
05 YX LL HH  =  DRW RX, RY, HHLL 

Come si può notare, l'opcode richiede che il byte XY venga scomposto in X e Y, mentre i restanti 1+1 byte LL e HH vengano ricomposti come HHLL. In cifre:
Codice: [Seleziona]
 05 24 7A 9E  =  DRW R4, R2, 9E7A 

Una soluzione sarebbe quella di scrivere delle funzioni che, a partire dall'opcode, restituiscano i valori richiesti, tramite operazioni sui bit. Io ho preferito sfruttare alcune caratteristiche dei record (bit packing, varianza ed helpers):

Codice: [Seleziona]
  TOpCode = bitpacked record
    case integer of
      0: ( full: longword; );
      1: ( case integer of
             0: ( LLHH: 0..$FFFF; );
             1: ( HH: 0..$FF;
                  LL: 0..$FF; );
             2: ( dummy_0: 0..$FF;
                  Z: 0..$F;
                  dummy_1: 0..$F;
                  X:  $0..$F;
                  Y:  $0..$F;
                  OP: $0..$FF; ); );
  end;

  TOpCodeHelper = record helper for TOpCode
    function HHLL(): word;   
  end;

...

function TOpCodeHelper.HHLL(): word;
begin
  result := (HH shl or LL;
end; 

Ricapitolando, utilizzando una combinazione di variant record e bitpacking riesco ad ottenere la porzione di OpCode che mi serve. Per ricomporre LL e HH invece ho utilizzato i record avanzati di freepascal, da attivare tramite
Codice: [Seleziona]
{$modeswitch advancedrecords}
In questo modo aggiungo al record precedente un campo HHLL calcolato dalla funzione HHLL() dell'helper. :)

Edit: ho corretto alcune imprecisioni sulla parte degli OpCodes
continua... ;)
« Ultima modifica: Gennaio 31, 2012, 01:49:31 pm da Legolas »

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Re:Emulatore di Chip 16
« Risposta #7 il: Gennaio 31, 2012, 02:33:10 pm »
...segue!

Faccio un esempio per far comprendere meglio come funziona il bitpacked record qui sopra. Per prima cosa assegno un valore al campo "full" del record (nel nostro caso si tratta dei 4 byte dell'opcode letto direttamente dalla memoria dell'emulatore):

Codice: [Seleziona]
var
 fOpCode: TOpCode;
...
  fOpCode.full := $05247A9E;

Con questa semplice operazione ho già tutti gli altri campi del record pronti per essere utilizzati, senza dover ricorrere a chiamate a funzioni o operazioni sui bit, che richiedono cicli macchina. In un emulatore così semplice la differenza è impercettibile, ma in emulatori più pesanti il risparmio in termini di pesantezza di calcolo si fa sentire!
Codice: [Seleziona]
fOpCode.full -> $05247A9E

fOpCode.OP -> $05
fOpCode.Y -> $2
fOpCode.X -> $4
fOpCode.Z -> $7
fOpCode.LL -> $7A
fOpCode.HH -> $9E
fOpCode.LLHH -> $7A9E
fOpCode.HHLL -> $9E7A

A questo punto nella variabile fOpCode ho l'opcode corrente e tutti i parametri che mi occorrono per stabilire cosa dovrà fare la CPU. Non rimane che trovare un metodo per associare ogni opcode ad una specifica funzione. Occorre per prima cosa creare le funzioni che ci serviranno. Ne mostro qualcuna, per dare un'idea:

Codice: [Seleziona]
    procedure cpuNOP();                 
    procedure cpuCLS();                 
    procedure cpuVBLNK();             
    procedure cpuBGC_N();           
    procedure cpuMOV_RX_RY();
...

procedure TC16CPUCore.cpuNOP();
begin
  // Take a coffee while I'm wasting a cycle
end;

procedure TC16CPUCore.cpuCLS();
begin
  ClearScreen();
end;

procedure TC16CPUCore.cpuVBLNK();
begin
  WaitForVBlank := true;
end;

procedure TC16CPUCore.cpuBGC_N();
begin
  BGColor := fOpcode.Z;
end;

procedure TC16CPUCore.cpuMOV_RX_RY();
begin
  fRegisters.R[fOpcode.X] := fRegisters.R[fOpcode.Y];
end; 

continua... :P

Legolas

  • Global Moderator
  • Sr. Member
  • *****
  • Post: 366
  • Karma: +3/-0
Re:Emulatore di Chip 16
« Risposta #8 il: Febbraio 01, 2012, 12:31:32 pm »
...segue!

Ora c'è tutto quello che occorre per eseguire il tipico loop degli emulatori:
  • Fetch: viene recuperato dalla memoria l'opcode da eseguire
  • Decode: l'opcode viene decodificato ed associato ad una funzione
  • Execute: viene eseguita la funzione associata all'opcode
Uno dei punti cruciali nell'emulazione della CPU è il modo in cui vengono associati gli opcode alle funzioni da eseguire. Un modo potrebbe essere quello di creare un enorme blocco "case...of" contenente tutti gli opcode:
Codice: [Seleziona]
case fOpcode.OP of
    $00: cpuNOP();    // nop
    $01: cpuCLS();     // cls
    $02: cpuVBLNK(); // vblnk 
...
else
  cpuUnknown();
end;

Io ho preferito implementare una "jump table", ossia un array di funzioni in cui l'indice corrisponde all'opcode da eseguire.
Codice: [Seleziona]
type
  TProc = procedure of object;
...
var
  fTableOP: array [$00..$D1] of TProc;

...

procedure fillTableOP();
var
  a: integer;
begin
  // riempio l'array con un opcode di default
  for a := low(fTableOP) to high(fTableOP) do
    fTableOP[a] := @cpuUnknown;

  // sostituisco i valori con gli opcode implementati
  fTableOP[$00] := @cpuNOP;
  fTableOP[$01] := @cpuCLS;
  fTableOP[$02] := @cpuVBLNK; 
  ...
end;

...

procedure Fetch();
begin
  fOpcode.full := (fMemory[fRegisters.PC] shl 24) or
                  (fMemory[fRegisters.PC + 1] shl 16) or
                  (fMemory[fRegisters.PC + 2] shl or
                   fMemory[fRegisters.PC + 3];

  if fRegisters.PC >= $FFFF then
    Dec(fRegisters.PC, 4);
end;

procedure Execute();
begin
    Fetch();
    if (fOpcode.OP >= $00) and (fOpcode.OP <= $D1) then
       fTableOP[fOpcode.OP];
    inc(fRegisters.PC, 4);
end;

Come si può vedere, le operazioni di decode ed execute vengono eseguite in un singolo passaggio, con un buon incremento di velocità di esecuzione.

Ecco, in linea di massima questo è il funzionamento di base del mio emulatore. Se avete domande, sono qua  ;D

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 3276
  • Karma: +12/-0
Re:Emulatore di Chip 16
« Risposta #9 il: Febbraio 01, 2012, 07:08:17 pm »
Lgolas molto interessante. Che ne dici di raggrupparlo in un unico post e farne un bell'articolo?!  ;)
Ieri è passato, domani è futuro, oggi è un dono...

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Emulatore di Chip 16
« Risposta #10 il: Novembre 16, 2016, 01:48:50 pm »
Faccio salite il post :)
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Emulatore di Chip 16
« Risposta #11 il: Novembre 16, 2016, 03:09:24 pm »
Questi sono gli opcode in ordine numerico :)
Codice: [Seleziona]
  00 00 00 00 | NOP | No operation. | | 0.8 |
  01 00 00 00 | CLS | Clear `FG`, `BG` = 0. | |0.8 |
  02 00 00 00 | VBLNK | Wait for VBlank. If (!vblank) `PC` -= 4; | |0.8 |
  03 00 0N 00 | BGC N | Set background color to index `N` (0 is black). | |0.8 |
  04 00 LL HH | SPR HHLL | Set sprite width (`LL`) and height (`HH`). | |0.8 |
  05 YX LL HH | DRW RX, RY, HHLL | Draw sprite from address `HHLL` at (`RX`, `RY`). | `C` | 0.8 |
  06 YX 0Z 00 | DRW RX, RY, RZ | Draw sprite from `[RZ]` at (RX, RY). | `C` | 0.8 |
  07 0X LL HH | RND RX, HHLL | Store random number in `RX` (max. `HHLL`). || 0.8 |
  08 00 00 00 | FLIP 0, 0 | Set `hflip` = false, `vflip` = false | |0.8 |
  08 00 00 01 | FLIP 0, 1 | Set `hflip` = false, `vflip` = true | |0.8 |
  08 00 00 02 | FLIP 1, 0 | Set `hflip` = true,  `vflip` = false | |0.8 |
  08 00 00 03 | FLIP 1, 1 | Set `hflip` = true,  `vflip` = true | |0.8 |
  09 00 00 00 | SND0 | Stop playing sounds. | |0.8 |
  0A 00 LL HH | SND1 HHLL | Play 500Hz tone for `HHLL` ms. ||0.8 |
  0B 00 LL HH | SND2 HHLL | Play 1000Hz tone for `HHLL` ms. ||0.8 |
  0C 00 LL HH | SND3 HHLL | Play 1500Hz tone for `HHLL` ms. ||0.8 |
  0D 0X LL HH | SNP RX, HHLL | Play tone from `RX` for `HHLL` ms. ||1.1 |
  0E AD SR VT | SNG AD, VTSR | Set sound generation parameters. | |1.1 |
  10 00 LL HH | JMP HHLL | Set `PC` to `HHLL`. ||0.8 |
  11 00 LL HH | JMC HHLL | Jump to the specified address if carry flag is raised. ||0.8 |
  12 0x LL HH | Jx  HHLL | If `x`, then perform a _JMP_. ||0.9 |
  13 YX LL HH | JME RX, RY, HHLL | Set `PC` to `HHLL` if `RX == RY`. ||0.8 |
  14 00 LL HH | CALL HHLL | Store `PC` to `[SP]`, increase `SP` by 2, set `PC` to `HHLL`. ||0.8 |
  15 00 00 00 | RET | Decrease `SP` by 2, set `PC` to `[SP]`. ||0.8 |
  16 0X 00 00 | JMP RX | Set `PC` to `RX`. ||0.8 |
  17 0x LL HH | Cx HHLL | If `x`, then perform a _CALL_. ||0.9 |
  18 0X 00 00 | CALL RX | Store `PC` to `[SP]`, increase `SP` by 2, set `PC` to `RX`. ||0.8 |
  20 0X LL HH | LDI RX, HHLL | Set `RX` to `HHLL`. | |0.8 |
  21 00 LL HH | LDI SP, HHLL | Set `SP` to `HHLL`. ||0.8 |
  22 0X LL HH | LDM RX, HHLL | Set `RX` to `[HHLL]`. ||0.8 |
  23 YX 00 00 | LDM RX, RY | Set `RX` to `[RY]`. ||0.8 |
  24 YX 00 00 | MOV RX, RY | Set `RX` to `RY`. ||0.8 |
  30 0X LL HH | STM RX, HHLL | Set `[HHLL]` to `RX`. | |0.8 |
  31 YX 00 00 | STM RX, RY | Set `[RY]` to `RX`. | |0.8 |
  40 0X LL HH | ADDI RX, HHLL | Set `RX` to `RX`+`HHLL`. | `C``Z``O``N` | 0.8 |
  41 YX 00 00 | ADD RX, RY | Set `RX` to `RX`+`RY`. | `C``Z``O``N` | 0.8 |
  42 YX 0Z 00 | ADD RX, RY, RZ | Set `RZ` to `RX`+`RY`. | `C``Z``O``N` | 0.8 |
  50 0X LL HH | SUBI RX, HHLL | Set `RX` to `RX`-`HHLL`. | `C``Z``O``N` | 0.8 |
  51 YX 00 00 | SUB RX, RY | Set `RX` to `RX`-`RY`. | `C``Z``O``N` | 0.8 |
  52 YX 0Z 00 | SUB RX, RY, RZ | Set `RZ` to `RX`-`RY`. | `C``Z``O``N` | 0.8 |
  53 0X LL HH | CMPI RX, HHLL | Compute `RX`-`HHLL`, discard result. | `C``Z``O``N` | 0.8 |
  54 YX 00 00 | CMP RX, RY | Compute `RX`-`RY`, discard result. | `C``Z``O``N` | 0.8 |
  60 0X LL HH | ANDI RX, HHLL | Set `RX` to `RX`&`HHLL`. | `Z``N` | 0.8 |
  61 YX 00 00 | AND RX, RY | Set `RX` to `RX`&`RY`. | `Z``N` | 0.8 |
  62 YX 0Z 00 | AND RX, RY, RZ | Set `RZ` to `RX`&`RY`. | `Z``N` | 0.8 |
  63 0X LL HH | TSTI RX, HHLL | Compute `RX`&`HHLL`, discard result. | `Z``N` | 0.8 |
  64 YX 00 00 | TST RX, RY | Compute `RX`&`RY`, discard result. | `Z``N` | 0.8 |
  70 0X LL HH | ORI RX, HHLL | Set `RX` to `RX`|`HHLL`. | `Z``N` | 0.8 |
  71 YX 00 00 | OR RX, RY | Set `RX` to `RX`|`RY`. | `Z``N` | 0.8 |
  72 YX 0Z 00 | OR RX, RY, RZ | Set `RZ` to `RX`|`RY`. | `Z``N` | 0.8 |
  80 0X LL HH | XORI RX, HHLL | Set `RX` to `RX`^`HHLL`. | `Z``N` | 0.8 |
  81 YX 00 00 | XOR RX, RY | Set `RX` to `RX`^`RY`. | `Z``N` | 0.8 |
  82 YX 0Z 00 | XOR RX, RY, RZ | Set `RZ` to `RX`^`RY`. | `Z``N` | 0.8 |
  90 0X LL HH | MULI RX, HHLL | Set `RX` to `RX`*`HHLL` | `C``Z``N` | 1.1 |
  91 YX 00 00 | MUL RX, RY | Set `RX` to `RX`*`RY` | `C``Z``N` | 0.8 |
  92 YX 0Z 00 | MUL RX, RY, RZ | Set `RZ` to `RX`*`RY` | `C``Z``N` | 0.8 |
  A0 0X LL HH | DIVI RX, HHLL | Set `RX` to `RX`\\`HHLL` | `C``Z``N` | 0.8 |
  A1 YX 00 00 | DIV RX, RY | Set `RX` to `RX`\\`RY` | `C``Z``N` | 0.8 |
  A2 YX 0Z 00 | DIV RX, RY, RZ | Set `RZ` to `RX`\\`RY` | `C``Z``N` | 0.8 |
  A3 0X LL HH | MODI RX, HHLL  | Set `RX` to `RX` MOD `HHLL` | `Z``N` | 1.3 |
  A4 YX 00 00 | MOD RX, RY    | Set `RX` to `RX` MOD `RY`   | `Z``N` | 1.3 |
  A5 YX 0Z 00 | MOD RX, RY, RZ | Set `RZ` to `RX` MOD `RY` | `Z``N` | 1.3 |
  A6 0X LL HH | REMI RX, HHLL | Set `RX` to `RX` % `HHLL` | `Z``N` | 1.3 |
  A7 YX 00 00 | REM RX, RY | Set `RX` to `RX` % `RY` | `Z``N` | 1.3 |
  A8 YX 0Z 00 | REM RX, RY, RZ | Set `RZ` to `RX` % `RY` | `Z``N` | 1.3 |
  B0 0X 0N 00 | SHL RX, N | Set `RX` to `RX` << `N` | `Z``N` | 0.8 |
  B1 0X 0N 00 | SHR RX, N | Set `RX` to `RX` >> `N` | `Z``N` | 0.8 |
  B0 0X 0N 00 | SAL RX, N | Set `RX` to `RX` << `N` | `Z``N` | 0.8 |
  B2 0X 0N 00 | SAR RX, N | Set `RX` to `RX` >> `N`, copying leading bit | `Z``N` | 0.8 |
  B3 YX 00 00 | SHL RX, RY | Set `RX` to `RX` << `RY` | `Z``N` | 0.8 |
  B4 YX 00 00 | SHR RX, RY | Set `RX` to `RX` >> `RY` | `Z``N` | 0.8 |
  B3 YX 00 00 | SAL RX, RY | Set `RX` to `RX` << `RY` | `Z``N` | 0.8 |
  B5 YX 00 00 | SAR RX, RY | Set `RX` to `RX` >> `RY`, copying leading bit | `Z``N` | 0.8 |
  C0 0X 00 00 | PUSH RX | Set `[SP]` to `RX`, increase `SP` by 2 | | 0.8 |
  C1 0X 00 00 | POP  RX | Decrease `SP` by 2, set `RX` to `[SP]` | | 0.8 |
  C2 00 00 00 | PUSHALL | Store `R0`..`RF` at `[SP]`, increase SP by 32 | | 0.8 |
  C3 00 00 00 | POPALL | Decrease `SP` by 32, load `R0`..`RF` from `[SP]` | | 0.8 |
  C4 00 00 00 | PUSHF | Set `[SP]` to `FLAGS`, increase `SP` by 2 | | 1.1 |
  C5 00 00 00 | POPF | Decrease `SP` by 2, set `FLAGS` to `[SP]` | | 1.1 |
  D0 00 LL HH | PAL HHLL | Load palette from `[HHLL]` |  | 1.1 |
  D1 0X 00 00 | PAL RX | Load palette from `[RX]` |  | 1.1 |
  E0 0X LL HH | NOTI RX, HHLL | Set `RX` to NOT `HHLL` | `Z``N` | 1.3 |
  E1 0X 00 00 | NOT RX | Set `RX` to NOT `RX` | `Z``N` | 1.3 |
  E2 YX 00 00 | NOT RX, RY | Set `RX` to NOT `RY` | `Z``N` | 1.3 |
  E3 0X LL HH | NEGI RX, HHLL | Set `RX` to NEG `HHLL` | `Z``N` | 1.3 |
  E4 0X 00 00 | NEG RX | Set `RX` to NEG `RX` | `Z``N` | 1.3 |
  E5 YX 00 00 | NEG RX, RY | Set `RX` to NEG `RY` | `Z``N` | 1.3 |
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

nomorelogic

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2921
  • Karma: +20/-4
Re:Emulatore di Chip 16
« Risposta #12 il: Novembre 16, 2016, 03:22:25 pm »
con questo post mi hai fatto tornare indietro nel tempo di qualche lustro
mannaggia... ;)


e comunque non è solamente un puro e semplice esercizio, queste sono le basi per costruire virtual machine
Imagination is more important than knowledge (A.Einstein)

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Emulatore di Chip 16
« Risposta #13 il: Novembre 16, 2016, 03:25:47 pm »
Infatti ;)
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Emulatore di Chip 16
« Risposta #14 il: Novembre 16, 2016, 09:30:22 pm »
Em ... Legolas ...
B3 YX 00 00    SHL RX, RY    Set RX to RX << RY    ZN    0.8
B4 YX 00 00    SHR RX, RY    Set RX to RX >> RY    ZN    0.8
B3 YX 00 00    SAL RX, RY    Set RX to RX << RY    ZN    0.8
B5 YX 00 00    SAR RX, RY    Set RX to RX >> RY, copying leading bit    ZN    0.8

Qui ci sono 2 opcode uguali o sbaglio?

(https://github.com/chip16/chip16/wiki/Instructions)
EDIT:
Controllando in giro :(
(https://github.com/refractionpcsx2/refchip16/blob/master/Release/Chip16%20documentation.txt)
B0 0X 0N 00   SHL RX, N      Logical    Shift value in register X left N times.  Affects [z,n]
B1 0X 0N 00   SHR RX, N      Logical    Shift value in register X right N times. Affects [z,n]
B0 0X 0N 00   SAL RX, N      Arithmetic Shift value in register X left N times.  Affects [z,n] (same as SHL)
B2 0X 0N 00   SAR RX, N      Arithmetic Shift value in register X right N times. Affects [z,n]
B3 YX 00 00   SHL RX, RY      Logical    Shift value in register X left by the value in (RY & 0xf).  Affects [z,n]
B4 YX 00 00   SHR RX, RY      Logical    Shift value in register X right by the value in (RY & 0xf). Affects [z,n]
B3 YX 00 00   SAL RX, RY      Arithmetic Shift value in register X left by the value in (RY & 0xf).  Affects [z,n] (same as SHL)
B5 YX 00 00   SAR RX, RY      Arithmetic Shift value in register X right by the value in (RY & 0xf). Affects [z,n]
« Ultima modifica: Novembre 16, 2016, 10:07:15 pm da Stilgar »
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

 

Recenti

How To

Utenti
  • Utenti in totale: 803
  • Latest: maXim.FI
Stats
  • Post in totale: 19182
  • Topic in totale: 2288
  • Online Today: 97
  • Online Ever: 900
  • (Gennaio 21, 2020, 08:17:49 pm)
Utenti Online
Users: 1
Guests: 54
Total: 55

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.