RFC 005 OP-codes TOC ------------------------------------------------------------------------------- 1. Anm. zur Revision 2 2. Anm. zur VM 3. Definition 4. Beispiel ------------------------------------------------------------------------------- 1. Anm. zur Revision 2 Die Erweiterungen der OP-Codes betreffen Funktionen rund um die rekonfigurierbaren Ressourcen. Mit einem neuen Interface soll die VM in der Lage sein, Ăueber eine Treiber-Schnittstelle (RFC006) unterschiedliche Dienste (Hardware, Betriebsystem oder andere Processe) anzubieten oder zu nutzen. Fuer eine minimale Hardware-Steuerung (z.B. fuer Schrittmotoren) werden folgende Funktionen benoetigt: - Bit-Maskierungen fuer die Steuerung einzelner Pins - Sleep-Funktion fuer Pausen - Treiber-Interface Die OP-Code Erweiterung dient genau diesen drei Bereichen ------------------------------------------------------------------------------- 2. Anm. zur VM Die Definition der Hardware-Emulation ist nicht Gegenstand dieser RFC. Der genaue Aufbau und Beispiele bleibt der Emulations-Doku vorbehalten. Trotzdem werden hier nochmals kurz alle vorhandenen Komponenten aufgelistet: * Programm-Speicher, Byte-Array mit OP-Codes * Daten-Speicher, Int-Array mit globalen Daten * Stack, Int-Array mit Stack-Daten * BP: Basepointer, Basis-Adresse des aktuellen Kontextes * SP: Stack-Pointer, aktuelle Position im Stack * PC: Programm-Counter, aktuelle Position im Programm-Speicher Die VM implementiert ein 32Bit-System. Der Daten-Speicher, Stack und alle Register haben eine Groesse von 32Bit. Alle Daten werden als Big-Endian abgelegt. ------------------------------------------------------------------------------- 3. Definition Nachfolgend sind die OP-Codes der zweiten VM-Version definiert. Neu | OP (dec) | OP (hex) | Typ | Beschreibung | VM-Aktion ----+-----------+-----------+-------------+--------------+------------------------------------------- | 20 | 14 | Stack | CONST n | Push(n) | 21 | 15 | " | LOAD a | Push(stack[bp+a]) | 22 | 16 | " | LOADG a | Push(globals[a]) | 23 | 17 | " | STO a | stack[bp+a]=Pop() | 24 | 18 | " | STOG a | globals[a]=Pop(); | 40 | 28 | Arithmetik | ADD | Push(Pop()+Pop()); | 41 | 29 | " | SUB | Push(-Pop()+Pop()); | 42 | 2a | " | DIV | x=Pop(); Push(Pop()/x); | 43 | 2b | " | MUL | Push(Pop()*Pop()); | 44 | 2c | " | NEG | Push(-Pop()); X | 50 | 32 | " | AND | Push(Pop() & Pop()); X | 51 | 33 | " | OR | Push(Pop() | Pop()); X | 52 | 34 | " | NOT | Push(~Pop()); X | 53 | 35 | " | XOR | Push(Pop() ^ Pop()); | 60 | 3c | Vergleiche | EQU | if (Pop()==Pop()) Push(1); else Push(0); | 61 | 3d | " | LSS | if (Pop()>Pop()) Push(1); else Push(0); | 62 | 3e | " | GTR | if (Pop()=Pop()) Push(1); else Push(0); | 64 | 40 | " | GTE | if (Pop()<=Pop()) Push(1); else Push(0); | 80 | 50 | Spruenge | JMP a | pc = a; | 81 | 51 | " | FJMP a | if (Pop()==0) pc=a; | 100 | 64 | I/O | READ | Push(ReadInt()); | 101 | 65 | " | WRITE | WriteIntLine(Pop()); | 102 | 66 | " | READC | Push(ReadChar()); | 103 | 67 | " | WRITEC | WriteChar(Pop()); | 120 | 78 | Methoden | CALL a | Push(pc+2); pc=a; | 121 | 79 | " | RET | pc = Pop(); if (pc==0) return; | 122 | 7a | " | ENTER a | Push(bp); bp=sp; sp+=a; | 123 | 7b | " | LEAVE | sp=bp; bp=Pop(); X | 140 | 8C | Utilities | RTSLEEP a | sleepms(a); X | 145 | 91 | " | LDRIVER a | installDriver(a,Pop()); | 153 | 99 | " | NOP | ----+-----------+-----------+-------------+--------------+------------------------------------------- RTSLEEP ("Real-Time-Sleep") : eine auf der jeweiligen Plattform moeglichst genaue funktion, welche die Programmausfuehrung fuer "a" Millisekunden aussetzt. LDRIVER ("Load-Driver") : Installiert fuer eine bestimmte Ressource einen ueber eine weitere ID festgelegten Treiber. 3. Beispiel Addition mittles globalen Variabeln: Pseudocode | Mnemonicode (in Bytes) | Kommentar -----------+------------------------+----------------------------------------------------------------------------- VAR a,b; | | jede Variable bekommt einen Nummer, a -> 0, b -> 1 b = 42; | 020 000 000 000 042 | 42 auf den Stack legen | 024 000 000 000 001 | den auf den Stack gelegten Wert (42) der Variable mit Nr 1 zuweisen READ(a); | 100 | Auf Eingabe auf xy warten | 024 000 000 000 000 | Eingelesener Wert der Variable 0 zuweisen a = a+b; | 022 000 000 000 000 | Wert der Varibale 0 auf Stack legen | 022 000 000 000 001 | Wert der Varibale 1 auf Stack legen | 040 | beiden vorhergehenden Wert zusammenzaehlen(2 x Pop()) und auf Stack legen | 024 000 000 000 000 | Wert auf Stack der Variable mit Nr 0 zuweisen WRITE(a); | 022 000 000 000 000 | Wert der Variable 0 in den Stack laden | 101 | Pop() auf xy ausgeben -----------+------------------------+----------------------------------------------------------------------------- Ausgabe im "echten" GRINJ, einmal in Pseudo-Assembler, einmal in Zahlencode: 1: ENTER 2 4: CONST 42 7: STO 1 10: READ 11: STO 0 14: LOAD 0 17: LOAD 1 20: ADD 21: STO 0 24: LOAD 0 27: WRITE 28: LEAVE 29: RET 1: 122 2 4: 020 42 7: 023 1 10: 100 11: 023 0 14: 021 0 17: 021 1 20: 040 21: 023 0 24: 021 0 27: 101 28: 123 29: 121