[하만]세미콘 아카데미/verilog

0603 RISC-v GPI GPO

내머리속은이런걸로 2024. 7. 9. 17:48

AHB-Lite

: Advanced High Performance Bus-Lite

ARM AMBA[Advanced Microcontroller Bus Architecture] 버스 프로토콜의 lite 버전이다.

  • 싱글 마스터 : 마스터 1개가 버스를 제어하고, 여러 슬레이브 장치와 통신한다.
  • 고성능 : 고속 데이터 전송을 지원하며, 주로 고성능 마이크로컨트롤러와 프로세서에서 사용된다.

 

AHB-Lite block diagram

  • HWDATA [AHB Write Data] : 쓰기 명령 시, 마스터는 이 신호를 통해 스레이브로 데이터를 전송한다.
  • HADDR [AHB Address] : 읽기/쓰기 작업에서, 마스터는 이 신호를 통해 접근하고자 하는 슬레이브의 주소를 지정한다.
  • HSEL [AHB Select] : 여러 슬레이브 중 어느 하나를 어느 하나를 선택하기 위해 사용된다.
  • HRDATA [AHB Read Data] : 읽기 명령 시, 슬레이브는 이 신호를 통해 마스터로 데이터를 전송한다.
  • HREADY [AHB Ready] : 슬레이브가 현재 전송을 완료할 준비가 되었음을 나타내며, 마스터는 이 신호가 높을 때만 다음 전송을 시작한다.

 

Memory Mapping

: 메모리 주소 공간을 특정 하드웨어 장치나 메모리 위치와 연결하는 기술이ㅏㄷ.

 DataMemory → assign rdata = ram[addr[7:2]];

한 영역에 분별되는 주소 값을 얻기 위하여 공통되는 하위 비트 2개를 제외하여 사용한다.

 

ex)

int main()
{
	*(int *) (0x00002100) = 0x01;
    
    return 0;
}

 

0x0000 2100 시작주소에 0x01 값이 있다.


 

defines.sv

`define OP_TYPE_R 7'b0110011
`define OP_TYPE_IL 7'b0000011
`define OP_TYPE_I 7'b0010011
`define OP_TYPE_S 7'b0100011
`define OP_TYPE_B 7'b1100011
`define OP_TYPE_J 7'b1101111
`define OP_TYPE_JI 7'b1100111
`define OP_TYPE_U 7'b0110111
`define OP_TYPE_UA 7'b0010111

`define ADD 4'b0000
`define SUB 4'b1000
`define SLL 4'b0001
`define SRL 4'b0101
`define SRA 4'b1101
`define SLT 4'b0010
`define SLTU 4'b0011
`define XOR 4'b0100
`define OR 4'b0110
`define AND 4'b0111

`define BEQ 4'b0000
`define BNE 4'b0001
`define BLT 4'b0100
`define BGE 4'b0101
`define BLTU 4'b0110
`define BGEU 4'b0111

 

DataMemory.sv

`timescale 1ns / 1ps

module DataMemory (  // RAM

    input  logic        clk,
    input  logic        ce,
    input  logic        we,
    input  logic [ 7:0] addr,
    input  logic [31:0] wdata,
    output logic [31:0] rdata
);
    logic [31:0] ram[0:2**6-1];

    initial begin
        int i;
        for (i = 0; i < 2 ** 6; i++) begin
            ram[i] = 100 + i;
        end
    end

    assign rdata = ram[addr[7:2]];

    always_ff @(posedge clk) begin
        if (we & ce) ram[addr[7:2]] <= wdata;
    end
endmodule

 

DataPath.sv

`timescale 1ns / 1ps
`include "defines.sv"

