CPU Course Review - 08. RAM

2025. 2. 12. 14:27·AI SOC COURSE/SYSTEM VERILOG (CPU 설계)

1. Title

CPU RAM 설계


2. Category

"System Verilog", "BASYS3", "VIVADO"

 

3. Key Concepts

RAM in SystemVerilog

 

4. Setup

 

8 BIT DATA,  4 BIT ADDRESS를 갖는 간단한 동기식 RAM (Random Access Memory) 을 구현하고 TestBench를 진행한다.

RAM 기술 방식에 따른 RAM 모양의 차이를 이해한다.

 

5. Code Review

module RAM(
    input   logic clk,
    input   logic we,
    input   logic [3:0] addr,
    input   logic [7:0] W_data,
    output  logic [7:0] R_data
    );

    logic [8:0] mem[0:2**4-1];

    always_ff @( posedge clk ) begin
        if(we) begin
            mem [addr] <= W_data;
        end else begin
            R_data <= mem[addr];
        end 
    end

endmodule

// 동기식 읽기 + 쓰기, we=0일 때만 읽기 수행

 

 

 

module RAM(
    input   logic clk,
    input   logic we,
    input   logic [3:0] addr,
    input   logic [7:0] W_data,
    output  logic [7:0] R_data
    );

    logic [8:0] mem[0:2**4-1];

    always_ff @( posedge clk ) begin
        if(we) begin
            mem [addr] <= W_data;
        end 
    end

    assign R_data = we ? 'z : mem[addr];

endmodule

// 비동기 읽기, we=1이면 high-Z('z') 출력

 

 

 

module RAM(
    input   logic clk,
    input   logic we,
    input   logic [3:0] addr,
    input   logic [7:0] W_data,
    output  logic [7:0] R_data
    );

    logic [8:0] mem[0:2**4-1];

    always_ff @( posedge clk ) begin
        if(we) begin
            mem [addr] <= W_data;
        end 
    end

    assign R_data = mem[addr];

endmodule

// 비동기 읽기, we와 상관없이 R_data가 항상 mem[addr] 출력

 

 

module RAM(
    input   logic clk,
    input   logic we,
    input   logic [3:0] addr,
    input   logic [7:0] W_data,
    output  logic [7:0] R_data
    );

    logic [8:0] mem[0:2**4-1];

    always_ff @( posedge clk ) begin
        if(we) begin
            mem [addr] <= W_data;
        end 
    end

    always_ff @( posedge clk ) begin 
       R_data <= mem[addr];
    end

endmodule

// 동기식 읽기 + 쓰기, R_data가 한 클럭 늦게 반영됨

 

 

 

6. Testing and Debugging

* Testing Tools: VIVADO, Modelsim

