Reference book: Design and Implementation of RISC I
This project was created with the purpose of delving deeper into the knowledge of RISC-I opcodes. It has not been extensively tested and may present numerous issues, so do not consider this project as a faithful emulation of the RISC-I proposed by David A. Patterson. Not only is it incomplete, but it also contains decisions made by me that fundamentally differ from the original RISC-I model proposed.
Download the latest release and then execute the following command:
./Emulator --file filename.bin
Make sure you have C++, make and raylib installed, clone the repository and run make
Most instructions have the following characteristics:
- They consist of 6 bytes.
- They include: opcode (1 byte), operand1 (2 bytes), operand2 (2 bytes), operand3 (1 byte).
How operands work:
An operand can either result in an immediate value or a value stored in a register.
We have registers from 0x00 to 0x1F; above that, it is impossible to retrieve a value from a register.
Therefore, the first byte informs which register should be retrieved. If this value is above 0x1F (starting from 0x20), the emulator will retrieve the immediate value in the second byte.
For example:
- 0x0100 -> retrieves the value in the register (0x01).
- 0xFF05 -> retrieves the immediate value 0x05 since the value of the first byte (0xFF) is greater than 0x1F.
Exception for Third Operand
As the third operand consists of only one byte, it always represents a register.
Dictionary:
Op1: first operand, provides the 2 bytes corresponding to the first operand
Op2: second operand, provides the 2 bytes corresponding to the second operand
Op3: third operand, provides the byte corresponding to the third operand. Is always a register
a: Value in Op1 (can be either a value in a register or a direct value)
b: Value in Op2 (can be either a value in a register or a direct value)
-
Add: (0x01):
- 0x01 - opcode
- 0x0000 - op1
- 0x0000 - op2
- 0x00 - op3 (destination register)
- Operation:
registers[op3] = a+b
- Example:
-
0x01FF01FF0401
- Opcode: 0x01 (add)
- Op1: 0xFF01 (value 1)
- Op2: 0xFF04 (value 4)
- Op3: 0x01 (store result in register 01)
-
0x010001FF0502
- Opcode: 0x01 (add)
- Op1: 0x0001 (value in register 01, value = 5)
- Op2: 0xFF05 (value 5)
- Op3: 0x02 (store result in register 2)
-
-
- Functions similarly to ADD, but increments by one if the carry flag is activated.
-
- Function similarly to ADD and ADDC, but perform subtraction. Opcode varies.
-
- Performs bitwise AND operation between values
a
andb
, storing the result inop3
. - Operation:
registers[op3] = a & b
- Performs bitwise AND operation between values
-
- Performs bitwise OR operation between values
a
andb
, storing the result inop3
. - Operation:
registers[op3] = a | b
- Performs bitwise OR operation between values
-
- Performs bitwise XOR operation between values
a
andb
, storing the result inop3
. - Operation:
registers[op3] = a ^ b
- Performs bitwise XOR operation between values
-
- Performs left shift operation on value
a
by the number of shifts determined byb
, storing the result inop3
. - Operation:
registers[op3] = a << b
- Performs left shift operation on value
-
- Performs right shift operation on value
a
by the number of shifts determined byb
, storing the result inop3
. - Operation:
registers[op3] = a >>> b
- Performs right shift operation on value
-
- Performs arithmetic right shift operation on value
a
by the number of shifts determined byb
, storing the result inop3
. - Operation:
registers[op3] = a >> b
- Performs arithmetic right shift operation on value
-
- Loads data from memory at position
a + b
and stores its value inop3
. registers[op3] = memory[a+b]
- Note: Memory is byte-addressable, so the operation involves retrieving 4 bytes from the specified address and calculating the integer value to be stored.
- Loads data from memory at position
-
- Stores values from register
op3
into memory locationa + b
. memory[a+b] = registers[op3]
- Note: Similar to loading, but involves storing the register value into 4 memory addresses.
- Stores values from register
-
- If the value in the register on
op3
is equal to1
, then it sets pc toa + b
if(registers[op3] == 1) pc = a+b
- If the value in the register on
-
- If the value in the register on
op3
is equal to1
, then it increments pc bya + b
if(registers[op3] == 1) pc += a+b
- If the value in the register on
-
- Sets the value on the register on
op3
topc
, then setspc
toa + b
registers[op3] = pc; pc = a + b
- Sets the value on the register on
-
- Sets the value on the register on
op3
topc
, then incrementspc
toa + b
registers[op3] = pc; pc += a + b
- Sets the value on the register on
-
- Sets
pc
toa + b
- Its used to return from a
CALL
so its interesting to know from which register(s) (or numbers) you're pulling the data from pc = a + b
- Sets
-
- This is used to debug pring the value stored on the register referenced by
op3
- Use this while the emulator isn't finished
print(registers[op3]
- This is used to debug pring the value stored on the register referenced by
-
- Use this to read the values on the bus lanes
- the value in the
data lane
will be stored inregister[a]
- the value in the
address lane
will be stored inregister[b]
- the value in the
command lane
will be stored inop3
-
- Use this to write values on the bus lanes
- the
a
value will be writen to thedata lane
- the
b
value will be writen to theaddress lane
- the
op3
value will be writen to thecommand lane
-
- Stops the execution