module DataPath (
    input  logic        clk,
    input  logic        reset,
    input  logic [31:0] machineCode,
    input  logic        regFileWe,
    input  logic [ 3:0] aluControl,
    output logic [31:0] instrMemRAddr,
    output logic [31:0] dataMemRAddr,
    output logic [31:0] dataMemWData,
    input  logic [31:0] dataMemRData,
    input  logic        AluSrcMuxSel,
    input  logic [ 2:0] extType,
    input  logic [ 2:0] RFWriteDataSrcMuxSel,
    input  logic        branch,
    input logic [ 1:0] PCMuxSel
);
    logic [31:0] w_ALUResult, w_RegFileRData1, w_RegFileRData2, w_PC_Data, w_PC_IMM_Data;
    logic [31:0] w_extendOut, w_AluSrcMuxOut, w_RFWriteDataSrcMuxOut;
    logic [31:0] w_PCAdderSrcMuxOut, w_PC_out, w_PC_Adder;
    logic w_btaken, w_PCAdderSrcMuxSel;
    assign dataMemRAddr = w_ALUResult;
    assign dataMemWData = w_RegFileRData2;

    Register U_PC (
        .clk  (clk),
        .reset(reset),
        .d    (w_PC_out),
        .q    (instrMemRAddr)
    );

    assign w_PCAdderSrcMuxSel = branch & w_btaken;

    mux_2x1 U_PCAdderSrcMux (
        .sel(w_PCAdderSrcMuxSel),
        .a  (32'd4),
        .b  (w_extendOut),
        .y  (w_PCAdderSrcMuxOut)
    );

    adder U_Adder_PC (
        .a(instrMemRAddr),
        .b(w_PCAdderSrcMuxOut),
        .y(w_PC_Data)
    );

    RegisterFile U_RegisterFile (
        .clk   (clk),
        .we    (regFileWe),
        .RAddr1(machineCode[19:15]),
        .RAddr2(machineCode[24:20]),
        .WAddr (machineCode[11:7]),
        .WData (w_RFWriteDataSrcMuxOut),
        .RData1(w_RegFileRData1),
        .RData2(w_RegFileRData2)
    );

    mux_2x1 U_ALUSrcMux (
        .sel(AluSrcMuxSel),
        .a  (w_RegFileRData2),
        .b  (w_extendOut),
        .y  (w_AluSrcMuxOut)
    );

    alu U_ALU (
        .a         (w_RegFileRData1),
        .b         (w_AluSrcMuxOut),
        .aluControl(aluControl),
        .result    (dataMemRAddr),
        .btaken    (w_btaken)
    );

    mux_5x1 U_RFWriteDataSrcMux (
        .sel(RFWriteDataSrcMuxSel),
        .a  (dataMemRAddr),
        .b  (dataMemRData),
        .c  (w_extendOut), // u-type
        .d  (w_PC_IMM_Data), // ua-type
        .e  (w_PC_Adder),   // j-type, i-type
        .y  (w_RFWriteDataSrcMuxOut)
    );

    extend U_Extend (
        .extType(extType),
        .instr  (machineCode[31:7]),  // except opcode
        .immext (w_extendOut)
    );

    adder U_Adder_PC_IMM (
        .a(w_extendOut),
        .b(instrMemRAddr),
        .y(w_PC_IMM_Data)
    );

    mux_3x1 U_PC_Mux (
        .sel(PCMuxSel),
        .a(w_PC_Data),
        .b(w_PC_IMM_Data),
        .c(dataMemRAddr),
        .y(w_PC_out)
    );

    adder U_PC_Adder_4 (
        .a(32'd4),
        .b(instrMemRAddr),
        .y(w_PC_Adder)
    );

endmodule

module RegisterFile (
    input  logic        clk,
    input  logic        we,
    input  logic [ 4:0] RAddr1,
    input  logic [ 4:0] RAddr2,
    input  logic [ 4:0] WAddr,
    input  logic [31:0] WData,
    output logic [31:0] RData1,
    output logic [31:0] RData2
);
    logic [31:0] RegFile[0:31];

    initial begin
        RegFile[0] = 32'd0;
        RegFile[1] = 32'd1;
        RegFile[2] = 32'd2;
        RegFile[3] = 32'd3;
        RegFile[4] = 32'd4;
        RegFile[5] = 32'd5;
    end

    always_ff @(posedge clk) begin
        if (we) RegFile[WAddr] <= WData;
    end

    assign RData1 = (RAddr1 != 0) ? RegFile[RAddr1] : 0;
    assign RData2 = (RAddr2 != 0) ? RegFile[RAddr2] : 0;
endmodule

module Register (
    input  logic        clk,
    input  logic        reset,
    input  logic [31:0] d,
    output logic [31:0] q
);
    always_ff @(posedge clk, posedge reset) begin
        if (reset) q <= 0;
        else q <= d;
    end
endmodule

module alu (    // logic : unsigned 4 bit -> signed(-) change unsigned(+)
    input logic [31:0] a,
    input logic [31:0] b,
    input logic [3:0] aluControl,
    output logic btaken,
    output logic [31:0] result
);
    always_comb begin
        case (aluControl)
            `ADD:    result = a + b;
            `SUB:    result = a - b;
            `SLL:    result = a << b;
            `SRL:    result = a >> b;   // only unsigned
            `SRA:    result = $signed(a) >>> b; // Shiftt Right Arith (unsigned & signed)
            `SLT:    result = ($signed(a) < $signed(b)) ? 1 : 0;  // Set Less Than (unsigned & signed)
            `SLTU:   result = (a < b) ? 1 : 0;  // Set Less Than (only unsigned)
            `XOR:    result = a ^ b;
            `OR:     result = a | b;
            `AND:    result = a & b;
            default: result = 32'bx;
        endcase
    end

    always_comb begin : comparator  // B-Type
        case (aluControl[2:0])
            3'b000:  btaken = (a == b);  // BEQ: if (rs1 == rs2) PC += imm 
            3'b001:  btaken = (a != b);  // BNE: if (rs1 != rs2)
            3'b100:  btaken = ($signed(a) < $signed(b));   // BLT: if (rs1 < rs2)
            3'b101:  btaken = ($signed(a) >= $signed(b));  // BGE: if (rs1 >= rs2)
            3'b110:  btaken = (a < b);   // BLTU: if (rs1 < rs2) (U)
            3'b111:  btaken = (a >= b);  // BGEU: if (rs1 >= rs2) (U)
            default: btaken = 1'bx;
        endcase
    end
endmodule

module adder (
    input  logic [31:0] a,
    input  logic [31:0] b,
    output logic [31:0] y
);

    assign y = a + b;
endmodule

module extend (  // immext
    input  logic [ 2:0] extType,
    input  logic [31:7] instr,    // except opcode
    output logic [31:0] immext
);
    always_comb begin
        case (extType)
            3'b000: immext = {{21{instr[31]}}, instr[31:20]};  // I-Type
            3'b001:
            immext = {{21{instr[31]}}, instr[30:25], instr[11:7]};  // S-Type
            3'b010:
            immext = {
                {20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0
            };  // B-Type
            3'b011: immext = {instr[31:12], {12{1'b0}}};  // U-Type
            3'b100:
            immext = {
                {12{instr[31]}},
                instr[19:12],
                instr[20],
                instr[30:25],
                instr[24:21],
                1'b0
            };  // J-Type
            3'b111:
            immext = {
                {27{instr[24]}}, instr[24:20]
            };
        endcase
    end
