Commit dcd6b1f9 authored by twlostow's avatar twlostow

Added CONSTANT registers & #define REGISTER_ADDRESS macros in C code generator

git-svn-id: http://svn.ohwr.org/wishbone-gen@17 4537843c-45c2-4d80-8546-c3283569414f
parent 69763cad
...@@ -18,177 +18,191 @@ ...@@ -18,177 +18,191 @@
-- field1_value = FIELD1_R(regs_struct->reg); -- field1_value = FIELD1_R(regs_struct->reg);
-- --
function cgen_c_field_define(field, reg) function cgen_c_field_define(field, reg)
local prefix; local prefix;
-- anonymous field? -- anonymous field?
if(field.c_prefix == nil) then if(field.c_prefix == nil) then
return ; return ;
else else
prefix=string.upper(periph.c_prefix).."_"..string.upper (reg.c_prefix).."_"..string.upper(field.c_prefix); prefix=string.upper(periph.c_prefix).."_"..string.upper (reg.c_prefix).."_"..string.upper(field.c_prefix);
end end
emit(""); emit("");
emit("/* definitions for field: "..field.name.." in reg: "..reg.name.." */"); emit("/* definitions for field: "..field.name.." in reg: "..reg.name.." */");
-- for bit-type fields, emit only masks -- for bit-type fields, emit only masks
if(field.type == BIT or field.type == MONOSTABLE) then if(field.type == BIT or field.type == MONOSTABLE) then
emit(string.format("%-45s %s", "#define "..prefix, "WBGEN2_GEN_MASK("..field.offset..", 1)")); emit(string.format("%-45s %s", "#define "..prefix, "WBGEN2_GEN_MASK("..field.offset..", 1)"));
else else
-- SLV/signed/unsigned fields: emit masks, shifts and access macros -- SLV/signed/unsigned fields: emit masks, shifts and access macros
emit(string.format("%-45s %s", "#define "..prefix.."_MASK", "WBGEN2_GEN_MASK("..field.offset..", "..field.size..")")); emit(string.format("%-45s %s", "#define "..prefix.."_MASK", "WBGEN2_GEN_MASK("..field.offset..", "..field.size..")"));
emit(string.format("%-45s %d", "#define "..prefix.."_SHIFT", field.offset)); emit(string.format("%-45s %d", "#define "..prefix.."_SHIFT", field.offset));
emit(string.format("%-45s %s", "#define "..prefix.."_W(value)", "WBGEN2_GEN_WRITE(value, "..field.offset..", "..field.size..")")); emit(string.format("%-45s %s", "#define "..prefix.."_W(value)", "WBGEN2_GEN_WRITE(value, "..field.offset..", "..field.size..")"));
-- if the field is signed, generate read operation with sign-extension -- if the field is signed, generate read operation with sign-extension
if(field.type == SIGNED) then if(field.type == SIGNED) then
emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_SIGN_EXTEND(WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size.."), "..field.size..")")); emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_SIGN_EXTEND(WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size.."), "..field.size..")"));
else else
emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size..")")); emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size..")"));
end end
end end
end end
-- generates some definitions for RAM memory block -- generates some definitions for RAM memory block
function cgen_c_ramdefs(ram) function cgen_c_ramdefs(ram)
local prefix = string.upper(periph.c_prefix).."_"..string.upper(ram.c_prefix); local prefix = string.upper(periph.c_prefix).."_"..string.upper(ram.c_prefix);
emit("/* definitions for RAM: "..ram.name.." */"); emit("/* definitions for RAM: "..ram.name.." */");
emit(string.format("#define "..prefix.."_BYTES 0x%08x %-50s", ram.size * ram.width / 8, "/* size in bytes */")); emit(string.format("#define "..prefix.."_BYTES 0x%08x %-50s", ram.size * ram.width / 8, "/* size in bytes */"));
emit(string.format("#define "..prefix.."_WORDS 0x%08x %-50s", ram.size, "/* size in "..ram.width.."-bit words, 32-bit aligned */")); emit(string.format("#define "..prefix.."_WORDS 0x%08x %-50s", ram.size, "/* size in "..ram.width.."-bit words, 32-bit aligned */"));
end end
-- iterates all regs and rams and generates appropriate #define-s -- iterates all regs and rams and generates appropriate #define-s
function cgen_c_field_masks() function cgen_c_field_masks()
foreach_reg({TYPE_REG}, function(reg) foreach_reg({TYPE_REG}, function(reg)
dbg("DOCREG: ", reg.name, reg.num_fields); dbg("DOCREG: ", reg.name, reg.num_fields);
if(reg.num_fields ~= nil and reg.num_fields > 0) then if(reg.num_fields ~= nil and reg.num_fields > 0) then
emit(""); emit("");
emit("/* definitions for register: "..reg.name.." */"); emit("/* definitions for register: "..reg.name.." */");
foreach_subfield(reg, function(field, reg) cgen_c_field_define(field, reg) end); foreach_subfield(reg, function(field, reg) cgen_c_field_define(field, reg) end);
end end
end); end);
foreach_reg({TYPE_RAM}, function(ram) foreach_reg({TYPE_RAM}, function(ram)
cgen_c_ramdefs(ram); cgen_c_ramdefs(ram);
end); end);
end end
-- generates C file header -- generates C file header
function cgen_c_fileheader() function cgen_c_fileheader()
emit ("/*"); emit ("/*");
emit (" Register definitions for slave core: "..periph.name); emit (" Register definitions for slave core: "..periph.name);
emit (""); emit ("");
emit (" * File : "..options.output_c_header_file); emit (" * File : "..options.output_c_header_file);
emit (" * Author : auto-generated by wbgen2 from "..input_wb_file); emit (" * Author : auto-generated by wbgen2 from "..input_wb_file);
emit (" * Created : "..os.date()); emit (" * Created : "..os.date());
emit (" * Standard : ANSI C"); emit (" * Standard : ANSI C");
emit (""); emit ("");
emit (" THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE "..input_wb_file); emit (" THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE "..input_wb_file);
emit (" DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!"); emit (" DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!");
emit (""); emit ("");
emit ("*/"); emit ("*/");
emit(""); emit("");
emit("#ifndef __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_"))) emit("#ifndef __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit("#define __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_"))) emit("#define __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit(""); emit("");
emit("#include <inttypes.h>"); emit("#include <inttypes.h>");
emit(""); emit("");
emit("#if defined( __GNUC__)"); emit("#if defined( __GNUC__)");
emit("#define PACKED __attribute__ ((packed))"); emit("#define PACKED __attribute__ ((packed))");
emit("#else"); emit("#else");
emit("#error \"Unsupported compiler?\""); emit("#error \"Unsupported compiler?\"");
emit("#endif"); emit("#endif");
emit(""); emit("");
emit("#ifndef __WBGEN2_MACROS_DEFINED__"); emit("#ifndef __WBGEN2_MACROS_DEFINED__");
emit("#define __WBGEN2_MACROS_DEFINED__"); emit("#define __WBGEN2_MACROS_DEFINED__");
emit("#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))"); emit("#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))");
emit("#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))"); emit("#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))");
emit("#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))"); emit("#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))");
emit("#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))"); emit("#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))");
emit("#endif"); emit("#endif");
emit(""); emit("");
end end
-- generates C structure reflecting the memory map of the peripheral. -- generates C structure reflecting the memory map of the peripheral.
function cgen_c_struct() function cgen_c_struct()
local cur_offset = 0; local cur_offset = 0;
local pad_id = 0; local pad_id = 0;
-- generates padding entry (if the offset of the register in memory is ahead of current offset in the structure) -- generates padding entry (if the offset of the register in memory is ahead of current offset in the structure)
function pad_struct(base) function pad_struct(base)
if(cur_offset < base) then if(cur_offset < base) then
emit("/* padding to: "..base.." words */"); emit("/* padding to: "..base.." words */");
emit("uint32_t __padding_"..pad_id.."["..(base - cur_offset).."];"); emit("uint32_t __padding_"..pad_id.."["..(base - cur_offset).."];");
pad_id=pad_id+1; pad_id=pad_id+1;
cur_offset = base; cur_offset = base;
end end
end end
-- emit the structure definition... -- emit the structure definition...
emit(""); emit("");
emit("PACKED struct "..string.upper(periph.c_prefix).."_WB {"); emit("PACKED struct "..string.upper(periph.c_prefix).."_WB {");
indent_right(); indent_right();
-- emit struct entires for REGs -- emit struct entires for REGs
foreach_reg({TYPE_REG}, function(reg) foreach_reg({TYPE_REG}, function(reg)
-- print(reg.name, reg.prefix, reg.c_prefix, reg.hdl_prefix); -- print(reg.name, reg.prefix, reg.c_prefix, reg.hdl_prefix);
pad_struct(reg.base); pad_struct(reg.base);
emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8)); emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8));
-- this is just simple :) -- this is just simple :)
emit("uint32_t "..string.upper(reg.c_prefix)..";"); emit("uint32_t "..string.upper(reg.c_prefix)..";");
cur_offset = cur_offset + 1; cur_offset = cur_offset + 1;
end); end);
-- .. and for RAMs
foreach_reg({TYPE_RAM}, function(ram)
-- calculate base address of the RAM
-- print("SelBits: ram "..ram.name.." sb "..ram.select_bits);
local base = ram.select_bits *
math.pow (2, address_bus_width - address_bus_select_bits);
pad_struct(base);
-- output some comments
emiti();
emitx(string.format("/* [0x%x - 0x%x]: RAM "..ram.name..", "..ram.size.." "..ram.width.."-bit words, "..DATA_BUS_WIDTH.."-bit aligned, "..csel(ram.byte_select, "byte", "word").."-addressable", base * DATA_BUS_WIDTH / 8, (base + math.pow(2, ram.wrap_bits)*ram.size) * (DATA_BUS_WIDTH / 8) - 1));
if(ram.wrap_bits > 0) then
emitx(", mirroring: "..math.pow(2, ram.wrap_bits).." times */\n");
else
emitx(" */\n");
end
-- and the RAM, as an array
if(ram.byte_select) then
emit("uint8_t "..string.upper(ram.c_prefix).." ["..(ram.size * (DATA_BUS_WIDTH/8) * math.pow(2, ram.wrap_bits)) .."];");
else
emit("uint32_t "..string.upper(ram.c_prefix).." ["..(ram.size * math.pow(2, ram.wrap_bits)) .."];");
end
end);
indent_left();
emit("};");
emit("");
end
-- .. and for RAMs
foreach_reg({TYPE_RAM}, function(ram)
-- calculate base address of the RAM function cgen_c_defines()
foreach_reg({TYPE_REG}, function(reg)
-- print("SelBits: ram "..ram.name.." sb "..ram.select_bits); emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8));
local base = ram.select_bits * emit("#define "..string.upper(periph.c_prefix).."_REG_"..string.upper(reg.c_prefix).." "..string.format("0x%08x", reg.base * DATA_BUS_WIDTH/8));
math.pow (2, address_bus_width - address_bus_select_bits); end);
pad_struct(base);
-- output some comments
emiti();
emitx(string.format("/* [0x%x - 0x%x]: RAM "..ram.name..", "..ram.size.." "..ram.width.."-bit words, "..DATA_BUS_WIDTH.."-bit aligned, "..csel(ram.byte_select, "byte", "word").."-addressable", base * DATA_BUS_WIDTH / 8, (base + math.pow(2, ram.wrap_bits)*ram.size) * (DATA_BUS_WIDTH / 8) - 1));
if(ram.wrap_bits > 0) then
emitx(", mirroring: "..math.pow(2, ram.wrap_bits).." times */\n");
else
emitx(" */\n");
end
-- and the RAM, as an array
if(ram.byte_select) then
emit("uint8_t "..string.upper(ram.c_prefix).." ["..(ram.size * (DATA_BUS_WIDTH/8) * math.pow(2, ram.wrap_bits)) .."];");
else
emit("uint32_t "..string.upper(ram.c_prefix).." ["..(ram.size * math.pow(2, ram.wrap_bits)) .."];");
end
end);
indent_left();
emit("};");
emit("");
end end
-- main C code generator function. Takes the peripheral definition and generates C code. -- main C code generator function. Takes the peripheral definition and generates C code.
function cgen_generate_c_header_code() function cgen_generate_c_header_code()
cgen_new_snippet(); cgen_new_snippet();
cgen_c_fileheader(); cgen_c_fileheader();
cgen_c_field_masks(); cgen_c_field_masks();
cgen_c_struct();
if(options.c_regs_style == "struct") then
emit("#endif"); cgen_c_struct();
cgen_write_current_snippet(); else
cgen_c_defines();
end
emit("#endif");
cgen_write_current_snippet();
end end
...@@ -49,6 +49,7 @@ PASS_THROUGH = 0x40; ...@@ -49,6 +49,7 @@ PASS_THROUGH = 0x40;
INTEGER = 0x80; INTEGER = 0x80;
EXPRESSION = 0x100; EXPRESSION = 0x100;
UNDEFINED = 0x200; UNDEFINED = 0x200;
CONSTANT = 0x400;
-- reg LOAD types -- reg LOAD types
LOAD_INT = 1; LOAD_INT = 1;
...@@ -308,6 +309,7 @@ function fix_access(field, reg) ...@@ -308,6 +309,7 @@ function fix_access(field, reg)
default_access(field, MONOSTABLE, WRITE_ONLY, READ_ONLY); default_access(field, MONOSTABLE, WRITE_ONLY, READ_ONLY);
default_access(field, ENUM, READ_WRITE, READ_ONLY); default_access(field, ENUM, READ_WRITE, READ_ONLY);
default_access(field, PASS_THROUGH, WRITE_ONLY, READ_ONLY); default_access(field, PASS_THROUGH, WRITE_ONLY, READ_ONLY);
default_access(field, CONSTANT, READ_ONLY, WRITE_ONLY);
if(field.access ~= nil) then if(field.access ~= nil) then
return; return;
......
...@@ -25,6 +25,7 @@ options.reset_type = "asynchronous"; ...@@ -25,6 +25,7 @@ options.reset_type = "asynchronous";
options.target_interconnect = "wb-classic"; options.target_interconnect = "wb-classic";
options.register_data_output = false; options.register_data_output = false;
options.lang = "vhdl"; options.lang = "vhdl";
options.c_reg_style = "struct";
require "alt_getopt" require "alt_getopt"
...@@ -32,14 +33,16 @@ local usage_string = [[slave Wishbone generator ...@@ -32,14 +33,16 @@ local usage_string = [[slave Wishbone generator
wbgen2 [options] input_file.wb]] wbgen2 [options] input_file.wb]]
local commands_string = [[options: local commands_string = [[options:
-C, --co=FILE Write the slave's generated C header file to FILE -C, --co=FILE Write the slave's generated C header file to FILE
-D, --doco=FILE Write the slave's generated HTML documentation to FILE -D, --doco=FILE Write the slave's generated HTML documentation to FILE
-h, --help Show this help text -h, --help Show this help text
-l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG -l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG
Valid values for LANG: {vhdl,verilog} Valid values for LANG: {vhdl,verilog}
-K, --constco=FILE Populate FILE with Verilog output (mainly constants) -s, --cstyle=STYLE Set the style of register bank in generated C headers
-v, --version Show version information Valid values for STYLE: {struct, defines}
-V, --vo=FILE Write the slave's generated HDL code to FILE -K, --constco=FILE Populate FILE with Verilog output (mainly constants)
-v, --version Show version information
-V, --vo=FILE Write the slave's generated HDL code to FILE
wbgen2 (c) Tomasz Wlostowski/CERN BE-CO-HT 2010]] wbgen2 (c) Tomasz Wlostowski/CERN BE-CO-HT 2010]]
...@@ -55,18 +58,19 @@ end ...@@ -55,18 +58,19 @@ end
function parse_args(arg) function parse_args(arg)
local long_opts = { local long_opts = {
help = "h", help = "h",
version = "v", version = "v",
co = "C", co = "C",
doco = "D", doco = "D",
constco = "K", constco = "K",
lang = "l", lang = "l",
vo = "V", vo = "V",
cstyle = "s"
} }
local optarg local optarg
local optind local optind
optarg,optind = alt_getopt.get_opts (arg, "hvC:D:K:l:V:", long_opts) optarg,optind = alt_getopt.get_opts (arg, "hvC:D:K:l:V:s:", long_opts)
for key,value in pairs (optarg) do for key,value in pairs (optarg) do
if key == "h" then if key == "h" then
usage_complete() usage_complete()
...@@ -91,6 +95,12 @@ function parse_args(arg) ...@@ -91,6 +95,12 @@ function parse_args(arg)
die("Unknown HDL: "..options.lang); die("Unknown HDL: "..options.lang);
end end
elseif key == "s" then
options.c_reg_style = value;
if (options.c_reg_style ~= "struct" and options.c_reg_style ~= "defines") then
die("Unknown C RegBank style: "..options.c_reg_style);
end
elseif key == "V" then elseif key == "V" then
options.output_hdl_file = value options.output_hdl_file = value
end end
......
...@@ -622,6 +622,18 @@ function gen_hdl_code_passthrough(field, reg) ...@@ -622,6 +622,18 @@ function gen_hdl_code_passthrough(field, reg)
end end
function gen_hdl_code_constant(field, reg)
local prefix = gen_hdl_field_prefix(field, reg);
if(field.value == nil) then
die("No value defined for CONSTANT field '"..field.name.."'.");
end
field.ports = {};
field.acklen = 1;
field.read_code = { va(vir("rddata_reg", field), field.value ); };
end
-- generates code which loads data unused bits of data output register with Xs -- generates code which loads data unused bits of data output register with Xs
function fill_unused_bits(target, reg) function fill_unused_bits(target, reg)
local t={}; local t={};
...@@ -629,7 +641,7 @@ function fill_unused_bits(target, reg) ...@@ -629,7 +641,7 @@ function fill_unused_bits(target, reg)
local all_wo = true; local all_wo = true;
foreach_subfield(reg, function(field, reg) foreach_subfield(reg, function(field, reg)
if(field.type == SLV or field.type == SIGNED or field.type == UNSIGNED) then if(field.type == SLV or field.type == SIGNED or field.type == UNSIGNED or field.type == CONSTANT) then
for i=field.offset, (field.offset+field.size-1) do t[i] = 1; end for i=field.offset, (field.offset+field.size-1) do t[i] = 1; end
elseif(field.type == BIT or field.type == MONOSTABLE) then elseif(field.type == BIT or field.type == MONOSTABLE) then
t[field.offset] = 1; t[field.offset] = 1;
...@@ -666,7 +678,10 @@ function gen_hdl_code_reg_field(field, reg) ...@@ -666,7 +678,10 @@ function gen_hdl_code_reg_field(field, reg)
gen_hdl_code_slv(field, reg); gen_hdl_code_slv(field, reg);
elseif(field.type == PASS_THROUGH) then elseif(field.type == PASS_THROUGH) then
gen_hdl_code_passthrough(field, reg); gen_hdl_code_passthrough(field, reg);
elseif(field.type == CONSTANT) then
gen_hdl_code_constant(field, reg);
end end
end end
-- generates VHDL for single register -- generates VHDL for single register
......
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