This repository contains the source code for an Assembler and Simulator designed for a given Instruction Set Architecture (ISA). The project was created by Siddharth Rajput, Kartik Gupta, and Sanmay Sood as part of the Computer Organization course.
The Assembler and Simulator provide the following features:
-
Assembler:
- Converts assembly code written in the given ISA into binary machine code.
- Supports instructions for arithmetic operations, memory access, control flow, and more.
- Generates a binary file in the same format as the input assembly code.
-
Simulator:
- Simulates the execution of binary machine code generated by the Assembler.
- Loads the binary file into system memory and starts executing the code.
- Outputs the program counter (PC) and register values after each instruction.
- Halts execution when the "hlt" instruction is reached.
- Prints the memory dump of the entire memory after execution.
This document provides a description of the 16-bit Instruction Set Architecture (ISA) along with the syntax of the assembly language that supports this ISA. The ISA includes various instructions and their opcodes, as well as the semantics and encoding types of each instruction.
The ISA consists of the following instructions, their opcodes, and their corresponding syntax:
Opcode | Instruction | Semantics | Syntax | Type |
---|---|---|---|---|
10000 | Addition | Performs reg3 = reg1 + reg2. Sets overflow flag if computation overflows. | add reg1 reg2 reg3 | A |
10001 | Subtraction | Performs reg3 = reg1 - reg2. Sets reg3 to 0 and overflow flag if reg2 > reg1. | sub reg1 reg2 reg3 | A |
10010 | Move Immediate | Performs reg1 = $Imm, where Imm is an 8-bit value. | mov reg1 $Imm | B |
10011 | Move Register | Performs reg2 = reg1. | mov reg1 reg2 | C |
10100 | Load | Loads data from mem_addr into reg1. | ld reg1 mem_addr | D |
10101 | Store | Stores data from reg1 to mem_addr. | st reg1 mem_addr | D |
10110 | Multiply | Performs reg3 = reg1 x reg2. Sets overflow flag if computation overflows. | mul reg1 reg2 reg3 | A |
10111 | Divide | Performs reg3/reg4. Stores quotient in R0 and remainder in R1. | div reg3 reg4 | C |
11000 | Right Shift | Right shifts reg1 by $Imm, where $Imm is an 8-bit value. | rs reg1 $Imm | |
11001 | Left Shift | Left shifts reg1 by $Imm, where $Imm is an 8-bit value. | ls reg1 $Imm | B |
11010 | Exclusive OR | Performs bitwise XOR of reg1 and reg2. Stores result in reg3. | xor reg1 reg2 reg3 | A |
11011 | Or | Performs bitwise OR of reg1 and reg2. Stores result in reg3. | or reg1 reg2 reg3 | A |
11100 | And | Performs bitwise AND of reg1 and reg2. Stores result in reg3. | and reg1 reg2 reg3 | A |
11101 | Invert | Performs bitwise NOT of reg1. Stores result in reg2. | not reg1 reg2 | C |
11110 | Compare | Compares reg1 and reg2. Sets up the FLAGS register. | cmp reg1 reg2 | C |
11111 | Unconditional Jump | Jumps to mem_addr, where mem_addr is a memory address. | jmp mem_addr | E |
01100 | Jump If Less Than | Jumps to mem_addr if the less than flag is set. | jlt mem_addr | E |
01101 | Jump If Greater Than | Jumps to mem_addr if the greater than flag is set. | jgt mem_addr | E |
01111 | Jump If Equal | Jumps to mem_addr if the equal flag is set. | je mem_addr | E |
01010 | Halt | Stops the machine from executing until reset. | hlt | F |
Note: The syntax uses reg(x) to denote a register, mem_addr for a memory address (8-bit binary number), and $Imm for a constant value (8-bit binary number). The ISA has 7 general-purpose registers (R0-R6) and 1 flag register (FLAGS).
The ISA supports an address size of 8 bits, making it double byte addressable and resulting in a total address space of 512 bytes. The ISA only supports whole number arithmetic, and all number representations are unsigned.
The FLAGS register includes the following flags:
- Overflow (V): Set by add, sub, and mul instructions when the result overflows.
- Less than (L): Set by the "cmp reg1 reg2" instruction if reg1 < reg2.
- Greater than (G): Set by the "cmp reg1 reg2" instruction if reg1 > reg2.
- Equal (E): Set by the "cmp reg1 reg2" instruction if reg1 = reg2.
The default state of the FLAGS register is all zeros. The only operation allowed on the FLAGS register is "mov reg1 FLAGS," where reg1 can be any register from R0 to R6. All other operations on the FLAGS register are prohibited.
The ISA utilizes 6 types of instructions, each encoded as 16 bits with distinct encoding styles:
- Type A: 3-register type (opcode - 5 bits, unused - 2 bits, reg1 - 3 bits, reg2 - 3 bits, reg3 - 3 bits)
- Type B: register and immediate type (opcode - 5 bits, reg1 - 3 bits, immediate value - 8 bits)
- Type C: 2-registers type (opcode - 5 bits, unused - 5 bits, reg1 - 3 bits, reg2 - 3 bits)
- Type D: register and memory address type (opcode - 5 bits, reg1 - 3 bits, memory address - 8 bits)
- Type E: memory address type (opcode - 5 bits, unused - 3 bits, memory address - 8 bits)
- Type F: halt (opcode - 5 bits, unused - 11 bits)
The binary representation for the registers is as follows:
Register | Address |
---|---|
R0 | 000 |
R1 | 001 |
R2 | 010 |
R3 | 011 |
R4 | 100 |
R5 | 101 |
R6 | 110 |
FLAGS | 111 |
The ISA executes the code provided to it in the following format until it reaches the "hlt" instruction. There can only be one "hlt" instruction in the program, and it must be the last instruction. Execution starts from the 0th address, and the ISA follows the von Neumann architecture with a unified code and data memory.
Note: The variables are allocated in the binary in program order.