Commit 7cc2ac4a authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

new code generator (vlog/vhdl)

parent dee54890
#!/usr/bin/lua
-- wbgen2, (c) 2010 Tomasz Wlostowski
-- CERN BE-Co-HT
-- LICENSED UNDER GPL v2
------------------------------
-- HDL syntax tree constructors
------------------------------
-- assignment: dst <= src;
function va (dst, src)
local s={};
s.t="assign";
s.dst=dst;
s.src=src;
return s;
end
-- index: name(h downto l)
function vi(name, h, l)
local s={};
s.t="index";
s.name=name;
s.h=h;
s.l=l;
return s;
end
-- synchronous process: process(clk, rst) begin {code} end process;
function vsyncprocess(clk, rst, code)
local s={};
s.t="syncprocess";
s.clk=clk;
s.rst=rst;
s.code=code;
return s;
end
-- reset in process
function vreset(level, code)
local s={};
s.t="reset";
s.level=level;
s.code=code;
return s;
end
function vposedge(code)
local s={};
s.t="posedge";
s.code=code;
return s;
end
function vif(cond, code, code_else)
local s={};
s.t="if";
s.cond={ cond };
s.code=code;
s.code_else=code_else;
return s;
end
function vequal(a,b)
local s={};
s.t="eq";
s.a=a;
s.b=b;
return s;
end
function vand(a,b)
local s={};
s.t="and";
s.a=a;
s.b=b;
return s;
end
function vnot(a)
local s={};
s.t="not";
s.a=a;
return s;
end
function vswitch(a, code)
local s={};
s.t="switch";
s.a=a;
s.code=code;
return s;
end
function vcase(a, code)
local s={};
s.t="case";
s.a=a;
s.code=code;
return s;
end
function vcasedefault(code)
local s={};
s.t="casedefault";
s.code=code;
return s;
end
function vcomment(str)
local s={};
s.t="comment";
s.str=str;
return s;
end
function vsub(a,b)
local s={};
s.t="sub";
s.a=a;
s.b=b;
return s;
end
-- constructor for a HDL signal
function signal(type, nbits, name, comment)
local t = {}
t.comment = comment;
t.type = type;
t.range= nbits;
t.name = name;
return t;
end
-- constructor for a HDL port
function port(type, nbits, dir, name, comment)
local t = {}
t.comment = comment;
t.type = type;
t.range= nbits;
t.name = name;
t.dir = dir;
return t;
end
function cgen_build_wishbone_ports()
local ports = {
port(BIT, 0, "in", "rst_n_i"),
port(BIT, 0, "in", "wb_clk_i"),
};
if(address_bus_width > 0 ) then
table_join(ports, { port(SLV, address_bus_width, "in", "wb_addr_i") });
end
table_join(ports, {
port(SLV, DATA_BUS_WIDTH, "in", "wb_data_i"),
port(SLV, DATA_BUS_WIDTH, "out", "wb_data_o"),
port(BIT, 0, "in", "wb_cyc_i"),
port(BIT, 0, "in", "wb_sel_i"),
port(BIT, 0, "in", "wb_stb_i"),
port(BIT, 0, "in", "wb_we_i"),
port(BIT, 0, "out", "wb_ack_o")
});
return ports;
end
function cgen_build_clock_list()
local allclocks = tree_2_table("clock");
local i,v;
local clockports = {};
remove_duplicates(allclocks);
for i,v in pairs(allclocks) do
table.insert(clockports, port(BIT, 0, "in", v));
end
return clockports;
end
function cgen_build_siglist()
local siglist = {};
local i,v;
local s;
siglist = tree_2_table("signals");
wb_sigs = { signal(BIT, 0, "wb_ack_regbank"),
signal(UNSIGNED, 4, "ack_cntr"),
signal(BIT,0, "ack_in_progress"),
signal(BIT,0, "tmpbit"),
signal(SLV, DATA_BUS_WIDTH, "rddata_reg"),
signal(SLV, DATA_BUS_WIDTH, "wrdata_reg"),
signal(SLV, address_bus_width, "rwaddr_reg")
};
table_join(siglist, wb_sigs);
return siglist;
end
function cgen_build_portlist()
local portlist = {};
table_join(portlist, cgen_build_wishbone_ports());
table_join(portlist, cgen_build_clock_list());
table_join(portlist, tree_2_table("ports"));
return portlist;
end
function cgen_find_sigport(name)
for i,v in pairs(g_portlist) do if(name == v.name) then return v; end end
for i,v in pairs(g_siglist) do if(name == v.name) then return v; end end
return nil;
end
function cgen_build_signals_ports()
g_portlist = cgen_build_portlist();
g_siglist = cgen_build_siglist();
end
cur_indent = 0;
function indent_zero()
cur_indent=0;
end
function indent_left()
cur_indent = cur_indent - 1;
end
function indent_right()
cur_indent = cur_indent + 1;
end
function cgen_new_snippet()
emit_code = "";
end
function emiti()
local i;
for i = 1,cur_indent do emit_code=emit_code.." "; end
end
function emit(s)
local i;
for i = 1,cur_indent do emit_code=emit_code.." "; end
emit_code=emit_code..s.."\n";
end
function emitx(s)
emit_code=emit_code..s;
end
function cgen_get_snippet()
return emit_code;
end
function cgen_write_current_snippet()
hdl_file.write(hdl_file, emit_code);
end
function cgen_write_snippet(s)
hdl_file.write(hdl_file, s);
end
function cgen_generate_hdl_init(filename)
hdl_file = io.open(filename, "w");
end
function cgen_generate_hdl_done()
hdl_file.close(hdl_file);
end
#!/usr/bin/lua
-- wbgen2, (c) 2010 Tomasz Wlostowski/CERN BE-Co-HT
-- LICENSED UNDER GPL v2
-- File: cgen_vhdl.lua
-- The Verilog code generator
VLOG_WIRE = 1;
VLOG_REG = 2;
function cgen_verilog_header()
emit("//////////////////////////////////////////////////////////////////////////////////////");
emit("// Title : Wishbone slave core for "..periph.name);
emit("//////////////////////////////////////////////////////////////////////////////////////");
emit("// File : "..options.output_hdl_file);
emit("// Author : auto-generated by wbgen2 from "..input_wb_file);
emit("// Created : "..os.date());
emit("// Standard : Verilog 2001");
emit("//////////////////////////////////////////////////////////////////////////////////////");
emit("// THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE "..input_wb_file);
emit("// DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!");
emit("//////////////////////////////////////////////////////////////////////////////////////");
emit("");
end
function cgen_verilog_module()
local last;
indent_zero();
emit ("module "..periph.hdl_entity.." (");
indent_right();
for i=1,table.getn(g_portlist) do
local port = g_portlist[i];
if(i == table.getn(g_portlist)) then
last = true;
else
last = false;
end
if(port.comment ~= nil) then
emitx("// "..port.comment.."\n");
end
local dirstr;
if(port.dir=="in") then
dirstr="input";
elseif(port.dir=="out") then
dirstr="output";
elseif(port.dir=="inout") then
dirst="inout";
end
print("Port: ", port.name, "type ", port.vlog_type);
if(port.vlog_type == VLOG_REG) then
dirstr=dirstr.." reg";
end
local rangestr="";
if(port.range > 0) then
rangestr = "["..(port.range-1)..":0]";
end
local line = string.format("%-11s %-6s %s", dirstr, rangestr, port.name);
line=line..csel(last, "", ",");
emit(line);
end
indent_left();
emit(");");
indent_left();
emit("");
for i,v in pairs (g_siglist) do
local rwire=csel(v.vlog_type==VLOG_REG, "reg", "wire");
local rangestr="";
if(v.range > 0) then
rangestr=string.format("[%d:0] ", v.range-1);
end
emit(string.format("%-5s %-7s %s;", rwire, rangestr, v.name));
end
emit("");
indent_right();
end
function cgen_verilog_ending()
indent_left();
emit("endmodule");
end
-- Generates the vlog code from syntax tree <tree>, writing it into previously chosen file.
function cgen_generate_verilog_code(tree)
local inside_process = false;
function find_code(node, t)
for i,v in ipairs(node) do if ((v.t ~= nil) and (v.t == t)) then return v; end end
return nil;
end
function cgen_verilog_syncprocess(node)
local vrst = find_code(node.code, "reset");
if(vrst ~= nil and options.reset_type=="asynchronous") then
emit("always @(posedge "..node.clk.." or "..csel(vrst.level==0, "negedge", "posedge").." rst_n_i) begin")
else
emit("always @(posedge "..node.clk..") begin");
end
indent_right();
inside_process = true;
local vpe = find_code(node.code, "posedge");
if(vpe == nil) then die("verilog code generation error: no vposedge defined for vsyncprocess"); end
if(vrst ~= nil) then
emit("if ("..node.rst.." == 1'b"..vrst.level..") begin ");
indent_right();
recurse(vrst.code);
indent_left();
emit("end else begin");
indent_right();
end
recurse(vpe.code);
if(vrst ~= nil) then
indent_left();
emit("end");
end
indent_left();
emit("end");
emit("");
inside_process = false;
end
function node_typesize(node)
local ts = {};
local sig;
print(node);
if(type(node) == "table") then
print("table!");
if(node.t ~= nil and node.t == "index") then
sig = cgen_find_sigport(node.name);
ts.h=node.h;
ts.l=node.l;
ts.sig=sig;
ts.name=sig.name;
ts.type=sig.type;
ts.size = csel(ts.l==nil,1,ts.h-ts.l+1);
return ts;
else
print("expr2: ", node.t);
ts.type = EXPRESSION;
ts.code = node;
return ts;
end
elseif(type(node) == "string") then
print("string-type node: "..node);
sig = cgen_find_sigport(node);
ts.sig=sig;
ts.size = sig.range;
ts.type = sig.type;
ts.name = node;
return ts;
elseif(type(node) == "number") then
ts.type = INTEGER;
ts.name = node;
ts.size = 0;
return ts;
else
print("Unknown node?");
end
end
function gen_subrange(t)
if(t.h ~= nil and t.l == nil) then
return t.name.."["..t.h.."]";
elseif(t.h ~= nil and t.l ~= nil) then
return t.name.."["..t.h..":"..t.l.."]";
else
return t.name;
end
end
function calc_size(t)
if(t.h ~= nil and t.l == nil) then
return 1;
elseif(t.h ~= nil and t.l ~= nil) then
return t.h-t.l+1;
else
local sig= cgen_find_sigport(t.name);
return sig.range;
end
end
function cgen_verilog_assign(node)
local tsd = node_typesize(node.dst);
local tss = node_typesize(node.src);
-- for i,v in pairs(tsd) do
-- print(i,v);
-- end
-- vlog synchronous assignment
if(inside_process) then
if(tss.type == EXPRESSION) then
print("EXPR!");
emiti();
emitx(gen_subrange(tsd).." <= ");
tsd.sig.vlog_type = VLOG_REG;
recurse({tss.code});
emitx(";\n");
else
emit(gen_subrange(tsd).." <= "..gen_subrange(tss)..";");
tsd.sig.vlog_type = VLOG_REG;
end
else -- vlog combinatorial assignment
emit("assign "..gen_subrange(tsd).." = "..gen_subrange(tss)..";");
tsd.sig.vlog_type = VLOG_WIRE;
end
end
function cgen_verilog_if(node)
emiti(); emitx("if (");
-- print("EMIT IF:", node.cond);
for i,v in pairs(node.cond) do print(i,v); end
recurse(node.cond);
emitx(") begin\n");
if(node.code_else ~= nil) then
indent_right();
recurse(node.code);
indent_left();
emit("end else begin");
indent_right();
recurse(node.code_else);
indent_left();
emit("end");
else
indent_right();
recurse(node.code);
indent_left();
emit("end");
end
end
function cgen_verilog_not(node)
local tsa = node_typesize(node.a);
emitx("! ");
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
emitx(gen_subrange(tsa));
end
end
function cgen_verilog_op(node, op)
local tsa = node_typesize(node.a);
local tsb = node_typesize(node.b);
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
emitx(gen_subrange(tsa));
end
if(op=="eq") then emitx(" == "); end
if(op=="and") then emitx(" && "); end
if(op=="or") then emitx(" || "); end
if(op=="sub") then emitx(" - "); end
if(op=="add") then emitx(" + "); end
if(tsb.type == EXPRESSION) then
emitx("("); recurse({node.b}); emitx(")");
else
emitx(gen_subrange(tsb));
end
end
function cgen_verilog_comment(node)
emitx("// "..node.str.."\n");
end
-- switch/case statement --
function cgen_verilog_switch(node)
local tsa = node_typesize(node.a);
emiti(); emitx("case ");
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
emitx("("..gen_subrange(tsa)..")");
end
emit("");
for i,v in pairs(node.code) do
print("CA: ", v.t);
if(v.t == "case") then
emit(string.format("%d'h%x: begin", tsa.size, v.a));
indent_right();
recurse({v.code});
indent_left();
emit("end");
elseif(v.t == "casedefault") then
emit("default: begin");
indent_right();
recurse({v.code});
indent_left();
emit("end");
end
end
emit("endcase");
end
function recurse(t)
print("recurse: ", t);
for i,v in pairs(t) do
print("-> i ",i,"v ",v, "vt ",v.t);
if(v.t == nil) then
recurse(v);
elseif(v.t == "comment") then
cgen_verilog_comment(v);
elseif(v.t == "syncprocess") then
cgen_verilog_syncprocess(v);
elseif(v.t=="assign") then
cgen_verilog_assign(v);
elseif(v.t=="if") then
cgen_verilog_if(v);
elseif(v.t=="eq" or v.t=="sub" or v.t=="add" or v.t == "or" or v.t=="and") then
cgen_verilog_op(v,v.t);
elseif(v.t=="switch") then
cgen_verilog_switch(v);
elseif(v.t=="not") then
cgen_verilog_not(v);
else
print("unimpl: "..v.t);
os.exit(-1);
end
end
print("end recurse");
end
cgen_new_snippet();
cgen_verilog_header();
local c_header = cgen_get_snippet();
cgen_new_snippet();
recurse(tree);
cgen_verilog_ending();
local c_body = cgen_get_snippet();
-- generate the module definions and signals - this must done after the module body has been generated in order to determine whether to declare things
-- as regs or wires.
cgen_new_snippet();
cgen_verilog_module();
local c_mod = cgen_get_snippet();
cgen_write_snippet(c_header);
cgen_write_snippet(c_mod);
cgen_write_snippet(c_body);
--cgen_write_snippet();
end
#!/usr/bin/lua
-- wbgen2, (c) 2010 Tomasz Wlostowski/CERN BE-Co-HT
-- LICENSED UNDER GPL v2
-- File: cgen_vhdl.lua
-- The VHDL code generator
fieldtype_2_vhdl={};
fieldtype_2_vhdl[BIT]="std_logic";
fieldtype_2_vhdl[MONOSTABLE]="std_logic";
fieldtype_2_vhdl[SIGNED] = "signed";
fieldtype_2_vhdl[UNSIGNED] = "unsigned";
fieldtype_2_vhdl[ENUM] = "std_logic_vector";
fieldtype_2_vhdl[SLV] = "std_logic_vector";
cvtfunc_hdl = {};
cvtfunc_hdl[SLV] = "";
cvtfunc_hdl[SIGNED] = "signed";
cvtfunc_hdl[UNSIGNED] = "unsigned";
-- generates a string containing VHDL-compatible binary numeric value of size numbits
function gen_vhdl_bin_literal(value, numbits)
local str ='\"';
local i,n,d,r;
n=value;
r=math.pow(2, numbits-1);
for i=1,numbits do
d=math.floor(n/r);
str=str..csel(d>0,"1","0");
n=n%r;
r=r/2;
end
return str..'\"';
end
function cgen_vhdl_header()
emit("---------------------------------------------------------------------------------------");
emit("-- Title : Wishbone slave core for "..periph.name);
emit("---------------------------------------------------------------------------------------");
emit("-- File : "..options.output_hdl_file);
emit("-- Author : auto-generated by wbgen2 from "..input_wb_file);
emit("-- Created : "..os.date());
emit("-- Standard : VHDL'87");
emit("---------------------------------------------------------------------------------------");
emit("-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE "..input_wb_file);
emit("-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!");
emit("---------------------------------------------------------------------------------------");
emit("");
emit("library ieee;");
emit("use ieee.std_logic_1164.all;");
emit("use ieee.numeric_std.all;");
emit("");
end
function cgen_vhdl_entity()
local last;
emit ("entity "..periph.hdl_entity.." is");
indent_right();
emit ("port (");
indent_right();
for i=1,table.getn(g_portlist) do
local port = g_portlist[i];
if(i == table.getn(g_portlist)) then
last = true;
else
last = false;
end
if(port.comment ~= nil) then
emitx("-- "..port.comment.."\n");
end
local line = string.format("%-40s : %-6s %s", port.name, port.dir, fieldtype_2_vhdl[port.type]);
if(port.range > 0) then
line = line.."("..(port.range-1).." downto 0)";
end
line=line..csel(last, "", ";");
emit(line);
end
indent_left();
emit(");");
indent_left();
emit("end "..periph.hdl_entity..";");
emit("");
emit("architecture syn of "..periph.hdl_entity.." is");
emit("");
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
s=s..string.format("(%d downto 0)", v.range-1);
end
s=s..";";
emit(s);
end
emit("");
emit("begin");
indent_right();
end
function cgen_vhdl_ending()
indent_left();
emit("end syn;");
end
-- Generates the VHDL code from syntax tree <tree>, writing it into previously chosen file.
function cgen_generate_vhdl_code(tree)
function find_code(node, t)
for i,v in ipairs(node) do if ((v.t ~= nil) and (v.t == t)) then return v; end end
return nil;
end
function cgen_vhdl_syncprocess(node)
emit("process ("..node.clk..", "..node.rst..")");
emit("begin");
indent_right();
local vrst = find_code(node.code, "reset");
local vpe = find_code(node.code, "posedge");
if(vpe == nil) then die("vhdl code generation error: no vposedge defined for vsyncprocess"); end
if(options.reset_type == "asynchronous") then
if(vrst ~= nil) then
emit("if ("..node.rst.." = '"..vrst.level.."') then ");
indent_right();
recurse(vrst.code);
indent_left();
emit("elsif rising_edge("..node.clk..") then");
indent_right();
else
emit("if rising_edge("..node.clk..") then");
indent_right();
end
recurse(vpe.code);
indent_left();
emit("end if;");
else -- sync reset
emit("if rising_edge("..node.clk..") then");
indent_right();
if(vrst ~= nil) then
emit("if ("..node.rst.." = '"..vrst.level.."') then ");
indent_right();
recurse(vrst.code);
indent_left();
emit("else ");
end
indent_right();
recurse(vpe.code);
indent_left();
emit("end if;");
indent_left();
emit("end if;");
end
indent_left();
emit("end process;");
emit("");
end
function node_typesize(node)
local ts = {};
local sig;
print(node);
if(type(node) == "table") then
print("table!");
if(node.t ~= nil and node.t == "index") then
sig = cgen_find_sigport(node.name);
ts.h=node.h;
ts.l=node.l;
ts.name=sig.name;
ts.type=sig.type;
ts.size = csel(ts.l==nil,1,ts.h-ts.l+1);
return ts;
else
print("expr2: ", node.t);
ts.type = EXPRESSION;
ts.code = node;
return ts;
end
elseif(type(node) == "string") then
print("string-type node: "..node);
sig = cgen_find_sigport(node);
ts.size = sig.range;
ts.type = sig.type;
ts.name = node;
return ts;
elseif(type(node) == "number") then
ts.type = INTEGER;
ts.name = node;
ts.size = 0;
return ts;
else
print("Unknown node?");
end
end
function gen_subrange(t)
if(t.h ~= nil and t.l == nil) then
return t.name.."("..t.h..")";
elseif(t.h ~= nil and t.l ~= nil) then
return t.name.."("..t.h.." downto "..t.l..")";
else
return t.name;
end
end
function calc_size(t)
if(t.h ~= nil and t.l == nil) then
return 1;
elseif(t.h ~= nil and t.l ~= nil) then
return t.h-t.l+1;
else
local sig= cgen_find_sigport(t.name);
return sig.range;
end
end
function gen_vhdl_typecvt(tsd, tss)
if(tsd.type == tss.type) then -- assign same types
return(gen_subrange(tss));
elseif (tss.type == INTEGER) then
if(tsd.type == BIT) then -- assign bit/slv/signed/unsigned <= number;
return("'"..tss.name.."'");
elseif(tsd.type == SLV) then
return("std_logic_vector(to_unsigned("..tss.name..", "..calc_size(tsd).."))");
elseif(tsd.type == SIGNED) then
return("to_signed("..tss.name..", "..calc_size(tsd)..")");
elseif(tsd.type == UNSIGNED) then
return("to_unsigned("..tss.name..", "..calc_size(tsd)..")");
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tss.type == BIT) then
if(tsd.type == SLV) then
return(gen_subrange(tss.name));
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tss.type == SIGNED or tss.type == UNSIGNED) then
if(tsd.type == SLV) then
return("std_logic_vector("..gen_subrange(tss.name)..")");
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
elseif (tss.type == SLV) then
if(tsd.type == SIGNED) then
return("signed("..gen_subrange(tss.name)..")");
elseif (tsd.type == UNSIGNED) then
return("unsigned("..gen_subrange(tss.name)..")");
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
else die ("unsupported assignment: "..tsd.name.." "..tss.name); end
end
function cgen_vhdl_assign(node)
local tsd = node_typesize(node.dst);
local tss = node_typesize(node.src);
for i,v in pairs(tsd) do
print(i,v);
end
if(tss.type == EXPRESSION) then
print("EXPR!");
emiti();
emitx(gen_subrange(tsd).." <= ");
recurse({tss.code});
emitx(";\n");
else
emit(gen_subrange(tsd).." <= "..gen_vhdl_typecvt(tsd, tss)..";");
end
end
function cgen_vhdl_if(node)
emiti(); emitx("if (");
print("EMIT IF:", node.cond);
for i,v in pairs(node.cond) do print(i,v); end
recurse(node.cond);
emitx(") then\n");
if(node.code_else ~= nil) then
indent_right();
recurse(node.code);
indent_left();
emit("else");
indent_right();
recurse(node.code_else);
indent_left();
emit("end if;");
else
indent_right();
recurse(node.code);
indent_left();
emit("end if;");
end
end
function cgen_vhdl_not(node)
local tsa = node_typesize(node.a);
emitx("not ");
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
emitx(gen_subrange(tsa));
end
end
function cgen_vhdl_op(node, op)
local tsa = node_typesize(node.a);
local tsb = node_typesize(node.b);
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
emitx(gen_subrange(tsa));
end
if(op=="eq") then emitx(" = "); end
if(op=="and") then emitx(" and "); end
if(op=="or") then emitx(" or "); end
if(op=="sub") then emitx(" - "); end
if(op=="add") then emitx(" + "); end
if(tsb.type == EXPRESSION) then
emitx("("); recurse({node.b}); emitx(")");
else
emitx(gen_vhdl_typecvt(tsa, tsb));
end
end
function cgen_vhdl_comment(node)
emitx("-- "..node.str.."\n");
end
-- switch/case statement --
function cgen_vhdl_switch(node)
local tsa = node_typesize(node.a);
emiti(); emitx("case ");
if(tsa.type == EXPRESSION) then
emitx("("); recurse({node.a}); emitx(")");
else
local tsb = {};
tsb.type = SLV;
emitx(gen_vhdl_typecvt(tsb, tsa));
end
emitx(" is\n");
for i,v in pairs(node.code) do
print("CA: ", v.t);
if(v.t == "case") then
emit("when "..gen_vhdl_bin_literal(v.a, tsa.size).." => ");
indent_right();
recurse({v.code});
indent_left();
elseif(v.t == "casedefault") then
emit("when others =>");
indent_right();
recurse({v.code});
indent_left();
end
end
emit("end case;");
end
function recurse(t)
print("recurse: ", t);
for i,v in pairs(t) do
print("-> i ",i,"v ",v, "vt ",v.t);
if(v.t == nil) then
recurse(v);
elseif(v.t == "comment") then
cgen_vhdl_comment(v);
elseif(v.t == "syncprocess") then
cgen_vhdl_syncprocess(v);
elseif(v.t=="assign") then
cgen_vhdl_assign(v);
elseif(v.t=="if") then
cgen_vhdl_if(v);
elseif(v.t=="eq" or v.t=="sub" or v.t=="add" or v.t == "or" or v.t=="and") then
cgen_vhdl_op(v,v.t);
elseif(v.t=="switch") then
cgen_vhdl_switch(v);
elseif(v.t=="not") then
cgen_vhdl_not(v);
else
print("unimpl: "..v.t);
os.exit(-1);
end
end
print("end recurse");
end
cgen_new_snippet();
cgen_vhdl_header();
cgen_vhdl_entity();
recurse(tree);
cgen_vhdl_ending();
cgen_write_current_snippet();
end
[General]
def_graphic_ext=eps
img_extIsRegExp=false
img_extensions=.eps .jpg .jpeg .png .pdf .ps .fig .gif
kileprversion=2
kileversion=2.0.84
lastDocument=regs.tex
masterDocument=
name=wbgen2_doc
pkg_extIsRegExp=false
pkg_extensions=.cls .sty .bbx .cbx .lbx
src_extIsRegExp=false
src_extensions=.tex .ltx .latex .dtx .ins
[Tools]
MakeIndex=
QuickBuild=
[item:intro.tex]
archive=true
column=1
encoding=
highlight=
line=0
mode=
open=false
order=-1
[item:main.tex]
archive=true
column=0
encoding=UTF-8
highlight=LaTeX
line=76
mode=LaTeX
open=true
order=0
[item:processing.tex]
archive=true
column=0
encoding=UTF-8
highlight=LaTeX
line=6
mode=LaTeX
open=true
order=1
[item:regs.tex]
archive=true
column=101
encoding=UTF-8
highlight=LaTeX
line=12
mode=LaTeX
open=true
order=2
[item:title.tex]
archive=true
column=167092456
encoding=
highlight=
line=0
mode=
open=false
order=-1
[item:wbgen2_doc.kilepr]
archive=true
column=7209065
encoding=
highlight=
line=0
mode=
open=false
order=-1
[view-settings,view=0,item:main.tex]
CursorColumn=0
CursorLine=76
[view-settings,view=0,item:processing.tex]
CursorColumn=0
CursorLine=6
[view-settings,view=0,item:regs.tex]
CursorColumn=101
CursorLine=12
-- -*- Mode: LUA; tab-width: 2 -*-
-- wbgen2 - a simple Wishbone slave generator
-- (c) 2010 Tomasz Wlostowski
-- CERN BE-Co-HT
-- LICENSED UNDER GPL v2
function gen_hdl_field_prefix(field, reg)
local field_count;
if(reg.hdl_prefix == nil) then
die("no prefix specified for reg: "..reg.name);
end
field_count = 0;
foreach_subfield(reg, function(field, reg) field_count = field_count+1; end );
if(field.count == 0) then
die("empty reg: "..reg.name);
end
if(field.hdl_prefix == nil) then
if(field_count >1 ) then die("multiple anonymous-prefix fields declared for reg: "..reg.name); end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);
end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix.."_"..field.hdl_prefix);
end
-- generates VHDL for monostable-type field (both same-clock and other-clock)
function gen_hdl_code_monostable(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
-- field.prefix = prefix;
-- monostable type field using WB bus clock
if(field.clock == nil) then
-- WB-synchronous monostable port (bus write-only)
field.signals = { signal(BIT, 0, prefix.."_dly0"),
signal(BIT, 0, prefix.."_int") };
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.acklen = 3;
field.extra_code = vsyncprocess("wb_clk_i", "rst_n_i", {
vreset (0, {
va(prefix.."_dly0", 0);
va(prefix.."_o", 0);
});
vposedge {
va(prefix.."_dly0", prefix.."_int");
va(prefix.."_o", vand(prefix.."_int", vnot(prefix.."_dly0")));
};
});
field.reset_code_main = { va(prefix.."_int", 0) };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { };
field.ackgen_code = { va(prefix.."_int", 0) };
else
-- WB-asynchronous monostable port (bus write-only)
field.signals = { signal(BIT, 0, prefix.."_int"),
signal(BIT, 0, prefix.."_int_delay"),
signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1"),
signal(BIT, 0, prefix.."_sync2") };
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for asynchronous (clock: "..field.clock..") MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.acklen = 5;
field.extra_code = { vsyncprocess(field.clock, "rst_n_i", {
vreset (0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
va(prefix.."_sync2", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_sync2", prefix.."_sync1");
va(prefix.."_o", vand(prefix.."_sync2", vnot(prefix.."_sync1")));
});
}); };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_int_delay", 0); };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset));
va(prefix.."_int_delay", vi("wrdata_reg", field.offset)); };
field.read_code = { };
field.ackgen_code_pre = { va(prefix.."_int", prefix.."_int_delay");
va(prefix.."_int_delay", 0); };
end
end
-- generates code for BIT-type field
function gen_hdl_code_bit(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
field.prefix = prefix;
-- BIT-type field using WB bus clock
if(field.clock == nil) then
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.signals = { signal(BIT, 0, prefix.."_int") };
field.acklen = 1;
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { va(prefix.."_o", prefix.."_int") };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(read-only) bitfield
field.ports = { port(BIT, 0, "in", prefix.."_i", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.reset_code_main = { };
field.extra_code = { };
elseif (field.access == ACC_WO_RO) then
-- bus(write-only), dev(read-only) bitfield - unsupported yet (use RW/RO type instead)
die("WO-RO type unsupported yet ("..field.name..")");
elseif (field.access == ACC_RW_RW) then
-- dual-write bitfield (both from the bus and the device)
if(field.load == LOAD_EXT) then
-- external load type (e.g. the register itself is placed outside the WB slave, which only outputs new value and asserts the "load" signal for single clock cycle upon bus write.
field.ports = { port(BIT, 0, "out", prefix.."_o", "Ports for BIT field: '"..field.name.."' in reg: '"..reg.name.."'"),
port(BIT, 0, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.acklen = 1;
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.write_code = { va(prefix.."_load_o", 1) };
field.extra_code = { va(prefix.."_o", vi("wrdata_reg", field.offset)) };
field.ackgen_code_pre = { va(prefix.."_load_o", 0) };
field.ackgen_code = { va(prefix.."_load_o", 0) };
field.reset_code_main = { va(prefix.."_load_o", 0) };
else
die("internal RW/RW register storage unsupported yet ("..field.name..")");
end
end
else
-- asynchronous bit-type register
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield, asynchronous
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(BIT, 0, prefix.."_int"),
signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1") };
field.acklen = 4;
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RW/RO, wb_clk_i <-> "..field.clock..")");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_o", prefix.."_sync1");
});
});
};
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) bitfield, asynchronous
field.ports = { port(BIT, 0, "in", prefix.."_i", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1") };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_sync1") };
field.reset_code_main = { };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RO/WO, "..field.clock.." -> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_i");
va(prefix.."_sync1", prefix.."_sync0");
});
});
};
elseif (field.access == ACC_RW_RW) then
-- asynchronous dual-write bitfield. Tough shit :/
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW bit fields");
end
local comment = "Ports for asynchronous (clock: "..field.clock..") RW/RW BIT field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(BIT, 0, "out", prefix.."_o", comment),
port(BIT, 0, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.signals = { signal(BIT, 0, prefix.."_int_read"),
signal(BIT, 0, prefix.."_int_write"),
signal(BIT, 0, prefix.."_lw"),
signal(BIT, 0, prefix.."_lw_delay"),
signal(BIT, 0, prefix.."_lw_read_in_progress"),
signal(BIT, 0, prefix.."_lw_s0"),
signal(BIT, 0, prefix.."_lw_s1"),
signal(BIT, 0, prefix.."_lw_s2"),
signal(BIT, 0, prefix.."_rwsel") };
field.acklen = 6;
field.write_code = { va(prefix.."_int_write", vi("wrdata_reg", field.offset));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vi("rddata_reg", field.offset), prefix.."_int_read");
va(prefix.."_lw_read_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous BIT register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_int_read", 0);
va(prefix.."_load_o", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
elseif (field.access == ACC_WO_RO) then
die("WO-RO type unsupported yet ("..field.name..")");
end
end
end
-- generates the bit-range for accessing a certain register field from WB-bus
function vir(name, field)
local syn = {};
syn.t="index";
syn.name=name;
syn.h=field.offset+field.size-1;
syn.l=field.offset;
return syn;
end
-- generates code for slv, signed or unsigned fields
function gen_hdl_code_slv(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
field.prefix = prefix;
-- synchronous signed/unsigned/slv field
if(field.clock == nil) then
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv
field.ports = { port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(SLV, field.size, prefix.."_int") };
field.acklen = 1;
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field)); };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { va(prefix.."_int", 0); };
field.extra_code = { va(prefix.."_o", prefix.."_int"); };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) slv
field.ports = { port(field.type, field.size, "in", prefix.."_i", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.reset_code_main = { };
field.extra_code = { };
elseif (field.access == ACC_RW_RW) then
-- bus(read-write), dev(read-write) slv
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW slv/signed/unsigned fields");
end
field.ports = { port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'"),
port(field.type, field.size, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.acklen = 1;
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.write_code = { va(prefix.."_load_o", 0); };
field.extra_code = { va(prefix.."_o", vir("wrdata_reg", field)); };
field.ackgen_code_pre = { va(prefix.."_load_o", 0);};
field.ackgen_code = { va(prefix.."_load_o", 0); };
field.reset_code_main = { va(prefix.."_load_o", 0); };
end
else
-- asynchronous register. Even tougher shit :(
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv/signed/unsigned
local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "out", prefix.."_o", comment) };
field.signals = { signal(SLV, field.size, prefix.."_int"),
signal(BIT, 0, prefix.."_swb"),
signal(BIT, 0, prefix.."_swb_delay"),
signal(BIT, 0, prefix.."_swb_s0"),
signal(BIT, 0, prefix.."_swb_s1"),
signal(BIT, 0, prefix.."_swb_s2") };
field.acklen = 4;
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field));
va(prefix.."_swb", 1);
va(prefix.."_swb_delay", 1); };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_swb", 0);
va(prefix.."_swb_delay", 0); };
field.ackgen_code_pre = { va(prefix.."_swb", prefix.."_swb_delay");
va(prefix.."_swb_delay", 0); };
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/RO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_swb_s0", 0);
va(prefix.."_swb_s1", 0);
va(prefix.."_swb_s2", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_swb_s0", prefix.."_swb");
va(prefix.."_swb_s1", prefix.."_swb_s0");
va(prefix.."_swb_s2", prefix.."_swb_s1");
vif(vand(vequal(prefix.."_swb_s2", 0), vequal(prefix.."_swb_s1", 1)), {
va(prefix.."_o", prefix.."_int");
});
});
});
};
elseif(field.access == ACC_RO_WO) then
-- bus(read-write), dev(read-only) slv
local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "in", prefix.."_i", comment) };
field.signals = { signal(SLV, field.size, prefix.."_int"),
signal(BIT, 0, prefix.."_lwb"),
signal(BIT, 0, prefix.."_lwb_delay"),
signal(BIT, 0, prefix.."_lwb_in_progress"),
signal(BIT, 0, prefix.."_lwb_s0"),
signal(BIT, 0, prefix.."_lwb_s1"),
signal(BIT, 0, prefix.."_lwb_s2") };
field.acklen = 6;
field.write_code = { };
field.read_code = { va(prefix.."_lwb", 1);
va(prefix.."_lwb_delay", 1);
va(prefix.."_lwb_in_progress", 1); };
field.reset_code_main = { va(prefix.."_lwb", 0);
va(prefix.."_lwb_delay", 0);
va(prefix.."_lwb_in_progress", 0); };
field.ackgen_code_pre = { va(prefix.."_lwb", prefix.."_lwb_delay");
va(prefix.."_lwb_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lwb_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int");
va(prefix.."_lwb_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RO/WO, "..field.clock.." <-> wb_clk_i)"),
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lwb_s0", 0);
va(prefix.."_lwb_s1", 0);
va(prefix.."_lwb_s2", 0);
va(prefix.."_int", 0);
});
vposedge({
va(prefix.."_lwb_s0", prefix.."_lwb");
va(prefix.."_lwb_s1", prefix.."_lwb_s0");
va(prefix.."_lwb_s2", prefix.."_lwb_s1");
vif(vand(vequal(prefix.."_lwb_s1", 1), vequal(prefix.."_lwb_s2", 0)), {
va(prefix.."_int", prefix.."_i");
});
});
});
};
elseif(field.access == ACC_RW_RW) then
-- async bus(read-write), dev(read-write) slv. gooosh...
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW slv/signed/unsigned fields");
end
local comment = "Ports for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "out", prefix.."_o", comment),
port(field.type, field.size, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.signals = { signal(SLV, field.size, prefix.."_int_read"),
signal(SLV, field.size, prefix.."_int_write"),
signal(BIT, 0, prefix.."_lw"),
signal(BIT, 0, prefix.."_lw_delay"),
signal(BIT, 0, prefix.."_lw_read_in_progress"),
signal(BIT, 0, prefix.."_lw_s0"),
signal(BIT, 0, prefix.."_lw_s1"),
signal(BIT, 0, prefix.."_lw_s2"),
signal(BIT, 0, prefix.."_rwsel") };
field.acklen = 6;
field.write_code = { va(prefix.."_int_write", vir("wrdata_reg", field));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif (vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int_read");
});
va(prefix.."_lw_read_in_progress", 0);
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_o", 0);
va(prefix.."_load_o", 0);
va(prefix.."_int_read", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
end
end
end
function gen_hdl_code_passthrough(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
if(field.clock == nil) then
-- sync pass-through
local comment = "Ports for PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(SLV, field.size, "out", prefix.."_o", comment),
port(BIT, 0, "out", prefix.."_wr_o") };
field.acklen = 1;
field.reset_code_main = { va(prefix.."_wr_o", 0); };
field.read_code = {};
field.write_code = { va(prefix.."_wr_o", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_o", 0); };
field.ackgen_code = { va(prefix.."_wr_o", 0); };
field.extra_code = { vcomment("-- pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field)); }
else
local comment = "Ports for asynchronous (clock: "..field.clock..") PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(SLV, field.size, "out", prefix.."_o", comment),
port(BIT, 0, "out", prefix.."_wr_o") };
field.signals = { signal(BIT, 0, prefix.."_wr_int"),
signal(BIT, 0, prefix.."_wr_int_delay"),
signal(BIT, 0, prefix.."_wr_sync0"),
signal(BIT, 0, prefix.."_wr_sync1"),
signal(BIT, 0, prefix.."_wr_sync2") };
field.acklen = 4;
field.reset_code_main = { va(prefix.."_wr_int", 0);
va(prefix.."_wr_int_delay", 0); };
field.read_code = {};
field.write_code = { va(prefix.."_wr_int", 1);
va(prefix.."_wr_int_delay", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_int", prefix.."_wr_int_delay");
va(prefix.."_wr_int_delay", 0); };
field.extra_code = { vcomment("pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field));
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_wr_sync0", 0);
va(prefix.."_wr_sync1", 0);
va(prefix.."_wr_sync2", 0);
});
vposedge({
va(prefix.."_wr_sync0", prefix.."_wr_int");
va(prefix.."_wr_sync1", prefix.."_wr_sync0");
va(prefix.."_wr_sync2", prefix.."_wr_sync1");
va(prefix.."_wr_o", vand(prefix.."_wr_sync1", vnot(prefix.."_wr_sync2")));
});
});
}
end
end
-- generates VHDL code for single register field
function gen_hdl_code_reg_field(field, reg)
if(field.type == MONOSTABLE) then
gen_hdl_code_monostable(field, reg);
elseif(field.type == BIT) then
gen_hdl_code_bit(field, reg);
elseif(field.type == SIGNED or field.type == UNSIGNED or field.type == SLV) then
gen_hdl_code_slv(field, reg);
elseif(field.type == PASS_THROUGH) then
gen_hdl_code_passthrough(field, reg);
end
end
-- generates VHDL for single register
function gen_hdl_code_reg(reg)
foreach_subfield(reg, function(field, reg) gen_hdl_code_reg_field(field, reg); end );
end
function gen_hdl_block_select_bits()
return vi("rwaddr_reg", address_bus_width-1, (address_bus_width - address_bus_select_bits));
end
-- generates the entire VHDL register-bank access stuff
function gen_hdl_regbank()
local s;
local ramcount = 0;
-- vhdl_new_code();
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
gen_hdl_code_reg(reg);
end
end );
-- vhdl ("");
local resetcode={};
local ackgencode={};
local preackcode={};
foreach_field(function(field, reg)
-- print("rstcode: ", field.reset_code_main);
table_join(resetcode, field.reset_code_main);
end );
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
table_join(ackgencode, field.ackgen_code);
end );
end
end);
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
table_join(preackcode, field.ackgen_code_pre);
end );
end
end);
-- count the RAMs in the design
foreach_reg(function(reg)
if(reg.__type == TYPE_RAM) then
ramcount = ramcount + 1;
end
end
);
local fsmcode={};
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
local acklen = find_max(reg, "acklen");
local rcode={};
local wcode={};
foreach_subfield(reg, function(field, reg) table_join(wcode, field.write_code); end );
foreach_subfield(reg, function(field, reg) table_join(rcode, field.read_code); end );
local rwcode = {
vif(vequal("wb_we_i" ,1), {
wcode
}, {
rcode
}); };
table_join(rwcode, { va("wb_ack_regbank", csel((acklen==1),1,0)); } );
table_join(rwcode, { va("ack_cntr", math.max(acklen-1, 0)); } );
table_join(rwcode, { va("ack_in_progress", 1); } );
if(regbank_address_bits > 0) then
rwcode = { vcase(reg.base, rwcode); };
end
table_join(fsmcode, rwcode);
end
end );
-- vhdl ("if ( wb_sel_i = '1' and wb_cyc_i = '1' and wb_stb_i = '1' ) then");
if(regbank_address_bits > 0) then
table_join(fsmcode, { vcasedefault({
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("wb_ack_regbank", 0);
}); });
fsmcode = { vswitch(vi("rwaddr_reg", regbank_address_bits - 1, 0), fsmcode); };
end
fsmcode = { vif(vand(vequal("wb_cyc_i", 1), vequal("wb_stb_i", 1)), { fsmcode }, { va("wb_ack_regbank", 0) }); };
local code = {
vsyncprocess("wb_clk_i", "rst_n_i", {
vreset(0, {
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("rddata_reg", 0);
resetcode
});
vposedge ({
vif(vequal("ack_in_progress",1), {
vif(vequal("ack_cntr", 0), {
ackgencode;
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
}, {
preackcode;
va("ack_cntr", vsub("ack_cntr", 1));
vif(vequal("ack_cntr", 1), {
va("wb_ack_regbank", 1);
} , {
va("wb_ack_regbank", 0);
});
});}, { -- else ack_in_progress = 0
fsmcode
});
});
});
va("wb_data_o", "rddata_reg");
va("wrdata_reg", "wb_data_i");
va("rwaddr_reg", "wb_addr_i");
};
-- vhdl_indent_right();
foreach_reg(function(reg)
if(reg.extra_code ~= nil) then
table_join(code, {vcomment("extra code for reg/fifo/mem: "..reg.name);});
table_join(code, reg.extra_code);
end
foreach_subfield(reg, function(field, reg) table_join(code, field.extra_code); end );
end);
return code;
end
-- -*- Mode: LUA; tab-width: 2 -*-
-- wbgen2 - a simple Wishbone slave generator
-- (c) 2010 Tomasz Wlostowski
-- CERN BE-Co-HT
-- LICENSED UNDER GPL v2
function gen_hdl_field_prefix(field, reg)
local field_count;
if(reg.hdl_prefix == nil) then
die("no prefix specified for reg: "..reg.name);
end
field_count = 0;
foreach_subfield(reg, function(field, reg) field_count = field_count+1; end );
if(field.count == 0) then
die("empty reg: "..reg.name);
end
if(field.hdl_prefix == nil) then
if(field_count >1 ) then die("multiple anonymous-prefix fields declared for reg: "..reg.name); end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);
end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix.."_"..field.hdl_prefix);
end
-- generates VHDL for monostable-type field (both same-clock and other-clock)
function gen_hdl_code_monostable(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
-- field.prefix = prefix;
-- monostable type field using WB bus clock
if(field.clock == nil) then
-- WB-synchronous monostable port (bus write-only)
field.signals = { signal(BIT, 0, prefix.."_dly0"),
signal(BIT, 0, prefix.."_int") };
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.acklen = 3;
field.extra_code = vsyncprocess("wb_clk_i", "rst_n_i", {
vreset (0, {
va(prefix.."_dly0", 0);
va(prefix.."_o", 0);
});
vposedge {
va(prefix.."_dly0", prefix.."_int");
va(prefix.."_o", vand(prefix.."_int", vnot(prefix.."_dly0")));
};
});
field.reset_code_main = { va(prefix.."_int", 0) };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { };
field.ackgen_code = { va(prefix.."_int", 0) };
else
-- WB-asynchronous monostable port (bus write-only)
field.signals = { signal(BIT, 0, prefix.."_int"),
signal(BIT, 0, prefix.."_int_delay"),
signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1"),
signal(BIT, 0, prefix.."_sync2") };
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for asynchronous (clock: "..field.clock..") MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.acklen = 5;
field.extra_code = { vsyncprocess(field.clock, "rst_n_i", {
vreset (0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
va(prefix.."_sync2", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_sync2", prefix.."_sync1");
va(prefix.."_o", vand(prefix.."_sync2", vnot(prefix.."_sync1")));
});
}); };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_int_delay", 0); };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset));
va(prefix.."_int_delay", vi("wrdata_reg", field.offset)); };
field.read_code = { };
field.ackgen_code_pre = { va(prefix.."_int", prefix.."_int_delay");
va(prefix.."_int_delay", 0); };
end
end
-- generates code for BIT-type field
function gen_hdl_code_bit(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
field.prefix = prefix;
-- BIT-type field using WB bus clock
if(field.clock == nil) then
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.signals = { signal(BIT, 0, prefix.."_int") };
field.acklen = 1;
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { va(prefix.."_o", prefix.."_int") };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(read-only) bitfield
field.ports = { port(BIT, 0, "in", prefix.."_i", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.reset_code_main = { };
field.extra_code = { };
elseif (field.access == ACC_WO_RO) then
-- bus(write-only), dev(read-only) bitfield - unsupported yet (use RW/RO type instead)
die("WO-RO type unsupported yet ("..field.name..")");
elseif (field.access == ACC_RW_RW) then
-- dual-write bitfield (both from the bus and the device)
if(field.load == LOAD_EXT) then
-- external load type (e.g. the register itself is placed outside the WB slave, which only outputs new value and asserts the "load" signal for single clock cycle upon bus write.
field.ports = { port(BIT, 0, "out", prefix.."_o", "Ports for BIT field: '"..field.name.."' in reg: '"..reg.name.."'"),
port(BIT, 0, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.acklen = 1;
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.write_code = { va(prefix.."_load_o", 1) };
field.extra_code = { va(prefix.."_o", vi("wrdata_reg", field.offset)) };
field.ackgen_code_pre = { va(prefix.."_load_o", 0) };
field.ackgen_code = { va(prefix.."_load_o", 0) };
field.reset_code_main = { va(prefix.."_load_o", 0) };
else
die("internal RW/RW register storage unsupported yet ("..field.name..")");
end
end
else
-- asynchronous bit-type register
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield, asynchronous
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(BIT, 0, prefix.."_int"),
signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1") };
field.acklen = 4;
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RW/RO, wb_clk_i <-> "..field.clock..")");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_o", prefix.."_sync1");
});
});
};
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) bitfield, asynchronous
field.ports = { port(BIT, 0, "in", prefix.."_i", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(BIT, 0, prefix.."_sync0"),
signal(BIT, 0, prefix.."_sync1") };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_sync1") };
field.reset_code_main = { };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RO/WO, "..field.clock.." -> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_i");
va(prefix.."_sync1", prefix.."_sync0");
});
});
};
elseif (field.access == ACC_RW_RW) then
-- asynchronous dual-write bitfield. Tough shit :/
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW bit fields");
end
local comment = "Ports for asynchronous (clock: "..field.clock..") RW/RW BIT field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(BIT, 0, "out", prefix.."_o", comment),
port(BIT, 0, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.signals = { signal(BIT, 0, prefix.."_int_read"),
signal(BIT, 0, prefix.."_int_write"),
signal(BIT, 0, prefix.."_lw"),
signal(BIT, 0, prefix.."_lw_delay"),
signal(BIT, 0, prefix.."_lw_read_in_progress"),
signal(BIT, 0, prefix.."_lw_s0"),
signal(BIT, 0, prefix.."_lw_s1"),
signal(BIT, 0, prefix.."_lw_s2"),
signal(BIT, 0, prefix.."_rwsel") };
field.acklen = 6;
field.write_code = { va(prefix.."_int_write", vi("wrdata_reg", field.offset));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vi("rddata_reg", field.offset), prefix.."_int_read");
va(prefix.."_lw_read_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous BIT register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_int_read", 0);
va(prefix.."_load_o", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
elseif (field.access == ACC_WO_RO) then
die("WO-RO type unsupported yet ("..field.name..")");
end
end
end
-- generates the bit-range for accessing a certain register field from WB-bus
function vir(name, field)
local syn = {};
syn.t="index";
syn.name=name;
syn.h=field.offset+field.size-1;
syn.l=field.offset;
return syn;
end
-- generates code for slv, signed or unsigned fields
function gen_hdl_code_slv(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
field.prefix = prefix;
-- synchronous signed/unsigned/slv field
if(field.clock == nil) then
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv
field.ports = { port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(SLV, field.size, prefix.."_int") };
field.acklen = 1;
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field)); };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { va(prefix.."_int", 0); };
field.extra_code = { va(prefix.."_o", prefix.."_int"); };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) slv
field.ports = { port(field.type, field.size, "in", prefix.."_i", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.reset_code_main = { };
field.extra_code = { };
elseif (field.access == ACC_RW_RW) then
-- bus(read-write), dev(read-write) slv
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW slv/signed/unsigned fields");
end
field.ports = { port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'"),
port(field.type, field.size, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.acklen = 1;
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.write_code = { va(prefix.."_load_o", 0); };
field.extra_code = { va(prefix.."_o", vir("wrdata_reg", field)); };
field.ackgen_code_pre = { va(prefix.."_load_o", 0);};
field.ackgen_code = { va(prefix.."_load_o", 0); };
field.reset_code_main = { va(prefix.."_load_o", 0); };
end
else
-- asynchronous register. Even tougher shit :(
if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv/signed/unsigned
local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "out", prefix.."_o", comment) };
field.signals = { signal(SLV, field.size, prefix.."_int"),
signal(BIT, 0, prefix.."_swb"),
signal(BIT, 0, prefix.."_swb_delay"),
signal(BIT, 0, prefix.."_swb_s0"),
signal(BIT, 0, prefix.."_swb_s1"),
signal(BIT, 0, prefix.."_swb_s2") };
field.acklen = 4;
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field));
va(prefix.."_swb", 1);
va(prefix.."_swb_delay", 1); };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_swb", 0);
va(prefix.."_swb_delay", 0); };
field.ackgen_code_pre = { va(prefix.."_swb", prefix.."_swb_delay");
va(prefix.."_swb_delay", 0); };
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/RO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_swb_s0", 0);
va(prefix.."_swb_s1", 0);
va(prefix.."_swb_s2", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_swb_s0", prefix.."_swb");
va(prefix.."_swb_s1", prefix.."_swb_s0");
va(prefix.."_swb_s2", prefix.."_swb_s1");
vif(vand(vequal(prefix.."_swb_s2", 0), vequal(prefix.."_swb_s1", 1)), {
va(prefix.."_o", prefix.."_int");
});
});
});
};
elseif(field.access == ACC_RO_WO) then
-- bus(read-write), dev(read-only) slv
local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "in", prefix.."_i", comment) };
field.signals = { signal(SLV, field.size, prefix.."_int"),
signal(BIT, 0, prefix.."_lwb"),
signal(BIT, 0, prefix.."_lwb_delay"),
signal(BIT, 0, prefix.."_lwb_in_progress"),
signal(BIT, 0, prefix.."_lwb_s0"),
signal(BIT, 0, prefix.."_lwb_s1"),
signal(BIT, 0, prefix.."_lwb_s2") };
field.acklen = 6;
field.write_code = { };
field.read_code = { va(prefix.."_lwb", 1);
va(prefix.."_lwb_delay", 1);
va(prefix.."_lwb_in_progress", 1); };
field.reset_code_main = { va(prefix.."_lwb", 0);
va(prefix.."_lwb_delay", 0);
va(prefix.."_lwb_in_progress", 0); };
field.ackgen_code_pre = { va(prefix.."_lwb", prefix.."_lwb_delay");
va(prefix.."_lwb_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lwb_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int");
va(prefix.."_lwb_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RO/WO, "..field.clock.." <-> wb_clk_i)"),
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lwb_s0", 0);
va(prefix.."_lwb_s1", 0);
va(prefix.."_lwb_s2", 0);
va(prefix.."_int", 0);
});
vposedge({
va(prefix.."_lwb_s0", prefix.."_lwb");
va(prefix.."_lwb_s1", prefix.."_lwb_s0");
va(prefix.."_lwb_s2", prefix.."_lwb_s1");
vif(vand(vequal(prefix.."_lwb_s1", 1), vequal(prefix.."_lwb_s2", 0)), {
va(prefix.."_int", prefix.."_i");
});
});
});
};
elseif(field.access == ACC_RW_RW) then
-- async bus(read-write), dev(read-write) slv. gooosh...
if(field.load ~= LOAD_EXT) then
die("Only external load is supported for RW/RW slv/signed/unsigned fields");
end
local comment = "Ports for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(field.type, field.size, "out", prefix.."_o", comment),
port(field.type, field.size, "in", prefix.."_i"),
port(BIT, 0, "out", prefix.."_load_o") };
field.signals = { signal(SLV, field.size, prefix.."_int_read"),
signal(SLV, field.size, prefix.."_int_write"),
signal(BIT, 0, prefix.."_lw"),
signal(BIT, 0, prefix.."_lw_delay"),
signal(BIT, 0, prefix.."_lw_read_in_progress"),
signal(BIT, 0, prefix.."_lw_s0"),
signal(BIT, 0, prefix.."_lw_s1"),
signal(BIT, 0, prefix.."_lw_s2"),
signal(BIT, 0, prefix.."_rwsel") };
field.acklen = 6;
field.write_code = { va(prefix.."_int_write", vir("wrdata_reg", field));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif (vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int_read");
});
va(prefix.."_lw_read_in_progress", 0);
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_o", 0);
va(prefix.."_load_o", 0);
va(prefix.."_int_read", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
end
end
end
function gen_hdl_code_passthrough(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
if(field.clock == nil) then
-- sync pass-through
local comment = "Ports for PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(SLV, field.size, "out", prefix.."_o", comment),
port(BIT, 0, "out", prefix.."_wr_o") };
field.acklen = 1;
field.reset_code_main = { va(prefix.."_wr_o", 0); };
field.read_code = {};
field.write_code = { va(prefix.."_wr_o", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_o", 0); };
field.ackgen_code = { va(prefix.."_wr_o", 0); };
field.extra_code = { vcomment("-- pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field)); }
else
local comment = "Ports for asynchronous (clock: "..field.clock..") PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";
field.ports = { port(SLV, field.size, "out", prefix.."_o", comment),
port(BIT, 0, "out", prefix.."_wr_o") };
field.signals = { signal(BIT, 0, prefix.."_wr_int"),
signal(BIT, 0, prefix.."_wr_int_delay"),
signal(BIT, 0, prefix.."_wr_sync0"),
signal(BIT, 0, prefix.."_wr_sync1"),
signal(BIT, 0, prefix.."_wr_sync2") };
field.acklen = 4;
field.reset_code_main = { va(prefix.."_wr_int", 0);
va(prefix.."_wr_int_delay", 0); };
field.read_code = {};
field.write_code = { va(prefix.."_wr_int", 1);
va(prefix.."_wr_int_delay", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_int", prefix.."_wr_int_delay");
va(prefix.."_wr_int_delay", 0); };
field.extra_code = { vcomment("pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field));
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_wr_sync0", 0);
va(prefix.."_wr_sync1", 0);
va(prefix.."_wr_sync2", 0);
});
vposedge({
va(prefix.."_wr_sync0", prefix.."_wr_int");
va(prefix.."_wr_sync1", prefix.."_wr_sync0");
va(prefix.."_wr_sync2", prefix.."_wr_sync1");
va(prefix.."_wr_o", vand(prefix.."_wr_sync1", vnot(prefix.."_wr_sync2")));
});
});
}
end
end
-- generates VHDL code for single register field
function gen_hdl_code_reg_field(field, reg)
if(field.type == MONOSTABLE) then
gen_hdl_code_monostable(field, reg);
elseif(field.type == BIT) then
gen_hdl_code_bit(field, reg);
elseif(field.type == SIGNED or field.type == UNSIGNED or field.type == SLV) then
gen_hdl_code_slv(field, reg);
elseif(field.type == PASS_THROUGH) then
gen_hdl_code_passthrough(field, reg);
end
end
-- generates VHDL for single register
function gen_hdl_code_reg(reg)
foreach_subfield(reg, function(field, reg) gen_hdl_code_reg_field(field, reg); end );
end
function gen_hdl_block_select_bits()
return vi("rwaddr_reg", address_bus_width-1, (address_bus_width - address_bus_select_bits));
end
-- generates the entire VHDL register-bank access stuff
function gen_hdl_regbank()
local s;
local ramcount = 0;
-- vhdl_new_code();
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
gen_hdl_code_reg(reg);
end
end );
-- vhdl ("");
local resetcode={};
local ackgencode={};
local preackcode={};
foreach_field(function(field, reg)
-- print("rstcode: ", field.reset_code_main);
table_join(resetcode, field.reset_code_main);
end );
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
table_join(ackgencode, field.ackgen_code);
end );
end
end);
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
table_join(preackcode, field.ackgen_code_pre);
end );
end
end);
-- count the RAMs in the design
foreach_reg(function(reg)
if(reg.__type == TYPE_RAM) then
ramcount = ramcount + 1;
end
end
);
local fsmcode={};
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
local acklen = find_max(reg, "acklen");
local rcode={};
local wcode={};
foreach_subfield(reg, function(field, reg) table_join(wcode, field.write_code); end );
foreach_subfield(reg, function(field, reg) table_join(rcode, field.read_code); end );
local rwcode = {
vif(vequal("wb_we_i" ,1), {
wcode
}, {
rcode
}); };
table_join(rwcode, { va("wb_ack_regbank", csel((acklen==1),1,0)); } );
table_join(rwcode, { va("ack_cntr", math.max(acklen-1, 0)); } );
table_join(rwcode, { va("ack_in_progress", 1); } );
if(regbank_address_bits > 0) then
rwcode = { vcase(reg.base, rwcode); };
end
table_join(fsmcode, rwcode);
end
end );
-- vhdl ("if ( wb_sel_i = '1' and wb_cyc_i = '1' and wb_stb_i = '1' ) then");
if(regbank_address_bits > 0) then
table_join(fsmcode, { vcasedefault({
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("wb_ack_regbank", 0);
}); });
fsmcode = { vswitch(vi("rwaddr_reg", regbank_address_bits - 1, 0), fsmcode); };
end
fsmcode = { vif(vand(vequal("wb_cyc_i", 1), vequal("wb_stb_i", 1)), { fsmcode }, { va("wb_ack_regbank", 0) }); };
local code = {
vsyncprocess("wb_clk_i", "rst_n_i", {
vreset(0, {
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("rddata_reg", 0);
resetcode
});
vposedge ({
vif(vequal("ack_in_progress",1), {
vif(vequal("ack_cntr", 0), {
ackgencode;
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
}, {
preackcode;
va("ack_cntr", vsub("ack_cntr", 1));
vif(vequal("ack_cntr", 1), {
va("wb_ack_regbank", 1);
} , {
va("wb_ack_regbank", 0);
});
});}, { -- else ack_in_progress = 0
fsmcode
});
});
});
va("wb_data_o", "rddata_reg");
va("wrdata_reg", "wb_data_i");
va("rwaddr_reg", "wb_addr_i");
};
-- vhdl_indent_right();
foreach_reg(function(reg)
if(reg.extra_code ~= nil) then
table_join(code, {vcomment("extra code for reg/fifo/mem: "..reg.name);});
table_join(code, reg.extra_code);
end
foreach_subfield(reg, function(field, reg) table_join(code, field.extra_code); end );
end);
return code;
end
......@@ -2,12 +2,20 @@
wbgen2_version="0.3"
wbgen2_libdir="/home/slayer/wbgen2-dev"
wbgen2_libdir="."
device_family="altera_cyclone3";
options = {};
options.reset_type = "asynchronous";
options.target_interconnect = "wishbone";
dofile(wbgen2_libdir.."/wbgen_common.lua");
dofile(wbgen2_libdir.."/wbgen_vhdl.lua");
dofile(wbgen2_libdir.."/cgen_common.lua");
dofile(wbgen2_libdir.."/cgen_vhdl.lua");
dofile(wbgen2_libdir.."/cgen_verilog.lua");
dofile(wbgen2_libdir.."/wbgen_regbank.lua");
dofile(wbgen2_libdir.."/wbgen_rams.lua");
......@@ -46,7 +54,7 @@ function parse_args(arg)
local sw = arg[n];
if(sw == "-vo") then
output_vhdl_file = chk_nil(arg[n+1], "VHDL output filename expected");
options.output_hdl_file = chk_nil(arg[n+1], "HDL output filename expected");
n=n+2;
elseif(sw == "-co") then
output_c_file = chk_nil(arg[n+1], "C header output filename expected");
......@@ -97,9 +105,10 @@ assign_addresses();
--foreach_reg(gen_vhdl_signals);
--foreach_reg(gen_vhdl_constants);
tree=gen_hdl_regbank();
gen_vhdl_code(output_vhdl_file);
cgen_build_signals_ports();
cgen_generate_hdl_init(options.output_hdl_file)
cgen_generate_vhdl_code(tree);
cgen_generate_hdl_done();
if(vlog_gen_reg_constants) then
gen_vlog_constants(output_vlog_constants_file);
end
......@@ -36,6 +36,8 @@ SIGNED = 0x8;
UNSIGNED = 0x10;
ENUM = 0x20;
PASS_THROUGH = 0x40;
INTEGER = 0x80;
EXPRESSION = 0x100;
LOAD_INT = 1;
LOAD_EXT = 2;
......@@ -415,4 +417,4 @@ function remove_duplicates(t)
i=i+1;
end
end
\ No newline at end of file
end
......@@ -5,7 +5,7 @@
-- CERN BE-Co-HT
-- LICENSED UNDER GPL v2
function gen_vhdl_field_prefix(field, reg)
function gen_hdl_field_prefix(field, reg)
local field_count;
if(reg.hdl_prefix == nil) then
......@@ -19,18 +19,20 @@ function gen_vhdl_field_prefix(field, reg)
die("empty reg: "..reg.name);
end
if(field.prefix == nil) then
if(field.hdl_prefix == nil) then
if(field_count >1 ) then die("multiple anonymous-prefix fields declared for reg: "..reg.name); end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);
end
return string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix.."_"..field.hdl_prefix);
end
-- generates VHDL for monostable-type field (both same-clock and other-clock)
function gen_vhdl_code_monostable(field, reg)
local prefix = gen_vhdl_field_prefix(field, reg);
function gen_hdl_code_monostable(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
-- field.prefix = prefix;
......@@ -43,21 +45,21 @@ function gen_vhdl_code_monostable(field, reg)
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.acklen = 3;
field.extra_code = {"process (wb_clk_i, rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_dly0 <= '0';",
prefix.."_o <= '0';",
"elsif rising_edge(wb_clk_i) then",
prefix.."_dly0 <= "..prefix.."_int;",
prefix.."_o <= "..prefix.."_int and (not "..prefix.."_dly0);",
"end if;",
"end process;" };
field.reset_code_main = { prefix.."_int <= '0';" };
field.write_code = { prefix.."_int <= wb_data_i("..field.offset..");" };
field.read_code = { "" };
field.ackgen_code = { prefix.."_int <= '0';" };
field.extra_code = vsyncprocess("wb_clk_i", "rst_n_i", {
vreset (0, {
va(prefix.."_dly0", 0);
va(prefix.."_o", 0);
});
vposedge {
va(prefix.."_dly0", prefix.."_int");
va(prefix.."_o", vand(prefix.."_int", vnot(prefix.."_dly0")));
};
});
field.reset_code_main = { va(prefix.."_int", 0) };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { };
field.ackgen_code = { va(prefix.."_int", 0) };
else
-- WB-asynchronous monostable port (bus write-only)
......@@ -71,38 +73,41 @@ function gen_vhdl_code_monostable(field, reg)
field.acklen = 5;
field.extra_code = { "process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_o <= '0';",
prefix.."_sync0 <= '0';",
prefix.."_sync1 <= '0';",
prefix.."_sync2 <= '0';",
"elsif rising_edge("..field.clock..") then",
prefix.."_sync0 <= "..prefix.."_int;",
prefix.."_sync1 <= "..prefix.."_sync0;",
prefix.."_sync2 <= "..prefix.."_sync1;",
prefix.."_o <= "..prefix.."_sync2 and (not "..prefix.."_sync1);",
"end if;",
"end process;" };
field.reset_code_main = { prefix.."_int <= '0';",
prefix.."_int_delay <= '0';" };
field.write_code = { prefix.."_int <= wb_data_i("..field.offset..");",
prefix.."_int_delay <= wb_data_i("..field.offset..");" };
field.read_code = { "" };
field.ackgen_code_pre = { prefix.."_int <= "..prefix.."_int_delay;",
prefix.."_int_delay <= '0';" };
field.extra_code = { vsyncprocess(field.clock, "rst_n_i", {
vreset (0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
va(prefix.."_sync2", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_sync2", prefix.."_sync1");
va(prefix.."_o", vand(prefix.."_sync2", vnot(prefix.."_sync1")));
});
}); };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_int_delay", 0); };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset));
va(prefix.."_int_delay", vi("wrdata_reg", field.offset)); };
field.read_code = { };
field.ackgen_code_pre = { va(prefix.."_int", prefix.."_int_delay");
va(prefix.."_int_delay", 0); };
end
end
-- generates code for BIT-type field
function gen_vhdl_code_bit(field, reg)
local prefix = gen_vhdl_field_prefix(field, reg);
function gen_hdl_code_bit(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
field.prefix = prefix;
......@@ -113,10 +118,11 @@ function gen_vhdl_code_bit(field, reg)
field.ports = { port(BIT, 0, "out", prefix.."_o", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'" ) };
field.signals = { signal(BIT, 0, prefix.."_int") };
field.acklen = 1;
field.write_code = { prefix.."_int <= wb_data_i("..field.offset..");" };
field.read_code = { "wb_data_out_int("..field.offset..") <= "..prefix.."_int;" };
field.reset_code_main = { prefix.."_int <= '0';" };
field.extra_code = { prefix.."_o <= "..prefix.."_int; "};
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { va(prefix.."_o", prefix.."_int") };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(read-only) bitfield
......@@ -124,7 +130,7 @@ function gen_vhdl_code_bit(field, reg)
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { "wb_data_out_int("..field.offset..") <= "..prefix.."_i;" };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.reset_code_main = { };
field.extra_code = { };
......@@ -143,12 +149,12 @@ function gen_vhdl_code_bit(field, reg)
field.acklen = 1;
field.read_code = { "wb_data_out_int("..field.offset..") <= "..prefix.."_i;" };
field.write_code = { prefix.."_load_o <= '1';" };
field.extra_code = { prefix.."_o <= wb_data_i("..field.offset..");" };
field.ackgen_code_pre = { prefix.."_load_o <= '0';" };
field.ackgen_code = { prefix.."_load_o <= '0';" };
field.reset_code_main = { prefix.."_load_o <= '0';" };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_i") };
field.write_code = { va(prefix.."_load_o", 1) };
field.extra_code = { va(prefix.."_o", vi("wrdata_reg", field.offset)) };
field.ackgen_code_pre = { va(prefix.."_load_o", 0) };
field.ackgen_code = { va(prefix.."_load_o", 0) };
field.reset_code_main = { va(prefix.."_load_o", 0) };
else
die("internal RW/RW register storage unsupported yet ("..field.name..")");
......@@ -165,24 +171,25 @@ function gen_vhdl_code_bit(field, reg)
signal(BIT, 0, prefix.."_sync1") };
field.acklen = 4;
field.write_code = { prefix.."_int <= wb_data_i("..field.offset..");" };
field.read_code = { "wb_data_out_int("..field.offset..") <= "..prefix.."_int;" };
field.reset_code_main = { prefix.."_int <= '0';" };
field.extra_code = { "-- synchronizer chain for field : "..field.name.." (type RW/RO, wb_clk_i <-> "..field.clock..")",
"process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_o <= '0';",
prefix.."_sync0 <= '0';",
prefix.."_sync1 <= '0';",
"elsif rising_edge("..field.clock..") then",
prefix.."_sync0 <= "..prefix.."_int;",
prefix.."_sync1 <= "..prefix.."_sync0;",
prefix.."_o <= "..prefix.."_sync1;",
"end if;",
"end process;" };
field.write_code = { va(prefix.."_int", vi("wrdata_reg", field.offset)) };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_int") };
field.reset_code_main = { va(prefix.."_int", 0) };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RW/RO, wb_clk_i <-> "..field.clock..")");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_o", 0);
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_int");
va(prefix.."_sync1", prefix.."_sync0");
va(prefix.."_o", prefix.."_sync1");
});
});
};
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) bitfield, asynchronous
......@@ -193,21 +200,23 @@ function gen_vhdl_code_bit(field, reg)
field.acklen = 1;
field.write_code = { };
field.read_code = { "wb_data_out_int("..field.offset..") <= "..prefix.."_sync1;" };
field.read_code = { va(vi("rddata_reg", field.offset), prefix.."_sync1") };
field.reset_code_main = { };
field.extra_code = { "-- synchronizer chain for field : "..field.name.." (type RO/WO, "..field.clock.." -> wb_clk_i)",
"process (wb_clk_i, rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_sync0 <= '0';",
prefix.."_sync1 <= '0';",
"elsif rising_edge(wb_clk_i) then",
prefix.."_sync0 <= "..prefix.."_i;",
prefix.."_sync1 <= "..prefix.."_sync0;",
"end if;",
"end process;" };
field.extra_code = { vcomment("synchronizer chain for field : "..field.name.." (type RO/WO, "..field.clock.." -> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_sync0", 0);
va(prefix.."_sync1", 0);
});
vposedge({
va(prefix.."_sync0", prefix.."_i");
va(prefix.."_sync1", prefix.."_sync0");
});
});
};
elseif (field.access == ACC_RW_RW) then
-- asynchronous dual-write bitfield. Tough shit :/
......@@ -235,62 +244,63 @@ function gen_vhdl_code_bit(field, reg)
field.acklen = 6;
field.write_code = { prefix.."_int_write <= wb_data_i("..field.offset..");",
prefix.."_lw <= '1';",
prefix.."_lw_delay <= '1';",
prefix.."_lw_read_in_progress <= '0';",
prefix.."_rwsel <= '1'; " };
field.read_code = { prefix.."_lw <= '1';",
prefix.."_lw_delay <= '1';",
prefix.."_lw_read_in_progress <= '1';",
prefix.."_rwsel <= '0'; " };
field.write_code = { va(prefix.."_int_write", vi("wrdata_reg", field.offset));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { prefix.."_lw <= '0';",
prefix.."_lw_delay <= '0';",
prefix.."_lw_read_in_progress <= '0';",
prefix.."_rwsel <= '0';",
prefix.."_int_write <= '0';"
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { prefix.."_lw <= "..prefix.."_lw_delay; ",
prefix.."_lw_delay <= '0'; ",
"if ((ack_cntr = "..gen_vhdl_bin_literal(1,4)..") and ("..prefix.."_lw_read_in_progress = '1')) then",
"wb_data_out_int("..field.offset..") <= "..prefix.."_int_read;",
prefix.."_lw_read_in_progress <= '0';",
"end if;" };
field.extra_code = { "-- asynchronous BIT register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)",
"process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_lw_s0 <= '0';",
prefix.."_lw_s1 <= '0';",
prefix.."_lw_s2 <= '0';",
prefix.."_int_read <= '0';",
prefix.."_load_o <= '0';",
prefix.."_o <= '0';",
"elsif rising_edge("..field.clock..") then",
prefix.."_lw_s0 <= "..prefix.."_lw;",
prefix.."_lw_s1 <= "..prefix.."_lw_s0;",
prefix.."_lw_s2 <= "..prefix.."_lw_s1;",
"if("..prefix.."_lw_s2 = '0' and "..prefix.."_lw_s1 = '1') then",
"if("..prefix.."_rwsel = '1') then",
prefix.."_o <= "..prefix.."_int_write;",
prefix.."_load_o <= '1';",
"else",
prefix.."_load_o <= '0';",
prefix.."_int_read <= "..prefix.."_i;",
"end if;",
"else",
prefix.."_load_o <= '0';",
"end if;",
"end if;",
"end process;" };
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vi("rddata_reg", field.offset), prefix.."_int_read");
va(prefix.."_lw_read_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous BIT register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_int_read", 0);
va(prefix.."_load_o", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
elseif (field.access == ACC_WO_RO) then
die("WO-RO type unsupported yet ("..field.name..")");
......@@ -299,38 +309,19 @@ function gen_vhdl_code_bit(field, reg)
end
-- generates the bit-range for accessing a certain register field from WB-bus
function gen_vhdl_subrange(field)
local s;
s="("..(field.offset+field.size-1).." downto "..(field.offset)..")";
return s;
end
-- converts field of type (slv) to type (type)
function convert_from_slv(type, prefix)
if(type == UNSIGNED) then
return "unsigned("..prefix..")";
elseif (type == SIGNED) then
return "signed("..prefix..")";
else return prefix; end
end
-- ... and vice versa
function convert_to_slv(type, prefix)
if(type == UNSIGNED) then
return "std_logic_vector("..prefix..")";
elseif (type == SIGNED) then
return "std_logic_vector("..prefix..")";
else return prefix; end
function vir(name, field)
local syn = {};
syn.t="index";
syn.name=name;
syn.h=field.offset+field.size-1;
syn.l=field.offset;
return syn;
end
-- generates code for slv, signed or unsigned fields
function gen_vhdl_code_slv(field, reg)
local prefix = gen_vhdl_field_prefix(field, reg);
function gen_hdl_code_slv(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
local is_slv = (field.type == SLV);
local name_slv_i = csel(is_slv , prefix.."_i", prefix.."_i_slv");
local name_slv_o = csel(is_slv , prefix.."_o", prefix.."_o_slv");
field.prefix = prefix;
......@@ -342,10 +333,10 @@ function gen_vhdl_code_slv(field, reg)
field.ports = { port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'") };
field.signals = { signal(SLV, field.size, prefix.."_int") };
field.acklen = 1;
field.write_code = { prefix.."_int <= wb_data_i"..gen_vhdl_subrange(field)..";" };
field.read_code = { "wb_data_out_int"..gen_vhdl_subrange(field).." <= "..prefix.."_int;" };
field.reset_code_main = { prefix.."_int <= (others => '0');" };
field.extra_code = { prefix.."_o <= "..convert_from_slv(field.type, prefix.."_int")..";"};
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field)); };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { va(prefix.."_int", 0); };
field.extra_code = { va(prefix.."_o", prefix.."_int"); };
elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) slv
......@@ -353,7 +344,7 @@ function gen_vhdl_code_slv(field, reg)
field.signals = { };
field.acklen = 1;
field.write_code = { };
field.read_code = { "wb_data_out_int"..gen_vhdl_subrange(field).." <= "..convert_to_slv(field.type, prefix.."_i")..";" };
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.reset_code_main = { };
field.extra_code = { };
......@@ -369,12 +360,12 @@ function gen_vhdl_code_slv(field, reg)
field.acklen = 1;
field.read_code = { "wb_data_out_int"..gen_vhdl_subrange(field).." <= "..convert_to_slv(field.type, prefix.."_i")..";" };
field.write_code = { prefix.."_load_o <= '1';" };
field.extra_code = { prefix.."_o <= "..convert_from_slv(field.type, "wb_data_i"..gen_vhdl_subrange(field))..";" };
field.ackgen_code_pre = { prefix.."_load_o <= '0';" };
field.ackgen_code = { prefix.."_load_o <= '0';" };
field.reset_code_main = { prefix.."_load_o <= '0';" };
field.read_code = { va(vir("rddata_reg", field), prefix.."_i"); };
field.write_code = { va(prefix.."_load_o", 0); };
field.extra_code = { va(prefix.."_o", vir("wrdata_reg", field)); };
field.ackgen_code_pre = { va(prefix.."_load_o", 0);};
field.ackgen_code = { va(prefix.."_load_o", 0); };
field.reset_code_main = { va(prefix.."_load_o", 0); };
end
else
-- asynchronous register. Even tougher shit :(
......@@ -394,37 +385,38 @@ function gen_vhdl_code_slv(field, reg)
field.acklen = 4;
field.write_code = { prefix.."_int <= wb_data_i"..gen_vhdl_subrange(field)..";",
prefix.."_swb <= '1';",
prefix.."_swb_delay <= '1';" };
field.write_code = { va(prefix.."_int", vir("wrdata_reg", field));
va(prefix.."_swb", 1);
va(prefix.."_swb_delay", 1); };
field.read_code = { "wb_data_out_int"..gen_vhdl_subrange(field).." <= "..prefix.."_int;" };
field.read_code = { va(vir("rddata_reg", field), prefix.."_int"); };
field.reset_code_main = { prefix.."_int <= (others => '0');",
prefix.."_swb <= '0'; ",
prefix.."_swb_delay <= '0';" };
field.reset_code_main = { va(prefix.."_int", 0);
va(prefix.."_swb", 0);
va(prefix.."_swb_delay", 0); };
field.ackgen_code_pre = { prefix.."_swb <= "..prefix.."_swb_delay; ",
prefix.."_swb_delay <= '0';" };
field.ackgen_code_pre = { va(prefix.."_swb", prefix.."_swb_delay");
va(prefix.."_swb_delay", 0); };
field.extra_code = { "-- asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/RO, "..field.clock.." <-> wb_clk_i)",
"process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_swb_s0 <= '0';",
prefix.."_swb_s1 <= '0';",
prefix.."_swb_s2 <= '0';",
prefix.."_o <= (others => '0');",
"elsif rising_edge("..field.clock..") then",
prefix.."_swb_s0 <= "..prefix.."_swb;",
prefix.."_swb_s1 <= "..prefix.."_swb_s0;",
prefix.."_swb_s2 <= "..prefix.."_swb_s1;",
"if("..prefix.."_swb_s2 = '0' and "..prefix.."_swb_s1 = '1') then",
prefix.."_o <= "..convert_from_slv(field.type, prefix.."_int")..";",
"end if;",
"end if;",
"end process;" };
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/RO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_swb_s0", 0);
va(prefix.."_swb_s1", 0);
va(prefix.."_swb_s2", 0);
va(prefix.."_o", 0);
});
vposedge({
va(prefix.."_swb_s0", prefix.."_swb");
va(prefix.."_swb_s1", prefix.."_swb_s0");
va(prefix.."_swb_s2", prefix.."_swb_s1");
vif(vand(vequal(prefix.."_swb_s2", 0), vequal(prefix.."_swb_s1", 1)), {
va(prefix.."_o", prefix.."_int");
});
});
});
};
elseif(field.access == ACC_RO_WO) then
-- bus(read-write), dev(read-only) slv
......@@ -443,39 +435,41 @@ function gen_vhdl_code_slv(field, reg)
field.acklen = 6;
field.write_code = { };
field.read_code = { prefix.."_lwb <= '1';",
prefix.."_lwb_delay <= '1';",
prefix.."_lwb_in_progress <= '1';" };
field.reset_code_main = { prefix.."_lwb <= '0';",
prefix.."_lwb_delay <= '0';",
prefix.."_lwb_in_progress <= '0';" };
field.ackgen_code_pre = { prefix.."_lwb <= "..prefix.."_lwb_delay; ",
prefix.."_lwb_delay <= '0'; ",
"if ((ack_cntr = "..gen_vhdl_bin_literal(1,4)..") and ("..prefix.."_lwb_in_progress = '1')) then",
"wb_data_out_int"..gen_vhdl_subrange(field).." <= "..prefix.."_int;",
prefix.."_lwb_in_progress <= '0';",
"end if;", };
field.extra_code = { "-- asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RO/WO, "..field.clock.." <-> wb_clk_i)",
"process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_lwb_s0 <= '0';",
prefix.."_lwb_s1 <= '0';",
prefix.."_lwb_s2 <= '0';",
prefix.."_int <= (others => '0');",
"elsif rising_edge("..field.clock..") then",
prefix.."_lwb_s0 <= "..prefix.."_lwb;",
prefix.."_lwb_s1 <= "..prefix.."_lwb_s0;",
prefix.."_lwb_s2 <= "..prefix.."_lwb_s1;",
"if("..prefix.."_lwb_s1 = '1' and "..prefix.."_lwb_s2 = '0') then",
prefix.."_int <= "..convert_to_slv(field.type, prefix.."_i")..";",
"end if;",
"end if;",
"end process;" };
field.read_code = { va(prefix.."_lwb", 1);
va(prefix.."_lwb_delay", 1);
va(prefix.."_lwb_in_progress", 1); };
field.reset_code_main = { va(prefix.."_lwb", 0);
va(prefix.."_lwb_delay", 0);
va(prefix.."_lwb_in_progress", 0); };
field.ackgen_code_pre = { va(prefix.."_lwb", prefix.."_lwb_delay");
va(prefix.."_lwb_delay", 0);
vif(vand(vequal("ack_cntr", 1), vequal(prefix.."_lwb_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int");
va(prefix.."_lwb_in_progress", 0);
});
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RO/WO, "..field.clock.." <-> wb_clk_i)"),
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lwb_s0", 0);
va(prefix.."_lwb_s1", 0);
va(prefix.."_lwb_s2", 0);
va(prefix.."_int", 0);
});
vposedge({
va(prefix.."_lwb_s0", prefix.."_lwb");
va(prefix.."_lwb_s1", prefix.."_lwb_s0");
va(prefix.."_lwb_s2", prefix.."_lwb_s1");
vif(vand(vequal(prefix.."_lwb_s1", 1), vequal(prefix.."_lwb_s2", 0)), {
va(prefix.."_int", prefix.."_i");
});
});
});
};
elseif(field.access == ACC_RW_RW) then
-- async bus(read-write), dev(read-write) slv. gooosh...
......@@ -504,68 +498,68 @@ function gen_vhdl_code_slv(field, reg)
field.acklen = 6;
field.write_code = { prefix.."_int_write <= wb_data_i"..gen_vhdl_subrange(field)..";",
prefix.."_lw <= '1';",
prefix.."_lw_delay <= '1';",
prefix.."_lw_read_in_progress <= '0';",
prefix.."_rwsel <= '1'; " };
field.read_code = { prefix.."_lw <= '1';",
prefix.."_lw_delay <= '1';",
prefix.."_lw_read_in_progress <= '1';",
prefix.."_rwsel <= '0'; " };
field.write_code = { va(prefix.."_int_write", vir("wrdata_reg", field));
va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 1); };
field.read_code = { va(prefix.."_lw", 1);
va(prefix.."_lw_delay", 1);
va(prefix.."_lw_read_in_progress", 1);
va(prefix.."_rwsel", 0); };
field.reset_code_main = { prefix.."_lw <= '0';",
prefix.."_lw_delay <= '0';",
prefix.."_lw_read_in_progress <= '0';",
prefix.."_rwsel <= '0';",
prefix.."_int_write <= (others => '0');"
field.reset_code_main = { va(prefix.."_lw", 0);
va(prefix.."_lw_delay", 0);
va(prefix.."_lw_read_in_progress", 0);
va(prefix.."_rwsel", 0);
va(prefix.."_int_write", 0);
};
field.ackgen_code_pre = { prefix.."_lw <= "..prefix.."_lw_delay; ",
prefix.."_lw_delay <= '0'; ",
"if ((ack_cntr = "..gen_vhdl_bin_literal(1,4)..") and ("..prefix.."_lw_read_in_progress = '1')) then",
"wb_data_out_int"..gen_vhdl_subrange(field).." <= "..prefix.."_int_read;",
prefix.."_lw_read_in_progress <= '0';",
"end if;", };
field.extra_code = { "-- asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)",
"process ("..field.clock..", rst_n_i)",
"begin",
"if(rst_n_i = '0') then",
prefix.."_lw_s0 <= '0';",
prefix.."_lw_s1 <= '0';",
prefix.."_lw_s2 <= '0';",
prefix.."_o <= (others => '0');",
prefix.."_load_o <= '0';",
prefix.."_int_read <= (others => '0');",
"elsif rising_edge("..field.clock..") then",
prefix.."_lw_s0 <= "..prefix.."_lw;",
prefix.."_lw_s1 <= "..prefix.."_lw_s0;",
prefix.."_lw_s2 <= "..prefix.."_lw_s1;",
"if("..prefix.."_lw_s2 = '0' and "..prefix.."_lw_s1 = '1') then",
"if("..prefix.."_rwsel = '1') then",
prefix.."_o <= "..convert_from_slv(field.type, prefix.."_int_write")..";",
prefix.."_load_o <= '1';",
"else",
prefix.."_load_o <= '0';",
prefix.."_int_read <= "..convert_to_slv(field.type, prefix.."_i")..";",
"end if;",
"else",
prefix.."_load_o <= '0';",
"end if;",
"end if;",
"end process;" };
field.ackgen_code_pre = { va(prefix.."_lw", prefix.."_lw_delay");
va(prefix.."_lw_delay", 0);
vif (vand(vequal("ack_cntr", 1), vequal(prefix.."_lw_read_in_progress", 1)), {
va(vir("rddata_reg", field), prefix.."_int_read");
});
va(prefix.."_lw_read_in_progress", 0);
};
field.extra_code = { vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/WO, "..field.clock.." <-> wb_clk_i)");
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_lw_s0", 0);
va(prefix.."_lw_s1", 0);
va(prefix.."_lw_s2", 0);
va(prefix.."_o", 0);
va(prefix.."_load_o", 0);
va(prefix.."_int_read", 0);
});
vposedge({
va(prefix.."_lw_s0", prefix.."_lw");
va(prefix.."_lw_s1", prefix.."_lw_s0");
va(prefix.."_lw_s2", prefix.."_lw_s1");
vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
vif(vequal(prefix.."_rwsel", 1), {
va(prefix.."_o", prefix.."_int_write");
va(prefix.."_load_o", 1);
}, {
va(prefix.."_load_o", 0);
va(prefix.."_int_read", prefix.."_i");
});
}, {
va(prefix.."_load_o", 0);
});
});
});
};
end
end
end
function gen_vhdl_code_passthrough(field, reg)
local prefix = gen_vhdl_field_prefix(field, reg);
function gen_hdl_code_passthrough(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
if(field.clock == nil) then
-- sync pass-through
......@@ -577,13 +571,13 @@ function gen_vhdl_code_passthrough(field, reg)
field.acklen = 1;
field.reset_code_main = { prefix.."_wr_o <= '0';" };
field.reset_code_main = { va(prefix.."_wr_o", 0); };
field.read_code = {};
field.write_code = { prefix.."_wr_o <= '1';" };
field.ackgen_code_pre = { prefix.."_wr_o <= '0';" };
field.ackgen_code = { prefix.."_wr_o <= '0';" };
field.extra_code = { "-- pass-through field: "..field.name.." in register: "..reg.name,
prefix.."_o <= wb_data_i"..gen_vhdl_subrange(field)..";" }
field.write_code = { va(prefix.."_wr_o", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_o", 0); };
field.ackgen_code = { va(prefix.."_wr_o", 0); };
field.extra_code = { vcomment("-- pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field)); }
else
local comment = "Ports for asynchronous (clock: "..field.clock..") PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";
......@@ -599,126 +593,99 @@ function gen_vhdl_code_passthrough(field, reg)
field.acklen = 4;
field.reset_code_main = { prefix.."_wr_int <= '0';",
prefix.."_wr_int_delay <= '0';" };
field.reset_code_main = { va(prefix.."_wr_int", 0);
va(prefix.."_wr_int_delay", 0); };
field.read_code = {};
field.write_code = { prefix.."_wr_int <= '1';",
prefix.."_wr_int_delay <= '1';" };
field.ackgen_code_pre = { prefix.."_wr_int <= "..prefix.."_wr_int_delay;",
prefix.."_wr_int_delay <= '0';" };
field.extra_code = { "-- pass-through field: "..field.name.." in register: "..reg.name,
prefix.."_o <= wb_data_i"..gen_vhdl_subrange(field)..";",
"process ("..field.clock..", rst_n_i )",
"begin",
"if(rst_n_i = '0') then",
prefix.."_wr_sync0 <= '0';",
prefix.."_wr_sync1 <= '0';",
prefix.."_wr_sync2 <= '0';",
"elsif rising_edge("..field.clock..") then",
prefix.."_wr_sync0 <= "..prefix.."_wr_int;",
prefix.."_wr_sync1 <= "..prefix.."_wr_sync0;",
prefix.."_wr_sync2 <= "..prefix.."_wr_sync1;",
prefix.."_wr_o <= "..prefix.."_wr_sync1 and (not "..prefix.."_wr_sync2);",
"end if;",
"end process;" };
end
field.write_code = { va(prefix.."_wr_int", 1);
va(prefix.."_wr_int_delay", 1); };
field.ackgen_code_pre = { va(prefix.."_wr_int", prefix.."_wr_int_delay");
va(prefix.."_wr_int_delay", 0); };
field.extra_code = { vcomment("pass-through field: "..field.name.." in register: "..reg.name);
va(prefix.."_o", vir("wrdata_reg", field));
vsyncprocess(field.clock, "rst_n_i", {
vreset(0, {
va(prefix.."_wr_sync0", 0);
va(prefix.."_wr_sync1", 0);
va(prefix.."_wr_sync2", 0);
});
vposedge({
va(prefix.."_wr_sync0", prefix.."_wr_int");
va(prefix.."_wr_sync1", prefix.."_wr_sync0");
va(prefix.."_wr_sync2", prefix.."_wr_sync1");
va(prefix.."_wr_o", vand(prefix.."_wr_sync1", vnot(prefix.."_wr_sync2")));
});
});
}
end
end
-- generates VHDL code for single register field
function gen_vhdl_code_reg_field(field, reg)
function gen_hdl_code_reg_field(field, reg)
if(field.type == MONOSTABLE) then
gen_vhdl_code_monostable(field, reg);
gen_hdl_code_monostable(field, reg);
elseif(field.type == BIT) then
gen_vhdl_code_bit(field, reg);
gen_hdl_code_bit(field, reg);
elseif(field.type == SIGNED or field.type == UNSIGNED or field.type == SLV) then
gen_vhdl_code_slv(field, reg);
gen_hdl_code_slv(field, reg);
elseif(field.type == PASS_THROUGH) then
gen_vhdl_code_passthrough(field, reg);
gen_hdl_code_passthrough(field, reg);
end
end
-- generates VHDL for single register
function gen_vhdl_code_reg(reg)
foreach_subfield(reg, function(field, reg) gen_vhdl_code_reg_field(field, reg); end );
function gen_hdl_code_reg(reg)
foreach_subfield(reg, function(field, reg) gen_hdl_code_reg_field(field, reg); end );
end
function gen_vhdl_block_select_bits()
return "wb_addr_i("..(address_bus_width-1).." downto "..(address_bus_width - address_bus_select_bits)..")";
function gen_hdl_block_select_bits()
return vi("rwaddr_reg", address_bus_width-1, (address_bus_width - address_bus_select_bits));
end
-- generates the entire VHDL register-bank access stuff
function gen_vhdl_regbank()
function gen_hdl_regbank()
local s;
local ramcount = 0;
vhdl_new_code();
-- vhdl_new_code();
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
gen_vhdl_code_reg(reg);
gen_hdl_code_reg(reg);
end
end );
vhdl ("");
vhdl ("begin");
vhdl ("-- MAIN REGISTER BANK PROCESS --");
vhdl ("process (wb_clk_i, rst_n_i)");
vhdl ("begin");
-- generate reset code for the main process
vhdl ("if(rst_n_i = '0') then");
vhdl ("-- Resetting the signals --");
vhdl ("");
-- vhdl ("");
local resetcode={};
local ackgencode={};
local preackcode={};
foreach_field(function(field, reg)
if (field.reset_code_main ~= nil) then
vhdl_paste_code (field.reset_code_main);
end
end );
vhdl ("wb_ack_regbank <= '0';");
vhdl ("ack_in_progress <= '0';");
vhdl ("ack_cntr <= "..gen_vhdl_bin_literal(0,4)..";");
vhdl ("wb_data_out_int <= (others => '0');");
vhdl ("");
vhdl ("elsif rising_edge(wb_clk_i) then");
vhdl ("-- ACK signal generator --");
vhdl ("if ack_in_progress = '1' then");
vhdl ("if(ack_cntr = "..gen_vhdl_bin_literal(0,4)..") then");
-- print("rstcode: ", field.reset_code_main);
table_join(resetcode, field.reset_code_main);
end );
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
vhdl_paste_code(field.ackgen_code);
table_join(ackgencode, field.ackgen_code);
end );
end
end );
end);
vhdl ("ack_in_progress <= '0';");
vhdl ("wb_ack_regbank <= '0';");
vhdl ("else");
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
foreach_subfield(reg, function(field, reg)
vhdl_paste_code(field.ackgen_code_pre);
table_join(preackcode, field.ackgen_code_pre);
end );
end
end );
vhdl ("ack_cntr <= ack_cntr - 1;");
vhdl ("if (ack_cntr = "..gen_vhdl_bin_literal(1,4)..") then");
vhdl ("wb_ack_regbank <= '1';");
vhdl ("else");
vhdl ("wb_ack_regbank <= '0';");
vhdl ("end if;");
vhdl ("end if;");
vhdl ("else");
end);
-- count the RAMs in the design
foreach_reg(function(reg)
......@@ -727,85 +694,110 @@ function gen_vhdl_regbank()
end
end
);
if(ramcount > 0) then
vhdl ("case "..gen_vhdl_block_select_bits().." is ");
foreach_reg(function(reg)
if (reg.__type == TYPE_RAM) then
vhdl ("when "..gen_vhdl_bin_literal(reg.select_bits, address_bus_select_bits).." => ");
vhdl ("wb_ack_regbank <= '1'; ack_in_progress <= '1'; ack_cntr <= "..gen_vhdl_bin_literal(0,4).."; ");
end
end );
vhdl ("when "..gen_vhdl_bin_literal(0, address_bus_select_bits).." => ");
end
vhdl ("if ( wb_sel_i = '1' and wb_cyc_i = '1' and wb_stb_i = '1' ) then");
if(regbank_address_bits > 0) then
vhdl ("case (wb_addr_i("..(regbank_address_bits -1 ).." downto 0)) is");
end
local fsmcode={};
foreach_reg(function(reg)
if(reg.__type == TYPE_REG) then
local acklen = find_max(reg, "acklen");
local rcode={};
local wcode={};
foreach_subfield(reg, function(field, reg) table_join(wcode, field.write_code); end );
foreach_subfield(reg, function(field, reg) table_join(rcode, field.read_code); end );
local rwcode = {
vif(vequal("wb_we_i" ,1), {
wcode
}, {
rcode
}); };
table_join(rwcode, { va("wb_ack_regbank", csel((acklen==1),1,0)); } );
table_join(rwcode, { va("ack_cntr", math.max(acklen-1, 0)); } );
table_join(rwcode, { va("ack_in_progress", 1); } );
if(regbank_address_bits > 0) then
vhdl ("when "..gen_vhdl_bin_literal(reg.base, regbank_address_bits).." => \t-- "..reg.name.."");
rwcode = { vcase(reg.base, rwcode); };
end
vhdl ("if(wb_we_i = '1') then -- write access");
foreach_subfield(reg, function(field, reg) vhdl_paste_code(field.write_code); end );
vhdl ("else -- read access");
foreach_subfield(reg, function(field, reg) vhdl_paste_code(field.read_code); end );
vhdl ("end if; ");
-- emit the ACK generation code. Special case for 1-cycle ACK
-- if(acklen == 1) then
-- vhdl("ack_in_progress <= '0'; ");
--else
vhdl("wb_ack_regbank <= "..csel((acklen==1),"'1'","'0'")..";");
vhdl("ack_cntr <= "..gen_vhdl_bin_literal(math.max(acklen-1, 0),4)..";");
vhdl("ack_in_progress <= '1'; ");
table_join(fsmcode, rwcode);
end
end );
-- vhdl ("if ( wb_sel_i = '1' and wb_cyc_i = '1' and wb_stb_i = '1' ) then");
if(regbank_address_bits > 0) then
vhdl("when others => ");
vhdl("ack_in_progress <= '0'; ack_cntr <= "..gen_vhdl_bin_literal(0,4).."; wb_ack_regbank <= '0';");
vhdl ("end case;");
end
vhdl ("else");
vhdl ("wb_ack_regbank <= '0';");
vhdl ("end if;");
table_join(fsmcode, { vcasedefault({
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("wb_ack_regbank", 0);
}); });
if(ramcount > 0) then
vhdl("when others => ack_in_progress <= '0'; ack_cntr <= "..gen_vhdl_bin_literal(0,4).."; ");
-- vhdl_indent_left();
-- vhdl_indent_left();
vhdl("end case; ");
fsmcode = { vswitch(vi("rwaddr_reg", regbank_address_bits - 1, 0), fsmcode); };
end
vhdl ("end if;")
vhdl ("end if;")
vhdl ("end process;");
vhdl("");
fsmcode = { vif(vand(vequal("wb_cyc_i", 1), vequal("wb_stb_i", 1)), { fsmcode }, { va("wb_ack_regbank", 0) }); };
local code = {
vsyncprocess("wb_clk_i", "rst_n_i", {
vreset(0, {
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
va("ack_cntr", 0);
va("rddata_reg", 0);
resetcode
});
vposedge ({
vif(vequal("ack_in_progress",1), {
vif(vequal("ack_cntr", 0), {
ackgencode;
va("wb_ack_regbank", 0);
va("ack_in_progress", 0);
}, {
preackcode;
va("ack_cntr", vsub("ack_cntr", 1));
vif(vequal("ack_cntr", 1), {
va("wb_ack_regbank", 1);
} , {
va("wb_ack_regbank", 0);
});
});}, { -- else ack_in_progress = 0
fsmcode
});
});
});
va("wb_data_o", "rddata_reg");
va("wrdata_reg", "wb_data_i");
va("rwaddr_reg", "wb_addr_i");
};
-- vhdl_indent_right();
foreach_reg(function(reg)
if(reg.extra_code ~= nil) then
vhdl("-- extra code for reg/fifo/mem: "..reg.name);
vhdl_paste_code(reg.extra_code);
vhdl("");
table_join(code, {vcomment("extra code for reg/fifo/mem: "..reg.name);});
table_join(code, reg.extra_code);
end
foreach_subfield(reg, function(field, reg) vhdl_paste_code(field.extra_code); vhdl("");end );
foreach_subfield(reg, function(field, reg) table_join(code, field.extra_code); end );
end);
return code_vhdl;
return code;
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