Basic Assembler and Simulator programs for a simplified MIPS Architecture Processor
The Simulator implements Arithmetic, Branching, and I/O instructions, Interrupts derived from devices and user-generated, and interconnection between CPU and I/O devices
The project is comprised of 3 parts: Assembly Files, Assembler program, and Simulator Program. Both the Assembler and Simulator are implemented in C language
Lines of code: ~1800
- The Assembler receives an Assembly file which its content corresponds to the CPU's ISA (further description in 'ISA & Memory' section) For your Convenience, several Assembly files with different functionality are provided.
- The Assembler translates the Assembly language to machine language instructions and outputs two txt files - Instruction Memory and Data Memory files
- The Simulator receives the output from the Assembler along with additional input files (further description in the 'files' section) and simulates a fetch-decode-execute loop according to the input files
- The Simulator generates txt files which provide overall extensive information regarding CPU and I/O devices state at each cycle
The files which are marked in red are the input files from the user and the files marked in green will be created automatically by the Assembler and Simulator programs (description for each file is provided in the 'files' segment below)
At your convenience, several Assembly files with different functionalities have been provided and further detailed in the 'Assembly_Files_Description.md' file
- Clock Rate - 1024 cycles per second
- Assembly Instructions which utilize the $imm register - takes 2 cycles to complete; other Instructions takes 1 cycle.
- The CPU executes only a single instruction at a time
The CPU contains 16 32-bit registers, as seen below:
Memory is divided between Instruction Memory and Data Memory:
- Instruction memory is comprised of 1024 20-bit instructions (1024 instructions encoded to machine language)
- Data Memory is comprised of 4096 32-bit memory addresses
Assembly Code to Machine Language
The CPU has two instructions encoding formats:
- Instructions which utilizes the $imm register:
- Other Instructions:
Instructions Set and Encoding
The CPU is connected to the following I/O devices - LEDs, screen, timer, and hard-drive
The processor is a dedicated I/O processor - each device has its own I/O register and the CPU is able to communicate with these registers using the 'in' and 'out' I/O commands. below are the I/O registers and their encodings:
Computer Screen
The CPU is connected to a 352x288 monochromatic computer screen. each pixel is represented with 8 bits where 0 is black and 256 is white
The screen has a 352x288 frame buffer which at any time will store the current screen state. at the beginning all values are set to 0
‘monitorx’ register contains the x coordinate where the CPU will change it's pixel value. equivalently to monitory register and y coordinate. the ‘monitordata’ register holds the pixel value which the CPU wishes to write
Timer
when changing the ‘timerenable’ register value to 1 - the timer is activated. in each clock cycle where timer is enabled – ‘timercurren’t register's value is incremented by 1
Hard Drive
The CPU is connected to 64KB hard-drive, comprised of 128 512-bytes sectors. The CPU uses DMA to copy a sector from main memory to disk and vice versa
It takes 1024 clock cycles to copy a sector which during this time the diskstatus register value will be 1 (indicating hard-drive is busy). Upon receiving write/read command, the Assembly code must assure that the hard-drive is free to receive a new command by checking the diskstatus register. after 1024 clock cycles, diskcmd and diskstatus registers' values will be set to zero
The CPU supports 3 types of interrupts, as detailed at the table below:
Name | Device | Description |
---|---|---|
irq0 | Timer | when timercurrent=timermax, 'irq0status' is set to 1 and timercurrent is reset to 0 |
irq1 | Hard-Disk | when DMA is done copying a sector - 'irq1status' is set to 1 |
irq2 | User-Generated | The simulator is provided by the user with the irq2in.txt file which specifies at which clock cycles an interrupt should occur |
before carrying out each machine language instruction, the CPU examines the signals: irq = (irq0enable & irq0status) | (irq1enable & irq1status) | (irq2enable & irq2status) if irq == 1, and the CPU is not currently using its interrupt service routine, the processor handles the signal, by moving the PC register to the address stored in the irqhandler register while saving the original PC value in the irqreturn register The Assembly code should reset the irqstatus registers. terminating the interrupt service is done with the ‘reti’ command, which will result in PC=irqreturn
At the beginning of the simulation, PC=0. with each iteration, the simulator fetches the next instruction according to the PC, decodes it, and updates registers' state and other internal constituents of the program
The Simulator program will receive the following files (files' path name) as command line arguments:
imemin.txt dmemin.txt diskin.txt irq2in.txt dmemout.txt regout.txt trace.txt hwregtrace.txt cycles.txt leds.txt monitor.txt monitor.yuv diskout.txt
File | Type | Description |
---|---|---|
imemin.txt | input | contains Instruction Memory (machine language instructions). each row is a memory address and contains an instruction comprised of 5 hex digits. if the number of rows is less than 1024, we assume that the rest of the data is uninitialized |
dmemin.txt | input | contains Data Memory. each row contains data comprised of 8 hex digits. Data is stored in memory using a special command which can used in the assembly program - .word (address) (data) |
diskin.txt | input | this file has the same format as 'dmemin.txt' and represents the data stored in the disk when the program is executed |
irq2in.txt | input | specifies in which clock cycles an interrupt should occur (can contain nothing) |
dmemout.txt | output | this file specifies the information stored on the RAM when the execution is finished. has the same format as 'dmemout.txt' |
regout.txt | output | contains the CPU’s registers' content at the end of the simulation |
trace.txt | output | This file contains a line of text for each instruction executed by the simulator, in the following format: PC INST R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15. each field is printed with hex digits. the PC is the Program Counter, INST is the encoded opcode, and the following are the register's content prior to executing the current command (with sign extension) |
hwregtrace.txt | output | contains a line of text for each I/O operation, in the following format: CYCLE READ/WRITE NAME DATA. where CYCLE is the current time cycle, READ/WRITE is dependent on the operation executed, NAME is the HW register's name, and DATA is the data written/ read |
| | cycles.txt | output | contains two lines, one with the overall time cycles taken to simulate the program and the second with the overall machine instructions executed | | monitor.txt | output | contains the pixel values at the end of the simulation on the screen. each row contains a single pixel's value represented with two hex digits. The screen's overview is top-down, left-right. | | diskout.txt | output | contains the disk's data at the end of the simulation |
As mentioned, the assembler program translates assembly file to machine language instructions. data can be stored into memory using the '.word (address) (data)' special command
Each assembly line of code must contain all of the 5 parameters separated by commas, for example:
add $t2, $t1, $t0, 0 # $t2 = $t1 + $t0
add $t1, $t1, $imm, 2 # $t1 = $t1 + 2
add $t1, $imm, $imm, 2 # $t1 = 2 + 2
In addition, the assembly files can contain LABELS. As in MIPS, A label can be placed at the beginning of a statement and can be assigned the current value of the active location counter and be served as an instruction operand. The following exemplifies proper usage of Labels:
>bne $imm, $t0, $t1, L1 # if ($t0 != $t1) goto L1 (reg1 = address of L1)
>add $t2, $t2, $imm, 1 # $t2 = $t2 + 1 (reg1 = 1)
>beq $imm, $zero, $zero, L2 # unconditional jump to L2 (reg1 = address L2)
L1:
>sub $t2, $t2, $imm, 1 # $t2 = $t2 – 1 (reg1 = 1)
L2:
>add $t1, $zero, $imm, L3 # $t1 = address of L3 (reg1 = address L3)
>beq $t1, $zero, $zero, 0 # jump to the address specified in t1 (reg1 = 0)
L3:
>jal $imm, $zero, $zero, L4 # function call L4, save return addr in $ra
>halt $zero, $zero, $zero, 0 # halt execution
L4:
>beq $ra, $zero, $zero, 0 # return from function in address in $ra (reg1=0)
Note: each label must start with an alphabet character and end with a colon
The Assembler program can handle white spaces, and blank lines in the assembly files - feel free to leave blank lines, use tabs etc. the program can handle it.