Maintenance scheduled 24th July -- expect downtime along that day

Commit 7c043042 authored by twlostow's avatar twlostow

Beta release

git-svn-id: http://svn.ohwr.org/wishbone-gen@1 4537843c-45c2-4d80-8546-c3283569414f
parents
This diff is collapsed.
SOURCES = cgen_c_headers.lua cgen_common.lua cgen_verilog.lua cgen_vhdl.lua target_wishbone.lua wbgen_common.lua wbgen_main.lua wbgen_rams.lua wbgen_regbank.lua wbgen_eic.lua
OUTPUT = wbgen2
VHDL_LIBRARY = lib/wbgen2_dpssram.vhd lib/wbgen2_eic.vhd
VERILOG_LIBRARY = $(VHDL_LIBRARY:.vhd=.v)
all: $(SOURCES)
# make -C utils/vhd2vl/src
./utils/process_dofiles.lua wbgen_main.lua wbgen2
chmod +x wbgen2
%.v: %.vhd
./utils/vhd2vl/src/vhd2vl $^ > $@
\ No newline at end of file
This is the initial version of wbgen2. Requires Lua 5.1.4+. Enjoy it :)
There is still some stuff to do:
- add FIFOs
- add documentation generator
- CONSTANT registers
\ No newline at end of file
#!/usr/bin/lua
-- wbgen2, (c) 2010 Tomasz Wlostowski/CERN BE-Co-HT
-- LICENSED UNDER GPL v2
-- File: cgen_c_headers.lua
--
-- The C header code generator.
--
-- generates #defines for a register field:
-- NAME_MASK - bit mask of the field
-- NAME_SHIFT - bit offset of the field
-- NAME_W - write access macro packing given field value into the register:
-- regs_struct->reg = FIELD1_W(value1) | FIELD2_W(value2) | ....;
--
-- NAME_R - read access macro extracting the value of certain field from the register:
-- 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
print(field.offset, field.size);
emit(string.format("%-45s %s", "#define "..prefix.."_MASK", "WBGEN2_GEN_MASK("..field.offset..", "..field.size..")"));
emit(string.format("%-45s %d", "#define "..prefix.."_SHIFT", field.offset));
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 */"));
end
-- iterates all regs and rams and generates appropriate #define-s
function cgen_c_field_masks()
foreach_reg({TYPE_REG}, function(reg)
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("");
end
-- generates C structure reflecting the memory map of the peripheral.
function cgen_c_struct()
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);
-- .. 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
-- 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();
end
#!/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
-- instance of a component
function vinstance(name, component, maps)
local s={};
s.t="instance";
s.name=name;
s.component = component;
s.maps = maps;
return s;
end
-- port map
function vpm(to, from)
local s={};
s.t="portmap";
s.to = to;
s.from = from;
return s;
end
-- generic map
function vgm(to, from)
local s={};
s.t="genmap";
s.to = to;
s.from = from;
return s;
end
-- combinatorial process: process(sensitivity_list) begin {code} end process;
function vcombprocess(slist, code)
local s={};
s.t="combprocess";
s.slist = slist;
s.code=code;
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
function vothers(value)
local s={}
s.t="others";
s.val=value;
return s;
end
function vopenpin()
local s={}
s.t="openpin";
return s;
end
function vundefined()
local s={}
s.t="undefined";
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, is_wb)
local t = {}
t.comment = comment;
t.type = type;
t.range= nbits;
t.name = name;
t.dir = dir;
if(is_wb ~= nil and is_wb) then
t.is_wb = true;
else
t.is_wb = false;
end
return t;
end
global_ports = {};
global_signals = {};
function add_global_signals(s)
table_join(global_signals, s);
end
function add_global_ports(p)
table_join(global_ports, p);
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, "", true));
end
return clockports;
end
function cgen_build_siglist()
local siglist = {};
local i,v;
local s;
siglist = tree_2_table("signals");
table_join(siglist, global_signals);
return siglist;
end
function cgen_build_portlist()
local portlist = {};
table_join(portlist, global_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
die("cgen internal error: undefined signal '"..name.."'");
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()
output_code_file.write(output_code_file, emit_code);
end
function cgen_write_snippet(s)
output_code_file.write(output_code_file, s);
end
function cgen_generate_init(filename)
output_code_file = io.open(filename, "w");
if(output_code_file == nil) then
die("Can't open code output file: "..filename);
end
end
function cgen_generate_done()
output_code_file.close(output_code_file);
end
function cgen_gen_vlog_constants(filename)
local file = io.open(filename, "w");
if(file == nil) then
die("can't open "..filename.." for writing.");
end
foreach_reg({TYPE_REG}, function(reg)
file.write(file, string.format("`define %-30s %d'h%x\n", "ADDR_"..string.upper(periph.hdl_prefix.."_"..reg.hdl_prefix), address_bus_width+2, (DATA_BUS_WIDTH/8) * reg.base));
end);
foreach_reg({TYPE_RAM}, function(reg)
local base = reg.select_bits *
math.pow (2, address_bus_width - address_bus_select_bits);
file.write(file, string.format("`define %-30s %d'h%x\n", "BASE_"..string.upper(periph.hdl_prefix.."_"..reg.hdl_prefix), address_bus_width+2, (DATA_BUS_WIDTH/8) *base));
file.write(file, string.format("`define %-30s 32'h%x\n", "SIZE_"..string.upper(periph.hdl_prefix.."_"..reg.hdl_prefix), reg.size));
end);
io.close(file);
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
-- here comes our peripheral definition
peripheral {
-- short (human-readable) name for the peripheral.
name = "Test RAM memories";
-- a longer description, if you want
description = "A slave containing various types of RAM memories";
-- name of the target VHDL entity to be generated
hdl_entity = "wb_slave_test_rams";
-- prefix for all the generated ports belonging to our peripheral
prefix = "RAMS";
-- RAM 1: 256 32-bit words, using asynchronous clock, writable from both the bus and the core, with 1 address wrap bit (mirrored 2 times)
ram {
name = "Memory 1";
prefix = "mem1k";
-- number of words of size 'width' in the RAM
size = 256;
-- width (bit count) of the memory's data bus
width = 32;
-- yes, we want the memory to be byte-addressable
byte_select = true;
-- core ports work in different clock domain
clock = "clk1_i";
-- here we define address wraparound. The memory address space is extended by 'wrap_bits' number of bits, thus mirroring the memory 2^(wrap_bits) times.
-- This allows for wrap-around read/write operations passing from the end to the beginning of the memory with no extra math. Useful for implementing circular buffers, etc.
wrap_bits = 1;
-- access. Defined the same way as for the registers.
access_bus = READ_WRITE;
access_dev = READ_WRITE;
};
-- simple, 2-kilobyte (1024 x 16 bits) memory with no extra features.
ram {
name = "Memory 2";
prefix = "mem2K";
size = 1024;
width = 16;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
set input_wb_file "rams.wb"
set test_module "wb_test_rams"
set target "classic"
set lang "vhdl"
set library_files {
"../../lib/wbgen2_pkg.vhd"
"../../lib/altera/wbgen2_dpssram.vhd"
};
mkdir -p output
vlib work
vlib wbgen2
foreach file $library_files { vcom -work wbgen2 $file }
if { $lang == "vhdl" } {
set target_filename [format "./output/%s.vhd" $test_module ]
set target_wb "+define+WB_USE_CLASSIC"
set wbgen_opt "-target classic"
} else {
set target_filename [format "./output/%s.v" $test_module ]
set target_wb "+define+WB_USE_PIPELINED"
set wbgen_opt "-target pipelined"
}
puts $target_filename
../../wbgen2 $input_wb_file -vo $target_filename -consto ./output/vlog_constants.v -co ./output/regdefs.h -lang $lang $wbgen_opt
if { $lang == "verilog" } {
vlog -work work -work wbgen2 $target_filename
} else {
vcom -work work $target_filename
}
vlog ./testbench.v
vsim work.main
radix -hexadecimal
do wave.do
run 100us
wave zoomfull
`timescale 1ns/1ps
`define wbclk_period 100
`define async_clk_period 63
`include "output/vlog_constants.v"
`include "../common/wishbone_test_master.v"
module RAM_TEST_MASTER (input wb_clk_i,
input wb_rst_n_i);
parameter RAM_WIDTH = 32;
parameter RAM_ASYNC_CLOCK = 0;
parameter MAX_BLOCK_SIZE = 1024;
wire ram_clk;
reg clk_gen_reg = 1;
reg [RAM_WIDTH-1:0] buffer [0:MAX_BLOCK_SIZE-1];
reg [31:0] ram_addr = 0;
reg [RAM_WIDTH-1:0] ram_data_o = 0;
wire [RAM_WIDTH-1:0] ram_data_i;
reg ram_rd = 0;
reg ram_wr = 0;
reg [RAM_WIDTH/8-1:0] ram_bwsel = 'hff;
time last_op_time = 0;
reg last_op_rw = 0;
reg [31:0] last_addr = 0;
reg ready= 0;
initial begin
@(posedge wb_rst_n_i);
#1000 ready = 1;
end
if(RAM_ASYNC_CLOCK == 0)
assign ram_clk = wb_clk_i;
else begin
always #(RAM_ASYNC_CLOCK/2) clk_gen_reg = ~clk_gen_reg;