endmodule

module mux_2x1 (
    input  logic        sel,
    input  logic [31:0] a,
    input  logic [31:0] b,
    output logic [31:0] y
);
    always_comb begin
        case (sel)
            1'b0: y = a;
            1'b1: y = b;
            default: y = 32'bx;
        endcase
    end
endmodule

module mux_3x1 (
    input  logic [ 1:0] sel,
    input  logic [31:0] a,
    input  logic [31:0] b,
    input  logic [31:0] c,
    output logic [31:0] y
);
    always_comb begin
        case (sel)
            2'b00:   y = a;
            2'b01:   y = b;
            2'b10:   y = c;
            default: y = 32'bx;
        endcase
    end
endmodule

module mux_5x1 (
    input  logic [ 2:0] sel,
    input  logic [31:0] a,
    input  logic [31:0] b,
    input  logic [31:0] c,
    input  logic [31:0] d,
    input  logic [31:0] e,
    output logic [31:0] y
);
    always_comb begin
        case (sel)
            3'b000:   y = a;
            3'b001:   y = b;
            3'b010:   y = c;
            3'b011:   y = d;
            3'b100:    y = e;
            default: y = 32'bx;
        endcase
    end
endmodule

 

CPU_Core.sv

`timescale 1ns / 1ps

module CPU_Core (
    input  logic        clk,
    input  logic        reset,
    input  logic [31:0] machineCode,
    output logic [31:0] instrMemRAddr,
    output logic        dataMemWe,
    output logic [31:0] dataMemRAddr,
    output logic [31:0] dataMemWData,
    input  logic [31:0] dataMemRData
);

    logic w_regFileWe, w_AluSrcMuxSel, w_branch;
    logic [3:0] w_aluControl;
    logic [2:0] w_extType, w_RFWriteDataSrcMuxSel;
    logic [1:0] w_PCMuxSel;

    ControlUnit U_ControlUnit (
        .op                  (machineCode[6:0]),
        .funct3              (machineCode[14:12]),
        .funct7              (machineCode[31:25]),
        .regFileWe           (w_regFileWe),
        .AluSrcMuxSel        (w_AluSrcMuxSel),
        .RFWriteDataSrcMuxSel(w_RFWriteDataSrcMuxSel),
        .dataMemWe           (dataMemWe),
        .aluControl          (w_aluControl),
        .extType             (w_extType),
        .branch              (w_branch),
        .PCMuxSel            (w_PCMuxSel)
    );

    DataPath U_DataPath (
        .clk                 (clk),
        .reset               (reset),
        .machineCode         (machineCode),
        .regFileWe           (w_regFileWe),
        .aluControl          (w_aluControl),
        .instrMemRAddr       (instrMemRAddr),
        .AluSrcMuxSel        (w_AluSrcMuxSel),
        .RFWriteDataSrcMuxSel(w_RFWriteDataSrcMuxSel),
        .dataMemRAddr        (dataMemRAddr),
        .dataMemRData        (dataMemRData),
        .extType             (w_extType),
        .dataMemWData        (dataMemWData),
        .branch              (w_branch),
        .PCMuxSel            (w_PCMuxSel)
    );
endmodule

 

ControlUnit.sv

`timescale 1ns / 1ps
`include "defines.sv"

module ControlUnit (
    input  logic [6:0] op,
    input  logic [2:0] funct3,
    input  logic [6:0] funct7,
    output logic       regFileWe,
    output logic       AluSrcMuxSel,
    output logic [2:0] RFWriteDataSrcMuxSel,
    output logic       dataMemWe,
    output logic [2:0] extType,
    output logic [3:0] aluControl,
    output logic       branch,
    output logic [1:0] PCMuxSel
);
    logic [11:0] controls;
    // logic [1:0] w_AluOp;
    assign {regFileWe, AluSrcMuxSel, RFWriteDataSrcMuxSel, dataMemWe, extType, branch, PCMuxSel} = controls;

    always_comb begin : main_decoder
        case (op)  // Opcode
            // regFisleWe, AluSrcMuxSel, RFWriteDataSrcMuxSel, dataMemWe, extType, branch, PCMuxSel
            `OP_TYPE_R:  controls = 12'b1_0_000_0_xxx_0_00;
            `OP_TYPE_IL: controls = 12'b1_1_001_0_000_0_00;
            `OP_TYPE_I:  
                if (funct3 == 3'b001 || funct3 == 3'b101) begin
                    controls = 12'b1_1_000_0_111_0_00;
                end
                else begin
                    controls = 12'b1_1_000_0_000_0_00;
                end
            `OP_TYPE_S:  controls = 12'b0_1_xxx_1_001_0_00;
            `OP_TYPE_B:  controls = 12'b0_0_xxx_0_010_1_00;
            `OP_TYPE_J:  controls = 12'b1_x_100_0_100_0_01;
            `OP_TYPE_JI: controls = 12'b1_1_100_0_000_0_10;
            `OP_TYPE_U:  controls = 12'b1_x_010_0_011_0_00;
            `OP_TYPE_UA: controls = 12'b1_x_011_0_011_0_00;
            default:     controls = 12'bx;
        endcase
    end

    always_comb begin : alu_control_signal
        case (op)
            `OP_TYPE_R: aluControl = {funct7[5], funct3};
            `OP_TYPE_IL: aluControl = {1'b0, 3'b000};    // only Add
            `OP_TYPE_I:
                if (funct3 == 3'b001 || funct3 == 3'b101) begin
                   aluControl = {funct7[5], funct3};
                end
                else begin
                    aluControl = {1'b0, 3'b000};
                end
            `OP_TYPE_S: aluControl = {1'b0, 3'b000};    // only Add
            `OP_TYPE_B: aluControl = {1'b0, funct3};
            `OP_TYPE_J: aluControl = {1'b0, 3'b000};
            `OP_TYPE_JI: aluControl = {1'b0, 3'b000};
            default:    aluControl = 4'bx;
        endcase
    end
endmodule

 

InstructionMemory.sv

`timescale 1ns / 1ps

