-
To run the CPU for synthesis(Quartus) and simulation(ModelSim)
- Create Quartus Project
- Assemble the program and generate 3 files: machine_code.txt, pc_lut.txt, and im_lut.txt
- Copy those 3 files to your Quartus project simulation/modelsim folder, and copy the test_input.txt into this folder as well
- Run simulation
-
To run the assembler for any other assembly scripts
make assemble ARGS="<your file name>.PANDA_ASM" -
To run the simulator, follow the steps:
- Assemble the program
make assemble_prog<1, 2 or 3>- Build the simulator with preload values
make sim PROG=<1, 2, 3> DATASET=<1, 2, 3>- Run the simulator
- Batch mode:
make batch- Interactive mode:
make interactive
- Introduction
- Architectural Overview
- Machine Specification
- Programmer’s Model [Lite]
- Individual Component Specification
- Program Implementation
- Software And Assembler
- Testbench Output
- Change Log
The name of this architecture is PANDA, stands for pretty average, not-well designed architecture. The main goal of this ISA is to provide a smooth and user-friendly programming experience when coding in the PANDA assembly. To achieve this, we designed a special encoding and instructions to provide a large number of registers(16 General Purpose Registers). Additionally, we introduced macro instructions that expand into lower-level instructions, improving usability and readability. The PANDA machine follows a load-store architecture, so users who are familiar with ARMS and MIPS can easily transition to PANDA.
- Instruction Width: 9 bits
- Datapath: 8 bits
- Program Counter: 12 bits
- CPU: Single Cycle CPU
| TYPE | FORMAT | CORRESPONDING INSTRUCTIONS |
|---|---|---|
| R | 4 bits opcode, 1 bit for choosing source register rs or use the special register IM as the source(rs will be ignored), 2 bit destination register rd, 2 bit source register rs | ADD, INC, DEC, SUB, AND, OR, XOR, MOV |
| B | 4 bits opcode, 5 bits for LUT index | BLT, BGT, BEQ |
| CMP | 4 bits opcode, 1 bit for choosing source register rs or use the special register IM as the source(rs will be ignored), 2 bit destination register rd, 2 bit source register rs. | CMP |
| SHIFT | 4 bits opcode, 1 bit for choosing direction(left or right), 1 bit for choosing it's arithmetics or logical shift, 1 bit unused, 2 bit dest register | SHIFT |
| MEM | 4 bits opcode, 1 bit for choosing source register rs or use the special register IM as the source(rs will be ignored), 2 bit destination register rd, 2 bit source register rs | LOAD, STORE |
| IM | 4 bits opcode, 5 bits for immediate | LOAD_IMMEDIATE |
| FUNCTIONAL | 4 bits opcode, the rest of the bits depend on what the next bit is 1. SET_REG: next bit is 0, then the followed 2 bit for destination register indexing, 2 bit for source register indexing. 2. HALT: next bit is 1, and the rest are all 1's as well. 3. NOOP: next bit is 1, but rest of the bits are all 0's |
SET_REG, HALT, NOOP |
| Instruction Number | NAME | TYPE | OP CODE | BIT BREAKDOWN | EXAMPLE | NOTES |
|---|---|---|---|---|---|---|
| 1 | ADD = arithmetic add | R | 0000 | 4 bits opcode (0000), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | ADD R0, R1 ⇔ 0000_0_00_01, ADD R0, IM ⇔ 0000_1_00_xx |
After ADD, R0 holds result of R0 + R1/R0 + IM |
| 2 | INC = arithmetic increment one | R | 0001 | 4 bits opcode (0001), 1 bit to choose it's increment(0) or decrement(1), 2 bit destination register rd(xx), 2 bit don't care (xx) | INC R0 ⇔ 0001_0_00_xx |
After INC, R0 holds result of R0 + 1 |
| 3 | DEC = arithmetic decrement by one | R | 0001 | 4 bits opcode (0001), 1 bit to choose it's increment(0) or decrement(1), 2 bit destination register rd(xx), 2 bit don't care (xx) | DEC R0 ⇔ 0001_1_00_xx |
After DEC, R0 holds result of R0 - 1 |
| 4 | SUB = arithmetic sub | R | 0010 | 4 bits opcode (0010), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | SUB R0, R1 ⇔ 0010_0_00_01, SUB R0, IM ⇔ 0010_1_00_xx |
After SUB, R0 holds result of R0 - R1/R0 - IM |
| 5 | AND = logical and | R | 0011 | 4 bits opcode (0011), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | AND R0, R1 ⇔ 0011_0_00_01, AND R0, IM ⇔ 0011_1_00_xx |
After AND, R0 holds result of R0 & R1/R0 & IM |
| 6 | OR = logical or | R | 0100 | 4 bits opcode (0100), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | OR R0, R1 ⇔ 0100_0_00_01, OR R0, IM ⇔ 0100_1_00_xx |
After OR, R0 holds result of R0 or R1/R0 or IM |
| 7 | XOR = logical xor | R | 0101 | 4 bits opcode (0101), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | XOR R0, R1 ⇔ 0101_0_00_01, XOR R0, IM ⇔ 0101_1_00_xx |
After XOR, R0 holds result of R0 ^ R1/R0 ^ IM |
| 8 | MOV = MOVE value from one reg to the other | R | 0110 | 4 bits opcode (0110), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | MOV R0, R1 ⇔ 0110_0_00_01, MOV R0, IM ⇔ 0110_1_00_xx |
After MOV, R0 holds result of R1/IM |
| 9 | BLT = branch if less than | B | 0111 | 4 bits opcode (0111), 5 bits(xxxxx) for the LUT index. If the LT register is set, the program counter(PC) will be set to PC = LUT[index] | If @L<Label Name> has index of 12, BLT @L<Label Name> ⇔ 0111_01100 |
After BLT, PC will be updated to the value previously described |
| 10 | BGT = branch if greater than | B | 1000 | 4 bits opcode (1000), 5 bits(xxxxx) for the LUT index. If the GT register is set, the program counter(PC) will be set to PC = LUT[index] | If @L<Label Name> has index of 12, BGT @L<Label Name> ⇔ 1000_01100 |
After BGT, PC will be updated to the value previously described |
| 11 | BEQ = branch if equal | B | 1001 | 4 bits opcode (1001), 5 bits(xxxxx) for the LUT index. If the EQ register is set, the program counter(PC) will be set to PC = LUT[index] | If @L<Label Name> has index of 12, BEQ @L<Label Name> ⇔ 1001_01100 |
After BEQ, PC will be updated to the value previously described |
| 12 | CMP = compare | CMP | 1010 | 4 bits opcode (1010), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx). This instruction will compare the value of pairs (rd and rs) or (rd and IM) depending on the 5th bit, for simplification, we name the first operand A, and second operand B. There are 3 cases: 1. A > B, then GT register will be set to 1 2. A < B, then LT register will be set to 1 3. A == B, then EQ register will be set to 1 |
CMP R0, R1 ⇔ 1010_0_00_01, CMP R0, IM ⇔ 1010_1_00_xx |
After CMP, At most one of the registers LT, GT, and EQ will be set to 1 |
| 13 | SHIFT = general shift operation | SHIFT | 1011 | 4 bits opcode (1011), 1 bit for choosing direction(left(0) or right(1)) 1 bit for choosing it's logical(0) or arithmetics(1) shift, 1 bit unused(x), 2 bit dest register rd(xx). | SHIFT_LEFT_LOGICAL R2 ⇔ 1011_0_0_x_10, SHIFT_RIGHT_LOGICAL R2⇔ 1011_1_0_x_10, SHIFT_LEFT_ARITHMETIC R2⇔ 1011_0_1_x_10, SHIFT_RIGHT_ARITHMETIC R2⇔ 1011_1_1_x_10 |
After SHIFT, R2 holds result of R2 logical/arithmetic left/right shift by 1 |
| 14 | LOAD = load from memory | MEM | 1100 | 4 bits opcode (1100), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | LOAD R0, R1 ⇔ 1100_0_00_01, LOAD R0, IM ⇔ 1100_1_00_xx |
After LOAD, R0 holds result of memory[R1]/memory[IM] |
| 15 | STORE = store value to memory | MEM | 1101 | 4 bits opcode (1101), 1 bit for choosing source register rs(0) or use the special register IM(1) as the source(rs will be ignored), 2 bit destination register rd(xx), 2 bit source register rs(xx) | STORE R0, R1 ⇔ 1101_0_00_01, STORE R0, IM ⇔ 1101_1_00_xx |
After STORE, mem[R0] holds result of R1/IM |
| 16 | LOAD_IMMEDIATE = loading immediate from LUT | IM | 1110 | 4 bits opcode (1110), 5 bits for LUT index(xxxxx) | LOAD_IMMEDIATE 29 ⇔ 1110_11101 |
After LOAD_IMMEDIATE, special purpose register IM holds result of LUT[index] |
| 17 | SET_REG = setting registers extension index | FUNCTIONAL | 1111 | 4 bits opcode (1111), 1 bit to choose it's SET_REG(0), if it's SET_REG, then 2 bit for destination register indexing(xx), and 2 bit for source register indexing(xx). |
SET_REG 3, 2 ⇔ 1111_0_11_10 |
After SET_REG, special purpose register DEST_REG_IDX = 3, SRC_REG_IDX=2, so that for the next instruction, their dest register will be(assuming rd=2) DEST_REG_IDX*4 + rd = 3*4+2=14, so it will be using R14 instead of R2 for rd. Similarly, the the src register will be (assuming rs=1) SRC_REG_IDX*4 + rs = 2*4 + 1 = 9, so it will be using R9 instead of R1 for rs. Once the next instruction is done, both special purpose register will be reset to 0 SRC_REG_IDX<=0, DEST_REG_IDX<=0. The purpose of this instruction is to expand the number of register that the programmer can use, in the cost of a higher CPI. |
| 18 | HALT = halt the program | FUNCTIONAL | 1111 | 4 bits opcode (1111), instruction is fixed to be 1111_1_1111 |
HALT ⇔ 1111_1_1111 |
After HALT, the done signal will be sent and the program will stop its execution. |
| 19 | NOOP = no operation in one cycle | FUNCTIONAL | 1111 | 4 bits opcode (1111), the instruction is fixed to be 1111_1_0000 |
NOOP ⇔ 1111_1_0000 |
After NOOP, the CPU will do nothing in this cycle |
Note: In the assembler, each label is assigned a LUT index (0–31). The PC_LUT stores the actual absolute target address for each label.
There are 16 general purpose registers, 6 special purpose registers.
| Register | Purpose | Note |
|---|---|---|
| R0-R15 | General purpose | N/A |
| LT | Special purpose | Will be set in CMP, will be cleared in the next instruction after CMP |
| GT | Special purpose | Will be set in CMP, will be cleared in the next instruction after CMP |
| EQ | Special purpose | Will be set in CMP, will be cleared in the next instruction after CMP |
| IM | Special purpose | Can be set by using LOAD_IMMEDIATE instruction |
| SRC_REG_IDX | Special purpose | Will be set by the SET_REG instruction, will be cleared after the next instruction of SET_REG is done |
| DEST_REG_IDX | Special purpose | Will be set by the SET_REG instruction, will be cleared after the next instruction of SET_REG is done |
Only absolute branching is supported. For absolute branching, it will be using the extracted 5 bits as the index.
- Absolute Branching: user can branch to an absolute address that's hardcoded and stored in the LUT, the 5 bits will be unsigned and will be the index of the LUT. The values inside the LUT can be address of any instruction in the program. So this will be the way to handle large jumps.
Below is the method of using branching in PANDA:
BLTBGTBEQ
Only indirect addressing is supported. If user wants to use immediate as operands for load/store or any other operations, they will have to be done by using the special LOAD_IMMEDIATE instruction. All of the immediates will be stored in a LUT, users can use indices to access the LUT and load the actual immediate into an IM special register, and use IM instead.
- Example
// assume R1 = 10
// assume IM = 300
LOAD R1, R0 // this will be R1 <- memory[R0] = memory[10]
LOAD R1, IM // this will be R1 <- memory[IM] = memory[300]
-
Programmer's Strategy: The user should prioritize using as many general purpose registers provided as possible by utilizing the special
SET_REGinstruction. If all of the GPRs are used, the user can load/store stuff from/to memory, the memory operation can happen in between of other operations. If the user wants to use immediate, they must do it via theLOAD_IMMEDIATEinstructions. For branching, the user can only branch absolutely to the labels. -
Restrictions: Copying instructions from ARMS/MIPS generally won't work out of the box, due to the PANDA ISA needed
SET_REGto use the other general purpose registers besidesR0-R3. Other than that, the user should be careful using the store command in PANDA, since the operands order is differed from ARMS/MIPS(see the operation chart). Other than that, most of the common operations are supported in the PANDA ISA.
This module initializes the instances of other modules (PC, LUTs, DataMem, Control, ALU, and RegFile).
It also contains the special register (IM) and registers the ALU flags for the next cycle.
This module implements the program counter, which can only branch absolutely (PC = new PC) based on the ALU flags passed in.
The PC is 12 bits wide.
This module implements the instruction memory, where it preloads the instructions (9 bits wide) into a 2D array.
Every cycle the PC advances or changes, the instruction at that address is output via the instr_out signal.
The instruction memory is read-only and entirely combinational.
This module implements the control decoder, which parses different control signals or data that the ALU or memory operations need,
and correctly decodes the operation type of the current instruction. This module is entirely combinational.
This module implements the register file. It supports one synchronous write (on the rising edge of clk)
and two asynchronous/combinational reads within a single cycle. The datapath width is 8 bits.
This module implements the ALU. It performs various arithmetic and logical operations depending on the input opcode.
The ALU outputs the result of the operation (out) and three comparison flags: EQ, LT, and GT.
This module is entirely combinational.
Demonstrated operations:
- Arithmetic instructions:
- ADD
- AND
- INC / DEC
- SUB
- OR
- XOR
- SHIFT
- Non-Arithmetic instructions:
- MOV
- CMP
This module implements the data memory. It allows one synchronous write (on the rising edge of clk)
and one asynchronous/combinational read in a single cycle. The datapath width is 8 bits.
These modules implement:
- PC_LUT — used for absolute branch addresses
- IM_LUT — used for storing larger 8-bit immediate values
Both tables are preloaded, and reads are performed combinationally based on the given index.
Closest pair -- Write a program to find the smallest and largest Hamming distances among all pairs of values in an array of 16 bytes. Assume all values are 8-bit integers. The array of integers starts at location 0. Write the minimum distance in location 16 and the maximum distance in location 17.
2-Term Product – For full credit, write a program that finds the product of two two’s complement numbers, ie, A * B. The operands are found in memory locations 0 (A), and 1 (B). The result will be written into locations 3 (high bits) and 2 (low bits). Your ISA will not have a one-cycle “multiply” operation, so you will need some sort of shift-and-add algorithm. You may restrict your values to positive numbers (MSB = 0) only, with a 1/3-letter grade penalty for the course.
3-Term Product – For full credit, write a program that finds the product of three two’s complement numbers, ie, A * B * C. The operands are found in memory locations 0 (A), and 1 (B), and 2 (C). The result will be written into locations 5 (highest bits), 4 (middle bits), and 3 (low bits). Your ISA will not have a one-cycle “multiply” operation, so you will need some sort of shift-and-add algorithm. You may restrict your values to positive numbers (MSB = 0) only, with a 1/3-letter grade penalty for the course.
PANDA provides an assembler and has set the rules of writing the panda assembly program. Basically the following
- If the users want to use immediates, define them on the top by using
.IMM_<your immediate's name>-><Your immediate value> - If the users want to define a label, write it in the format
@L<your label name>: - With the provided assembler, users can write instructions like
ADD R14, R15, the assembler will automatically convert it into two instructionsSET_REG 3, 3andADD R2, R3so the users can have a better programming experience. But users can still useSET_REGif they want.
To assemble the file, run
make assemble ARGS="<your file name>.PANDA_ASM"
- Program 1(Max and Min Hamming Distance):
run -all
# 0: 00000000
# 1: 00001011
# 2: 00010101
# 3: 00011110
# 4: 00100110
# 5: 00101101
# 6: 00110011
# 7: 00111000
# 8: 01000111
# 9: 01001100
# 10: 01010010
# 11: 01011001
# 12: 01100001
# 13: 01101010
# 14: 01110100
# 15: 01111111
#
# j,kj = [ 0, 1] dist= 3
# j,kj = [ 0, 2] dist= 3
# j,kj = [ 0, 3] dist= 4
# j,kj = [ 0, 4] dist= 3
# j,kj = [ 0, 5] dist= 4
# j,kj = [ 0, 6] dist= 4
# j,kj = [ 0, 7] dist= 3
# j,kj = [ 0, 8] dist= 4
# j,kj = [ 0, 9] dist= 3
# j,kj = [ 0, 10] dist= 3
# j,kj = [ 0, 11] dist= 4
# j,kj = [ 0, 12] dist= 3
# j,kj = [ 0, 13] dist= 4
# j,kj = [ 0, 14] dist= 4
# j,kj = [ 0, 15] dist= 7
# j,kj = [ 1, 2] dist= 4
# j,kj = [ 1, 3] dist= 3
# j,kj = [ 1, 4] dist= 4
# j,kj = [ 1, 5] dist= 3
# j,kj = [ 1, 6] dist= 3
# j,kj = [ 1, 7] dist= 4
# j,kj = [ 1, 8] dist= 3
# j,kj = [ 1, 9] dist= 4
# j,kj = [ 1, 10] dist= 4
# j,kj = [ 1, 11] dist= 3
# j,kj = [ 1, 12] dist= 4
# j,kj = [ 1, 13] dist= 3
# j,kj = [ 1, 14] dist= 7
# j,kj = [ 1, 15] dist= 4
# j,kj = [ 2, 3] dist= 3
# j,kj = [ 2, 4] dist= 4
# j,kj = [ 2, 5] dist= 3
# j,kj = [ 2, 6] dist= 3
# j,kj = [ 2, 7] dist= 4
# j,kj = [ 2, 8] dist= 3
# j,kj = [ 2, 9] dist= 4
# j,kj = [ 2, 10] dist= 4
# j,kj = [ 2, 11] dist= 3
# j,kj = [ 2, 12] dist= 4
# j,kj = [ 2, 13] dist= 7
# j,kj = [ 2, 14] dist= 3
# j,kj = [ 2, 15] dist= 4
# j,kj = [ 3, 4] dist= 3
# j,kj = [ 3, 5] dist= 4
# j,kj = [ 3, 6] dist= 4
# j,kj = [ 3, 7] dist= 3
# j,kj = [ 3, 8] dist= 4
# j,kj = [ 3, 9] dist= 3
# j,kj = [ 3, 10] dist= 3
# j,kj = [ 3, 11] dist= 4
# j,kj = [ 3, 12] dist= 7
# j,kj = [ 3, 13] dist= 4
# j,kj = [ 3, 14] dist= 4
# j,kj = [ 3, 15] dist= 3
# j,kj = [ 4, 5] dist= 3
# j,kj = [ 4, 6] dist= 3
# j,kj = [ 4, 7] dist= 4
# j,kj = [ 4, 8] dist= 3
# j,kj = [ 4, 9] dist= 4
# j,kj = [ 4, 10] dist= 4
# j,kj = [ 4, 11] dist= 7
# j,kj = [ 4, 12] dist= 4
# j,kj = [ 4, 13] dist= 3
# j,kj = [ 4, 14] dist= 3
# j,kj = [ 4, 15] dist= 4
# j,kj = [ 5, 6] dist= 4
# j,kj = [ 5, 7] dist= 3
# j,kj = [ 5, 8] dist= 4
# j,kj = [ 5, 9] dist= 3
# j,kj = [ 5, 10] dist= 7
# j,kj = [ 5, 11] dist= 4
# j,kj = [ 5, 12] dist= 3
# j,kj = [ 5, 13] dist= 4
# j,kj = [ 5, 14] dist= 4
# j,kj = [ 5, 15] dist= 3
# j,kj = [ 6, 7] dist= 3
# j,kj = [ 6, 8] dist= 4
# j,kj = [ 6, 9] dist= 7
# j,kj = [ 6, 10] dist= 3
# j,kj = [ 6, 11] dist= 4
# j,kj = [ 6, 12] dist= 3
# j,kj = [ 6, 13] dist= 4
# j,kj = [ 6, 14] dist= 4
# j,kj = [ 6, 15] dist= 3
# j,kj = [ 7, 8] dist= 7
# j,kj = [ 7, 9] dist= 4
# j,kj = [ 7, 10] dist= 4
# j,kj = [ 7, 11] dist= 3
# j,kj = [ 7, 12] dist= 4
# j,kj = [ 7, 13] dist= 3
# j,kj = [ 7, 14] dist= 3
# j,kj = [ 7, 15] dist= 4
# j,kj = [ 8, 9] dist= 3
# j,kj = [ 8, 10] dist= 3
# j,kj = [ 8, 11] dist= 4
# j,kj = [ 8, 12] dist= 3
# j,kj = [ 8, 13] dist= 4
# j,kj = [ 8, 14] dist= 4
# j,kj = [ 8, 15] dist= 3
# j,kj = [ 9, 10] dist= 4
# j,kj = [ 9, 11] dist= 3
# j,kj = [ 9, 12] dist= 4
# j,kj = [ 9, 13] dist= 3
# j,kj = [ 9, 14] dist= 3
# j,kj = [ 9, 15] dist= 4
# j,kj = [ 10, 11] dist= 3
# j,kj = [ 10, 12] dist= 4
# j,kj = [ 10, 13] dist= 3
# j,kj = [ 10, 14] dist= 3
# j,kj = [ 10, 15] dist= 4
# j,kj = [ 11, 12] dist= 3
# j,kj = [ 11, 13] dist= 4
# j,kj = [ 11, 14] dist= 4
# j,kj = [ 11, 15] dist= 3
# j,kj = [ 12, 13] dist= 3
# j,kj = [ 12, 14] dist= 3
# j,kj = [ 12, 15] dist= 4
# j,kj = [ 13, 14] dist= 4
# j,kj = [ 13, 15] dist= 3
# j,kj = [ 14, 15] dist= 3
# good Min = 3
# Min addr = 1, 0
# Min valu = 00001011, 00000000
# good Max = 7
# Max pair = 15, 0
# Max valu = 01111111, 00000000
- Program 2 (A * B signed multiplication):
run -all
# -------------------------------------------------------------
# Starting Test for Program 2
# -------------------------------------------------------------
# [PASS] Case 0: -128 * -128 = 16384 (Hex: 4000)
# [PASS] Case 1: -128 * 127 = -16256 (Hex: c080)
# [PASS] Case 2: 127 * -128 = -16256 (Hex: c080)
# [PASS] Case 3: -128 * -127 = 16256 (Hex: 3f80)
# [PASS] Case 4: -127 * 127 = -16129 (Hex: c0ff)
# [PASS] Case 5: 63 * -59 = -3717 (Hex: f17b)
# [PASS] Case 6: 0 * 125 = 0 (Hex: 0000)
# [PASS] Case 7: 125 * 0 = 0 (Hex: 0000)
# [PASS] Case 8: 127 * 127 = 16129 (Hex: 3f01)
# [PASS] Case 9: -1 * -1 = 1 (Hex: 0001)
# [PASS] Case 10: 0 * 0 = 0 (Hex: 0000)
# [PASS] Case 11: -59 * 63 = -3717 (Hex: f17b)
# [PASS] Case 12: 59 * 63 = 3717 (Hex: 0e85)
# [PASS] Case 13: -63 * -59 = 3717 (Hex: 0e85)
# -------------------------------------------------------------
# SUCCESS: All 14 corner cases passed.
# -------------------------------------------------------------
- Program 3 (A * B * C signed multiplication)
run -all
# -------------------------------------------------------------
# Starting Targeted Corner Case Test for Program 3 (A*B*C)
# Output Mapping: Mem[5]=Upper, Mem[4]=Mid, Mem[3]=Lower
# -------------------------------------------------------------
# [PASS] Case 0: 127 * 127 * 127 = 2048383 (Hex: 1f417f)
# [PASS] Case 1: -128 * -128 * -128 = -2097152 (Hex: e00000)
# [PASS] Case 2: 127 * -49 * 89 = -553847 (Hex: f78c89)
# [PASS] Case 3: 10 * 10 * 10 = 1000 (Hex: 0003e8)
# [PASS] Case 4: 10 * 10 * -10 = -1000 (Hex: fffc18)
# [PASS] Case 5: 10 * -10 * 10 = -1000 (Hex: fffc18)
# [PASS] Case 6: 10 * -10 * -10 = 1000 (Hex: 0003e8)
# [PASS] Case 7: -10 * 10 * 10 = -1000 (Hex: fffc18)
# [PASS] Case 8: -10 * 10 * -10 = 1000 (Hex: 0003e8)
# [PASS] Case 9: -10 * -10 * 10 = 1000 (Hex: 0003e8)
# [PASS] Case 10: -10 * -10 * -10 = -1000 (Hex: fffc18)
# [PASS] Case 11: 0 * 125 * -128 = 0 (Hex: 000000)
# [PASS] Case 12: -128 * -128 * 1 = 16384 (Hex: 004000)
# [PASS] Case 13: -1 * -1 * -1 = -1 (Hex: ffffff)
# -------------------------------------------------------------
# SUCCESS: All 14 corner cases passed.
# -------------------------------------------------------------
- Added specification of non arithmetic operations in the report
- Added Assembler (assembler.py)
- Added the assembly(program1.PANDA_ASM) and its machine code(program1_machine_code.txt) for program 1
- Removed relative branching so that now it can use more labels(32 max)
- Removed the
ADCinstruction and changed it toINC/DEC. - Added
HALTandNOOPspecial instruction to handle the sending done sinal logic. - Changed program 2 pseudocode to fully test the correctness of the algorithm
- Initial version










