활동시기 : 2023년도 여름, 전자회로연구회(소모임 ECR)

저장위치 : project_bus

컴퓨터구조를 한학기동안 스스로 학습하고 난 후, 소모임 인원들과 함께 프로젝트로 진행한 내용입니다.

한 학기동안 컴퓨터구조를 학습한 후, 버스시스템을 베릴로그로 구현하기로 하였다.

일반적으로 D램을 램으로 사용하지만, 베릴로그상에선 S램이 D램의 역할을 대신 할 수 있다. 그렇기에 S램을 D램 대신하여 사용했다. 해당 구조는 다음과 같다.

Untitled

따라서 bus의 dut에서 sram을 하위모델로 가지면 안된다는 것이다.

`timescale 1ns / 1ps

module bus(clk, reset, sel, load, din, dout);

input clk, reset;
input [2:0] load, sel;
input [15:0] din; //s램으로 받는 데이터
output [15:0] dout; //s램으로 내보내는 데이터

reg [11:0] ar, pc;
reg [15:0] dr, ac, ir;
reg [15:0] dout;

parameter
nar = 3'b000, npc = 3'b001, ndr = 3'b010,
nac = 3'b011, nir = 3'b100, nram = 3'b101;

always @ (posedge clk or negedge reset) begin
    if(!reset)begin
        ar <= 12'd0;
        pc <= 12'd0;
        dr <= 16'd0;
        ac <= 16'd0;
        ir <= 16'd0;
    end
    
    else if (sel == nar) begin
        case(load)
        nar : ar <= ar;
        npc : pc <= ar;
        ndr : dr <= ar;
        nac : ac <= ar;
        nir : ir <= ar;
        nram : dout <= ar;
        default : ;
        endcase
    end
    
     else if (sel == npc) begin
        case(load)
        nar : ar <= pc;
        npc : pc <= pc;
        ndr : dr <= pc;
        nac : ac <= pc;
        nir : ir <= pc;
        nram : dout <= pc;
        default : ;
        endcase
    end

     else if (sel == ndr) begin
        case(load)
        nar : ar <= dr;
        npc : pc <= dr;
        ndr : dr <= dr;
        nac : ac <= dr;
        nir : ir <= dr;
        nram : dout <= dr;
        default : ;
        endcase
    end

     else if (sel == nac) begin
        case(load)
        nar : ar <= ac;
        npc : pc <= ac;
        ndr : dr <= ac;
        nac : ac <= ac;
        nir : ir <= ac;
        nram : dout <= ac;
        default : ;
        endcase
    end

     else if (sel == nir) begin
        case(load)
        nar : ar <= ir;
        npc : pc <= ir;
        ndr : dr <= ir;
        nac : ac <= ir;
        nir : ir <= ir;
        nram : dout <= ir;
        default : ;
        endcase
    end

     else if (sel == nram) begin
        case(load)
        nar : ar <= din;
        npc : pc <= din;
        ndr : dr <= din;
        nac : ac <= din;
        nir : ir <= din;
        nram : dout <= din;
        default : ;
        endcase
    end

end
endmodule

처음과는 달리 모든 경우의 버스를 만들었다.

`timescale 1ns / 1ps

module sram(clk, we, addr, data_in, data_out);

parameter ADDR_WIDTH = 12, WORD_DEPTH = 4096, WORD_WIDTH = 16;
//bit수를 선언해준다

input [ADDR_WIDTH-1 : 0] addr;
input [WORD_WIDTH-1 : 0] data_in;
input clk, we;
output reg [WORD_WIDTH -1 : 0] data_out;
//output과 reg를 함께 사용할 수 있다.

reg [WORD_WIDTH-1 : 0] mem [0 : WORD_DEPTH-1];

always @ (posedge clk) begin
    if(!we) //write
        mem[addr] <= data_in;
    else begin
        data_out <= mem[addr];
    end
end

endmodule

s램의 경우 큰 변화가 없다.

`timescale 1ns / 1ps

module tb_bus( );

reg clk, reset, we;
reg [2:0] load;
reg [2:0] sel;
reg [11:0] addr;
integer pointer_sram, pointer_reg, i;
wire WORD_DEPTH;
wire [15:0] cpu_to_ram, ram_to_cpu;

parameter
nar = 3'b000, npc = 3'b001, ndr = 3'b010,
nac = 3'b011, nir = 3'b100, nram = 3'b101;

bus bus0(.clk(clk), .reset(reset), .sel(sel), .load(load), .din(ram_to_cpu), .dout(cpu_to_ram));
sram sram0(.clk(clk), .we(we), .addr(addr), .data_in(cpu_to_ram), .data_out(ram_to_cpu));

always #5 clk = ~clk;

initial begin
    clk = 0;
    reset = 1; #1
    $readmemb("C:/Xilinx/Verilogproject/project_bus/initial.txt", tb_bus.sram0.mem);//s램 메모리덤프
    reset = 0; #1
    reset = 1;

    //버스로 data 교환
    //mem[0000 0000 0000] -> IR
    we = 1;
    addr = 12'b0; #8//s램에서 내보냄 (미리 data를 준비시킨다)
    sel = nram;
    load = nir; #10 //버스를 통해 ir이 데이터 받음
    //도중에 #8을 넣는 이유는 setuptime을 고려하기 위해
    
    //ir -> mem[0000 0000 0010]
    sel = nir;
    load = nram; #10 //(데이터를 준비시킨다)
    addr = 12'b10;
    we = 0; #10
    
    //mem[0000 0000 0001] -> ac
    we = 1;
    addr = 12'b1; #10 //데이터 준비
    sel = nram;
    load = nac; #10
    
    //ac -> mem[0000 0000 0011]
    sel = nac;
    load = nram; #10 //(데이터를 준비시킨다)
    addr = 12'b11;
    we = 0; #10
        
    
    //바뀐 메모리를 메모장에 표현
    pointer_reg = $fopen("C:/Xilinx/Verilogproject/project_bus/register.txt");
    $fdisplay(pointer_reg, "%b", tb_bus.bus0.ar);
    $fdisplay(pointer_reg, "%b", tb_bus.bus0.ir);
    $fdisplay(pointer_reg, "%b", tb_bus.bus0.pc);
    $fdisplay(pointer_reg, "%b", tb_bus.bus0.dr);
    $fdisplay(pointer_reg, "%b", tb_bus.bus0.ac);
    $fclose(pointer_reg); #10
    
    //sram을 메모장에 표현
    pointer_sram = $fopen("C:/Xilinx/Verilogproject/project_bus/sram.txt");
    i = 0;
    while ( i < 10) begin
        $fdisplay(pointer_sram, "%b", tb_bus.sram0.mem[i]);
        i = i + 1;
     end
    $fclose(pointer_sram);
    $finish;
    
end
endmodule

테스트벤치의 경우 setup time에 의해 신경을 많이 써야 했다.