module InstructionMemory (
    input  logic [31:0] addr,   // 1 byte standard
    output logic [31:0] data
);
    logic [31:0] rom[0:63];

    initial begin
        $readmemh("inst.mem", rom); // hex code instruction
    end

    // use 4 byte (32bit)
    assign data = rom[addr[31:2]];  // 0, 4, 8 ...
endmodule

 

Bus_Interconnector.sv

`timescale 1ns / 1ps

module BUS_Interconnector (
    input  logic [31:0] address,
    output logic [ 2:0] slave_sel,
    input  logic [31:0] slave_rdata1,
    input  logic [31:0] slave_rdata2,
    input  logic [31:0] slave_rdata3,
    output logic [31:0] master_rdata
);

    decoder U_Decoder(
        .x(address),
        .y(slave_sel)
    );

    mux U_Mux(
        .sel(address),
        .a(slave_rdata1),
        .b(slave_rdata2),
        .c(slave_rdata3),
        .y(master_rdata)
    );
endmodule

module decoder (
    input  logic [31:0] x,
    output logic [ 2:0] y
);

    always_comb begin : decoder
        case (x[31:8])
            24'h0000_10: y = 3'b001;
            24'h0000_20: y = 3'b010; 
            24'h0000_21: y = 3'b100; 
            default: y = 3'b0;
        endcase
    end
endmodule

module mux (
    input  logic [31:0] sel,
    input  logic [31:0] a,
    input  logic [31:0] b,
    input  logic [31:0] c,
    output logic [31:0] y
);
    always_comb begin : decoder
        case (sel[31:8])
            24'h0000_10: y = a;
            24'h0000_20: y = b; 
            24'h0000_21: y = c; 
            default: y = 32'bx;
        endcase
    end
    
endmodule

 

GPO.sv

`timescale 1ns / 1ps

