Commit 8003bae5 authored by twlostow's avatar twlostow

Alpha FIFO support added

git-svn-id: http://svn.ohwr.org/wishbone-gen@13 4537843c-45c2-4d80-8546-c3283569414f
parent 67939682
This is the initial version of wbgen2. Requires Lua 5.1.4+. Enjoy it :)
Compilation instructions:
Just type "make" in the main directory of wbgen2. The resulting file will be "wbgen2".
There is still some stuff to do:
- add FIFOs
- add documentation generator
- CONSTANT registers
\ No newline at end of file
- add FIFO register support
- CONSTANT registers
- Verilog primitive library
\ No newline at end of file
......@@ -36,7 +36,6 @@ function cgen_c_field_define(field, reg)
else
-- SLV/signed/unsigned fields: emit masks, shifts and access macros
print(field.offset, field.size);
emit(string.format("%-45s %s", "#define "..prefix.."_MASK", "WBGEN2_GEN_MASK("..field.offset..", "..field.size..")"));
emit(string.format("%-45s %d", "#define "..prefix.."_SHIFT", field.offset));
......@@ -65,6 +64,7 @@ end
-- iterates all regs and rams and generates appropriate #define-s
function cgen_c_field_masks()
foreach_reg({TYPE_REG}, function(reg)
dbg("DOCREG: ", reg.name, reg.num_fields);
if(reg.num_fields ~= nil and reg.num_fields > 0) then
emit("");
emit("/* definitions for register: "..reg.name.." */");
......
......@@ -252,7 +252,7 @@ function cgen_build_siglist()
table_join(siglist, global_signals);
for i,v in pairs(siglist) do
print("SIGNAL: ", v.name);
dbg("SIGNAL: ", v.name);
end
return siglist;
......
......@@ -74,52 +74,64 @@ function htable_frame(tbl, r,c1,c2)
end
function htable_emit(tbl)
emit("<table cellpadding=0 cellspacing=0 border=0>");
for i = 1, tbl.rows do
if(tbl.data[i].is_header ~= nil) then
tag = "th";
else
tag = "td";
end
if(tbl.data[i].style ~= nil) then emit('<tr class="'..tbl.data[i].style..'">'); else emit('<tr>'); end
for j=1,tbl.cols do
local extra = "";
if(tbl.data[i][j].extra ~= nil) then extra = tbl.data[i][j].extra; end
if(tbl.data[i][j].colspan ~= nil) then extra = extra..' colspan='..tbl.data[i][j].colspan..' '; end
if(tbl.data[i][j].style ~= nil) then emit('<'..tag..' '..extra..' class="'..tbl.data[i][j].style..'">'); else emit('<'..tag..'>'); end
emit(tbl.data[i][j].text);
emit('</'..tag..'>');
end
emit("</tr>");
end
emit("</table>");
emit("<table cellpadding=0 cellspacing=0 border=0>");
for i = 1, tbl.rows do
if(tbl.data[i].is_header ~= nil) then
tag = "th";
else
tag = "td";
end
if(tbl.data[i].style ~= nil) then
emit('<tr class="'..tbl.data[i].style..'">');
else
emit('<tr>');
end
for j=1,tbl.cols do
local extra = "";
if(tbl.data[i][j].extra ~= nil) then
extra = tbl.data[i][j].extra;
end
if(tbl.data[i][j].colspan ~= nil) then
extra = extra..' colspan='..tbl.data[i][j].colspan..' ';
end
if(tbl.data[i][j].style ~= nil) then
emit('<'..tag..' '..extra..' class="'..tbl.data[i][j].style..'">');
else
emit('<'..tag..' '..extra..'>');
end
emit(tbl.data[i][j].text);
emit('</'..tag..'>');
end
emit("</tr>");
end
emit("</table>");
end
function has_any_ports(reg)
local has = false;
if(reg.ports ~= nil) then return true; end
foreach_subfield(reg, function(field) if (field.ports ~= nil) then has = true; end end);
return has;
local has = false;
if(reg.ports ~= nil) then return true; end
foreach_subfield(reg, function(field) if (field.ports ~= nil) then has = true; end end);
return has;
end
function htable_add_row(tbl, r)
if(r>tbl.rows) then
for i=tbl.rows+1,r do
tbl.data[i]={};
for j=1,tbl.cols do
tbl.data[i][j] = {};
tbl.data[i][j].text = "";
end
end
tbl.rows=r;
end
if(r>tbl.rows) then
for i=tbl.rows+1,r do
tbl.data[i]={};
for j=1,tbl.cols do
tbl.data[i][j] = {};
tbl.data[i][j].text = "";
end
end
tbl.rows=r;
end
end
......@@ -189,6 +201,7 @@ function cgen_doc_hdl_symbol()
foreach_reg(ALL_REG_TYPES, function(reg)
if(has_any_ports(reg)) then
dbg("HasAnyPorts: ",reg.name);
table.insert(ports, reg.name);
if(reg.ports ~= nil) then
......@@ -339,7 +352,12 @@ function cgen_doc_memmap()
row[1].style = "td_code";
row[1].text = string.format("0x%x", reg.base);
row[2].text = "REG";
if(reg.doc_is_fiforeg == nil) then
row[2].text = "REG";
else
row[2].text = "FIFOREG";
end
row[3].text = hlink("#"..string.upper(reg.c_prefix), reg.name);
row[4].style = "td_code";
......@@ -389,7 +407,8 @@ function cgen_doc_fieldtable(reg, bitoffs)
local td_width = 70;
local tbl;
local n= 1;
local cellidx = 1;
tbl= htable_new(2,8);
......@@ -403,6 +422,7 @@ function cgen_doc_fieldtable(reg, bitoffs)
while (bit >= bitoffs) do
local f = find_field_by_offset(reg, bit);
if(f == nil) then
tbl.data[2][n].style = "td_unused";
tbl.data[2][n].text = "-";
......@@ -417,7 +437,10 @@ function cgen_doc_fieldtable(reg, bitoffs)
end
local ncells = (bit - fend) + 1;
if(ncells > 1) then tbl.data[2][n].colspan = ncells; end
dbg("ncells: ",ncells,"bit: ", bit, "name: ",f.prefix);
tbl.data[2][n].colspan = ncells;
local prefix;
......@@ -427,16 +450,12 @@ function cgen_doc_fieldtable(reg, bitoffs)
tbl.data[2][n].style = "td_field";
tbl.data[2][n].text = csel(f.size>1, string.format("%s[%d:%d]", string.upper(prefix), bit-f.offset, fend-f.offset), string.upper(prefix));
htable_frame(tbl, 2, cellidx);
htable_frame(tbl, 2, n);
bit = bit - ncells;
n=n+ncells;
n=n+1;
end
cellidx = cellidx + 1;
end
htable_emit(tbl);
......
......@@ -87,7 +87,7 @@ function cgen_vhdl_entity()
-- generate code for the port
local line = string.format("%-40s : %-6s %s", port.name, port.dir, fieldtype_2_vhdl[port.type]);
if(port.range > 0) then
if(port.range > 1) then
line = line.."("..(port.range-1).." downto 0)";
end
......@@ -113,7 +113,7 @@ function cgen_vhdl_entity()
-- we do it the same way as for the ports.
for i,v in pairs (g_siglist) do
s=string.format("signal %-40s : %-15s", v.name, fieldtype_2_vhdl[v.type]);
if(v.range > 0) then
if(v.range > 0 and v.type ~= BIT) then
s=s..string.format("(%d downto 0)", v.range-1);
end
s=s..";";
......@@ -310,7 +310,9 @@ function cgen_generate_vhdl_code(tree)
return "open";
end
if(t.h ~= nil and t.l == nil) then
--print("gensub: ", t.name);
if (t.h ~= nil and ( t.l == nil or (t.l == t.h))) then
return t.name.."("..t.h..")";
elseif(t.h ~= nil and t.l ~= nil) then
return t.name.."("..t.h.." downto "..t.l..")";
......@@ -335,6 +337,9 @@ function cgen_generate_vhdl_code(tree)
-- generates a VHDL type-conversion code for assignment between tsd (destination node) and tss (source node).
function gen_vhdl_typecvt(tsd, tss)
-- print("Gen_typecvt:", tsd.name);
-- print("Gen_typecvt:", tss.name, tss.type);
-- types match? Coool, we have nothing to do
if(tsd.type == tss.type) then
return(gen_subrange(tss));
......@@ -358,7 +363,7 @@ function cgen_generate_vhdl_code(tree)
elseif (tss.type == BIT) then
if(tsd.type == SLV) then
return(gen_subrange(tss.name));
return(gen_subrange(tss));
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tss.type == SIGNED or tss.type == UNSIGNED) then
......@@ -366,7 +371,7 @@ function cgen_generate_vhdl_code(tree)
-- dest: slv <= src: signed/unsigned
if(tsd.type == SLV) then
return("std_logic_vector("..gen_subrange(tss)..")");
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tss.type == SLV) then
......@@ -376,8 +381,11 @@ function cgen_generate_vhdl_code(tree)
elseif (tsd.type == UNSIGNED) then
-- print(tss);
return("unsigned("..gen_subrange(tss)..")");
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tsd.type == BIT) then
return gen_subrange(tss);
else
die ("unsupported assignment: "..tsd.name.." "..tss.name); end
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
end
......@@ -387,6 +395,8 @@ function cgen_generate_vhdl_code(tree)
local tsd = node_typesize(node.dst);
local tss = node_typesize(node.src);
-- print(tsd.name);
-- source node is an expression? - recurse it
if(tss.type == EXPRESSION) then
emiti();
......@@ -396,7 +406,6 @@ function cgen_generate_vhdl_code(tree)
emitx(";\n");
else
-- not an expression? - assign the destination with proper type casting.
-- print(gen_subrange(tsd));
emit(gen_subrange(tsd).." <= "..gen_vhdl_typecvt(tsd, tss)..";");
end
end
......@@ -473,7 +482,7 @@ function cgen_generate_vhdl_code(tree)
--
function cgen_vhdl_comment(node)
print("COMMENT: "..node.str);
-- print("COMMENT: "..node.str);
emitx("-- "..node.str.."\n");
end
......@@ -608,7 +617,7 @@ function cgen_generate_vhdl_code(tree)
["openpin"] = cgen_vhdl_openpin;
};
-- print(node);
-- print(node);
for i,v in pairs(node) do
-- no type? probably just a block of code. recurse it deeper.
......
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name ="FIFO test";
prefix="ft";
hdl_entity="wb_test_fifos";
fifo_reg {
size = 256;
direction = CORE_TO_BUS;
prefix = "tsf";
name = "Timestamp FIFO";
description = "This FIFO holds the TX packet timestamps gathered from all switch endpoints";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
field {
name = "Timestamp value taken on rising clock edge (full word)";
prefix = "val_r";
type = SLV;
size = 28;
};
field {
name = "Timestamp value taken on falling clock edge (few LSBs)";
prefix = "val_f";
type = SLV;
size = 4;
};
field {
name ="Physical port ID";
prefix = "pid";
type = SLV;
size = 5;
align= 16;
};
field {
name = "Frame ID";
prefix = "fid";
type = SLV;
size = 16;
align = 16;
};
};
fifo_reg {
size = 32;
direction = BUS_TO_CORE;
prefix = "memacc";
name = "Memory Access FIFO";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
field {
name = "Memory address/data select";
description = "0: current entry contains memory address value (auto-incremented at each write)\
1: current entry contains data word to be written to memory at previously set address";
prefix = "ad_sel";
type = BIT;
};
field {
name = "Memory address/data value";
description = "Value of data word to be written (when ad_sel = 1) or new memory address (when ad_sel = 0)";
prefix = "ad";
type = SLV;
size = 32;
};
};
};
\ No newline at end of file
set input_wb_file "fifotest.wb"
set test_module "wb_test_fifos"
set target "classic"
set lang "vhdl"
set library_files {
"../../lib/wbgen2_pkg.vhd"
"../../lib/altera/wbgen2_fifo_sync.vhd"
};
mkdir -p output
vlib work
vlib wbgen2
foreach file $library_files { vcom -work wbgen2 $file }
if { $lang == "vhdl" } {
set target_filename [format "./output/%s.vhd" $test_module ]
set target_wb "+define+WB_USE_CLASSIC"
set wbgen_opt "-target classic"
} else {
set target_filename [format "./output/%s.v" $test_module ]
set target_wb "+define+WB_USE_PIPELINED"
set wbgen_opt "-target pipelined"
}
puts $target_filename
../../wbgen2 -V $target_filename -K ./output/vlog_constants.v -C ./output/regdefs.h -D ./output/docs.html -l $lang $input_wb_file
if { $lang == "verilog" } {
vlog -work work -work wbgen2 $target_filename
} else {
vcom -work work $target_filename
}
vlog ./testbench.v
vsim work.main
radix -hexadecimal
do wave.do
run 1000us
wave zoomfull
`timescale 1ns/1ps
`include "output/vlog_constants.v"
`include "../common/wishbone_test_master.v"
`define FIFO_FULL 16
`define FIFO_EMPTY 17
module main;
reg tsf_wr_req = 0;
wire tsf_wr_full;
wire tsf_wr_empty;
wire [7:0] tsf_wr_usedw;
reg [27:0] tsf_val_r;
reg [3:0] tsf_val_f;
reg [4:0] tsf_pid;
reg [15:0] tsf_fid;
reg memacc_rd_req = 0;
wire memacc_rd_full;
wire memacc_rd_empty;
wire [4:0] memacc_rd_usedw;
wire memacc_ad_sel ;
wire [31:0] memacc_ad ;
WB_TEST_MASTER WB();
wire clk = WB.wb_clk;
wire rst = WB.wb_rst;
wb_test_fifos
dut (
.rst_n_i (WB.wb_rst),
.wb_clk_i (WB.wb_clk),
.wb_addr_i (WB.wb_addr[2:0]),
.wb_data_i (WB.wb_data_o),
.wb_data_o (WB.wb_data_i),
.wb_cyc_i (WB.wb_cyc),
.wb_sel_i (WB.wb_bwsel),
.wb_stb_i (WB.wb_stb),
.wb_we_i (WB.wb_we),
.wb_ack_o (WB.wb_ack),
.ft_tsf_wr_req_i (tsf_wr_req),
.ft_tsf_wr_full_o (tsf_wr_full),
.ft_tsf_wr_empty_o (tsf_wr_empty),
.ft_tsf_wr_usedw_o (tsf_wr_usedw),
.ft_tsf_val_r_i (tsf_val_r),
.ft_tsf_val_f_i (tsf_val_f),
.ft_tsf_pid_i (tsf_pid),
.ft_tsf_fid_i (tsf_fid),
.ft_memacc_rd_req_i (memacc_rd_req),
.ft_memacc_rd_full_o (memacc_rd_full),
.ft_memacc_rd_empty_o (memacc_rd_empty),
.ft_memacc_rd_usedw_o (memacc_rd_usedw),
.ft_memacc_ad_sel_o (memacc_ad_sel),
.ft_memacc_ad_o (memacc_ad)
);
reg [31:0] memacc_prev_addr = 'hffffffff;
task wait_fifo_flag(input [31:0] cr_addr, input [31:0] flag, input value);
begin: fifo_full_body
reg [31:0] cr_val;
WB.read32(cr_addr, cr_val);
while(cr_val[flag] != value)
WB.read32(cr_addr, cr_val);
end
endtask
// writes from the host side to MEMACC fifo
task memacc_write( input [31:0] address,
input [31:0] data);
begin
if(memacc_prev_addr + 1 != address)
begin
wait_fifo_flag(`ADDR_FT_MEMACC_CSR, `FIFO_FULL, 0);
WB.write32(`ADDR_FT_MEMACC_R0, 0);
WB.write32(`ADDR_FT_MEMACC_R1, address);
end
wait_fifo_flag(`ADDR_FT_MEMACC_CSR, `FIFO_FULL, 0);
WB.write32(`ADDR_FT_MEMACC_R0, 1);
WB.write32(`ADDR_FT_MEMACC_R1, data);
memacc_prev_addr = address;
end
endtask // UNMATCHED !!
task ts_fifo_write
(
input [27:0] value_r,
input [3:0] value_f,
input [4:0] pid,
input [15:0] fid);
begin
while(tsf_wr_full) @(posedge clk);
tsf_val_r <= value_r;
tsf_val_f <= value_f;
tsf_pid <= pid;
tsf_fid <= fid;
tsf_wr_req = 1;
@(posedge clk);
tsf_wr_req = 0;
end
endtask // ts_fifo_write
task ts_fifo_read ( output [27:0] value_r,
output [3:0] value_f,
output [4:0] pid,
output [15:0] fid);
begin : TS_FIFO_READ_BODY
reg [31:0] rval;
wait_fifo_flag(`ADDR_FT_TSF_CSR, `FIFO_EMPTY, 0);
WB.read32(`ADDR_FT_TSF_R0, rval);
value_f = rval[31:28];
value_r = rval[27:0];
WB.read32(`ADDR_FT_TSF_R1, rval);
fid = rval[31:16];
pid = rval[4:0];
end
endtask // ts_fifo_read
integer i;
integer rd_val_f, rd_val_r, rd_pid, rd_fid;
initial begin
wait (WB.ready);
WB.monitor_bus(0);
WB.verbose(0);
for(i=0;i<100;i=i+1) memacc_write(i, 3*i);
for(i=0;i<300;i=i+1) begin
ts_fifo_read(rd_val_r, rd_val_f, rd_pid, rd_fid);
$display("TS FIFO READ: val_f %d val_r %d pid %d fid %d", rd_val_f, rd_val_r, rd_pid, rd_fid);
end
end
// MEMACC FIFO data sink
always @(memacc_rd_empty)
memacc_rd_req <= ~memacc_rd_empty;
reg memacc_rd_d0 = 0;
reg [31:0] memacc_addr = 0;
always @(posedge clk) begin
memacc_rd_d0 <= memacc_rd_req;
if(memacc_rd_d0) begin
if(!memacc_ad_sel) begin
$display("MEMACC_SetAddress: %x", memacc_ad);
memacc_addr <= memacc_ad;
end else begin
$display("MEMACC_Write: addr %x data %x", memacc_addr, memacc_ad);
memacc_addr <= memacc_addr + 1;
end
end
end
// write some data to the timestamping FIFO
integer j;
initial begin
wait(WB.ready);
for(j=0;j<300;j=j+1)
ts_fifo_write(j, j+10, j+20, j+30);
end
endmodule
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -format Logic /main/tsf_wr_req
add wave -noupdate -format Logic /main/tsf_wr_full
add wave -noupdate -format Logic /main/tsf_wr_empty
add wave -noupdate -format Literal /main/tsf_wr_usedw
add wave -noupdate -format Literal /main/tsf_val_r
add wave -noupdate -format Literal /main/tsf_val_f
add wave -noupdate -format Literal /main/tsf_pid
add wave -noupdate -format Literal /main/tsf_fid
add wave -noupdate -format Logic /main/memacc_rd_req
add wave -noupdate -format Logic /main/memacc_rd_full
add wave -noupdate -format Logic /main/memacc_rd_empty
add wave -noupdate -format Literal /main/memacc_rd_usedw
add wave -noupdate -format Logic /main/memacc_ad_sel
add wave -noupdate -format Literal /main/memacc_ad
add wave -noupdate -format Logic /main/clk
add wave -noupdate -format Logic /main/rst
add wave -noupdate -format Logic /main/dut/ft_memacc_inst/wr_req_i
add wave -noupdate -format Literal /main/dut/ft_tsf_inst/rd_data_o
add wave -noupdate -format Logic /main/dut/ft_tsf_inst/rd_req_i
add wave -noupdate -format Logic /main/dut/ft_tsf_inst/rd_empty_o
add wave -noupdate -format Logic /main/dut/ft_tsf_inst/rd_full_o
add wave -noupdate -format Literal /main/dut/ft_tsf_inst/rd_usedw_o
add wave -noupdate -format Logic /main/dut/ft_tsf_rdreq_int
add wave -noupdate -format Logic /main/dut/ft_tsf_rdreq_int_d0
add wave -noupdate -format Literal /main/WB/wb_addr
add wave -noupdate -format Literal /main/WB/wb_data_o
add wave -noupdate -format Literal /main/WB/wb_bwsel
add wave -noupdate -format Literal /main/WB/wb_data_i
add wave -noupdate -format Logic /main/WB/wb_ack
add wave -noupdate -format Logic /main/WB/wb_cyc
add wave -noupdate -format Logic /main/WB/wb_stb
add wave -noupdate -format Logic /main/WB/wb_we
add wave -noupdate -format Logic /main/WB/wb_rst
add wave -noupdate -format Logic /main/WB/wb_clk
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {61000000 ps} 0}
configure wave -namecolwidth 288
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
update
WaveRestoreZoom {57718750 ps} {64281250 ps}
......@@ -23,9 +23,14 @@ entity wbgen2_fifo_sync is
rd_data_o : out std_logic_vector(g_width-1 downto 0);
rd_req_i : in std_logic;
empty_o : out std_logic;
full_o : out std_logic;
usedw_o : out std_logic_vector(g_usedw_size-1 downto 0)
wr_empty_o : out std_logic;
wr_full_o : out std_logic;
wr_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0);
rd_empty_o : out std_logic;
rd_full_o : out std_logic;
rd_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0)
);
end wbgen2_fifo_sync;
......@@ -46,7 +51,7 @@ architecture rtl of wbgen2_fifo_sync is
use_eab : string
);
port (
usedw : out std_logic_vector (7 downto 0);
usedw : out std_logic_vector (g_usedw_size-1 downto 0);
rdreq : in std_logic;
empty : out std_logic;
clock : in std_logic;
......@@ -57,6 +62,10 @@ architecture rtl of wbgen2_fifo_sync is
);
end component;
signal empty_int, full_int : std_logic;
signal usedw_int : std_logic_vector(g_usedw_size -1 downto 0);
begin
scfifo_component : scfifo
......@@ -77,10 +86,19 @@ begin
clock => clk_i,
wrreq => wr_req_i,
data => wr_data_i,
usedw => usedw_o,
empty => empty_o,
usedw => usedw_int,
empty => empty_int,
q => rd_data_o,
full => full_o
full => full_int
);
rd_empty_o <= empty_int;
rd_full_o <= full_int;
rd_usedw_o <= usedw_int;
wr_empty_o <= empty_int;
wr_full_o <= full_int;
wr_usedw_o <= usedw_int;
end rtl;
......@@ -30,25 +30,6 @@ package wbgen2_pkg is
wr_b_i : in std_logic);
end component;
component wbgen2_fifo_async
generic (
g_size : integer;
g_width : integer;
g_usedw_size : integer);
port (
rd_clk_i : in std_logic;
rd_req_i : in std_logic;
rd_data_o : out std_logic_vector(g_width-1 downto 0);
rd_empty_o : out std_logic;
rd_full_o : out std_logic;
rd_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0);
wr_clk_i : in std_logic;
wr_req_i : in std_logic;
wr_data_i : in std_logic_vector(g_width-1 downto 0);
wr_empty_o : out std_logic;
wr_full_o : out std_logic;
wr_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0));
end component;
component wbgen2_eic
generic (
......@@ -99,5 +80,45 @@ package wbgen2_pkg is
reg_isr_wr_stb_i : in std_logic;
wb_irq_o : out std_logic);
end component;
component wbgen2_fifo_async
generic (
g_size : integer;
g_width : integer;
g_usedw_size : integer);
port (
rd_clk_i : in std_logic;
rd_req_i : in std_logic;
rd_data_o : out std_logic_vector(g_width-1 downto 0);
rd_empty_o : out std_logic;
rd_full_o : out std_logic;
rd_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0);
wr_clk_i : in std_logic;
wr_req_i : in std_logic;
wr_data_i : in std_logic_vector(g_width-1 downto 0);
wr_empty_o : out std_logic;
wr_full_o : out std_logic;
wr_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0));
end component;
component wbgen2_fifo_sync
generic (
g_width : integer;
g_size : integer;
g_usedw_size : integer);
port (
clk_i : in std_logic;
wr_data_i : in std_logic_vector(g_width-1 downto 0);
wr_req_i : in std_logic;
rd_data_o : out std_logic_vector(g_width-1 downto 0);
rd_req_i : in std_logic;
wr_empty_o : out std_logic;
wr_full_o : out std_logic;
wr_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0);
rd_empty_o : out std_logic;
rd_full_o : out std_logic;
rd_usedw_o : out std_logic_vector(g_usedw_size -1 downto 0));
end component;
end wbgen2_pkg;
......@@ -112,8 +112,11 @@ function gen_bus_logic_wishbone()
padcode
}); };
table_join(rwcode, { va(vi("ack_sreg", math.max(acklen-1, 0)), 1); } );
table_join(rwcode, { va("ack_in_progress", 1); });
if(not (reg.dont_emit_ack_code == true)) then -- we don't want the main generator to mess with ACK line for this register
table_join(rwcode, { va(vi("ack_sreg", math.max(acklen-1, 0)), 1); } );
table_join(rwcode, { va("ack_in_progress", 1); });
end
if(regbank_address_bits > 0) then
rwcode = { vcase(reg.base, rwcode); };
......
......@@ -2,6 +2,9 @@
-- some constants --
-- DEBUG MACROS
VERBOSE_DEBUG = 0;
-- bus properties
DATA_BUS_WIDTH = 32;
SYNC_CHAIN_LENGTH = 3;
......@@ -76,6 +79,10 @@ function enum(x) x['__type']=TYPE_ENUM; return x; end
function irq(x) x['__type']=TYPE_IRQ; return x; end
function dbg(...)
if(VERBOSE_DEBUG) then print(arg); end
end
-- function chceks if argument p is nil and if it is, throws fatal error message s
function chk_nil(p,s)
if(p == nil) then
......@@ -190,25 +197,49 @@ end
function calc_field_offset(field, reg)
-- align the field offset next to the current offset in the reg
local ofs = reg.current_offset;
ofs = align(field, ofs);
local ofs = reg.current_offset;
-- FIFOs can span multiple I/O registers.
if (reg.__type == TYPE_FIFO) then
local ofs_new = align(field, ofs);
if((ofs_new % DATA_BUS_WIDTH) + field.size > DATA_BUS_WIDTH) then
field.align = DATA_BUS_WIDTH;
ofs = align(field, ofs);
else
ofs = ofs_new;
end
reg.current_offset = ofs + field.size;
field.offset = ofs;
else
ofs = align(field, ofs);
-- update the current offset
reg.current_offset = ofs + field.size;
field.offset = ofs;
field.offset_unaligned = reg.current_offset_unaligned;
reg.current_offset_unaligned = reg.current_offset_unaligned + field.size;
reg.current_offset = ofs + field.size;
field.offset = ofs;
end
-- update the "unaligned" offset - for FIFOs
field.offset_unaligned = reg.current_offset_unaligned;
reg.current_offset_unaligned = reg.current_offset_unaligned + field.size;
-- calculate the number of fields in the register
if(reg.num_fields == nil) then reg.num_fields = 0; end
reg.num_fields = reg.num_fields + 1;
-- oops, we have too many fields (the total size exceeds the data bus width)
if( reg.__type == TYPE_REG and reg.current_offset > DATA_BUS_WIDTH ) then
die ("Total size of register '"..reg.name.."' ("..reg.current_offset..") exceeds data bus width ("..DATA_BUS_WIDTH..")");
end
die ("Total size of register '"..reg.name.."' ("..reg.current_offset..") exceeds data bus width ("..DATA_BUS_WIDTH..")");
end
end
-- calculate the number of fields in the register
function calc_num_fields(field, reg)
if(reg.num_fields == nil) then reg.num_fields = 0; end
reg.num_fields = reg.num_fields + 1;
end
-- commits a suicide with error message "s"
......@@ -467,3 +498,20 @@ end
function deepcopy(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
......@@ -12,6 +12,9 @@ function fifo_wire_core_ports(fifo)
csel(fifo.direction == BUS_TO_CORE, "FIFO read request", "FIFO write request" ))
};
-- wire the read/write request port
table_join(fifo.maps, { vpm (fifo.rdwr.."_req_i", prefix.."_"..fifo.rdwr.."_req_i") });
-- add full/empty/usedw ports
if inset(FIFO_FULL, fifo.flags_dev) then
table_join(ports, { port (BIT, 0, "out", prefix.."_"..fifo.rdwr.."_full_o", "FIFO full flag") });
......@@ -24,9 +27,9 @@ function fifo_wire_core_ports(fifo)
end
if inset(FIFO_COUNT, fifo.flags_dev) then
table_join(ports, { port (SLV, fifo.usedw_size, "out", prefix.."_"..fifo.rdwr.."_count_o",
table_join(ports, { port (SLV, fifo.usedw_size, "out", prefix.."_"..fifo.rdwr.."_usedw_o",
"FIFO number of used words") });
table_join(fifo.maps, { vpm (fifo.rdwr.."_count_o", prefix.."_"..fifo.rdwr.."_count_o")});
table_join(fifo.maps, { vpm (fifo.rdwr.."_usedw_o", prefix.."_"..fifo.rdwr.."_usedw_o")});
end
foreach_subfield(fifo,
......@@ -35,16 +38,19 @@ function fifo_wire_core_ports(fifo)
total_size = total_size + field.size;
if(fifo.direction == BUS_TO_CORE) then -- bus -> core fifo
-- generate an output port for the field
table_join(ports, {port (field.type, field.size, "out", field_pfx.."_o")});
-- assign the output to the FIFO output port
-- table_join(fifo.extra_code, {
-- va(field_pfx.."_o",
-- vi(prefix.."_out_int", field.offset_unaligned + field.size -1,
--- field.current_unaligned)) });
else -- core -> bus fifo
table_join(fifo.extra_code, {
va(field_pfx.."_o",
vi(prefix.."_out_int", field.offset_unaligned + field.size -1,
field.offset_unaligned)) });
else
-- generate an input port for the field
table_join(ports, {port (field.type, field.size, "in", field_pfx.."_i")});
-- core -> bus fifo: wire the inputs to FIFO data input
table_join(fifo.extra_code, {
va(
vi(prefix.."_in_int", field.offset_unaligned + field.size -1,
......@@ -54,6 +60,8 @@ function fifo_wire_core_ports(fifo)
end);
table_join(fifo.ports, ports);
fifo.total_size = total_size;
......@@ -66,6 +74,7 @@ function fifo_wire_bus_ports(fifo)
local fifo_dregs = {};
local i;
local r;
for i=0, n_regs -1 do
local minofs = i * DATA_BUS_WIDTH;
......@@ -80,14 +89,18 @@ function fifo_wire_bus_ports(fifo)
fifo_dregs[i].extra_code = {};
fifo_dregs[i].ackgen_code= {};
print("DREG ", i);
-- print("DREG ", i);
-- allocate the registers.
foreach_subfield(fifo,
function(field)
if(field.offset >= minofs and field.offset + field.size - 1 <= maxofs) then
table.insert(fifo_dregs[i], field);
field.offset = field.offset - minofs;
print("FIELD: ", field.name, " OFS: ", field.offset, "SIZE: ",field.size);
dbg("FIELD: ", field.name, " OFS: ", field.offset, "SIZE: ",field.size);
end
end);
......@@ -101,6 +114,7 @@ function fifo_wire_bus_ports(fifo)
r.ack_len = 2;
r.ports = {};
r.signals = {};
r.doc_is_fiforeg = true;
if(fifo.direction == BUS_TO_CORE) then
r.name = "FIFO '"..fifo.name.."' data input register "..i;
......@@ -128,26 +142,81 @@ function fifo_wire_bus_ports(fifo)
field.access_dev = READ_ONLY;
else
field.read_code = {
va(
vi("rddata_reg", -- src
field.offset + field.size - 1,
field.offset),
vi(fifo.full_prefix.."_out_int", -- dst
field.offset_unaligned + field.size - 1,
field.offset_unaligned))
};
field.access_bus = READ_ONLY;
field.access_dev = WRITE_ONLY;
end
end);
print(r.hdl_prefix, r.c_prefix, prefix);
table.insert(periph, r);
end
print("lastreg: " ,r.name);
dbg("lastreg: " ,r.name);
-- last register:
if(fifo.direction == BUS_TO_CORE) then -- Last FIFO I/O register
table_join(r.write_code, { va(fifo.full_prefix.."_wrreq_int", 1) });
table_join(r.ackgen_code, { va(fifo.full_prefix.."_wrreq_int", 0) });
table_join(r.reset_code_main, { va(fifo.full_prefix.."_wrreq_int", 0) });
else
local r = fifo_dregs[0];
-- local old_readcode = deepcopy(r.read_code);
-- generate a delay for read request signal
table_join(r.extra_code, { vsyncprocess("bus_clock_int", "rst_n_i", {
vreset(0, {
va(fifo.full_prefix.."_rdreq_int_d0", 0)
});
vposedge ( {
va(fifo.full_prefix.."_rdreq_int_d0",fifo.full_prefix.."_rdreq_int")
});
}) });
local fields_readcode = {};
foreach_subfield(r,
function(field)
table_join(fields_readcode, field.read_code);
field.read_code = nil;
end);
table_join(r.reset_code_main, { va(fifo.full_prefix.."_rdreq_int", 0) });
r.read_code = {
vif(vequal(fifo.full_prefix.."_rdreq_int_d0", 0), {
va(fifo.full_prefix.."_rdreq_int", vnot(fifo.full_prefix.."_rdreq_int"));
}, { -- else
fields_readcode;
va("ack_in_progress", 1);
va(vi("ack_sreg", 0), 1);
})
};
r.dont_emit_ack_code = true;
end
-- add full/empty/usedw control register
local csr = {
......@@ -178,8 +247,8 @@ function fifo_wire_bus_ports(fifo)
local sig = fifo.full_prefix.."_"..field_prefix.."_int";
-- wire the FULL signal to appropriate FIFO output
table_join(fifo.maps, { vpm (fifo.rdwr.."_"..field_prefix.."_o", sig)});
-- wire the FULL/EMPTY/USEDW signals to appropriate FIFO outputs
table_join(fifo.maps, { vpm (fifo.nrdwr.."_"..field_prefix.."_o", sig)});
table_join(f.signals, { signal (type, size, sig) });
if(type == BIT) then
table_join(f.read_code, { va(vi("rddata_reg", f.offset), sig) });
......@@ -188,7 +257,7 @@ function fifo_wire_bus_ports(fifo)
end
table.insert(csr, f);
else
table_join(fifo.maps, { vpm (fifo.rdwr.."_full_o", vopenpin())});
table_join(fifo.maps, { vpm (fifo.nrdwr.."_"..field_prefix.."_o", vopenpin())});
end
end
......@@ -209,7 +278,7 @@ function fifo_wire_bus_ports(fifo)
17);
gen_fifo_csr_field(FIFO_COUNT,
"count",
"usedw",
"FIFO counter",
"Number of data records currently being stored in FIFO '"..fifo.name.."'",
fifo.usedw_size,
......@@ -217,12 +286,15 @@ function fifo_wire_bus_ports(fifo)
0);
-- add the FIFO CSR register to the peripheral
if(type(fifo.flags_bus) == "table") then
table.insert(periph, csr);
end
-- wire the bus-side read/write request port
table_join(fifo.maps, { vpm (fifo.nrdwr.."_req_i", fifo.full_prefix.."_"..fifo.nrdwr.."req_int") });
end
......@@ -230,7 +302,7 @@ end
function gen_code_fifo(fifo)
local prefix = string.lower(periph.hdl_prefix.."_"..fifo.hdl_prefix);
print("GenCodeFIFO");
dbg("GenCodeFIFO");
fifo.full_prefix = prefix;
fifo.ports= {};
......@@ -240,8 +312,10 @@ function gen_code_fifo(fifo)
if(fifo.direction == BUS_TO_CORE) then
fifo.rdwr = "rd";
fifo.nrdwr = "wr";
else
fifo.rdwr = "wr";
fifo.nrdwr = "rd";
end
......@@ -255,10 +329,42 @@ function gen_code_fifo(fifo)
if(fifo.direction == BUS_TO_CORE) then
table_join(fifo.signals, { signal (BIT, 0, fifo.full_prefix.."_wrreq_int") });
else
table_join(fifo.signals, { signal (BIT, 0, fifo.full_prefix.."_rdreq_int") });
table_join(fifo.signals, { signal (BIT, 0, fifo.full_prefix.."_rdreq_int_d0") });
end
if(fifo.clock == nil) then
table_join(fifo.maps, { vpm ("clk_i", "bus_clock_int"); });
elseif (fifo.directrion == BUS_TO_CORE) then
table_join(fifo.maps, { vpm ("rd_clk_i", fifo.clock);
vpm ("wr_clk_i", "bus_clock_int") });
elseif (fifo.direction == CORE_TO_BUS) then
table_join(fifo.maps, { vpm ("wr_clk_i", fifo.clock);
vpm ("rd_clk_i", "bus_clock_int") });
end
-- wire the data I/O
table_join(fifo.maps, {
vpm ("wr_data_i", fifo.full_prefix.."_in_int");
vpm ("rd_data_o", fifo.full_prefix.."_out_int") ;
-- and the generics
vgm ("g_size", fifo.size);
vgm ("g_width", fifo.total_size);
vgm ("g_usedw_size", log2up(fifo.size))
});
table_join(fifo.extra_code, {
vinstance(fifo.full_prefix.."_INST", "wbgen2_fifo_sync", fifo.maps);
});
end
......@@ -138,6 +138,10 @@ foreach_field(calc_field_offset);
foreach_reg({TYPE_FIFO}, gen_code_fifo);
foreach_field(calc_num_fields);
foreach_reg({TYPE_REG, TYPE_RAM, TYPE_FIFO}, calc_address_sizes);
assign_addresses();
......
......@@ -675,7 +675,7 @@ function gen_abstract_code(reg)
reg.full_hdl_prefix = string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);
if(reg.no_std_regbank == true) then
print("reg: ",reg.name," - no std regbank");
dbg("reg: ",reg.name," - no std regbank");
return;
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment