I created a microsystem which is composed of two clocked SRAMs, one designed for storing instruction-codes, and another to store some output values. The instruction SRAM has an interface module, named "user" which provides a mechanism to ease the writing process, consequently, when writing data in the memory, there is no need to specify the corresponding memory address at which those instructions have to be stored. Similarly, when reading data from the second SRAM, there is no need to specify the corresponding memory address from which data is extracted, thanks to "display" module. To be more specific, when writing data in the instructions memory, a counter increments the address pointer after each writing, while the second memory has another counter which increments the address pointer value after each reading. When one tries to read information from the instruction memory, they have to specify the memory address from which data should be read, and, as expected, when one tries to write information in the output memory, they have to specify the memory address in which data should be written. Furthermore, the microsystem has an automaton which takes input data from the instruction memory and processes it. After processing information, the automaton stores some output values in the output memory. I come across an issue when simulating, because, apparently, the read values from the SRAM memory cannot be seen, namely, rd_data_instrucions, thus, neither the input values "in" for the automaton cannot be found, nor the output values, as long as they depend on the data read from the first SRAM. I posted the code below and a diagram.
//wishbone module
module wishbone(
input clk,rst,
output reg [2:0]in,
output reg wr_en_instructions,wr_en_display,
input [2:0] wr_data_instructions,//created for usr, in order to make possible to write data
output reg [3:0] wr_data_display,
output [2:0] rd_data_instructions,
output [3:0] rd_data_display,//created for user, in order to make possible the display
output [12:0]o
);
reg [15:0] pointer_instructions,pointer_display;
initial wr_en_instructions = 1'b1;//?
control_unit i0(.clk(clk),.rst(rst),.in(in),.o(o));
user i1(.clk(clk),.wr_en(wr_en_instructions),.address_in(pointer_instructions),.wr_data(wr_data_instructions),.rd_data(rd_data_instructions));
display i2(.clk(clk),.wr_en(wr_en_display),.address_in(pointer_display),.wr_data(wr_data_display),.rd_data(rd_data_display));
integer i = 0;
always @ * begin
wr_en_display = ~wr_en_instructions;
end
always @(posedge clk) begin
if(rst) begin
wr_en_instructions <= 1'b1;
pointer_instructions <= 16'd0;
pointer_display <= 16'd0;
end
else begin
if(wr_en_instructions) begin
if(wr_data_instructions[2] == 1'b1) begin
pointer_instructions <= 16'd0;
pointer_display <= 16'd0;
wr_en_instructions <= 1'b0;
end
end
else begin
in <= rd_data_instructions;
pointer_instructions <= pointer_instructions + 1;
if(rd_data_instructions == 3'b010) begin
wr_data_display <= o;
pointer_display <= pointer_display + 1;
end
else if(rd_data_instructions == 3'b100) begin
wr_en_instructions <= 1'b1;
end
end
end
end
endmodule
//testbench for top module
module wishbone_tb(
output reg clk,rst,
output [2:0]in,
output wr_en_instructions,wr_en_display,
output reg [2:0] wr_data_instructions,//created for usr, in order to make possible to write data
output [3:0] wr_data_display,
output [2:0] rd_data_instructions,
output [3:0] rd_data_display,//created for user, in order to make possible the display
output [12:0]o
);
wishbone cut(
.clk(clk),.rst(rst),
.in(in),
.wr_en_instructions(wr_en_instructions),.wr_en_display(wr_en_display),
.wr_data_instructions(wr_data_instructions),
.wr_data_display(wr_data_display),
.rd_data_instructions(rd_data_instructions),
.rd_data_display(rd_data_display),
.o(o)
);
initial $dumpvars(0,wishbone_tb);
initial begin
clk = 1'b1;
repeat (600000)
#100 clk = ~clk;
end
initial begin
rst = 1'b1;
#400 rst = 1'b0;
end
initial begin
wr_data_instructions = 3'd1;
#3000400 wr_data_instructions = 3'd2;
#1000000 wr_data_instructions = 3'd1;
#3000000 wr_data_instructions = 3'd0;
#2000000 wr_data_instructions = 3'd3;
#1000000 wr_data_instructions = 3'd1;
#3000000 wr_data_instructions = 3'd4;//halt
end
endmodule
//code for the first memory:
//stores instructions
module sram_1port_instructions(
input clk,//clocked memory
input wr_en,//when high, data is writeen, otherwise is read
input [15:0] address_in,//suppose timer cannot count more than 13ms
input [2:0] wr_data,//3 bit instructions
output reg [2:0] rd_data
);
reg [2:0] memory [2 ** 15 - 1 : 0];
always @(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//user interface designed for the first memory
module user(
input clk,
input wr_en,
input [15:0] address_in,
input [2:0] wr_data,
output [2:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_instructions i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always @(posedge clk) begin
if(wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else begin
address <= address_in;
pointer <= 16'd0;
end
end
endmodule
//user tb
module user_tb(
output reg clk, wr_en,
output reg [15:0] address_in,
output reg [2:0] wr_data,
output [2:0] rd_data
);
user cut(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,user_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 wr_data = i;
end
end
initial begin
address_in = 16'd0;
#100000 address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 address_in = i;
end
end
endmodule
//code for the second memory:
//stores output data
module sram_1port_data(
input clk,//clocked memory
input wr_en,//when high, data is written, otherwise is read
input [15:0] address_in,//suppose timer cannout count more than 13ms
input [3:0] wr_data,//memory does not sotre values greater than 13(ms)
output reg [3:0] rd_data
);
reg [3:0] memory [2 ** 15 - 1 : 0];
always @(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//display interfacedesigned for the second memory
module display(
input clk,
input wr_en,
input [15:0] address_in,
input [3:0] wr_data,
output [3:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_data i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always @(posedge clk) begin
if(!wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else begin
address <= address_in;
pointer <= 16'd0;
end
end
endmodule
//tb for display
module display_tb(
output reg clk,
output reg wr_en,
output reg [15:0] address_in,
output reg [3:0] wr_data,
output [3:0] rd_data
);
display i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,display_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200;
wr_data = i;
address_in = i;
end
end
endmodule
//code for the control unit:
//control unit
module control_unit(
input clk,rst,
input [2:0]in,
output [12:0]o
);
wire f,g;
automaton i0(.clk(clk),.rst(rst),.in(in),.clr(f),.en(g));
circuit i1(.clk(clk),.clr(f),.en(g),.o(o));
endmodule
//code for automaton:
//atuomaton
module automaton(
input clk,rst,
input [2:0]in,
output reg clr,en
);
localparam S0_ST = 2'b00;
localparam S1_ST = 2'b01;
localparam S2_ST = 2'b10;
reg [1:0] st_reg,st_nxt;
always @ * begin
case(st_reg)
S0_ST: if(!in[1]) st_nxt = S0_ST;
else if(in[0]) st_nxt = S2_ST;
else st_nxt = S1_ST;
S1_ST: if(!in[0]) st_nxt = S1_ST;
else if(in[1]) st_nxt = S2_ST;
else st_nxt = S0_ST;
S2_ST: if(in == 2'd1) st_nxt = S0_ST;
else st_nxt = S2_ST;
endcase
end
always @ * begin
case(st_reg)
S0_ST: {clr,en} = 2'd1;
S1_ST: {clr,en} = 2'd0;
S2_ST: clr = 1'd1;
endcase
end
always @(posedge clk) begin
if(rst) st_reg <= S2_ST;
else st_reg <= st_nxt;
end
endmodule
//code for circuit:
//circuit
module circuit(
input clk,clr,en,
output [12:0] o
);
wire f;
generator i0(.clk(clk),.clr(clr),.en(en),.o(f));
counter i1(.clk(clk),.clr(clr),.en(f),.o(o));
endmodule
//code for counter:
//counter
module counter(
input clk,clr,en,
output reg [12:0] o
);
reg [12:0] st_nxt;
always @ (posedge clk) begin
if(clr) o <= 13'd0;
else o <= st_nxt;
end
always @ *
if(en) st_nxt = o + 1;
else st_nxt = o;
endmodule
//code for generator:
//pulse generator
module generator(
input clk,clr,en,
output reg o
);
reg [12:0] st_reg,st_nxt;
always @(posedge clk) begin
if(clr) st_reg <= 13'd0;
else st_reg <= st_nxt;
end
always @ * begin
if(en) begin
if(st_reg == 13'd4999) begin
st_nxt = 13'd0;
o = 1'b1;
end
else begin
st_nxt = st_reg + 1;
o = 1'b0;
end
end
else begin
if(st_reg == 13'd4999) begin
st_nxt = 13'd0;
o = 1'b0;
end
else begin
st_nxt = st_reg;
o = 1'b0;
end
end
end
endmodule
When you read from address 0x8001, that is beyond the limit of your memory size. You could increase your memory. Change:
reg [2:0] memory [2 ** 15 - 1 : 0];
to:
reg [2:0] memory [2 ** 16 - 1 : 0];
This gets rid of the unknown (X) when you read from address 0x8001.
Or, if you don't want to enlarge the memory, make sure you limit your addresses.