module GPO (
    input  logic        clk,
    input  logic        reset,
    input  logic        ce,
    input  logic        we,
    input  logic [ 1:0] addr,
    input  logic [31:0] wdata,
    output logic [31:0] rdata,
    output logic [ 3:0] outPort
);
    // GPO Register
    logic [31:0] ODR;

    // output logic
    assign outPort = ODR[3:0];

    // write logic
    always_ff @(posedge clk, posedge reset) begin : GPO
        if (reset) begin
            ODR <= 0;
        end else begin
            if (ce & we) ODR <= wdata;
        end
    end

    // read logic
    assign rdata = ODR;
endmodule

 

RV32I.sv

`timescale 1ns / 1ps

module RV32I (
    input logic clk,
    input logic reset,
    output logic [3:0] outPortA
);
    logic [31:0] w_InstrMemAddr, w_InsrtMemData;
    logic w_We;
    logic [31:0] w_Addr, w_dataMemRData, w_WData;
    logic [31:0] w_MasterRData, w_GPORData;
    logic [2:0] w_slave_sel;

    CPU_Core U_CPU_Core (
        .clk          (clk),
        .reset        (reset),
        .machineCode  (w_InsrtMemData),
        .instrMemRAddr(w_InstrMemAddr),
        .dataMemWe    (w_We),
        .dataMemRAddr (w_Addr),
        .dataMemRData (w_MasterRData),
        .dataMemWData (w_WData)
    );

    BUS_Interconnector U_BUS_InterConn (
        .address     (w_Addr),
        .slave_sel   (w_slave_sel),
        .slave_rdata1(w_dataMemRData),
        .slave_rdata2(w_GPORData),
        .slave_rdata3(),
        .master_rdata(w_MasterRData)
    );

    GPO U_GPO (
        .clk    (clk),
        .reset  (reset),
        .ce     (w_slave_sel[1]),
        .we     (w_We),
        .addr   (w_Addr[1:0]),
        .wdata  (w_WData),
        .rdata  (w_GPORData),
        .outPort(outPortA)
    );

    DataMemory U_RAM (
        .clk  (clk),
        .ce   (w_slave_sel[0]),
        .we   (w_We),
        .addr (w_Addr[7:0]),
        .wdata(w_WData),
        .rdata(w_dataMemRData)
    );

    InstructionMemory U_ROM (
        .addr(w_InstrMemAddr),
        .data(w_InsrtMemData)
    );
endmodule

 

tb_RISC_V

`timescale 1ns / 1ps

