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 @@
-- field1_value = FIELD1_R(regs_struct->reg);
--
function cgen_c_field_define(field, reg)
local prefix;
-- anonymous field?
if(field.c_prefix == nil) then
return ;
else
prefix=string.upper(periph.c_prefix).."_"..string.upper (reg.c_prefix).."_"..string.upper(field.c_prefix);
end
emit("");
emit("/* definitions for field: "..field.name.." in reg: "..reg.name.." */");
-- for bit-type fields, emit only masks
if(field.type == BIT or field.type == MONOSTABLE) then
emit(string.format("%-45s %s", "#define "..prefix, "WBGEN2_GEN_MASK("..field.offset..", 1)"));
else
-- 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 %d", "#define "..prefix.."_SHIFT", field.offset));
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(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..")"));
else
emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size..")"));
end
end
local prefix;
-- anonymous field?
if(field.c_prefix == nil) then
return ;
else
prefix=string.upper(periph.c_prefix).."_"..string.upper (reg.c_prefix).."_"..string.upper(field.c_prefix);
end
emit("");
emit("/* definitions for field: "..field.name.." in reg: "..reg.name.." */");
-- for bit-type fields, emit only masks
if(field.type == BIT or field.type == MONOSTABLE) then
emit(string.format("%-45s %s", "#define "..prefix, "WBGEN2_GEN_MASK("..field.offset..", 1)"));
else
-- 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 %d", "#define "..prefix.."_SHIFT", field.offset));
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(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..")"));
else
emit(string.format("%-45s %s", "#define "..prefix.."_R(reg)", "WBGEN2_GEN_READ(reg, "..field.offset..", "..field.size..")"));
end
end
end
-- generates some definitions for RAM memory block
function cgen_c_ramdefs(ram)
local prefix = string.upper(periph.c_prefix).."_"..string.upper(ram.c_prefix);
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.."_WORDS 0x%08x %-50s", ram.size, "/* size in "..ram.width.."-bit words, 32-bit aligned */"));
local prefix = string.upper(periph.c_prefix).."_"..string.upper(ram.c_prefix);
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.."_WORDS 0x%08x %-50s", ram.size, "/* size in "..ram.width.."-bit words, 32-bit aligned */"));
end
-- iterates all regs and rams and generates appropriate #define-s
function cgen_c_field_masks()
foreach_reg({TYPE_REG}, function(reg)
dbg("DOCREG: ", reg.name, reg.num_fields);
if(reg.num_fields ~= nil and reg.num_fields > 0) then
emit("");
emit("/* definitions for register: "..reg.name.." */");
foreach_subfield(reg, function(field, reg) cgen_c_field_define(field, reg) end);
end
end);
foreach_reg({TYPE_RAM}, function(ram)
cgen_c_ramdefs(ram);
end);
foreach_reg({TYPE_REG}, function(reg)
dbg("DOCREG: ", reg.name, reg.num_fields);
if(reg.num_fields ~= nil and reg.num_fields > 0) then
emit("");
emit("/* definitions for register: "..reg.name.." */");
foreach_subfield(reg, function(field, reg) cgen_c_field_define(field, reg) end);
end
end);
foreach_reg({TYPE_RAM}, function(ram)
cgen_c_ramdefs(ram);
end);
end
-- generates C file header
function cgen_c_fileheader()
emit ("/*");
emit (" Register definitions for slave core: "..periph.name);
emit ("");
emit (" * File : "..options.output_c_header_file);
emit (" * Author : auto-generated by wbgen2 from "..input_wb_file);
emit (" * Created : "..os.date());
emit (" * Standard : ANSI C");
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("");
emit("#ifndef __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit("#define __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit("");
emit("#include <inttypes.h>");
emit("");
emit("#if defined( __GNUC__)");
emit("#define PACKED __attribute__ ((packed))");
emit("#else");
emit("#error \"Unsupported compiler?\"");
emit("#endif");
emit("");
emit("#ifndef __WBGEN2_MACROS_DEFINED__");
emit("#define __WBGEN2_MACROS_DEFINED__");
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_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("#endif");
emit("");
emit ("/*");
emit (" Register definitions for slave core: "..periph.name);
emit ("");
emit (" * File : "..options.output_c_header_file);
emit (" * Author : auto-generated by wbgen2 from "..input_wb_file);
emit (" * Created : "..os.date());
emit (" * Standard : ANSI C");
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("");
emit("#ifndef __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit("#define __WBGEN2_REGDEFS_"..string.upper(string.gsub(input_wb_file,"%.","_")))
emit("");
emit("#include <inttypes.h>");
emit("");
emit("#if defined( __GNUC__)");
emit("#define PACKED __attribute__ ((packed))");
emit("#else");
emit("#error \"Unsupported compiler?\"");
emit("#endif");
emit("");
emit("#ifndef __WBGEN2_MACROS_DEFINED__");
emit("#define __WBGEN2_MACROS_DEFINED__");
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_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("#endif");
emit("");
end
-- generates C structure reflecting the memory map of the peripheral.
function cgen_c_struct()
local cur_offset = 0;
local pad_id = 0;
local cur_offset = 0;
local pad_id = 0;
-- generates padding entry (if the offset of the register in memory is ahead of current offset in the structure)
function pad_struct(base)
if(cur_offset < base) then
emit("/* padding to: "..base.." words */");
emit("uint32_t __padding_"..pad_id.."["..(base - cur_offset).."];");
pad_id=pad_id+1;
cur_offset = base;
end
end
-- emit the structure definition...
emit("");
emit("PACKED struct "..string.upper(periph.c_prefix).."_WB {");
indent_right();
-- emit struct entires for REGs
foreach_reg({TYPE_REG}, function(reg)
-- print(reg.name, reg.prefix, reg.c_prefix, reg.hdl_prefix);
pad_struct(reg.base);
emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8));
-- this is just simple :)
emit("uint32_t "..string.upper(reg.c_prefix)..";");
cur_offset = cur_offset + 1;
end);
function pad_struct(base)
if(cur_offset < base) then
emit("/* padding to: "..base.." words */");
emit("uint32_t __padding_"..pad_id.."["..(base - cur_offset).."];");
pad_id=pad_id+1;
cur_offset = base;
end
end
-- emit the structure definition...
emit("");
emit("PACKED struct "..string.upper(periph.c_prefix).."_WB {");
indent_right();
-- emit struct entires for REGs
foreach_reg({TYPE_REG}, function(reg)
-- print(reg.name, reg.prefix, reg.c_prefix, reg.hdl_prefix);
pad_struct(reg.base);
emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8));
-- this is just simple :)
emit("uint32_t "..string.upper(reg.c_prefix)..";");
cur_offset = cur_offset + 1;
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
-- 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);
function cgen_c_defines()
foreach_reg({TYPE_REG}, function(reg)
emit(string.format("/* [0x%x]: REG "..reg.name.." */", reg.base * DATA_BUS_WIDTH / 8));
emit("#define "..string.upper(periph.c_prefix).."_REG_"..string.upper(reg.c_prefix).." "..string.format("0x%08x", reg.base * DATA_BUS_WIDTH/8));
end);
-- 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
-- main C code generator function. Takes the peripheral definition and generates C code.
function cgen_generate_c_header_code()
cgen_new_snippet();
cgen_c_fileheader();
cgen_c_field_masks();
cgen_c_struct();
emit("#endif");
cgen_write_current_snippet();
cgen_new_snippet();
cgen_c_fileheader();
cgen_c_field_masks();
if(options.c_regs_style == "struct") then
cgen_c_struct();
else
cgen_c_defines();
end
emit("#endif");
cgen_write_current_snippet();
end
......@@ -49,6 +49,7 @@ PASS_THROUGH = 0x40;
INTEGER = 0x80;
EXPRESSION = 0x100;
UNDEFINED = 0x200;
CONSTANT = 0x400;
-- reg LOAD types
LOAD_INT = 1;
......@@ -308,6 +309,7 @@ function fix_access(field, reg)
default_access(field, MONOSTABLE, WRITE_ONLY, READ_ONLY);
default_access(field, ENUM, READ_WRITE, READ_ONLY);
default_access(field, PASS_THROUGH, WRITE_ONLY, READ_ONLY);
default_access(field, CONSTANT, READ_ONLY, WRITE_ONLY);
if(field.access ~= nil) then
return;
......
......@@ -25,6 +25,7 @@ options.reset_type = "asynchronous";
options.target_interconnect = "wb-classic";
options.register_data_output = false;
options.lang = "vhdl";
options.c_reg_style = "struct";
require "alt_getopt"
......@@ -32,14 +33,16 @@ local usage_string = [[slave Wishbone generator
wbgen2 [options] input_file.wb]]
local commands_string = [[options:
-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
-h, --help Show this help text
-l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG
Valid values for LANG: {vhdl,verilog}
-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
-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
-h, --help Show this help text
-l, --lang=LANG Set the output Hardware Description Language (HDL) to LANG
Valid values for LANG: {vhdl,verilog}
-s, --cstyle=STYLE Set the style of register bank in generated C headers
Valid values for STYLE: {struct, defines}
-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]]
......@@ -55,18 +58,19 @@ end
function parse_args(arg)
local long_opts = {
help = "h",
version = "v",
co = "C",
doco = "D",
constco = "K",
lang = "l",
vo = "V",
help = "h",
version = "v",
co = "C",
doco = "D",
constco = "K",
lang = "l",
vo = "V",
cstyle = "s"
}
local optarg
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
if key == "h" then
usage_complete()
......@@ -91,6 +95,12 @@ function parse_args(arg)
die("Unknown HDL: "..options.lang);
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
options.output_hdl_file = value
end
......
......@@ -622,6 +622,18 @@ function gen_hdl_code_passthrough(field, reg)
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
function fill_unused_bits(target, reg)
local t={};
......@@ -629,7 +641,7 @@ function fill_unused_bits(target, reg)
local all_wo = true;
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
elseif(field.type == BIT or field.type == MONOSTABLE) then
t[field.offset] = 1;
......@@ -666,7 +678,10 @@ function gen_hdl_code_reg_field(field, reg)
gen_hdl_code_slv(field, reg);
elseif(field.type == PASS_THROUGH) then
gen_hdl_code_passthrough(field, reg);
elseif(field.type == CONSTANT) then
gen_hdl_code_constant(field, reg);
end
end
-- 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