URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 311 to Rev 312
- ↔ Reverse comparison
Rev 311 → Rev 312
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/ramtest/ramtest.v
0,0 → 1,262
// |
// ramtest.v -- RAM test generator |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
`define SIMULATE |
`define VERBOSE |
|
`define INST_PERIOD 31 |
`define INST_PHASE 19 |
`define DATA_PERIOD 17 |
`define DATA_PHASE 7 |
|
|
// |
// memory test generator |
// |
// Algorithm: Three independent address/data generators |
// produce exactly the same sequence of address/data pairs, |
// although at different times: data write, data read, and |
// instruction read. Three out of four data cycles are writes, |
// one is a read. Instruction reads are also less frequent |
// than data writes: 1/31 < 1/17 * 3/4. The writing process |
// is therefore always ahead of the reading processes, with |
// an increasing gap in between. |
// |
|
module ramtest(clk, rst, |
inst_stb, inst_addr, |
inst_din, inst_ack, |
data_stb, data_we, data_addr, |
data_dout, data_din, data_ack, |
test_ended, test_error); |
input clk; |
input rst; |
output reg inst_stb; |
output [25:0] inst_addr; |
input [63:0] inst_din; |
input inst_ack; |
output reg data_stb; |
output reg data_we; |
output [25:0] data_addr; |
output [63:0] data_dout; |
input [63:0] data_din; |
input data_ack; |
output test_ended; |
output test_error; |
|
reg [4:0] inst_timer; |
reg [4:0] data_timer; |
reg [9:0] data_counter; |
|
wire ir_next; |
wire [21:0] ir_a; |
wire [63:0] ir_d; |
|
wire dw_next; |
wire [21:0] dw_a; |
wire [63:0] dw_d; |
|
wire dr_next; |
wire [21:0] dr_a; |
wire [63:0] dr_d; |
|
`ifdef SIMULATE |
reg error_1; |
reg error_3; |
`endif |
reg error_2; |
reg error_4; |
|
always @(posedge clk) begin |
if (rst) begin |
inst_timer <= 0; |
inst_stb <= 0; |
`ifdef SIMULATE |
error_1 <= 0; |
`endif |
error_2 <= 0; |
end else begin |
if (~test_ended) begin |
if (~inst_stb) begin |
if (inst_timer == `INST_PERIOD - 1) begin |
inst_timer <= 0; |
end else begin |
inst_timer <= inst_timer + 1; |
end |
if (inst_timer == `INST_PHASE) begin |
inst_stb <= 1; |
end |
end else begin |
if (inst_ack) begin |
inst_stb <= 0; |
`ifdef SIMULATE |
`ifdef VERBOSE |
$display("%t: inst read @ 0x%h", $realtime, ir_a); |
$display(" value = 0x%h", inst_din); |
`endif |
if (^inst_din[63:0] === 1'bx) begin |
$display("Warning: Input data has don't cares at %t", |
$realtime); |
error_1 <= 1; |
end |
`endif |
if (inst_din[63:0] != ir_d[63:0]) begin |
error_2 <= 1; |
end |
end |
end |
end |
end |
end |
|
adgen adgen_ir( |
.clk(clk), |
.rst(rst), |
.next(ir_next), |
.addr(ir_a), |
.data(ir_d) |
); |
|
assign ir_next = inst_ack; |
assign inst_addr[25:0] = { 4'h0, ir_a[21:0] }; |
|
always @(posedge clk) begin |
if (rst) begin |
data_timer <= 0; |
data_stb <= 0; |
data_we <= 0; |
data_counter <= 0; |
`ifdef SIMULATE |
error_3 <= 0; |
`endif |
error_4 <= 0; |
end else begin |
if (~test_ended) begin |
if (~data_stb) begin |
if (data_timer == `DATA_PERIOD - 1) begin |
data_timer <= 0; |
end else begin |
data_timer <= data_timer + 1; |
end |
if (data_timer == `DATA_PHASE) begin |
data_stb <= 1; |
data_we <= ~&data_counter[1:0]; |
end |
end else begin |
if (data_ack) begin |
data_stb <= 0; |
data_we <= 0; |
data_counter <= data_counter + 1; |
`ifdef SIMULATE |
`ifdef VERBOSE |
if (data_we == 1) begin |
$display("%t: data write @ 0x%h", $realtime, dw_a); |
$display(" value = 0x%h", dw_d); |
end else begin |
$display("%t: data read @ 0x%h", $realtime, dr_a); |
$display(" value = 0x%h", data_din); |
end |
`endif |
if (data_we == 0 && |
^data_din[63:0] === 1'bx) begin |
$display("Warning: Input data has don't cares at %t", |
$realtime); |
error_3 <= 1; |
end |
`endif |
if (data_we == 0 && |
data_din[63:0] != dr_d[63:0]) begin |
error_4 <= 1; |
end |
end |
end |
end |
end |
end |
|
adgen adgen_dw( |
.clk(clk), |
.rst(rst), |
.next(dw_next), |
.addr(dw_a), |
.data(dw_d) |
); |
|
adgen adgen_dr( |
.clk(clk), |
.rst(rst), |
.next(dr_next), |
.addr(dr_a), |
.data(dr_d) |
); |
|
assign dw_next = data_ack & data_we; |
assign dr_next = data_ack & ~data_we; |
assign data_addr[25:0] = { 4'h0, data_we ? dw_a[21:0] : dr_a[21:0] }; |
assign data_dout[63:0] = dw_d[63:0]; |
|
assign test_ended = &data_counter[9:0]; |
|
`ifdef SIMULATE |
assign test_error = error_1 | error_2 | error_3 | error_4; |
`else |
assign test_error = error_2 | error_4; |
`endif |
|
endmodule |
|
|
// |
// address & data generator |
// |
// compute pseudo-random 32-bit address |
// and 64-bit data on request |
// |
|
module adgen(clk, rst, |
next, addr, data); |
input clk; |
input rst; |
input next; |
output [21:0] addr; |
output [63:0] data; |
|
reg [31:0] a; |
reg [63:0] d; |
|
always @(posedge clk) begin |
if (rst) begin |
a[31: 0] <= 32'hC70337DB; |
d[63:32] <= 32'h7F4D514F; |
d[31: 0] <= 32'h75377599; |
end else begin |
if (next) begin |
if (a[0] == 0) begin |
a[31:0] <= a[31:0] >> 1; |
end else begin |
a[31:0] <= (a[31:0] >> 1) ^ 32'hD0000001; |
end |
if (d[32] == 0) begin |
d[63:32] <= d[63:32] >> 1; |
end else begin |
d[63:32] <= (d[63:32] >> 1) ^ 32'hD0000001; |
end |
if (d[0] == 0) begin |
d[31:0] <= d[31:0] >> 1; |
end else begin |
d[31:0] <= (d[31:0] >> 1) ^ 32'hD0000001; |
end |
end |
end |
end |
|
assign addr[21:0] = a[21:0]; |
assign data[63:0] = d[63:0]; |
|
endmodule |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/memtest.v
0,0 → 1,92
// |
// memtest.v -- test bench for memory controller |
// |
|
|
`include "ramtest/ramtest.v" |
`include "ramctrl/ramctrl.v" |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module memtest; |
|
reg clk; // system clock |
reg rst_in; // reset, input |
reg rst; // system reset |
|
wire inst_stb; |
wire [25:0] inst_addr; |
wire [63:0] inst_to_cache; |
wire inst_ack; |
wire inst_timeout; |
|
wire data_stb; |
wire data_we; |
wire [25:0] data_addr; |
wire [63:0] data_to_mctrl; |
wire [63:0] data_to_cache; |
wire data_ack; |
wire data_timeout; |
|
wire test_ended; |
wire test_error; |
|
// simulation control |
initial begin |
#0 $timeformat(-9, 1, " ns", 12); |
$dumpfile("dump.vcd"); |
$dumpvars(0, memtest); |
clk = 1; |
rst_in = 1; |
#23 rst_in = 0; |
#252400 $finish; |
end |
|
// clock generator |
always begin |
#5 clk = ~clk; // 10 nsec cycle time |
end |
|
// reset synchronizer |
always @(posedge clk) begin |
rst <= rst_in; |
end |
|
ramctrl ramctrl_1( |
.clk(clk), |
.rst(rst), |
.inst_stb(inst_stb), |
.inst_addr(inst_addr[25:0]), |
.inst_dout(inst_to_cache[63:0]), |
.inst_ack(inst_ack), |
.inst_timeout(inst_timeout), |
.data_stb(data_stb), |
.data_we(data_we), |
.data_addr(data_addr[25:0]), |
.data_din(data_to_mctrl[63:0]), |
.data_dout(data_to_cache[63:0]), |
.data_ack(data_ack), |
.data_timeout(data_timeout) |
); |
|
ramtest ramtest_1( |
.clk(clk), |
.rst(rst), |
.inst_stb(inst_stb), |
.inst_addr(inst_addr[25:0]), |
.inst_din(inst_to_cache[63:0]), |
.inst_ack(inst_ack | inst_timeout), |
.data_stb(data_stb), |
.data_we(data_we), |
.data_addr(data_addr[25:0]), |
.data_dout(data_to_mctrl[63:0]), |
.data_din(data_to_cache[63:0]), |
.data_ack(data_ack | data_timeout), |
.test_ended(test_ended), |
.test_error(test_error) |
); |
|
endmodule |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/ramctrl/ram.v
0,0 → 1,72
// |
// ram.v -- simulate external RAM |
// 8M x 32 bit = 32 MB |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
// |
// use this set of parameters for minimal access times |
// |
`define RD_CYCLES 4'd2 // # cycles for read, min = 2 |
`define WR_CYCLES 4'd2 // # cycles for write, min = 2 |
|
// |
// use this set of parameters for realistic access times |
// |
//`define RD_CYCLES 4'd14 // # cycles for read, min = 2 |
//`define WR_CYCLES 4'd6 // # cycles for write, min = 2 |
|
|
module ram(clk, rst, |
stb, we, addr, |
data_in, data_out, ack); |
input clk; |
input rst; |
input stb; |
input we; |
input [24:2] addr; |
input [31:0] data_in; |
output reg [31:0] data_out; |
output ack; |
|
reg [31:0] mem[0:8388607]; |
reg [3:0] counter; |
|
always @(posedge clk) begin |
if (stb) begin |
if (we) begin |
// write cycle |
mem[addr] <= data_in; |
end else begin |
// read cycle |
data_out <= mem[addr]; |
end |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
counter[3:0] <= 4'h0; |
end else begin |
if (counter[3:0] == 4'h0) begin |
if (stb & ~we) begin |
// a read may need some clock cycles |
counter[3:0] <= `RD_CYCLES - 1; |
end |
if (stb & we) begin |
// a write may need some clock cycles |
counter[3:0] <= `WR_CYCLES - 1; |
end |
end else begin |
counter[3:0] <= counter[3:0] - 1; |
end |
end |
end |
|
assign ack = (counter[3:0] == 4'h1) ? 1 : 0; |
|
endmodule |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/ramctrl/ramctrl.v
0,0 → 1,388
// |
// ramctrl.v -- RAM controller |
// |
|
|
`include "ramctrl/ram.v" |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module ramctrl(clk, rst, |
inst_stb, inst_addr, |
inst_dout, inst_ack, |
inst_timeout, |
data_stb, data_we, |
data_addr, data_din, |
data_dout, data_ack, |
data_timeout); |
input clk; |
input rst; |
input inst_stb; |
input [25:0] inst_addr; |
output [63:0] inst_dout; |
output reg inst_ack; |
output reg inst_timeout; |
input data_stb; |
input data_we; |
input [25:0] data_addr; |
input [63:0] data_din; |
output [63:0] data_dout; |
output reg data_ack; |
output reg data_timeout; |
|
reg ram_stb; |
reg ram_we; |
wire [22:0] ram_addr; |
wire [31:0] ram_dout; |
wire [31:0] ram_din; |
wire ram_ack; |
|
wire inst_addr_out_of_range; |
wire data_addr_out_of_range; |
|
reg ram_as; |
reg ram_a0; |
|
reg ram_ds; |
|
reg [63:0] data; |
reg data_wh; |
reg data_wl; |
|
reg [3:0] state; |
reg [3:0] next_state; |
|
// |
// create ram instance |
// |
|
ram ram_1( |
.clk(clk), |
.rst(rst), |
.stb(ram_stb), |
.we(ram_we), |
.addr(ram_addr[22:0]), |
.data_in(ram_dout[31:0]), |
.data_out(ram_din[31:0]), |
.ack(ram_ack) |
); |
|
// |
// address range check |
// |
|
assign inst_addr_out_of_range = | inst_addr[25:22]; |
assign data_addr_out_of_range = | data_addr[25:22]; |
|
// |
// address output to ram |
// |
|
assign ram_addr[22:0] = |
~ram_as ? { inst_addr[21:0], ram_a0 } : |
{ data_addr[21:0], ram_a0 }; |
|
// |
// data output to ram |
// |
|
assign ram_dout[31:0] = |
~ram_ds ? data_din[63:32] : data_din[31:0]; |
|
// |
// data output to cache |
// |
|
always @(posedge clk) begin |
if (data_wh) begin |
data[63:32] <= ram_din[31:0]; |
end |
if (data_wl) begin |
data[31: 0] <= ram_din[31:0]; |
end |
end |
|
assign inst_dout[63:0] = data[63:0]; |
assign data_dout[63:0] = data[63:0]; |
|
// |
// ramctrl state machine |
// |
|
always @(posedge clk) begin |
if (rst) begin |
state <= 0; |
end else begin |
state <= next_state; |
end |
end |
|
always @(*) begin |
case (state) |
4'd0: |
// idle, request arbitration |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
if (data_stb) begin |
if (data_addr_out_of_range) begin |
// illegal data address |
next_state = 4'd11; |
end else begin |
// data address is ok |
if (data_we) begin |
// data write request |
next_state = 4'd7; |
end else begin |
// data read request |
next_state = 4'd4; |
end |
end |
end else begin |
if (inst_stb) begin |
if (inst_addr_out_of_range) begin |
// illegal inst address |
next_state = 4'd10; |
end else begin |
// inst address is ok |
// inst read request |
next_state = 4'd1; |
end |
end else begin |
// no request |
next_state = 4'd0; |
end |
end |
end |
4'd1: |
// inst read, phase 1 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b0; |
ram_as = 1'b0; |
ram_a0 = 1'b0; |
ram_ds = 1'bx; |
data_wh = ram_ack; |
data_wl = 1'b0; |
if (ram_ack) begin |
next_state = 4'd2; |
end else begin |
next_state = 4'd1; |
end |
end |
4'd2: |
// inst read, phase 2 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b0; |
ram_as = 1'b0; |
ram_a0 = 1'b1; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = ram_ack; |
if (ram_ack) begin |
next_state = 4'd3; |
end else begin |
next_state = 4'd2; |
end |
end |
4'd3: |
// inst read, phase 3 |
begin |
inst_ack = 1'b1; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
4'd4: |
// data read, phase 1 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b0; |
ram_as = 1'b1; |
ram_a0 = 1'b0; |
ram_ds = 1'bx; |
data_wh = ram_ack; |
data_wl = 1'b0; |
if (ram_ack) begin |
next_state = 4'd5; |
end else begin |
next_state = 4'd4; |
end |
end |
4'd5: |
// data read, phase 2 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b0; |
ram_as = 1'b1; |
ram_a0 = 1'b1; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = ram_ack; |
if (ram_ack) begin |
next_state = 4'd6; |
end else begin |
next_state = 4'd5; |
end |
end |
4'd6: |
// data read, phase 3 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b1; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
4'd7: |
// data write, phase 1 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b1; |
ram_as = 1'b1; |
ram_a0 = 1'b0; |
ram_ds = 1'b0; |
data_wh = 1'b0; |
data_wl = 1'b0; |
if (ram_ack) begin |
next_state = 4'd8; |
end else begin |
next_state = 4'd7; |
end |
end |
4'd8: |
// data write, phase 2 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b1; |
ram_we = 1'b1; |
ram_as = 1'b1; |
ram_a0 = 1'b1; |
ram_ds = 1'b1; |
data_wh = 1'b0; |
data_wl = 1'b0; |
if (ram_ack) begin |
next_state = 4'd9; |
end else begin |
next_state = 4'd8; |
end |
end |
4'd9: |
// data write, phase 3 |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b1; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
4'd10: |
// illegal inst address |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b1; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
4'd11: |
// illegal data address |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b1; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
default: |
// not used |
begin |
inst_ack = 1'b0; |
inst_timeout = 1'b0; |
data_ack = 1'b0; |
data_timeout = 1'b0; |
ram_stb = 1'b0; |
ram_we = 1'b0; |
ram_as = 1'bx; |
ram_a0 = 1'bx; |
ram_ds = 1'bx; |
data_wh = 1'b0; |
data_wl = 1'b0; |
next_state = 4'd0; |
end |
endcase |
end |
|
endmodule |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/memtest.cfg
0,0 → 1,48
[timestart] 0 |
[size] 1280 725 |
[pos] -1 -1 |
*-16.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[treeopen] memtest. |
[treeopen] memtest.ramctrl_1. |
@28 |
memtest.clk |
memtest.rst_in |
memtest.rst |
@200 |
--- INST RD -- |
@28 |
memtest.inst_stb |
@22 |
memtest.inst_addr[25:0] |
memtest.inst_to_cache[63:0] |
@28 |
memtest.inst_ack |
memtest.inst_timeout |
@200 |
--- DATA RD/WR -- |
@28 |
memtest.data_stb |
memtest.data_we |
@22 |
memtest.data_addr[25:0] |
memtest.data_to_mctrl[63:0] |
memtest.data_to_cache[63:0] |
@28 |
memtest.data_ack |
memtest.data_timeout |
@200 |
--- TEST RESULT -- |
@28 |
memtest.test_ended |
memtest.test_error |
@200 |
---- RAM CHIP -- |
@28 |
memtest.ramctrl_1.ram_stb |
memtest.ramctrl_1.ram_we |
@22 |
memtest.ramctrl_1.ram_addr[22:0] |
memtest.ramctrl_1.ram_dout[31:0] |
memtest.ramctrl_1.ram_din[31:0] |
@28 |
memtest.ramctrl_1.ram_ack |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/Makefile
0,0 → 1,18
# |
# Makefile for testing the memory controller |
# |
|
all: show |
|
install: |
|
memtest: memtest.v |
iverilog -Wall -o memtest memtest.v |
|
show: memtest |
./memtest |
gtkwave dump.vcd memtest.cfg |
|
clean: |
rm -f *~ memtest dump.vcd |
rm -f ramtest/*~ ramctrl/*~ |
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-0/README
0,0 → 1,44
Structure |
--------- |
|
A top-level module (memtest.v) creates instances of a memory |
test circuit (ramtest/ramtest.v) and a memory controller |
(ramctrl/ramctrl.v), which in turn builds an internal model |
of the external RAM (ramctrl/ram.v). |
|
|
Intended Use |
------------ |
|
The memory controller offers a complete simulation of the memory |
subsystem, if the given (simplistic) RAM implementation is used. |
If the RAM is substituted by a word-oriented, single-access SDRAM |
controller, the memory controller will in fact do its job on a real |
FPGA too, although it won't exploit the full potential of the SDRAM |
chip. |
|
|
Front-End (interface to caches) |
------------------------------- |
|
instruction read: |
2^26 * 64 bit = 512 MB |
strobe/acknowledge/timeout handshake |
|
data read/write: |
2^26 * 64 bit = 512 MB |
strobe/acknowledge/timeout handshake |
|
|
Back-End (interface to RAM) |
--------------------------- |
|
2^23 * 32 bit = 32 MB |
strobe/acknowledge handshake |
|
|
RAM |
--- |
|
The RAM has got separately adjustable access times for read and |
write operations (minimum is two clock cycles each). |