module tb_RISC_V (); 
    logic clk; 
    logic reset; 
    logic [3:0] outPortA; 

    RV32I dut(.*); 
    always #5 clk = ~clk; 
    initial begin 
        clk = 0; 
        reset = 1; 
        #50 reset = 0;
    end
endmodule

 

Inst.mem

00000133
000017b7
10078793
00f10133
ff010113
00112623
00812423
01010413
000027b7
00f00713
00e7a023
00a00513
018000ef
000027b7
0007a023
00a00513
008000ef
fddff06f
fd010113
02812623
03010413
fca42e23
fe042623
0400006f
fe042423
01c0006f
fec42783
00178793
fef42623
fe842783
00178793
fef42423
fe842703
000187b7
69f78793
fce7dee3
fdc42783
fff78793
fcf42e23
fdc42783
fcf040e3
00000013
02c12403
03010113
00008067

 

schematic

 

simulation

 

constraint

## Clock signal
set_property -dict { PACKAGE_PIN W5   IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_34 ,Sch=CLK100MHZ
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
## LEDs

set_property -dict { PACKAGE_PIN U16  IOSTANDARD LVCMOS33 } [get_ports { outPortA[0]  }]; #IO_L23N_T3_A02_D18_14        ,Sch=LED0
set_property -dict { PACKAGE_PIN E19  IOSTANDARD LVCMOS33 } [get_ports { outPortA[1]  }]; #IO_L3N_T0_DQS_EMCCLK_14      ,Sch=LED1
set_property -dict { PACKAGE_PIN U19  IOSTANDARD LVCMOS33 } [get_ports { outPortA[2]  }]; #IO_L15P_T2_DQS_RDWR_B_14     ,Sch=LED2
set_property -dict { PACKAGE_PIN V19  IOSTANDARD LVCMOS33 } [get_ports { outPortA[3]  }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 ,Sch=LED3
##Buttons

set_property -dict { PACKAGE_PIN U18  IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L18N_T2_A11_D27_14 ,Sch=BTNC

'[하만]세미콘 아카데미 > verilog' 카테고리의 다른 글

0614 AMBA AXI BUS  00 2024.07.10
0604 RISC-v GPO GPI GPIO  0 2024.07.10
0530~0531 RISCV_Type  0 2024.07.09
0523 Team Project  0 2024.07.09
0529 DedicatedProcessor stackSum  0 2024.07.09