Commit f4b155be authored by Grzegorz Daniluk's avatar Grzegorz Daniluk Committed by Tomasz Wlostowski

adding generation of Latex docs

parent 6649e3f0
#!/usr/bin/lua
-- wbgen2, (c) 2013 Grzegorz Daniluk/CERN BE-CO-HT
-- LICENSED UNDER GPL v2
-- File: cgen_doc_latex.lua
--
-- LATEX documentation generator.
--
function lx_htable_emit(tbl)
local temp ="";
local cell_align = "";
if( tbl.data[1][1].style == nil ) then
cell_align = "l ";
elseif( tbl.data[1][1].style == "td_bit" ) then
cell_align = ">{\\centering\\arraybackslash}p{1.5cm} ";
end
temp = "\\begin{tabular}{";
for j=1, tbl.cols do
temp = temp..cell_align;
end
temp = temp.."}";
emit(temp);
for i = 1, tbl.rows do
local row = "";
j=1;
while j<=tbl.cols do
row = row..tbl.data[i][j].text;
if( tbl.data[i][j].style ~= nil ) then
if( tbl.data[i][j].style == "td_field" ) then
j = j + tbl.data[i][j].flen;
end
end
if(j ~= tbl.cols) then
row = row..' & ';
else
row = row..'\\\\';
end
j = j + 1;
end
emit(row);
end
emit("\\end{tabular}");
emit("");
end
function cgen_doc_lx_header_and_toc()
emit('\\subsection{'..periph.name..'}');
emit('\\label{subsec:wbgen:'..periph.prefix..'}');
local t = periph.description;
if(t == nil) then t = ""; end
emit(string.gsub(t, "\n", "\\\\"));
end
function cgen_doc_lx_memmap()
local n = 2;
local reg_text = " ";
emit('\\subsubsection{Memory map summary}');
emit('\\rowcolors{2}{gray!25}{white}');
emit('\\resizebox{\\textwidth}{!}{');
emit('\\begin{tabular}{|l|l|l|l|l|}');
emit('\\rowcolor{RoyalPurple}');
emit('\\color{white} H/W Addr & \\color{white} Type & \\color{white} Name &');
emit('\\color{white} HW prefix & \\color{white} C prefix\\\\');
foreach_reg({TYPE_REG}, function(reg)
if(reg.full_hdl_prefix ~= nil) then
reg_text = string.format("0x%x", reg.base)..'& ';
if(reg.doc_is_fiforeg == nil) then
reg_text = reg_text.."REG & ";
else
reg_text = reg_text.."FIFOREG & ";
end
reg_text = reg_text..reg.name.." & "..reg.full_hdl_prefix.." & "..string.upper(reg.c_prefix).."\\\\";
reg_text = string.gsub(reg_text, "_", "\\_");
emit(reg_text);
end
end);
foreach_reg({TYPE_RAM}, function(reg)
if(reg.full_hdl_prefix ~= nil) then
reg_text = string.format("0x%x - 0x%x", reg.base, reg.base+math.pow(2, reg.wrap_bits)*reg.size-1)..'& ';
reg_text = reg_text.."MEM & "..reg.name.." & "..reg.full_hdl_prefix.." & "..string.upper(reg.c_prefix).."\\\\";
reg_text = string.gsub(reg_text, "_", "\\_");
emit(reg_text);
end
end);
emit('\\end{tabular}');
emit('}'); --end of resizebox
end
function cgen_doc_lx_fieldtable(reg, bitoffs)
local td_width = 70;
local tbl;
local n= 1;
tbl= htable_new(2,8);
for i=1,8 do
tbl.data[1][i].style = "td_bit";
tbl.data[1][n].flen = 0;
tbl.data[1][i].text = string.format("%d", bitoffs+8-i);
end
local bit = bitoffs + 7;
while (bit >= bitoffs) do
local f = find_field_by_offset(reg, bit);
if(f == nil) then
tbl.data[2][n].style = "td_unused";
tbl.data[2][n].flen = 0;
if(n==1) then
tbl.data[2][n].text = "\\multicolumn{1}{|c}{-}";
elseif(n==8) then
tbl.data[2][n].text = "\\multicolumn{1}{c|}{-}";
else
tbl.data[2][n].text = "-";
end
n=n+1;
bit=bit-1;
else
local fend;
if(f.offset < bitoffs) then
fend = bitoffs;
else
fend = f.offset;
end
local ncells = (bit - fend) + 1;
dbg("ncells: ",ncells,"bit: ", bit, "name: ",f.prefix);
tbl.data[2][n].colspan = ncells;
local prefix;
prefix = f.c_prefix;
if(prefix == nil) then prefix = reg.c_prefix; end
prefix = string.gsub(prefix, "_", "\\_");
tbl.data[2][n].style = "td_field";
tbl.data[2][n].flen = bit-fend;
tbl.data[2][n].text = csel(f.size>1, string.format("\\multicolumn{%d}{|c|}{\\cellcolor{RoyalPurple!25}%s[%d:%d]}", bit-fend+1, string.upper(prefix), bit-f.offset, fend-f.offset), string.format("\\multicolumn{1}{|c|}{\\cellcolor{RoyalPurple!25}%s}", string.upper(prefix)));
bit = bit - ncells;
n=n+1;
end
end
--part of htable_emit()
for i = 1, tbl.rows do
local row = "";
j=1;
k=0;
while k<tbl.cols do
row = row..tbl.data[i][j].text;
if( tbl.data[i][j].style ~= nil ) then
if( tbl.data[i][j].style == "td_field" ) then
k = k + tbl.data[i][j].flen;
end
end
k = k + 1;
if(k ~= tbl.cols) then
row = row..' & ';
else
row = row..'\\\\';
end
j = j + 1;
end
emit(row);
emit("\\hline");
end
end
function cgen_doc_access(acc)
if(acc == READ_ONLY) then
return "read-only";
elseif(acc == READ_WRITE) then
return "read/write";
elseif(acc == WRITE_ONLY) then
return "write-only";
else
return "FIXME!";
end
end
cur_reg_no = 1;
function cgen_doc_lx_reg(reg)
local temp = "";
local description = "";
cur_reg_no = cur_reg_no + 1;
emit("\\paragraph*{"..reg.name.."}\\vspace{12pt}");
emit("");
local tbl = htable_new(4, 2);
tbl.data[1][1].text = "{\\bf HW prefix:} ";
tbl.data[2][1].text = "{\\bf HW address:} ";
tbl.data[3][1].text = "{\\bf SW prefix:} ";
tbl.data[4][1].text = "{\\bf SW offset:} ";
tbl.data[1][2].text = string.gsub(reg.full_hdl_prefix, "_", "\\_");
tbl.data[2][2].text = string.format("0x%x", reg.base);
tbl.data[3][2].text = string.gsub(string.upper(reg.c_prefix), "_", "\\_");
tbl.data[4][2].text = string.format("0x%x", reg.base * (DATA_BUS_WIDTH/8));
emit("\\rowcolors{1}{white}{white}");
lx_htable_emit(tbl);
if(reg.description ~= nil) then
emit("\\vspace{12pt}");
description = string.gsub(reg.description, "\n", "\\\\");
description = string.gsub(description, "_", "\\_");
description = string.gsub(description, "<code>", "\\texttt{");
description = string.gsub(description, "</code>", "}");
emit(description);
end
--generate header for tabular
temp = "\\begin{tabular}{";
for j=1, 8 do
temp = temp..">{\\centering\\arraybackslash}p{1.5cm} ";
end
temp = temp.."}";
emit("");
emit("\\vspace{12pt}");
emit("\\noindent");
emit('\\resizebox{\\textwidth}{!}{');
emit(temp);
for i=0,DATA_BUS_WIDTH/8-1 do
cgen_doc_lx_fieldtable(reg, (DATA_BUS_WIDTH/8-1-i)*8);
end
emit("\\end{tabular}");
emit("}");
emit("");
emit("\\begin{itemize}");
foreach_subfield(reg, function(field)
emit("\\item \\begin{small}");
emit("{\\bf ");
if(field.c_prefix == nil) then -- anonymous field?
emit(string.gsub(string.upper(reg.c_prefix), "_", "\\_"));
else
emit(string.gsub(string.upper(field.c_prefix), "_", "\\_"));
end
emit("} [\\emph{"..cgen_doc_access(field.access_bus).."}]: "..field.name);
if(field.description ~= nil) then
emit("\\\\");
description = string.gsub(field.description, "\n", "\\\\");
description = string.gsub(description, "_", "\\_");
description = string.gsub(description, "<code>", "\\texttt{");
description = string.gsub(description, "</code>", "}");
emit(description);
end
emit("\\end{small}");
end);
emit("\\end{itemize}");
end
cur_mem_no = 1;
function cgen_doc_lx_ram(ram)
local description = "";
emit("\\paragraph*{"..ram.name.."}\\vspace{12pt}");
emit("");
cur_mem_no = cur_mem_no + 1;
local tbl = htable_new(11, 2);
tbl.data[1][1].text = "{\\bf HW prefix:} ";
tbl.data[2][1].text = "{\\bf HW address:} ";
tbl.data[3][1].text = "{\\bf C prefix:} ";
tbl.data[4][1].text = "{\\bf C offset:} ";
tbl.data[5][1].text = "{\\bf Size:} ";
tbl.data[6][1].text = "{\\bf Data width:} ";
tbl.data[7][1].text = "{\\bf Access (bus):} ";
tbl.data[8][1].text = "{\\bf Access (device):} ";
tbl.data[9][1].text = "{\\bf Mirrored:} ";
tbl.data[10][1].text = "{\\bf Byte-addressable:} ";
tbl.data[11][1].text = "{\\bf Peripheral port:} ";
tbl.data[1][2].text = string.lower(string.gsub(periph.hdl_prefix, "_", "\\_").."\\_"..string.gsub(ram.hdl_prefix,"_","\\_"));
tbl.data[2][2].text = string.format("0x%x", ram.base);
tbl.data[3][2].text = string.upper(string.gsub(ram.c_prefix,"_","\\_"));
tbl.data[4][2].text = string.format("0x%x", ram.base * (DATA_BUS_WIDTH/8));
tbl.data[5][2].text = ram.size.." "..ram.width.."-bit words";
tbl.data[6][2].text = ram.width;
tbl.data[7][2].text = cgen_doc_access(ram.access_bus);
tbl.data[8][2].text = cgen_doc_access(ram.access_dev);
if(ram.byte_select ~= nil and ram.byte_select == true) then
tbl.data[10][2].text = "yes";
else
tbl.data[10][2].text = "no";
end
if(ram.wrap_bits ~= nil and 0 ~= ram.wrap_bits) then
tbl.data[9][2].text = math.pow(2, ram.wrap_bits).." times";
else
tbl.data[9][2].text = "no";
end
if(ram.clock ~= nil) then
tbl.data[11][2].text = "asynchronous ("..ram.clock..")";
else
tbl.data[11][2].text = "bus-synchronous";
end
emit("\\begin{small}");
lx_htable_emit(tbl);
emit("\\end{small}");
if(ram.description ~= nil) then
description = string.gsub(ram.description, "\n", "\\\\");
description = string.gsub(description, "_", "\\_");
description = string.gsub(description, "<code>", "\\texttt{");
description = string.gsub(description, "</code>", "}");
emit(description);
end
end
cur_irq_no = 1;
function cgen_doc_lx_irq(irq)
local description = "";
emit("\\paragraph*{"..irq.name.."}\\vspace{12pt}");
cur_irq_no = cur_irq_no + 1;
local tbl = htable_new(3, 2);
tbl.data[1][1].text = "{\\bf HW prefix:} ";
tbl.data[2][1].text = "{\\bf C prefix:} ";
tbl.data[3][1].text = "{\\bf Trigger:} ";
tbl.data[1][2].text = string.gsub(string.lower(periph.hdl_prefix.."_"..irq.hdl_prefix), "_", "\\_");
tbl.data[2][2].text = string.upper(string.gsub(irq.c_prefix,"_","\\_"));
local trigtab = {
[EDGE_RISING] = "rising edge";
[EDGE_FALLING] = "falling edge";
[LEVEL_0] = "low level";
[LEVEL_1] = "high level";
};
tbl.data[3][2].text = trigtab[irq.trigger];
emit("\\begin{small}");
lx_htable_emit(tbl);
emit("\\end{small}");
if(irq.description ~= nil) then
emit("\\vspace{12pt}");
description = string.gsub(irq.description, "\n", "\\\\");
description = string.gsub(description, "_", "\\_");
description = string.gsub(description, "<code>", "\\texttt{");
description = string.gsub(description, "</code>", "}");
emit(description);
end
end
function cgen_generate_latex_documentation()
cgen_new_snippet();
emit("\\subsubsection{Register description}");
foreach_reg({TYPE_REG}, function(reg) if(reg.no_docu == nil or reg.no_docu == false)then cgen_doc_lx_reg(reg);end end);
local h_regs = cgen_get_snippet();
local h_rams = "";
if(periph.ramcount > 0) then
emit("\\subsubsection{Memory blocks}");
cgen_new_snippet();
foreach_reg({TYPE_RAM}, function(reg) if(reg.no_docu == nil or reg.no_docu == false)then cgen_doc_lx_ram(reg);end end);
h_rams = cgen_get_snippet();
end
local h_irqs = "";
if(periph.irqcount > 0) then
cgen_new_snippet();
emit("\\subsubsection{Interrupts}");
foreach_reg({TYPE_IRQ}, function(reg) if(reg.no_docu == nil or reg.no_docu == false) then cgen_doc_lx_irq(reg); end end);
h_irqs = cgen_get_snippet();
end
cgen_new_snippet();
cgen_doc_lx_memmap();
local h_memmap = cgen_get_snippet();
cgen_new_snippet();
cgen_doc_lx_header_and_toc();
emit(h_memmap);
emit(h_regs);
emit(h_rams);
emit(h_irqs);
cgen_write_current_snippet();
end
......@@ -14,6 +14,7 @@ Main "cgen_verilog.lua"
Main "cgen_c_headers.lua"
Main "cgen_doc.lua"
Main "cgen_doc_texinfo.lua"
Main "cgen_doc_latex.lua"
Main "wbgen_regbank.lua"
Main "wbgen_rams.lua"
Main "wbgen_eic.lua"
......
#!/usr/bin/env lua
package.preload['alt_getopt']=(function(...)
local i,h,u,o,a=type,pairs,ipairs,io,os
local o,d,u,a,i=type,pairs,ipairs,io,os
module("alt_getopt")
local function r(e)
local t=1
local t=#e
local t={}
for e,a in e:gmatch("(%w)(:?)")do
t[e]=#a
local function c(t)
local e=1
local e=#t
local e={}
for a,t in t:gmatch("(%w)(:?)")do
e[a]=#t
end
return t
return e
end
local function d(e,t)
o.stderr:write(e)
a.exit(t)
local function r(t,e)
a.stderr:write(t)
i.exit(e)
end
local function a(e)
d("Unknown option `-"..
r("Unknown option `-"..
(#e>1 and"-"or"")..e.."'\n",1)
end
local function l(t,e)
if not t[e]then
a(e)
end
while i(t[e])=="string"do
while o(t[e])=="string"do
e=t[e]
if not t[e]then
a(e)
......@@ -31,13 +31,13 @@ end
end
return e
end
function get_ordered_opts(n,o,a)
function get_ordered_opts(n,a,s)
local t=1
local e=1
local i={}
local s={}
local o=r(o)
for e,t in h(a)do
local h={}
local o=c(a)
for e,t in d(s)do
o[e]=t
end
while t<=#n do
......@@ -48,49 +48,49 @@ break
elseif a=="-"then
break
elseif a:sub(1,2)=="--"then
local h=a:find("=",1,true)
if h then
local t=a:sub(3,h-1)
local s=a:find("=",1,true)
if s then
local t=a:sub(3,s-1)
t=l(o,t)
if o[t]==0 then
d("Bad usage of option `"..a.."'\n",1)
r("Bad usage of option `"..a.."'\n",1)
end
s[e]=a:sub(h+1)
h[e]=a:sub(s+1)
i[e]=t
else
local h=a:sub(3)
h=l(o,h)
if o[h]==0 then
i[e]=h
local s=a:sub(3)
s=l(o,s)
if o[s]==0 then
i[e]=s
else
if t==#n then
d("Missed value for option `"..a.."'\n",1)
r("Missed value for option `"..a.."'\n",1)
end
s[e]=n[t+1]
i[e]=h
h[e]=n[t+1]
i[e]=s
t=t+1
end
end
e=e+1
elseif a:sub(1,1)=="-"then
local h
for r=2,a:len()do
local h=l(o,a:sub(r,r))
if o[h]==0 then
i[e]=h
local s
for d=2,a:len()do
local s=l(o,a:sub(d,d))
if o[s]==0 then
i[e]=s
e=e+1
elseif a:len()==r then
elseif a:len()==d then
if t==#n then
d("Missed value for option `-"..h.."'\n",1)
r("Missed value for option `-"..s.."'\n",1)
end
s[e]=n[t+1]
i[e]=h
h[e]=n[t+1]
i[e]=s
t=t+1
e=e+1
break
else
s[e]=a:sub(r+1)
i[e]=h
h[e]=a:sub(d+1)
i[e]=s
e=e+1
break
end
......@@ -100,16 +100,16 @@ break
end
t=t+1
end
return i,t,s
return i,t,h
end
function get_opts(t,a,o)
function get_opts(a,t,o)
local e={}
local t,i,a=get_ordered_opts(t,a,o)
for o,t in u(t)do
if a[o]then
e[t]=a[o]
local t,i,o=get_ordered_opts(a,t,o)
for t,a in u(t)do
if o[t]then
e[a]=o[t]
else
e[t]=1
e[a]=1
end
end
return e,i
......@@ -176,22 +176,22 @@ die(t.." expected.");
end
return e;
end
function range2bits(e)
local t=e[1];
local a=e[2];
local e;
if(math.abs(t)>math.abs(a))then
e=math.abs(t);
function range2bits(t)
local e=t[1];
local a=t[2];
local t;
if(math.abs(e)>math.abs(a))then
t=math.abs(e);
else
e=math.abs(a);
t=math.abs(a);
end
local e=math.ceil(math.log(e)/math.log(2));
if(t<0)then
e=e+1;
local t=math.ceil(math.log(t)/math.log(2));
if(e<0)then
t=t+1;
end
return e;
return t;
end
function calc_size(e,t)
function calc_size(e,a)
if(e.type==MONOSTABLE or e.type==BIT)then
e.size=1;
elseif(e.type==SLV or e.type==PASS_THROUGH)then
......@@ -212,16 +212,16 @@ end
elseif(e.type==ENUM)then
die("ENUM-type fields are not yet supported. Sorry :(");
end
t.total_size=t.total_size+e.size;
a.total_size=a.total_size+e.size;
end
function foreach_reg(a,t,e)
function foreach_reg(t,a,e)
if(e==nil)then
e=periph;
end
for o,e in ipairs(e)do
if(type(e)=='table')then
if(e.__type~=nil and(match(e.__type,a)))then
t(e);
if(e.__type~=nil and(match(e.__type,t)))then
a(e);
end
end
end
......@@ -248,27 +248,27 @@ if(t.align==nil)then e=1;else e=t.align;end
local e=e*math.floor((a+e-1)/e);
return e;
end
function calc_field_offset(t,e)
local a=e.current_offset;
if(e.__type==TYPE_FIFO)then
local o=align(t,a);
if((o%DATA_BUS_WIDTH)+t.size>DATA_BUS_WIDTH)then
t.align=DATA_BUS_WIDTH;
a=align(t,a);
function calc_field_offset(e,t)
local a=t.current_offset;
if(t.__type==TYPE_FIFO)then
local o=align(e,a);
if((o%DATA_BUS_WIDTH)+e.size>DATA_BUS_WIDTH)then
e.align=DATA_BUS_WIDTH;
a=align(e,a);
else
a=o;
end
e.current_offset=a+t.size;
t.offset=a;
t.current_offset=a+e.size;
e.offset=a;
else
a=align(t,a);
e.current_offset=a+t.size;
t.offset=a;
a=align(e,a);
t.current_offset=a+e.size;
e.offset=a;
end
t.offset_unaligned=e.current_offset_unaligned;
e.current_offset_unaligned=e.current_offset_unaligned+t.size;
if(e.__type==TYPE_REG and e.current_offset>DATA_BUS_WIDTH)then
die("Total size of register '"..e.name.."' ("..e.current_offset..") exceeds data bus width ("..DATA_BUS_WIDTH..")");
e.offset_unaligned=t.current_offset_unaligned;
t.current_offset_unaligned=t.current_offset_unaligned+e.size;
if(t.__type==TYPE_REG and t.current_offset>DATA_BUS_WIDTH)then
die("Total size of register '"..t.name.."' ("..t.current_offset..") exceeds data bus width ("..DATA_BUS_WIDTH..")");
end
end
function calc_num_fields(t,e)
......@@ -286,15 +286,15 @@ if(t==e)then return true;end
end
return false;
end
function inset(t,e)
for a,e in ipairs(e)do if(t==e)then return true;end end
function inset(e,t)
for a,t in ipairs(t)do if(e==t)then return true;end end
return false;
end
function csel(t,a,e)
if(t)then
return a;
else
function csel(a,e,t)
if(a)then
return e;
else
return t;
end
end
function check_field_types(e)
......@@ -318,13 +318,13 @@ return e;
end
return e;
end
function default_access(e,t,a,o)
if(e.type==t)then
function default_access(e,o,a,t)
if(e.type==o)then
if(e.access_bus==nil)then
e.access_bus=a;
end
if(e.access_dev==nil)then
e.access_dev=o;
e.access_dev=t;
end
end
end
......@@ -369,9 +369,9 @@ end
function log2up(e)
return math.ceil(math.log(e)/math.log(2));
end
function is_power_of_2(t)
for e=1,24 do
if(t==math.pow(2,e))then return true;end
function is_power_of_2(e)
for t=1,24 do
if(e==math.pow(2,t))then return true;end
end
return false;
end
......@@ -426,36 +426,36 @@ table.insert(t,e);
end
end
function tree_2_table(e)
local a={};
foreach_reg({TYPE_REG,TYPE_RAM,TYPE_FIFO,TYPE_IRQ},function(t)
if(t[e]~=nil)then
if(type(t[e])=='table')then
table_join(a,t[e]);
local t={};
foreach_reg({TYPE_REG,TYPE_RAM,TYPE_FIFO,TYPE_IRQ},function(a)
if(a[e]~=nil)then
if(type(a[e])=='table')then
table_join(t,a[e]);
else
table.insert(a,t[e]);
table.insert(t,a[e]);
end
end
foreach_subfield(t,function(t,o)
if(t[e]~=nil)then
if(type(t[e])=='table')then
table_join(a,t[e]);
foreach_subfield(a,function(a,o)
if(a[e]~=nil)then
if(type(a[e])=='table')then
table_join(t,a[e]);
else
table.insert(a,t[e]);
table.insert(t,a[e]);
end
end
end);
end);
return a;
return t;
end
function remove_duplicates(o)
function count_entries(t,a)
function remove_duplicates(a)
function count_entries(a,t)
local o,o,e;
e=0;
for o,t in ipairs(t)do if(t==a)then e=e+1;end end
for o,a in ipairs(a)do if(a==t)then e=e+1;end end
return e;
end
local e={};
for a,t in ipairs(o)do
for a,t in ipairs(a)do
local a=count_entries(e,t);
if(a==0)then
table.insert(e,t);
......@@ -464,67 +464,67 @@ end
return e;
end
function wbgen_count_subblocks()
local t=0;
local o=0;
local a=0;
local e=0;
foreach_reg({TYPE_RAM},function(e)t=t+1;end);
foreach_reg({TYPE_REG},function(e)a=a+1;end);
foreach_reg({TYPE_FIFO},function(e)o=o+1;end);
foreach_reg({TYPE_IRQ},function(t)e=e+1;end);
periph.ramcount=t;
periph.fifocount=o;
periph.regcount=a;
periph.irqcount=e;
if(t+o+a+e==0)then
local t=0;
foreach_reg({TYPE_RAM},function(e)o=o+1;end);
foreach_reg({TYPE_REG},function(t)e=e+1;end);
foreach_reg({TYPE_FIFO},function(e)a=a+1;end);
foreach_reg({TYPE_IRQ},function(e)t=t+1;end);
periph.ramcount=o;
periph.fifocount=a;
periph.regcount=e;
periph.irqcount=t;
if(o+a+e+t==0)then
die("Can't generate an empty peripheral. Define some regs, RAMs, FIFOs or IRQs, please...");
end
end
function deepcopy(i)
local t={}
local o={}
local function a(e)
if type(e)~="table"then
return e
elseif t[e]then
return t[e]
elseif o[e]then
return o[e]
end
local o={}
t[e]=o
for t,e in pairs(e)do
o[a(t)]=a(e)
local t={}
o[e]=t
for e,o in pairs(e)do
t[a(e)]=a(o)
end
return setmetatable(o,getmetatable(e))
return setmetatable(t,getmetatable(e))
end
return a(i)
end
function va(t,a)
function va(a,t)
local e={};
e.t="assign";
e.dst=t;
e.src=a;
e.dst=a;
e.src=t;
return e;
end
function vi(t,a,o)
function vi(o,t,a)
local e={};
e.t="index";
e.name=t;
e.h=a;
e.l=o;
e.name=o;
e.h=t;
e.l=a;
return e;
end
function vinstance(a,t,o)
function vinstance(t,a,o)
local e={};
e.t="instance";
e.name=a;
e.component=t;
e.name=t;
e.component=a;
e.maps=o;
return e;
end
function vpm(t,a)
function vpm(a,t)
local e={};
e.t="portmap";
e.to=t;
e.from=a;
e.to=a;
e.from=t;
return e;
end
function vgm(t,a)
......@@ -534,26 +534,26 @@ e.to=t;
e.from=a;
return e;
end
function vcombprocess(a,t)
function vcombprocess(t,a)
local e={};
e.t="combprocess";
e.slist=a;
e.code=t;
e.slist=t;
e.code=a;
return e;
end
function vsyncprocess(o,a,t)
function vsyncprocess(a,t,o)
local e={};
e.t="syncprocess";
e.clk=o;
e.rst=a;
e.code=t;
e.clk=a;
e.rst=t;
e.code=o;
return e;
end
function vreset(t,a)
function vreset(a,t)
local e={};
e.t="reset";
e.level=t;
e.code=a;
e.level=a;
e.code=t;
return e;
end
function vposedge(t)
......@@ -562,33 +562,33 @@ e.t="posedge";
e.code=t;
return e;
end
function vif(o,a,t)
function vif(t,a,o)
local e={};
e.t="if";
e.cond={o};
e.cond={t};
e.code=a;
e.code_else=t;
e.code_else=o;
return e;
end
function vequal(t,a)
function vequal(a,t)
local e={};
e.t="eq";
e.a=t;
e.b=a;
e.a=a;
e.b=t;
return e;
end
function vand(t,a)
function vand(a,t)
local e={};
e.t="and";
e.a=t;
e.b=a;
e.a=a;
e.b=t;
return e;
end
function vor(a,t)
function vor(t,a)
local e={};
e.t="or";
e.a=a;
e.b=t;
e.a=t;
e.b=a;
return e;
end
function vnot(t)
......@@ -604,11 +604,11 @@ e.a=t;
e.code=a;
return e;
end
function vcase(t,a)
function vcase(a,t)
local e={};
e.t="case";
e.a=t;
e.code=a;
e.a=a;
e.code=t;
return e;
end
function vcasedefault(t)
......@@ -646,23 +646,23 @@ local e={}
e.t="undefined";
return e;
end
function signal(a,o,i,t)
function signal(t,o,a,i)
local e={}
e.comment=t;
e.type=a;
e.comment=i;
e.type=t;
e.range=o;
e.name=i;
e.name=a;
return e;
end
VPORT_WB=1;
VPORT_REG=2;
function port(s,o,i,a,n,t)
function port(a,n,s,i,o,t)
local e={}
e.comment=n;
e.type=s;
e.range=o;
e.name=a;
e.dir=i;
e.comment=o;
e.type=a;
e.range=n;
e.name=i;
e.dir=s;
if(t~=nil)then
if(t==VPORT_WB)then
e.is_wb=true;
......@@ -795,23 +795,23 @@ fieldtype_2_vhdl[SIGNED]="signed";
fieldtype_2_vhdl[UNSIGNED]="unsigned";
fieldtype_2_vhdl[ENUM]="std_logic_vector";
fieldtype_2_vhdl[SLV]="std_logic_vector";
function gen_vhdl_bin_literal(i,o)
if(o==1)then
function gen_vhdl_bin_literal(i,a)
if(a==1)then
return string.format("'%d'",csel(i==0,0,1));
end
local t='\"';
local s,a,n,e;
a=i;
e=math.pow(2,o-1);
local s,o,n,e;
o=i;
e=math.pow(2,a-1);
if(i==nil)then
for e=1,o do
for e=1,a do
t=t.."X";
end
else
for o=1,o do
n=math.floor(a/e);
for a=1,a do
n=math.floor(o/e);
t=t..csel(n>0,"1","0");
a=a%e;
o=o%e;
e=e/2;
end
end
......@@ -912,15 +912,15 @@ indent_left();
emit("");
emit("constant c_"..periph.hdl_prefix.."_"..o.."_registers_init_value: t_"..periph.hdl_prefix.."_"..o.."_registers := (");
indent_right();
for t=1,table.getn(a)do
local e=a[t];
line=strip_periph_prefix(e.name).." => ";
if(e.range>1)then
for e=1,table.getn(a)do
local t=a[e];
line=strip_periph_prefix(t.name).." => ";
if(t.range>1)then
line=line.."(others => '0')"
else
line=line.."'0'"
end
if(t~=table.getn(a))then
if(e~=table.getn(a))then
line=line..",";
end
emit(line);
......@@ -1049,22 +1049,22 @@ emit("end process;");
emit("");
emit("");
end
function cgen_vhdl_combprocess(t)
local e=true;
function cgen_vhdl_combprocess(e)
local t=true;
emiti();
emitx("process (");
for a,t in pairs(t.slist)do
if(e)then
e=false;
for a,e in pairs(e.slist)do
if(t)then
t=false;
else
emitx(", ");
end
emitx(t);
emitx(e);
end
emit(")");
emit("begin");
indent_right();
recurse(t.code);
recurse(e.code);
indent_left();
emit("end process;");
emit("");
......@@ -1168,16 +1168,16 @@ else
die("unsupported assignment: "..t.name.." "..e.name);end
else die("unsupported assignment: "..t.name.." "..e.name);end
end
function cgen_vhdl_assign(e)
local t=node_typesize(e.dst);
local e=node_typesize(e.src);
if(e.type==EXPRESSION)then
function cgen_vhdl_assign(t)
local e=node_typesize(t.dst);
local t=node_typesize(t.src);
if(t.type==EXPRESSION)then
emiti();
emitx(gen_subrange(t).." <= ");
recurse({e.code});
emitx(gen_subrange(e).." <= ");
recurse({t.code});
emitx(";\n");
else
emit(gen_subrange(t).." <= "..gen_vhdl_typecvt(t,e)..";");
emit(gen_subrange(e).." <= "..gen_vhdl_typecvt(e,t)..";");
end
end
function cgen_vhdl_if(e)
......@@ -1253,25 +1253,25 @@ end
emit("end case;");
end
function cgen_vhdl_instance(t)
local o=0;
local a=0;
local o=0;
local e;
emit(t.name.." : "..t.component);
for t,e in pairs(t.maps)do
if(e.t=="genmap")then
a=a+1;
elseif(e.t=="portmap")then
o=o+1;
elseif(e.t=="portmap")then
a=a+1;
end
end
if(a>0)then
if(o>0)then
indent_right();
emit("generic map (");
indent_right();
e=1;
for o,t in pairs(t.maps)do
for a,t in pairs(t.maps)do
if(t.t=="genmap")then
emit(string.format("%-20s => %s",t.to,t.from)..csel(e==a,"",","));
emit(string.format("%-20s => %s",t.to,t.from)..csel(e==o,"",","));
e=e+1;
end
end
......@@ -1279,15 +1279,15 @@ indent_left();
emit(")");
indent_left();
end
if(o>0)then
if(a>0)then
indent_right();
emit("port map (");
indent_right();
e=1;
for a,t in pairs(t.maps)do
for o,t in pairs(t.maps)do
if(t.t=="portmap")then
local a=node_typesize(t.from);
emit(string.format("%-20s => %s",t.to,gen_subrange(a))..csel(e==o,"",","));
local o=node_typesize(t.from);
emit(string.format("%-20s => %s",t.to,gen_subrange(o))..csel(e==a,"",","));
e=e+1;
end
end
......@@ -1776,7 +1776,7 @@ dbg("DOCREG: ",e.name,e.num_fields);
if(e.num_fields~=nil and e.num_fields>0)then
emit("");
emit("/* definitions for register: "..e.name.." */");
foreach_subfield(e,function(t,e)cgen_c_field_define(t,e)end);
foreach_subfield(e,function(e,t)cgen_c_field_define(e,t)end);
end
end);
foreach_reg({TYPE_RAM},function(e)
......@@ -1912,21 +1912,21 @@ end
end
return e;
end
function htable_tdstyle(e,a,t)
tbl.data[e][a].style=t;
function htable_tdstyle(a,t,e)
tbl.data[a][t].style=e;
end
function htable_trstyle(e,a,t)
tbl.data[e].style=t;
end
function htable_frame(a,o,t,e)
if(e==nil)then
a.data[o][t].extra='style="border: solid 1px black;"';
function htable_frame(e,t,o,a)
if(a==nil)then
e.data[t][o].extra='style="border: solid 1px black;"';
else
a.data[o][t].extra='style="border-left: solid 1px black; border-top: solid 1px black; border-bottom: solid 1px black;';
a.data[o][e].extra='style="border-right: solid 1px black; border-top: solid 1px black; border-bottom: solid 1px black;';
if(e>t+1)then
for e=t+1,e-1 do
a.data[o][e].extra='border-top: solid 1px black; border-bottom: solid 1px black;';
e.data[t][o].extra='style="border-left: solid 1px black; border-top: solid 1px black; border-bottom: solid 1px black;';
e.data[t][a].extra='style="border-right: solid 1px black; border-top: solid 1px black; border-bottom: solid 1px black;';
if(a>o+1)then
for a=o+1,a-1 do
e.data[t][a].extra='border-top: solid 1px black; border-bottom: solid 1px black;';
end
end
end
......@@ -1964,11 +1964,11 @@ emit("</tr>");
end
emit("</table>");
end
function has_any_ports(e)
local t=false;
if(e.ports~=nil)then return true;end
foreach_subfield(e,function(e)if(e.ports~=nil)then t=true;end end);
return t;
function has_any_ports(t)
local e=false;
if(t.ports~=nil)then return true;end
foreach_subfield(t,function(t)if(t.ports~=nil)then e=true;end end);
return e;
end
function htable_add_row(e,a)
if(a>e.rows)then
......@@ -1988,8 +1988,8 @@ end
function hitem(e)
return'<li>'..e..'</li>';
end
function hanchor(e,t)
return'<a name="'..e..'">'..t..'</a>';
function hanchor(t,e)
return'<a name="'..t..'">'..e..'</a>';
end
doc_toc={};
function hsection(t,a,o)
......@@ -2051,9 +2051,9 @@ end
end);
cgen_doc_symbol(t);
end
function cgen_doc_mem_symbol(e)
function cgen_doc_mem_symbol(a)
local t={};
for e,a in pairs(e.ports)do
for e,a in pairs(a.ports)do
local e=a;
if(string.find(a.name,"_i")~=nil)then
e.is_wb=true;
......@@ -2062,33 +2062,33 @@ e.is_wb=false;
end
table.insert(t,e);
end
if(e.clock~=nil)then
local e=port(BIT,0,"in",e.clock);
if(a.clock~=nil)then
local e=port(BIT,0,"in",a.clock);
e.is_wb=true;
table.insert(t,e);
end
cgen_doc_symbol(t);
end
function cgen_doc_symbol(o)
function cgen_doc_symbol(i)
local t=htable_new(3,5);
local a=1;
local e=1;
local i=true;
for o,e in pairs(o)do
local o=true;
for o,e in pairs(i)do
if(e.is_wb)then
htable_add_row(t,a);
cgen_doc_port(t.data[a],e,true);
a=a+1;
end
end
for o,a in ipairs(o)do
for i,a in ipairs(i)do
if(type(a)=="string")then
if(i==false)then
if(o==false)then
htable_add_row(t,e);
row=t.data[e];row[3].text="&nbsp;";
e=e+1;
else
i=false;
o=false;
end
htable_add_row(t,e);
local t=t.data[e];
......@@ -2180,27 +2180,27 @@ end
end);
htable_emit(o);
end
function find_field_by_offset(e,t)
local a=nil;
foreach_subfield(e,function(e)if(t>=e.offset and t<=(e.offset+e.size-1))then a=e;end end);
return a;
function find_field_by_offset(e,a)
local t=nil;
foreach_subfield(e,function(e)if(a>=e.offset and a<=(e.offset+e.size-1))then t=e;end end);
return t;
end
function cgen_doc_fieldtable(h,i)
local e=70;
local t;
local e=1;
t=htable_new(2,8);
for e=1,8 do
t.data[1][e].style="td_bit";
t.data[1][e].text=string.format("%d",i+8-e);
local e;
local t=1;
e=htable_new(2,8);
for t=1,8 do
e.data[1][t].style="td_bit";
e.data[1][t].text=string.format("%d",i+8-t);
end
local a=i+7;
while(a>=i)do
local o=find_field_by_offset(h,a);
if(o==nil)then
t.data[2][e].style="td_unused";
t.data[2][e].text="-";
e=e+1;
e.data[2][t].style="td_unused";
e.data[2][t].text="-";
t=t+1;
a=a-1;
else
local n;
......@@ -2211,18 +2211,18 @@ n=o.offset;
end
local s=(a-n)+1;
dbg("ncells: ",s,"bit: ",a,"name: ",o.prefix);
t.data[2][e].colspan=s;
e.data[2][t].colspan=s;
local i;
i=o.c_prefix;
if(i==nil)then i=h.c_prefix;end
t.data[2][e].style="td_field";
t.data[2][e].text=csel(o.size>1,string.format("%s[%d:%d]",string.upper(i),a-o.offset,n-o.offset),string.upper(i));
htable_frame(t,2,e);
e.data[2][t].style="td_field";
e.data[2][t].text=csel(o.size>1,string.format("%s[%d:%d]",string.upper(i),a-o.offset,n-o.offset),string.upper(i));
htable_frame(e,2,t);
a=a-s;
e=e+1;
t=t+1;
end
end
htable_emit(t);
htable_emit(e);
end
function cgen_doc_access(e)
if(e==READ_ONLY)then
......@@ -2322,47 +2322,47 @@ emit("<p>"..string.gsub(t.description,"\n","<br>").."</p>");
end
end
cur_irq_no=1;
function cgen_doc_irq(e)
emit(hanchor(string.upper(e.c_prefix),""));
emit(hsection(5,cur_irq_no,e.name));
function cgen_doc_irq(t)
emit(hanchor(string.upper(t.c_prefix),""));
emit(hsection(5,cur_irq_no,t.name));
cur_irq_no=cur_irq_no+1;
local t=htable_new(3,2);
t.data[1][1].text="<b>HW prefix: </b>";
t.data[2][1].text="<b>C prefix: </b>";
t.data[3][1].text="<b>Trigger: </b>";
t.data[1][2].text=string.lower(periph.hdl_prefix.."_"..e.hdl_prefix);
t.data[2][2].text=string.upper(e.c_prefix);
local e=htable_new(3,2);
e.data[1][1].text="<b>HW prefix: </b>";
e.data[2][1].text="<b>C prefix: </b>";
e.data[3][1].text="<b>Trigger: </b>";
e.data[1][2].text=string.lower(periph.hdl_prefix.."_"..t.hdl_prefix);
e.data[2][2].text=string.upper(t.c_prefix);
local a={
[EDGE_RISING]="rising edge";
[EDGE_FALLING]="falling edge";
[LEVEL_0]="low level";
[LEVEL_1]="high level";
};
t.data[3][2].text=a[e.trigger];
htable_emit(t);
if(e.description~=nil)then
emit("<p>"..string.gsub(e.description,"\n","<br>").."</p>");
e.data[3][2].text=a[t.trigger];
htable_emit(e);
if(t.description~=nil)then
emit("<p>"..string.gsub(t.description,"\n","<br>").."</p>");
end
end
function cgen_generate_documentation()
cgen_new_snippet();cgen_doc_hdl_symbol();local o=cgen_get_snippet();
cgen_new_snippet();cgen_doc_hdl_symbol();local i=cgen_get_snippet();
cgen_new_snippet();
emit(hsection(3,0,"Register description"));
foreach_reg({TYPE_REG},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_reg(e);end end);
local i=cgen_get_snippet();
local a="";
local o=cgen_get_snippet();
local t="";
if(periph.ramcount>0)then
emit(hsection(4,0,"Memory blocks"));
cgen_new_snippet();
foreach_reg({TYPE_RAM},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_ram(e);end end);
a=cgen_get_snippet();
t=cgen_get_snippet();
end
local t="";
local a="";
if(periph.irqcount>0)then
cgen_new_snippet();
emit(hsection(5,0,"Interrupts"));
foreach_reg({TYPE_IRQ},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_irq(e);end end);
t=cgen_get_snippet();
a=cgen_get_snippet();
end
cgen_new_snippet();
cgen_doc_memmap();
......@@ -2370,10 +2370,10 @@ local e=cgen_get_snippet();
cgen_new_snippet();
cgen_doc_header_and_toc();
emit(e);
emit(o);
emit(i);
emit(a);
emit(o);
emit(t);
emit(a);
emit('</BODY>');
emit('</HTML>');
cgen_write_current_snippet();
......@@ -2468,6 +2468,339 @@ cgen_tex_memmap();
foreach_reg({TYPE_REG},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_texinfo_reg(e);end end);
cgen_write_current_snippet();
end
function lx_htable_emit(e)
local t="";
local a="";
if(e.data[1][1].style==nil)then
a="l ";
elseif(e.data[1][1].style=="td_bit")then
a=">{\\centering\\arraybackslash}p{1.5cm} ";
end
t="\\begin{tabular}{";
for e=1,e.cols do
t=t..a;
end
t=t.."}";
emit(t);
for a=1,e.rows do
local t="";
j=1;
while j<=e.cols do
t=t..e.data[a][j].text;
if(e.data[a][j].style~=nil)then
if(e.data[a][j].style=="td_field")then
j=j+e.data[a][j].flen;
end
end
if(j~=e.cols)then
t=t..' & ';
else
t=t..'\\\\';
end
j=j+1;
end
emit(t);
end
emit("\\end{tabular}");
emit("");
end
function cgen_doc_lx_header_and_toc()
emit('\\subsection{'..periph.name..'}');
emit('\\label{subsec:wbgen:'..periph.prefix..'}');
local e=periph.description;
if(e==nil)then e="";end
emit(string.gsub(e,"\n","\\\\"));
end
function cgen_doc_lx_memmap()
local e=2;
local e=" ";
emit('\\subsubsection{Memory map summary}');
emit('\\rowcolors{2}{gray!25}{white}');
emit('\\resizebox{\\textwidth}{!}{');
emit('\\begin{tabular}{|l|l|l|l|l|}');
emit('\\rowcolor{RoyalPurple}');
emit('\\color{white} H/W Addr & \\color{white} Type & \\color{white} Name &');
emit('\\color{white} HW prefix & \\color{white} C prefix\\\\');
foreach_reg({TYPE_REG},function(t)
if(t.full_hdl_prefix~=nil)then
e=string.format("0x%x",t.base)..'& ';
if(t.doc_is_fiforeg==nil)then
e=e.."REG & ";
else
e=e.."FIFOREG & ";
end
e=e..t.name.." & "..t.full_hdl_prefix.." & "..string.upper(t.c_prefix).."\\\\";
e=string.gsub(e,"_","\\_");
emit(e);
end
end);
foreach_reg({TYPE_RAM},function(t)
if(t.full_hdl_prefix~=nil)then
e=string.format("0x%x - 0x%x",t.base,t.base+math.pow(2,t.wrap_bits)*t.size-1)..'& ';
e=e.."MEM & "..t.name.." & "..t.full_hdl_prefix.." & "..string.upper(t.c_prefix).."\\\\";
e=string.gsub(e,"_","\\_");
emit(e);
end
end);
emit('\\end{tabular}');
emit('}');
end
function cgen_doc_lx_fieldtable(h,i)
local e=70;
local e;
local t=1;
e=htable_new(2,8);
for a=1,8 do
e.data[1][a].style="td_bit";
e.data[1][t].flen=0;
e.data[1][a].text=string.format("%d",i+8-a);
end
local a=i+7;
while(a>=i)do
local o=find_field_by_offset(h,a);
if(o==nil)then
e.data[2][t].style="td_unused";
e.data[2][t].flen=0;
if(t==1)then
e.data[2][t].text="\\multicolumn{1}{|c}{-}";
elseif(t==8)then
e.data[2][t].text="\\multicolumn{1}{c|}{-}";
else
e.data[2][t].text="-";
end
t=t+1;
a=a-1;
else
local n;
if(o.offset<i)then
n=i;
else
n=o.offset;
end
local s=(a-n)+1;
dbg("ncells: ",s,"bit: ",a,"name: ",o.prefix);
e.data[2][t].colspan=s;
local i;
i=o.c_prefix;
if(i==nil)then i=h.c_prefix;end
i=string.gsub(i,"_","\\_");
e.data[2][t].style="td_field";
e.data[2][t].flen=a-n;
e.data[2][t].text=csel(o.size>1,string.format("\\multicolumn{%d}{|c|}{\\cellcolor{RoyalPurple!25}%s[%d:%d]}",a-n+1,string.upper(i),a-o.offset,n-o.offset),string.format("\\multicolumn{1}{|c|}{\\cellcolor{RoyalPurple!25}%s}",string.upper(i)));
a=a-s;
t=t+1;
end
end
for a=1,e.rows do
local t="";
j=1;
k=0;
while k<e.cols do
t=t..e.data[a][j].text;
if(e.data[a][j].style~=nil)then
if(e.data[a][j].style=="td_field")then
k=k+e.data[a][j].flen;
end
end
k=k+1;
if(k~=e.cols)then
t=t..' & ';
else
t=t..'\\\\';
end
j=j+1;
end
emit(t);
emit("\\hline");
end
end
function cgen_doc_access(e)
if(e==READ_ONLY)then
return"read-only";
elseif(e==READ_WRITE)then
return"read/write";
elseif(e==WRITE_ONLY)then
return"write-only";
else
return"FIXME!";
end
end
cur_reg_no=1;
function cgen_doc_lx_reg(t)
local o="";
local e="";
cur_reg_no=cur_reg_no+1;
emit("\\paragraph*{"..t.name.."}\\vspace{12pt}");
emit("");
local a=htable_new(4,2);
a.data[1][1].text="{\\bf HW prefix:} ";
a.data[2][1].text="{\\bf HW address:} ";
a.data[3][1].text="{\\bf SW prefix:} ";
a.data[4][1].text="{\\bf SW offset:} ";
a.data[1][2].text=string.gsub(t.full_hdl_prefix,"_","\\_");
a.data[2][2].text=string.format("0x%x",t.base);
a.data[3][2].text=string.gsub(string.upper(t.c_prefix),"_","\\_");
a.data[4][2].text=string.format("0x%x",t.base*(DATA_BUS_WIDTH/8));
emit("\\rowcolors{1}{white}{white}");
lx_htable_emit(a);
if(t.description~=nil)then
emit("\\vspace{12pt}");
e=string.gsub(t.description,"\n","\\\\");
e=string.gsub(e,"_","\\_");
e=string.gsub(e,"<code>","\\texttt{");
e=string.gsub(e,"</code>","}");
emit(e);
end
o="\\begin{tabular}{";
for e=1,8 do
o=o..">{\\centering\\arraybackslash}p{1.5cm} ";
end
o=o.."}";
emit("");
emit("\\vspace{12pt}");
emit("\\noindent");
emit('\\resizebox{\\textwidth}{!}{');
emit(o);
for e=0,DATA_BUS_WIDTH/8-1 do
cgen_doc_lx_fieldtable(t,(DATA_BUS_WIDTH/8-1-e)*8);
end
emit("\\end{tabular}");
emit("}");
emit("");
emit("\\begin{itemize}");
foreach_subfield(t,function(a)
emit("\\item \\begin{small}");
emit("{\\bf ");
if(a.c_prefix==nil)then
emit(string.gsub(string.upper(t.c_prefix),"_","\\_"));
else
emit(string.gsub(string.upper(a.c_prefix),"_","\\_"));
end
emit("} [\\emph{"..cgen_doc_access(a.access_bus).."}]: "..a.name);
if(a.description~=nil)then
emit("\\\\");
e=string.gsub(a.description,"\n","\\\\");
e=string.gsub(e,"_","\\_");
e=string.gsub(e,"<code>","\\texttt{");
e=string.gsub(e,"</code>","}");
emit(e);
end
emit("\\end{small}");
end);
emit("\\end{itemize}");
end
cur_mem_no=1;
function cgen_doc_lx_ram(t)
local a="";
emit("\\paragraph*{"..t.name.."}\\vspace{12pt}");
emit("");
cur_mem_no=cur_mem_no+1;
local e=htable_new(11,2);
e.data[1][1].text="{\\bf HW prefix:} ";
e.data[2][1].text="{\\bf HW address:} ";
e.data[3][1].text="{\\bf C prefix:} ";
e.data[4][1].text="{\\bf C offset:} ";
e.data[5][1].text="{\\bf Size:} ";
e.data[6][1].text="{\\bf Data width:} ";
e.data[7][1].text="{\\bf Access (bus):} ";
e.data[8][1].text="{\\bf Access (device):} ";
e.data[9][1].text="{\\bf Mirrored:} ";
e.data[10][1].text="{\\bf Byte-addressable:} ";
e.data[11][1].text="{\\bf Peripheral port:} ";
e.data[1][2].text=string.lower(string.gsub(periph.hdl_prefix,"_","\\_").."\\_"..string.gsub(t.hdl_prefix,"_","\\_"));
e.data[2][2].text=string.format("0x%x",t.base);
e.data[3][2].text=string.upper(string.gsub(t.c_prefix,"_","\\_"));
e.data[4][2].text=string.format("0x%x",t.base*(DATA_BUS_WIDTH/8));
e.data[5][2].text=t.size.." "..t.width.."-bit words";
e.data[6][2].text=t.width;
e.data[7][2].text=cgen_doc_access(t.access_bus);
e.data[8][2].text=cgen_doc_access(t.access_dev);
if(t.byte_select~=nil and t.byte_select==true)then
e.data[10][2].text="yes";
else
e.data[10][2].text="no";
end
if(t.wrap_bits~=nil and 0~=t.wrap_bits)then
e.data[9][2].text=math.pow(2,t.wrap_bits).." times";
else
e.data[9][2].text="no";
end
if(t.clock~=nil)then
e.data[11][2].text="asynchronous ("..t.clock..")";
else
e.data[11][2].text="bus-synchronous";
end
emit("\\begin{small}");
lx_htable_emit(e);
emit("\\end{small}");
if(t.description~=nil)then
a=string.gsub(t.description,"\n","\\\\");
a=string.gsub(a,"_","\\_");
a=string.gsub(a,"<code>","\\texttt{");
a=string.gsub(a,"</code>","}");
emit(a);
end
end
cur_irq_no=1;
function cgen_doc_lx_irq(a)
local e="";
emit("\\paragraph*{"..a.name.."}\\vspace{12pt}");
cur_irq_no=cur_irq_no+1;
local t=htable_new(3,2);
t.data[1][1].text="{\\bf HW prefix:} ";
t.data[2][1].text="{\\bf C prefix:} ";
t.data[3][1].text="{\\bf Trigger:} ";
t.data[1][2].text=string.gsub(string.lower(periph.hdl_prefix.."_"..a.hdl_prefix),"_","\\_");
t.data[2][2].text=string.upper(string.gsub(a.c_prefix,"_","\\_"));
local o={
[EDGE_RISING]="rising edge";
[EDGE_FALLING]="falling edge";
[LEVEL_0]="low level";
[LEVEL_1]="high level";
};
t.data[3][2].text=o[a.trigger];
emit("\\begin{small}");
lx_htable_emit(t);
emit("\\end{small}");
if(a.description~=nil)then
emit("\\vspace{12pt}");
e=string.gsub(a.description,"\n","\\\\");
e=string.gsub(e,"_","\\_");
e=string.gsub(e,"<code>","\\texttt{");
e=string.gsub(e,"</code>","}");
emit(e);
end
end
function cgen_generate_latex_documentation()
cgen_new_snippet();
emit("\\subsubsection{Register description}");
foreach_reg({TYPE_REG},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_lx_reg(e);end end);
local o=cgen_get_snippet();
local a="";
if(periph.ramcount>0)then
emit("\\subsubsection{Memory blocks}");
cgen_new_snippet();
foreach_reg({TYPE_RAM},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_lx_ram(e);end end);
a=cgen_get_snippet();
end
local t="";
if(periph.irqcount>0)then
cgen_new_snippet();
emit("\\subsubsection{Interrupts}");
foreach_reg({TYPE_IRQ},function(e)if(e.no_docu==nil or e.no_docu==false)then cgen_doc_lx_irq(e);end end);
t=cgen_get_snippet();
end
cgen_new_snippet();
cgen_doc_lx_memmap();
local e=cgen_get_snippet();
cgen_new_snippet();
cgen_doc_lx_header_and_toc();
emit(e);
emit(o);
emit(a);
emit(t);
cgen_write_current_snippet();
end
function gen_hdl_field_prefix(a,e)
local t;
if(e.hdl_prefix==nil)then
......@@ -2957,27 +3290,27 @@ e.ports={};
e.acklen=1;
e.read_code={va(vir("rddata_reg",e),e.value);};
end
function fill_unused_bits(o,e)
function fill_unused_bits(i,e)
local a={};
local t={};
local i=true;
local o=true;
foreach_subfield(e,function(e,t)
if(e.type==SLV or e.type==SIGNED or e.type==UNSIGNED or e.type==CONSTANT)then
for e=e.offset,(e.offset+e.size-1)do a[e]=1;end
elseif(e.type==BIT or e.type==MONOSTABLE)then
a[e.offset]=1;
end
if(e.access_bus~=WRITE_ONLY)then i=false;end
if(e.access_bus~=WRITE_ONLY)then o=false;end
end);
if(i)then
if(o)then
for e=0,DATA_BUS_WIDTH-1 do
table_join(t,{va(vi(o,e),vundefined());});
table_join(t,{va(vi(i,e),vundefined());});
end
return t;
end
for e=0,DATA_BUS_WIDTH-1 do
if(a[e]==nil)then
table_join(t,{va(vi(o,e),vundefined());});
table_join(t,{va(vi(i,e),vundefined());});
end
end
return t;
......@@ -3100,8 +3433,8 @@ end
function wbgen_generate_eic()
if(periph.irqcount==0)then return;end
local t=0;
local o={};
local a={["__type"]=TYPE_REG;
local s={};
local i={["__type"]=TYPE_REG;
["__blockindex"]=1e6;
["align"]=8;
["name"]="Interrupt disable register";
......@@ -3117,7 +3450,7 @@ signal(BIT,0,"eic_idr_write_int");};
["extra_code"]={va(vi("eic_idr_int",periph.irqcount-1,0),vi("wrdata_reg",periph.irqcount-1,0));};
["no_std_regbank"]=true;
};
local i={["__type"]=TYPE_REG;
local a={["__type"]=TYPE_REG;
["__blockindex"]=1000001;
["align"]=1;
["name"]="Interrupt enable register";
......@@ -3133,7 +3466,7 @@ signal(BIT,0,"eic_ier_write_int");};
["extra_code"]={va(vi("eic_ier_int",periph.irqcount-1,0),vi("wrdata_reg",periph.irqcount-1,0));};
["no_std_regbank"]=true;
};
local s={["__type"]=TYPE_REG;
local o={["__type"]=TYPE_REG;
["__blockindex"]=1000002;
["align"]=1;
["name"]="Interrupt status register";
......@@ -3167,7 +3500,7 @@ local n={["__type"]=TYPE_REG;
foreach_reg({TYPE_IRQ},function(e)
e.index=t;
t=t+1;
table.insert(o,{["index"]=e.index;["trigger"]=e.trigger;});
table.insert(s,{["index"]=e.index;["trigger"]=e.trigger;});
fix_prefix(e);
local t={
["__blockindex"]=e.index;
......@@ -3180,7 +3513,7 @@ local t={
["access_bus"]=READ_WRITE;
["access_dev"]=READ_WRITE;
};
local o={
local s={
["__blockindex"]=e.index;
["__type"]=TYPE_FIELD;
["type"]=BIT;
......@@ -3222,18 +3555,18 @@ end
if(e.mask_line==true)then
table_join(e.ports,{port(BIT,0,"out",e.full_prefix.."_mask_o");});
end
table.insert(a,r);
table.insert(s,t);
table.insert(i,r);
table.insert(o,t);
table.insert(n,h);
table.insert(i,o);
table.insert(a,s);
end);
add_global_signals({
signal(SLV,periph.irqcount,"irq_inputs_vector_int");
});
table.insert(periph,a);
table.insert(periph,i);
table.insert(periph,a);
table.insert(periph,n);
table.insert(periph,s);
table.insert(periph,o);
local e={vgm("g_num_interrupts",periph.irqcount);
vpm("clk_i","clk_sys_i");
vpm("rst_n_i","rst_n_i");
......@@ -3250,7 +3583,7 @@ vpm("reg_isr_wr_stb_i","eic_isr_write_int");
vpm("wb_irq_o","wb_int_o");
};
local a;
for o,t in ipairs(o)do
for o,t in ipairs(s)do
table_join(e,{vgm(string.format("g_irq%02x_mode",t.index),t.trigger)});
a=o;
end
......@@ -3430,7 +3763,7 @@ local s={
["hdl_prefix"]=e.hdl_prefix.."_CSR";
["no_std_regbank"]=true;
};
function gen_fifo_csr_field(d,n,t,r,h,o,a,i)
function gen_fifo_csr_field(d,n,t,a,h,o,r,i)
print("GenCSR Field "..t);
if(e.flags_bus==nil)then
return;
......@@ -3439,12 +3772,12 @@ if inset(d,e.flags_bus)then
local t={
["__type"]=TYPE_FIELD;
["name"]=t;
["description"]=r;
["description"]=a;
["access_bus"]=READ_ONLY;
["access_dev"]=WRITE_ONLY;
["type"]=o;
["size"]=h;
["offset"]=a;
["offset"]=r;
["c_prefix"]=n;
["hdl_prefix"]=n;
["signals"]={};
......@@ -3639,42 +3972,42 @@ gen_pipelined_wb_signals(e);
foreach_reg(ALL_REG_TYPES,function(e)
gen_abstract_code(e);
end);
local o={};
local i={};
local n={};
local i={};
local o={};
foreach_field(function(e,t)
table_join(o,e.reset_code_main);
table_join(n,e.reset_code_main);
end);
foreach_reg(ALL_REG_TYPES,function(e)
table_join(o,e.reset_code_main);
table_join(n,e.reset_code_main);
end);
foreach_reg({TYPE_REG},function(e)
foreach_subfield(e,function(e,t)
table_join(i,e.ackgen_code);
table_join(n,e.ackgen_code_pre);
table_join(o,e.ackgen_code_pre);
end);
table_join(i,e.ackgen_code);
table_join(n,e.ackgen_code_pre);
table_join(o,e.ackgen_code_pre);
end);
local e={};
foreach_reg({TYPE_REG},function(t)
local n=find_max(t,"acklen");
local a={};
local i=find_max(t,"acklen");
local o={};
foreach_subfield(t,function(e,t)table_join(o,e.write_code);end);
foreach_subfield(t,function(e,t)table_join(a,e.read_code);end);
local i=fill_unused_bits("rddata_reg",t);
table_join(o,t.write_code);
table_join(a,t.read_code);
local a={};
foreach_subfield(t,function(e,t)table_join(a,e.write_code);end);
foreach_subfield(t,function(e,t)table_join(o,e.read_code);end);
local n=fill_unused_bits("rddata_reg",t);
table_join(a,t.write_code);
table_join(o,t.read_code);
local a={
vif(vequal("wb_we_i",1),{
o,
});
a,
i
});
o,
n
};
if(not(t.dont_emit_ack_code==true))then
table_join(a,{va(vi("ack_sreg",math.max(n-1,0)),1);});
table_join(a,{va(vi("ack_sreg",math.max(i-1,0)),1);});
table_join(a,{va("ack_in_progress",1);});
end
if(regbank_address_bits>0)then
......@@ -3731,14 +4064,14 @@ vreset(0,{
va("ack_sreg",0);
va("ack_in_progress",0);
va("rddata_reg",0);
o
n
});
vposedge({
vcomment("advance the ACK generator shift register");
va(vi("ack_sreg",MAX_ACK_LENGTH-2,0),vi("ack_sreg",MAX_ACK_LENGTH-1,1));
va(vi("ack_sreg",MAX_ACK_LENGTH-1),0);
vif(vequal("ack_in_progress",1),{
vif(vequal(vi("ack_sreg",0),1),{i;va("ack_in_progress",0);},n);
vif(vequal(vi("ack_sreg",0),1),{i;va("ack_in_progress",0);},o);
},{
e
});
......@@ -3747,20 +4080,20 @@ e
};
if(periph.ramcount>0)then
if(not options.register_data_output)then
local a={"rddata_reg","rwaddr_reg"};
local t={};
local o={vswitch(vi("rwaddr_reg",address_bus_width-1,address_bus_width-address_bus_select_bits),t);};
local o={vcomment("Data output multiplexer process");vcombprocess(a,o);};
local t={"rddata_reg","rwaddr_reg"};
local a={};
local o={vswitch(vi("rwaddr_reg",address_bus_width-1,address_bus_width-address_bus_select_bits),a);};
local o={vcomment("Data output multiplexer process");vcombprocess(t,o);};
foreach_reg({TYPE_RAM},function(e)
table.insert(a,e.full_prefix.."_rddata_int");
local a={va(vi("wb_dat_o",e.width-1,0),e.full_prefix.."_rddata_int");};
table.insert(t,e.full_prefix.."_rddata_int");
local t={va(vi("wb_dat_o",e.width-1,0),e.full_prefix.."_rddata_int");};
if(e.width<DATA_BUS_WIDTH)then
table_join(a,{va(vi("wb_dat_o",DATA_BUS_WIDTH-1,e.width),0);});
table_join(t,{va(vi("wb_dat_o",DATA_BUS_WIDTH-1,e.width),0);});
end
table_join(t,{vcase(e.select_bits,a);});
table_join(a,{vcase(e.select_bits,t);});
end);
table.insert(a,"wb_adr_i");
table_join(t,{vcasedefault(va("wb_dat_o","rddata_reg"));});
table.insert(t,"wb_adr_i");
table_join(a,{vcasedefault(va("wb_dat_o","rddata_reg"));});
table_join(e,o);
end
local a={"wb_adr_i","rd_int","wr_int"};
......@@ -3814,7 +4147,7 @@ local e=[[slave Wishbone generator
wbgen2 [options] input_file.wb]]
local t=[[options:
-C, --co=FILE Write the slave's generated C header file to FILE
-f, --docformat=FORMAT Write documentation for texinfo or HTML (defaults to HTML)
-f, --docformat=FORMAT Write documentation for latex, texinfo or HTML (defaults to HTML)
-D, --doco=FILE Write the slave's generated documentation to FILE
-h, --help Show this help text
-l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG
......@@ -3941,7 +4274,10 @@ end
if(options.output_doc_file~=nil)then
cgen_generate_init(options.output_doc_file);
if(options.doc_format=="html")then
print("gen html");
cgen_generate_documentation();
elseif(options.doc_format=="latex")then
cgen_generate_latex_documentation();
else
cgen_generate_texinfo_documentation();
end
......
......@@ -36,7 +36,7 @@ local usage_string = [[slave Wishbone generator
local commands_string = [[options:
-C, --co=FILE Write the slave's generated C header file to FILE
-f, --docformat=FORMAT Write documentation for texinfo or HTML (defaults to HTML)
-f, --docformat=FORMAT Write documentation for latex, texinfo or HTML (defaults to HTML)
-D, --doco=FILE Write the slave's generated documentation to FILE
-h, --help Show this help text
-l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG
......@@ -209,8 +209,11 @@ if(options.output_doc_file ~= nil) then
cgen_generate_init(options.output_doc_file);
if(options.doc_format == "html") then
print("gen html");
cgen_generate_documentation();
else
elseif(options.doc_format == "latex") then
cgen_generate_latex_documentation();
else
cgen_generate_texinfo_documentation();
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