OpenCores
URL https://opencores.org/ocsvn/mcs-4/mcs-4/trunk

Subversion Repositories mcs-4

[/] [mcs-4/] [trunk/] [rtl/] [verilog/] [i4002/] [i4002_tb.v] - Rev 6

Compare with Previous | Blame | View Log

`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4001 RAM testbench
//
// This module is a testbench for the i4002 and i4002_ram modules.
//
// This testbench instantiates an i4002 RAM module, and enough of
// the i4004 system bus logic to be able to test RAM access.
//
// This file is part of the MCS-4 project hosted at OpenCores:
//      http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
module i4002_tb;
 
    localparam SYSCLK_TCY    = 20;   // sysclk period in nanoseconds
 
    // Inputs
    reg         rst;
    reg         reset;
    reg         cm;
    reg  [4:0]  ram0_addr2;
    reg  [4:0]  ram1_addr2;
    reg  [4:0]  ram2_addr2;
    reg  [4:0]  ram3_addr2;
 
    // Outputs
    wire [3:0]  oport;
    wire [3:0]  ram0_data2_out;
    wire [3:0]  ram1_data2_out;
    wire [3:0]  ram2_data2_out;
    wire [3:0]  ram3_data2_out;
 
    // Bidirs
    wire [3:0]  data;
 
    // Simulate the system clock
    reg     sysclk;
    always begin
        sysclk = 1'b0;
        #(SYSCLK_TCY / 2);
        sysclk = 1'b1;
        #(SYSCLK_TCY / 2);
    end
 
    // Instantiate a 2-phase clock generator
    wire    clk1, clk2;
    clockgen #(
        .SYSCLK_TCY (SYSCLK_TCY)
    ) clockgen (
        .sysclk     (sysclk),
        .clk1       (clk1),
        .clk2       (clk2)
    );
 
    // Generate the 8 execution phase indicators
    wire    a12, a22, a32, m12, m22, x12, x22, x32, sync;
    timing_generator timing_generator (
        .clk1   (clk1),
        .clk2   (clk2),
        .a12    (a12),
        .a22    (a22),
        .a32    (a32),
        .m12    (m12),
        .m22    (m22),
        .x12    (x12),
        .x22    (x22),
        .x32    (x32),
        .sync   (sync)
    );
 
 
    // Instantiate the Unit Under Test (UUT)
    i4002 uut (
        .sysclk         (sysclk),
        .clk1           (clk1),
        .clk2           (clk2),
        .sync           (sync),
        .reset          (reset),
        .cm             (cm),
        .data           (data),
        .oport          (oport),
        .ram0_addr2     (ram0_addr2),
        .ram0_data2_out (ram0_data2_out),
        .ram1_addr2     (ram1_addr2),
        .ram1_data2_out (ram1_data2_out),
        .ram2_addr2     (ram2_addr2),
        .ram2_data2_out (ram2_data2_out),
        .ram3_addr2     (ram3_addr2),
        .ram3_data2_out (ram3_data2_out)
    );
 
    reg         data_dir    = 1'b0;
    reg  [3:0]  data_out    = 4'bxxxx;
    reg  [3:0]  data_in     = 4'bxxxx;
    assign data = data_dir ? data_out : 4'bzzzz;
 
    initial begin
        // Initialize Inputs
        rst         = 1;
        reset       = 1;
        cm          = 0;
        ram0_addr2  = 5'h00;
        ram1_addr2  = 5'h00;
        ram2_addr2  = 5'h00;
        ram3_addr2  = 5'h00;
 
        // Wait 100 ns for global reset to finish
        #100;
        rst     = 0;
        @(negedge sync);
        reset   = 0;
    end
 
    // Simulate enough of a i4004 CPU to access RAM
    always @(*) begin
        data_dir = 1'b1;
        data_out = 4'bxxxx;
        cm       = 1'b0;
        case (1'b1)
                a12 :   task_a12;
                a22 :   task_a22;
                a32 :   task_a32;
                m12 :   task_m12;
                m22 :   task_m22;
                x12 :   task_x12;
                x22 :   task_x22;
                x32 :   task_x32;
            default : /* default */;
        endcase
    end
 
    //
    // i4004 simulation registers
    //
    //
    reg  [11:0] ip       = 12'h000;
    reg  [1:0]  chip_num = 2'b00;
    reg  [1:0]  reg_num  = 2'b01;
    reg  [3:0]  char_num = 4'ha;
    reg  [3:0]  acc;
 
    reg  [7:0]  rom[0:'hfff];
    wire [7:0]  rom_data = rom[ip];
    initial begin
`ifdef USE_READMEMH
        $readmemh("i4002_tb.mem", rom, 0);
`else
        rom[ 0] = 8'hFD;    // DCL
        rom[ 1] = 8'h21;    // SRC R0
        rom[ 2] = 8'hE9;    // RDM
        rom[ 3] = 8'hE0;    // WRM
        rom[ 4] = 8'h21;    // SRC R0
        rom[ 5] = 8'hE9;    // RDM
        rom[ 6] = 8'hE0;    // WRM
        rom[ 7] = 8'hFF;    // HLT (sim only)
`endif
    end
 
    // Capture OPR during the M1 phase
    reg  [3:0]  opr;
    always @(*) begin
        if (clk2 & m12)
            opr = data;
    end
 
    // Capture OPA during the M2 phase
    reg  [3:0]  opa;
    always @(*) begin
        if (clk2 & m22)
            opa = data;
    end
 
    // Instruction decode
    wire        src = (opr == 4'b0010) & opa[0];
    wire        io  = (opr == 4'b1110);
    wire        ior = io &  opa[3];
    wire        iow = io & ~opa[3];
    wire        ag  = (opr == 4'b1111);
    wire        iac = ag & (opa == 4'b0010);
 
    always @(*) begin
        if (clk2 & ior) begin
            acc = data;
        end
    end
 
    task task_a12();
    begin
        data_out = ip[3:0];
        data_dir = 1'b1;
    end
    endtask : task_a12
 
    task task_a22();
    begin
        data_out = ip[7:4];
    end
    endtask : task_a22
 
    task task_a32();
    begin
        data_out = ip[11:8];
        cm = 1'b1;
    end
    endtask : task_a32
 
    task task_m12();
    begin
        data_out = rom_data[7:4];
    end
    endtask : task_m12
 
    task task_m22();
    begin
        data_out = rom_data[3:0];
        cm = io;
        if (~reset) begin
            ip = ip + 'd1;
        end
    end
    endtask : task_m22
 
    task task_x12();
    begin
        data_out = opa;
        if ({opr, opa} == 8'hFF)
            $stop();
    end
    endtask : task_x12
 
    task task_x22();
    begin
        if (src) begin
            data_out = {chip_num, reg_num};
            cm       = 1'b1;
        end
        if (iow) begin
            data_out = acc + 'd1;
        end
        if (ior) begin
            data_dir = 1'b0;
        end
    end
    endtask : task_x22
 
    task task_x32();
    begin
        if (src) begin
            data_out = char_num;
        end
    end
    endtask : task_x32
 
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.