为什么读不到内存内容? - verilog数字系统设计
Why the memory content is not read? - verilog digital system design
我创建了一个由两个时钟 SRAM 组成的微系统,一个用于存储指令代码,另一个用于存储一些输出值。指令SRAM有一个名为“用户”的接口模块,它提供了一种简化写入过程的机制,因此,在内存中写入数据时,无需指定必须存储这些指令的相应内存地址。类似地,当从第二个SRAM读取数据时,由于有了“显示”模块,因此无需指定从中提取数据的相应内存地址。更具体地说,当在指令存储器中写入数据时,计数器在每次写入后递增地址指针,而第二存储器有另一个计数器在每次读取后递增地址指针值。当一个人试图从指令存储器中读取信息时,他们必须指定应该从中读取数据的存储器地址,并且正如预期的那样,当一个人试图将信息写入输出存储器时,他们必须指定其中的存储器地址应该写入数据。此外,微系统有一个自动机,它从指令存储器中获取输入数据并对其进行处理。处理完信息后,自动机将一些输出值存储在输出存储器中。我在模拟时遇到一个问题,因为显然无法看到从 SRAM 存储器读取的值,即 rd_data_instrucions,因此,既无法找到自动机的输入值“in”,也无法找到输出值,只要它们取决于从第一个 SRAM 读取的数据。我在下面发布了代码和图表。
//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
当您从地址 0x8001 读取时,这超出了您的内存大小限制。你可以增加你的记忆力。变化:
reg [2:0] memory [2 ** 15 - 1 : 0];
至:
reg [2:0] memory [2 ** 16 - 1 : 0];
当您从地址 0x8001 读取时,这会删除未知数 (X)。
或者,如果您不想扩大内存,请确保限制您的地址。
我创建了一个由两个时钟 SRAM 组成的微系统,一个用于存储指令代码,另一个用于存储一些输出值。指令SRAM有一个名为“用户”的接口模块,它提供了一种简化写入过程的机制,因此,在内存中写入数据时,无需指定必须存储这些指令的相应内存地址。类似地,当从第二个SRAM读取数据时,由于有了“显示”模块,因此无需指定从中提取数据的相应内存地址。更具体地说,当在指令存储器中写入数据时,计数器在每次写入后递增地址指针,而第二存储器有另一个计数器在每次读取后递增地址指针值。当一个人试图从指令存储器中读取信息时,他们必须指定应该从中读取数据的存储器地址,并且正如预期的那样,当一个人试图将信息写入输出存储器时,他们必须指定其中的存储器地址应该写入数据。此外,微系统有一个自动机,它从指令存储器中获取输入数据并对其进行处理。处理完信息后,自动机将一些输出值存储在输出存储器中。我在模拟时遇到一个问题,因为显然无法看到从 SRAM 存储器读取的值,即 rd_data_instrucions,因此,既无法找到自动机的输入值“in”,也无法找到输出值,只要它们取决于从第一个 SRAM 读取的数据。我在下面发布了代码和图表。
//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
当您从地址 0x8001 读取时,这超出了您的内存大小限制。你可以增加你的记忆力。变化:
reg [2:0] memory [2 ** 15 - 1 : 0];
至:
reg [2:0] memory [2 ** 16 - 1 : 0];
当您从地址 0x8001 读取时,这会删除未知数 (X)。
或者,如果您不想扩大内存,请确保限制您的地址。