`timescale 1ns / 1ps

interface RAM_interface ();
   logic         clk;
   logic         we; 
   logic [3:0]   addr; 
   logic [7:0]   W_data; 
   logic [7:0]   R_data; 
endinterface //RAM_interface




class transaction;
    rand logic         we; 
    rand logic [3:0]   addr; 
    rand logic [7:0]   W_data; 
    logic [7:0]   R_data; 

    task display(string name);
        $display("[%s] : we = %x | addr = %x | W_data = %x | R_data = %x ", name, we, addr, W_data, R_data);
    endtask 
endclass //transaction





class generator;

    transaction trans;
    mailbox #(transaction) gen2drv_mbx;
    event scb_gen_event;

    function new(mailbox #(transaction) gen2drv_mbx, event scb_gen_event);
        this.gen2drv_mbx = gen2drv_mbx;
        this.scb_gen_event = scb_gen_event;
    endfunction //new()

    task run(int run_time);
        repeat(run_time) begin
            trans = new();
            trans.randomize();
            gen2drv_mbx.put(trans);
            trans.display("GEN");
            @(scb_gen_event);
        end
    endtask 

endclass //generator





class driver;

    virtual RAM_interface RAM_interface;
    transaction trans;
    mailbox #(transaction) gen2drv_mbx;
    event drv_mon_event;

    function new(virtual RAM_interface RAM_interface, mailbox #(transaction)gen2drv_mbx, event drv_mon_event);
        this.RAM_interface = RAM_interface;
        this.gen2drv_mbx = gen2drv_mbx;
        this.drv_mon_event = drv_mon_event; 
    endfunction //new()


    task reset();
        RAM_interface.we        = 0;
        RAM_interface.addr      = 0;
        RAM_interface.W_data    = 0; 
        
        repeat (5) begin
            @(posedge RAM_interface.clk);
        end

        for(int i = 0; i < 16 ; i++) begin
            RAM_interface.we        = 1;
            RAM_interface.addr      = i;
            RAM_interface.W_data    = 8'hff;
            @(posedge RAM_interface.clk);
        end

        @(posedge RAM_interface.clk);
    endtask 


    task run();
       forever begin
            #1;     //      race condition 방지.
                    //      driver가 트랜잭션을 처리하고 #1만큼 대기하야만
                    //      이 대기 시간 동안 monitor가 drv_mon_event를 감지하고 트랜잭션을 처리할 수 있음.
            gen2drv_mbx.get(trans);
            RAM_interface.we = trans.we;
            RAM_interface.addr = trans.addr;
            RAM_interface.W_data = trans.W_data;
            trans.display("DRV");
            -> drv_mon_event;
       end 
    endtask 

endclass //driver
class monitor;

    virtual RAM_interface RAM_interface;
    transaction trans;
    mailbox #(transaction) mon2scb_mbx;
    event drv_mon_event;

    function new(virtual RAM_interface RAM_interface, mailbox #(transaction) mon2scb_mbx, event drv_mon_event);
       this.RAM_interface = RAM_interface;
       this.mon2scb_mbx = mon2scb_mbx;
       this.drv_mon_event = drv_mon_event; 
    endfunction //new()

    task run();
        forever begin
            @(drv_mon_event);
            trans = new();

            if(RAM_interface.we) begin
                trans.we = RAM_interface.we;
                trans.addr = RAM_interface.addr;
                trans.W_data = RAM_interface.W_data;
                @(posedge RAM_interface.clk);
                #1;
            end else begin
                #1;
                trans.we = RAM_interface.we;
                trans.addr = RAM_interface.addr;
                trans.R_data = RAM_interface.R_data;
            end

            mon2scb_mbx.put(trans);
            trans.display("MON");
        end        
    endtask 




endclass //monitor





class scoreboard;
    
    transaction trans;
    mailbox #(transaction) mon2scb_mbx;
    event scb_gen_event;

    int total_count, pass_count, fail_count;
    int read_count, write_count;

    byte mem[16];
    byte read_data;

    function new(mailbox #(transaction) mon2scb_mbx, event scb_gen_event);
        this.mon2scb_mbx = mon2scb_mbx;
        this.scb_gen_event = scb_gen_event;
        
        total_count = 0;
        pass_count = 0;
        fail_count = 0;
        read_count = 0;
        write_count = 0;

        for(int i = 0; i < 16; i++) begin
            mem[i] = 8'hff;
        end
    endfunction //new()


    task run();
        forever begin
            mon2scb_mbx.get(trans);
            trans.display("SCB");

            if(trans.we) begin
                mem[trans.addr] = trans.W_data;
                $display("Write!!");
                write_count++;
            end else begin
                read_data = mem[trans.addr];

                if(read_data == trans.R_data) begin
                    $display("PASS!!!  read data: %x == trans.R_data: %x", read_data, trans.R_data);
                    pass_count++;
                end else begin
                    $display("FAIL!!!  read data: %x == trans.R_data: %x", read_data, trans.R_data);
                    fail_count++;
                end
                read_count++;
            end

            total_count++;
            $display("");
            -> scb_gen_event;   
        end
    endtask 



endclass //scoreboard





class environment;

    virtual RAM_interface RAM_interface;
    transaction trans;
    generator generator;
    driver driver;
    monitor monitor;
    scoreboard scoreboard;
    event scb_gen_event, drv_mon_event;
    mailbox #(transaction) gen2drv_mbx, mon2scb_mbx;

    function new(virtual RAM_interface RAM_interface);
        gen2drv_mbx = new();
        mon2scb_mbx = new();

        generator = new(gen2drv_mbx, scb_gen_event);
        driver = new(RAM_interface, gen2drv_mbx, drv_mon_event);
        monitor = new(RAM_interface, mon2scb_mbx, drv_mon_event);
        scoreboard = new(mon2scb_mbx, scb_gen_event);

    endfunction //new()


    task report();
        $display("===============================================");
        $display("=============== FINAL REPORT  =================");
        $display("  TOTAL TEST : %d                              ", scoreboard.total_count);
        $display("  WRITE TEST : %d                              ", scoreboard.write_count);
        $display("  READ  TEST : %d                              ", scoreboard.read_count);
        $display("  PASS TEST  : %d                              ", scoreboard.pass_count);
        $display("  FAIL TEST  : %d                              ", scoreboard.fail_count);
        $display("===============================================");
        $display("===============================================");
        $display("===============================================");
        #10
        $finish;
    endtask 


    task pre_run();
        driver.reset();
    endtask 


    task run();
        fork
            generator.run(10000);
            driver.run();
            monitor.run();
            scoreboard.run();
        join_any
        report();
        #10;
        $finish;
    endtask 

endclass //environment

 

module tb_RAM(

    );

    RAM_interface RAM_interface();
    environment env;

    RAM DUT(
    .clk(RAM_interface.clk),
    .we(RAM_interface.we),
    .addr(RAM_interface.addr),
    .W_data(RAM_interface.W_data),
    .R_data(RAM_interface.R_data)
    );

    always
        #5 RAM_interface.clk = ~RAM_interface.clk;

    initial begin
        RAM_interface.clk = 0;
        env = new(RAM_interface);
        env.pre_run();
        env.run();
    end



endmodule

'AI SOC COURSE > SYSTEM VERILOG (CPU 설계)' 카테고리의 다른 글

CPU Course Review - 10. Analysis of Assembly Language (Single Cycle RISC-V)  (0) 2025.02.21
CPU Course Review - 09. RISC-V CPU 개요  (0) 2025.02.12
CPU Course Review - 07. Register  (0) 2025.02.11
CPU Course Review - 06. TestBench Revision  (0) 2025.02.11
CPU Course Review - 05. Accumulator (0 ~ 9)  (0) 2025.02.10
'AI SOC COURSE/SYSTEM VERILOG (CPU 설계)' 카테고리의 다른 글
  • CPU Course Review - 10. Analysis of Assembly Language (Single Cycle RISC-V)
  • CPU Course Review - 09. RISC-V CPU 개요
  • CPU Course Review - 07. Register
  • CPU Course Review - 06. TestBench Revision
Dinoj
Dinoj
  • Dinoj
    AlOG
    Dinoj
  • 전체
    오늘
    어제
    • 분류 전체보기 (199) N
      • PCB 이론 (13)
        • PI (2)
        • SI (11)
      • 회로 이론 (63)
        • 기타 학습 (20)
        • UVM (Universal Verification.. (12)
        • AI HARDWARE (12)
        • COMPUTER VISION (18)
        • Python (Pytorch) (1)
      • PROJECTS (29)
        • AI 가속기 (10)
        • 영상 처리 (3)
        • UVM (Universal Verification.. (2)
        • CPU 설계 (5)
        • CMOS VLSI (2)
        • Verilog (2)
        • Firmware (2)
        • C 언어 (2)
        • 기타 프로젝트 (1)
      • Linux (18) N
        • Embedded Linux (Rpi) (7)
        • Petalinux (5) N
        • Linux 기초 (6)
      • AMBA BUS (16)
        • AXI BUS (5)
        • APB BUS (2)
        • Vitis (8)
      • AI SOC COURSE (53)
        • 영상 처리 (5)
        • SYSTEM VERILOG (CPU 설계) (20)
        • VERILOG 기초 (5)
        • CMOS VLSI (7)
        • FIRMWARE (9)
        • C PROGRAMMING (1)
        • Python (Keras) (6)
      • 코딩 지식 (5)
        • SYSTEM VERILOG (3)
        • TCL (2)
      • TISTORY (1)
  • 블로그 메뉴

    • 홈
    • 글쓰기
    • 관리
    • Info
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Dinoj
CPU Course Review - 08. RAM
상단으로

티스토리툴바