**TO DO** - [x] Adder.v - [x] ALU_Ctrl.v - [x] ALU.v - [x] MUX_2to1.v - [x] MUX_3to1.v - [x] Decoder.v - [x] Sign_Extend.v - [x] Simple_Single_CPU.v - [x] Shift_Left_Two_32.v ### Sign Extend ![截圖 2025-08-07 中午12.41.59](https://hackmd.io/_uploads/r1LsCjZdle.png) 不太確定 always block 是用來幹嘛的 ```verilog // student ID : 314551134 module Sign_Extend( data_i, data_o ); // I/O ports input [16-1:0] data_i; output [32-1:0] data_o; // Internal Signals assign data_o[15:0] = data_i[15:0]; assign data_o[31:16] = {16{data_i[15]}}; // Main function always @(*) begin end endmodule ``` Testbench: ```shell Test Sign_Extend: data_i (hex) | data_o (hex) --------------|---------------- 1234 | 00001234 ffff | ffffffff fffe | fffffffe 7fff | 00007fff 8000 | ffff8000 Sign_Extend_tb.v:41: $finish called at 5000 (1ps) ``` ### Shift_Left_Two_32 ![截圖 2025-08-07 中午12.47.29](https://hackmd.io/_uploads/H1-lx3-dxg.png) verilog 支援 `<<` bit operation ```verilog // student ID module Shift_Left_Two_32( data_i, data_o ); // I/O ports input [32-1:0] data_i; output [32-1:0] data_o; // Internal Signals assign data_o = data_i << 2; // Main function always @(*) begin end endmodule ``` Testbench: ```shell Test Shift_Left_Two_32: data_i (hex) | data_o (hex) ----------------|---------------- 00000001 | 00000004 00000003 | 0000000c ffffffff | fffffffc 80000000 | 00000000 12345678 | 48d159e0 Shift_Left_Two_32_tb.v:38: $finish called at 5000 (1ps) ``` ### MUX_2to1 ```verilog // student ID module MUX_2to1( data0_i, data1_i, select_i, data_o ); parameter size = 0; // I/O ports input [size-1:0] data0_i; input [size-1:0] data1_i; input select_i; output [size-1:0] data_o; // Internal Signals assign data_o = (select_i) ? data1_i : data0_i; // Main function always@(*)begin end endmodule ``` Testbench: ```shell Test MUX_2to1: select | data0_i | data1_i | data_o -------|----------|----------|--------- 0 | a5 | 3c | a5 1 | a5 | 3c | 3c 0 | 55 | ff | 55 1 | 55 | ff | ff 0 | 00 | ff | 00 1 | 00 | ff | ff MUX_2to1_tb.v:49: $finish called at 6000 (1ps) ``` 帶參數的,用法: ```verilog // 設定 size parameter size = 8; reg [size-1:0] data0_i; reg [size-1:0] data1_i; reg select_i; wire [size-1:0] data_o; // 宣告待測 MUX MUX_2to1 #(.size(size)) uut ( .data0_i(data0_i), .data1_i(data1_i), .select_i(select_i), .data_o(data_o) ); ``` ### MUX_3to1 For 2-bits Control signals ```verilog // student ID module MUX_3to1( data0_i, data1_i, data2_i, select_i, data_o ); parameter size = 0; // I/O ports input [size-1:0] data0_i; input [size-1:0] data1_i; input [size-1:0] data2_i; input [2-1:0] select_i; output [size-1:0] data_o; // Internal Signals assign data_o = (select_i == 2'b00) ? data0_i : (select_i == 2'b01) ? data1_i : data2_i; // Main function always@(*)begin end endmodule ``` Testbench: ```shell Test MUX_3to1: sel | data0 | data1 | data2 | data_o ----|-------|-------|-------|-------- 00 | a5 | 3c | f0 | a5 01 | a5 | 3c | f0 | 3c 10 | a5 | 3c | f0 | f0 11 | a5 | 3c | f0 | f0 00 | 00 | ff | 7e | 00 01 | 00 | ff | 7e | ff 10 | 00 | ff | 7e | 7e MUX_3to1_tb.v:53: $finish called at 7000 (1ps) ``` ### Adder 一般的 Adder 沒在管 Overflow 的 ```verilog // student ID module Adder( src1_i, src2_i, sum_o ); // I/O ports input [32-1:0] src1_i; input [32-1:0] src2_i; output[32-1:0] sum_o; // Internal Signals assign sum_o = src1_i + src2_i; // Main function endmodule ``` Testbench: ```shell Test 32-bit Adder: src1_i | src2_i | sum_o --------------|---------------|-------------- 00000001 | 00000002 | 00000003 ffffffff | 00000001 | 00000000 80000000 | 80000000 | 00000000 12345678 | 11111111 | 23456789 00000000 | 00000000 | 00000000 Adder_tb.v:41: $finish called at 5000 (1ps) ``` ### Decoder (Main Control) #### Spec. 1. Input : opcode 2. output : RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch, ALUop, jump #### Instruction Set - R-type : add, sub, AND, OR, ==NOR==, slt, ==sll==, ==srl==, ==sllv==, ==srlv==, ==jr== - I-type : lw, sw, beq, bne, ==addi== - J-type : j, ==jal== #### Some Note - addi: `ALUop = 00` 才會跟著做加法 - jal:`Reg[31] = PC + 4` and perform jump, ($31 same as $ra) - jr:PC = Reg[rs] - 不細分 R-type,全部輸出一樣的,再讓 ALU control 根據 function code 來輸出對應的 control signal #### 2-bits control signals 1. RegDst | RegDst_o | Target | Instruction | | --------- | ------- | ---------------- | | `00` | `rt` field | I-type: addi, lw | | `01` | `rd` field | R-type | | `10` | `$31` | jal | | `11` | Preserve | Preserve | 2. MemtoReg | MemtoReg_o | Source | Instruction | | ----------- | ---------------- | ---------------- | | `00` | ALU or Shifter | R-type, addi| | `01` | memory read data | lw | | `10` | `PC + 4` | jal | | `11` | Preserve | | 3. Branch | Branch_o | Instruction | | -------- | --- | | `00` | Non-branch | | `01` | beq | | `10` | bne | | `11` | Preserve | Branch Taken Timing - beq :`branch = 01 and zero = 1` - bne :`branch = 10 and zero = 0` #### Truth Table | Instruction | RegDst | ALUSrc | MemtoReg | RegWrite | MemRead | MemWrite | Branch | ALUop | jump | | ----------- | ------ | ------ | -------- | -------- | ------- | -------- | ------ | ----- | ---- | | R-type | 01 | 0 | 00 | 1 | 0 | 0 | 00 | 10 | 0 | | addi | 00 | 1 | 00 | 1 | 0 | 0 | 00 | 00 | 0 | | lw | 00 | 1 | 01 | 1 | 1 | 0 | 00 | 00 | 0 | | sw | x | 1 | x | 0 | 0 | 1 | 00 | 00 | 0 | | beq | x | 0 | x | 0 | 0 | 0 | 01 | 01 | 0 | | bne | x | 0 | x | 0 | 0 | 0 | 10 | 01 | 0 | | j | x | x | x | 0 | 0 | 0 | 00 | x | 1 | | jal | 10 | x | 10 | 1 | 0 | 0 | 00 | x | 1 | #### PLA (Programmable Logic Array) ![截圖 2025-08-09 下午6.27.26](https://hackmd.io/_uploads/ryn5MjEdeg.png) ```verilog // student ID : 314551134 module Decoder( instr_op_i, ALU_op_o, ALUSrc_o, RegWrite_o, RegDst_o, Branch_o, Jump_o, MemRead_o, MemWrite_o, MemtoReg_o ); // I/O ports input [6-1:0] instr_op_i; output [2-1:0] ALU_op_o; output [2-1:0] RegDst_o, MemtoReg_o; output [2-1:0] Branch_o; output ALUSrc_o, RegWrite_o, Jump_o, MemRead_o, MemWrite_o; // Instruction opcode parameters parameter Rtype = 6'b000000; parameter ADDI = 6'b001001; parameter LW = 6'b101100; parameter SW = 6'b100100; parameter BEQ = 6'b000110; parameter BNE = 6'b000101; parameter J = 6'b000111; parameter JAL = 6'b000011; assign RegDst_o = (instr_op_i == Rtype) ? 2'b01 : (instr_op_i == JAL) ? 2'b10 : 2'b00; assign ALUSrc_o = (instr_op_i == ADDI || instr_op_i == LW || instr_op_i == SW); assign MemtoReg_o = (instr_op_i == LW) ? 2'b01 : (instr_op_i == JAL) ? 2'b10 : 2'b00; assign RegWrite_o = (instr_op_i == Rtype || instr_op_i == ADDI || instr_op_i == LW || instr_op_i == JAL); assign MemRead_o = (instr_op_i == LW); assign MemWrite_o = (instr_op_i == SW); assign Branch_o = (instr_op_i == BEQ) ? 2'b01 : (instr_op_i == BNE) ? 2'b10 : 2'b00; assign ALU_op_o = (instr_op_i == Rtype) ? 2'b10 : (instr_op_i == BEQ || instr_op_i == BNE) ? 2'b01 : 2'b00; assign Jump_o = (instr_op_i == J || instr_op_i == JAL); endmodule ``` Testbench: ```shell Time Opcode ALUop RegDst ALUSrc MemtoRegRegWriteMemRead MemWriteBranch Jump 10000 Rtype 10 01 0 00 1 0 0 00 0 20000 ADDI 00 00 1 00 1 0 0 00 0 30000 LW 00 00 1 01 1 1 0 00 0 40000 SW 00 00 1 00 0 0 1 00 0 50000 BEQ 01 00 0 00 0 0 0 01 0 60000 BNE 01 00 0 00 0 0 0 10 0 70000 J 00 00 0 00 0 0 0 00 1 80000 JAL 00 10 0 10 1 0 0 00 1 Decoder_tb.v:74: $finish called at 80000 (1ps) ``` ### ALU Control #### Spec. 1. input : ALUop, Function code 2. output : ALUCtrl_o, FURslt_o, leftRight_o, shifhterSource_o, PC_source_o #### Control signal | Control signal | bit|value | function | | --------------------- | ------ | --------------------------------------------------------------- | ---------------------------------------------------------------------- | | **FURslt\_o** | 1 bit | 0 = ALU <br>1 = Shifter | 決定最終寫回暫存器的資料是來自 ALU 還是 Shifte | | **leftRight\_o** | 1 bit | 0 =Shift Left<br>1 = Shift Right | 告訴 Shifter 模組要將輸入資料向左移還是向右移 | | **shifhterSource\_o** | 1 bit | 0 = shamt field<br>1 = register | 決定 Shifter 的移位位數是來自指令的shamt 還是 register | | **JR\_source\_o** | 1 bit | 0 = PC+4<br>1 = register | 在 `jr` 指令中,讓 PC 設定成暫存器的值 | - FURslt = Function Unit Result #### Truth Table | Instruction | ALUop1 | ALUop0 | F5 | F4 | F3 | F2 | F1 | F0 | Operation | Value | |-------------|--------|--------|----|----|----|----|----|----|-----------|---------------------| | add | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0010 | Src1 + Src2 | | sub | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0110 | Src1 - Src2 | | and | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 0001 | Src1 & Src2 | | or | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0000 | Src1 \| Src2 | | nor | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1101 | ~(Src1 \| Src2) | | slt | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0111 | (Src1 < Src2):? 1:0 | | sll | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | xxxx | Shifter | | srl | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | xxxx | Shifter | | sllv | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | xxxx | Shifter | | srlv | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | xxxx | Shifter | | jr | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | xxxx | x | | addi | 0 | 0 | x | x | x | x | x | x | 0010 | Src1 + imm1 | | lw | 0 | 0 | x | x | x | x | x | x | 0010 | Src1 + imm1 | | sw | 0 | 0 | x | x | x | x | x | x | 0010 | Src1 + imm1 | | beq | 0 | 1 | x | x | x | x | x | x | 0110 | Src1 - Src2 | | bne | 0 | 1 | x | x | x | x | x | x | 0110 | Src1 - Src2 | | j | x | x | x | x | x | x | x | x | xxxx | x | | jal | x | x | x | x | x | x | x | x | xxxx | x | ```verilog // student ID module ALU_Ctrl( funct_i, ALUOp_i, ALUCtrl_o, FURslt_o, leftRight_o, shifhterSource_o, PC_source_o ); // I/O ports input [6-1:0] funct_i; input [2-1:0] ALUOp_i; output reg [4-1:0] ALUCtrl_o; output reg FURslt_o; // 1-bit: 0=ALU, 1=Shifter output reg leftRight_o; output reg shifhterSource_o; output reg PC_source_o; // funct code parameters localparam ADD = 6'b100011; localparam SUB = 6'b100001; localparam AND = 6'b100110; localparam OR = 6'b100101; localparam NOR = 6'b101011; localparam SLT = 6'b101000; localparam SLL = 6'b000010; localparam SRL = 6'b000100; localparam SLLV = 6'b000110; localparam SRLV = 6'b001000; localparam JR = 6'b001100; always @(*) begin // default value ALUCtrl_o = 4'b0000; FURslt_o = 1'b0; leftRight_o = 1'b0; shifhterSource_o = 1'b0; PC_source_o = 1'b0; case (ALUOp_i) 2'b10: begin // R-type case (funct_i) ADD: ALUCtrl_o = 4'b0010; // add SUB: ALUCtrl_o = 4'b0110; // sub AND: ALUCtrl_o = 4'b0001; // and OR: ALUCtrl_o = 4'b0000; // or NOR: ALUCtrl_o = 4'b1101; // nor SLT: ALUCtrl_o = 4'b0111; // slt SLL: begin FURslt_o = 1'b1; // Shifter leftRight_o = 1'b0; // << shifhterSource_o = 1'b0; // shamt ALUCtrl_o = 4'bxxxx; end SRL: begin FURslt_o = 1'b1; // Shifter leftRight_o = 1'b1; // >> shifhterSource_o = 1'b0; // shamt ALUCtrl_o = 4'bxxxx; end SLLV: begin FURslt_o = 1'b1; leftRight_o = 1'b0; // << shifhterSource_o = 1'b1; // register ALUCtrl_o = 4'bxxxx; end SRLV: begin FURslt_o = 1'b1; leftRight_o = 1'b1; // << shifhterSource_o = 1'b1; // register ALUCtrl_o = 4'bxxxx; end JR: begin PC_source_o = 1'b1; // PC = register value ALUCtrl_o = 4'bxxxx; end default: ALUCtrl_o = 4'b0000; endcase end 2'b00: begin // addi, lw, sw ALUCtrl_o = 4'b0010; // add end 2'b01: begin // beq, bne ALUCtrl_o = 4'b0110; // sub end default: begin // j, jal ALUCtrl_o = 4'bxxxx; end endcase end endmodule ``` ### ALU ```verilog // student ID module ALU( src1_i, src2_i, ctrl_i, result_o, zero_o, overflow ); // I/O ports input [32-1:0] src1_i; input [32-1:0] src2_i; input [4-1:0] ctrl_i; output reg[32-1:0] result_o; output zero_o; output overflow; // Internal signals parameter ADD = 4'b0010; parameter SUB = 4'b0110; parameter AND = 4'b0001; parameter OR = 4'b0000; parameter NOR = 4'b1101; parameter SLT = 4'b0111; assign zero_o = (result_o == 32'b0); assign overflow = ~((ctrl_i == SUB) ^ (src1_i[31] ^ src2_i[31])) & (src1_i[31] ^ result_o[31]) & (ctrl_i == SUB | ctrl_i == ADD); // Main function always @(*) begin case (ctrl_i) ADD: result_o = src1_i + src2_i; SUB: result_o = src1_i - src2_i; AND: result_o = src1_i & src2_i; OR: result_o = src1_i | src2_i; NOR: result_o = ~(src1_i | src2_i); SLT: result_o = src1_i < src2_i; default: result_o = 32'b0; endcase end endmodule ``` ### Single Cycle Machine