활동시기 : 2023년도 여름, 전자회로연구회(소모임 ECR)
저장위치 : project_bus
컴퓨터구조를 한학기동안 스스로 학습하고 난 후, 소모임 인원들과 함께 프로젝트로 진행한 내용입니다.
한 학기동안 컴퓨터구조를 학습한 후, 버스시스템을 베릴로그로 구현하기로 하였다.
일반적으로 D램을 램으로 사용하지만, 베릴로그상에선 S램이 D램의 역할을 대신 할 수 있다. 그렇기에 S램을 D램 대신하여 사용했다. 해당 구조는 다음과 같다.

따라서 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에 의해 신경을 많이 써야 했다.