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;
assign ram_clk = clk_gen_reg;
end
function addr_2_bwsel;
input [31:0] addr;
begin
case(RAM_WIDTH)
8: addr_2_bwsel = 1'b1;
16: addr_2_bwsel = (addr[0] ? 2'b01: 2'b10);
32: begin
case (addr[1:0])
0: addr_2_bwsel = 4'b1000;
1: addr_2_bwsel = 4'b0100;
2: addr_2_bwsel = 4'b0010;
3: addr_2_bwsel = 4'b0001;
endcase // case(addr[1:0])
end
endcase // case(RAM_WIDTH)
end
endfunction // addr_2_bwsel
task write_block;
input [31:0] addr;
input [3:0] size;
input [31:0] n_transfers;
begin : ram_writeblk_body
integer i;
if($time != last_op_time) begin
@(posedge ram_clk);
end
for (i=0;i<n_transfers;i=i+size) begin
ram_addr <= (i+addr) >> 2;
ram_bwsel <= 4'b1111; //addr_2_bwsel(i+addr);
ram_data_o <= buffer[i];
ram_wr <= 1;
@(posedge ram_clk);
ram_wr <= 0;
end
last_op_time = $time;
end
endtask
task write8;
input[31:0] addr;
input[7:0] data;
begin : write8_body
buffer[0] = data;
write_block(addr, 1, 1);
end
endtask
task write32;
input[31:0] addr;
input[31:0] data;
begin : write32_body
buffer[0] = data;
write_block(addr, 4, 1);
end
endtask
endmodule // RAM_TEST_MASTER
module main;
reg [31:0] rval;
// generate clocks & reset
WB_TEST_MASTER WB();
RAM_TEST_MASTER
#(.RAM_ASYNC_CLOCK(67))
RAM1 (
.wb_clk_i(WB.wb_clk),
.wb_rst_n_i(WB.wb_rst));
wb_slave_test_rams
dut (
.rst_n_i (WB.wb_rst),
.wb_clk_i (WB.wb_clk),
.wb_addr_i(WB.wb_addr[10:0]),
.wb_data_i(WB.wb_data_o),
.wb_data_o(WB.wb_data_i),
.wb_cyc_i (WB.wb_cyc),
.wb_sel_i (WB.wb_bwsel),
.wb_stb_i (WB.wb_stb),
.wb_we_i (WB.wb_we),
.wb_ack_o (WB.wb_ack),
.clk1_i (RAM1.ram_clk),
.rams_mem1k_addr_i (RAM1.ram_addr[7:0]),
.rams_mem1k_data_o (RAM1.ram_data_i),
.rams_mem1k_rd_i (RAM1.ram_rd),
.rams_mem1k_data_i (RAM1.ram_data_o),
.rams_mem1k_wr_i (RAM1.ram_wr),
.rams_mem1k_bwsel_i(RAM1.ram_bwsel),
.rams_mem2k_addr_i (10'b0),
.rams_mem2k_data_o (),
.rams_mem2k_rd_i (1'b0)
);
integer i;
integer fail = 0;
initial begin
wait(RAM1.ready && WB.ready);
$display("Test simple bus reads/writes...");
WB.verbose(1);
WB.write32(`BASE_RAMS_MEM1K, 32'hdeadbeef);
WB.write32(`BASE_RAMS_MEM1K + 4, 32'hcafecafe);
WB.write32(`BASE_RAMS_MEM1K + 'h200, 32'hfacedead);
WB.read32(`BASE_RAMS_MEM1K, rval); if(rval != 'hdeadbeef) fail = 1;
WB.read32(`BASE_RAMS_MEM1K + 4, rval);if(rval != 'hcafecafe) fail = 1;
WB.read32(`BASE_RAMS_MEM1K + 'h200, rval);if(rval != 'hfacedead) fail = 1;
$display("Test mirrored bus reads/writes...");
WB.write32(`BASE_RAMS_MEM1K + 16, 32'h55555555);
WB.read32(`BASE_RAMS_MEM1K + 16, rval);if(rval != 'h55555555) fail = 1;
WB.write32(`BASE_RAMS_MEM1K + 4*`SIZE_RAMS_MEM1K + 16, 32'haaaaaaaa);
WB.read32(`BASE_RAMS_MEM1K + 16, rval);if(rval != 'haaaaaaaa) fail = 1;
$display("Byte-access test...");
WB.verbose(0);
/* for(i=0;i<32;i=i+1) WB.write8(`BASE_RAMS_MEM1K + i, i + 1);
for(i=0;i<32;i=i+1) begin
WB.read8(`BASE_RAMS_MEM1K + i, rval);
if(rval != i+1)
fail = 1;
end
*/
/*
$display("mem1k: Bus write/mem read test...");
for(i=0;i<256;i=i+1) WB.write32(`BASE_RAMS_MEM1K + i*4, i+1);
for(i=0;i<256;i=i+1) begin
// RAM1.read32(i*4, rval);
if(rval != i+1) fail =1;
end
*/
$display("mem1k: Mem write/bus read test...");
for(i=0;i<256;i=i+1)
RAM1.write32(i*4, 257-i);
for(i=0;i<2;i=i+1) begin
WB.read32(`BASE_RAMS_MEM1K+i*4, rval);
$display(rval);
if(rval != 257-i)
fail =1;
end
end
/*
$display("mem2k: Bus write/mem read test...");
for(i=0;i<512;i=i+1) wb_write(`BASE_RAMS_MEM2K + i*4, 113*i+41);
@(posedge clk); // sync back to wb clock
for(i=0;i<512;i=i+1) begin
ram2_read(i*4, rval);
if(rval != 113*i+41)
fail =1;
end
if(fail)
$display("TESTS FAILED");
else
$display("TESTS PASSED");
end
-----/\----- EXCLUDED -----/\----- */
endmodule
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/clk_a_i
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/clk_b_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/addr_a_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/addr_b_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/data_a_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/data_b_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/data_a_o
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/data_b_o
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/bwsel_a_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/bwsel_b_i
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/rd_a_i
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/rd_b_i
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/wr_a_i
add wave -noupdate -format Logic /main/dut/rams_mem1k_raminst/wr_b_i
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/clksel
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/bwsel_int_a
add wave -noupdate -format Literal /main/dut/rams_mem1k_raminst/bwsel_int_b
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {20259630 ps} 0}
configure wave -namecolwidth 524
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
update
WaveRestoreZoom {99610350 ps} {100020508 ps}
//
// Title : Software Wishbone master unit for testbenches
//
// File : wishbone_master_tb.v
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : Verilog 2001
//
// Default values of certain WB parameters.
// Bus clock period
`ifndef WB_CLOCK_PERIOD
`define WB_CLOCK_PERIOD 100
`define WB_RESET_DELAY (3*`WB_CLOCK_PERIOD)
`endif
// Widths of wishbone address/data/byte select
`ifndef WB_DATA_BUS_WIDTH
`define WB_DATA_BUS_WIDTH 32
`endif
`ifndef WB_ADDRESS_BUS_WIDTH
`define WB_ADDRESS_BUS_WIDTH 32
`endif
`define WB_BWSEL_WIDTH ((`WB_DATA_BUS_WIDTH + 7) / 8)
module WB_TEST_MASTER;
// these signals make the WB bus, which can be accessed from outside the module
reg [`WB_ADDRESS_BUS_WIDTH - 1 : 0] wb_addr = 0;
reg [`WB_DATA_BUS_WIDTH - 1 : 0] wb_data_o = 0;
reg [`WB_BWSEL_WIDTH - 1 : 0] wb_bwsel = 0;
wire [`WB_DATA_BUS_WIDTH -1 : 0] wb_data_i;
wire wb_ack;
reg wb_cyc = 0;
reg wb_stb = 0;
reg wb_we = 0;
reg wb_rst = 0;
reg wb_clk = 1;
reg wb_tb_verbose = 1;
reg wb_monitor_bus = 1;
time last_access_t = 0;
reg [`WB_DATA_BUS_WIDTH -1 : 0] dummy;
// ready signal. 1 indicates that WB_TEST unit is initialized and ready for commands
reg ready = 0;
// generate the WB bus clock
always #(`WB_CLOCK_PERIOD/2) wb_clk <= ~wb_clk;
// generate the reset and ready signals
initial begin
#(`WB_RESET_DELAY) wb_rst <= 1;
#(`WB_CLOCK_PERIOD*2) ready <= 1;
end
// enables/disables displaying information about each read/write operation.
task verbose;
input onoff;
begin
wb_tb_verbose = onoff;
end
endtask // wb_verbose
task monitor_bus;
input onoff;
begin
wb_monitor_bus = onoff;
end
endtask // monitor_bus
task rw_generic;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [`WB_DATA_BUS_WIDTH - 1 : 0] data_i;
output [`WB_DATA_BUS_WIDTH - 1 : 0] data_o;
input rw;
input [3:0] size;
begin : rw_generic_main
if(wb_tb_verbose && rw)
$display("WB write %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
addr, data_i);
if($time != last_access_t) begin
@(posedge wb_clk);
end
wb_stb<=1;
wb_cyc<=1;
wb_addr <= {2'b00, addr[31:2]};
wb_we <= rw;
if(rw) begin
case(size)
4: begin wb_data_o<=data_i; wb_bwsel <= 4'b1111; end
2: begin
if(addr[1]) begin
wb_data_o[31:16] = data_i[15:0];
wb_bwsel = 4'b1100;
end else begin
wb_data_o[15:0] = data_i[15:0];
wb_bwsel = 4'b0011;
end
end
1: begin
case(addr[1:0])
0: begin wb_data_o[31:24] = data_i[7:0]; wb_bwsel <= 4'b1000; end
1: begin wb_data_o[23:16] = data_i[7:0]; wb_bwsel <= 4'b0100; end
2: begin wb_data_o[15:8] = data_i[7:0]; wb_bwsel <= 4'b0010; end
3: begin wb_data_o[7:0] = data_i[7:0]; wb_bwsel <= 4'b0001; end
endcase // case(addr[1:0])
end
endcase // case(size)
end // if (rw)
#(`WB_CLOCK_PERIOD-1);
if(wb_ack == 0) begin
while(wb_ack == 0) begin @(posedge wb_clk); end
end
data_o = wb_data_i;
wb_cyc <= 0;
wb_we<=0;
wb_stb<=0;
if(wb_tb_verbose && !rw)
$display("WB read %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
addr, wb_data_i);
last_access_t = $time;
end
endtask // rw_generic
task write8;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [7 : 0] data_i;
begin
rw_generic(addr, data_i, dummy, 1, 1);
end
endtask // write8
task read8;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
output [7 : 0] data_o;
begin : read8_body
reg [`WB_DATA_BUS_WIDTH - 1 : 0] rval;
rw_generic(addr, 0, rval, 0, 1);
data_o = rval[7:0];
end
endtask // write8
task write32;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [31 : 0] data_i;
begin
rw_generic(addr, data_i, dummy, 1, 4);
end
endtask // write32
task read32;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
output [31 : 0] data_o;
begin : read32_body
reg [`WB_DATA_BUS_WIDTH - 1 : 0] rval;
rw_generic(addr, 0, rval, 0, 4);
data_o = rval[31:0];
end
endtask // write32
// bus monitor
always@(posedge wb_clk) begin
if(wb_monitor_bus && wb_cyc && wb_stb && wb_ack)begin
if(wb_we) $display("ACK-Write: addr %x wdata %x bwsel %b", wb_addr, wb_data_o, wb_bwsel);
else $display("ACK-Read: addr %x rdata %x", wb_addr, wb_data_i);
end
end
endmodule
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
set input_wb_file "gpio_port.wb"
set test_module "gpio_port"
set target "classic"
set lang "vhdl"
set library_files {}
set extra_files { "gpio_port.vhd" };
mkdir -p ./output
vlib work
vlib wbgen2
foreach file $library_files { vcom -work wbgen2 $file }
foreach file $extra_files { vcom -work work $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
`include "output/vlog_constants.v"
`include "../common/wishbone_test_master.v"
module main;
WB_TEST_MASTER WB();
wire [31:0] gpio_pins_b;
reg [31:0] gpio_reg = 32'bz;
wire clk = WB.wb_clk;
wire rst = WB.wb_rst;
gpio_port dut(
.rst_n_i (WB.wb_rst),
.wb_clk_i (WB.wb_clk),
.wb_addr_i (WB.wb_addr[2:0]),
.wb_data_i (WB.wb_data_o),
.wb_data_o (WB.wb_data_i),
.wb_cyc_i (WB.wb_cyc),
.wb_stb_i (WB.wb_stb),
.wb_we_i (WB.wb_we),
.wb_sel_i (WB.wb_bwsel),
.wb_ack_o (WB.wb_ack),
.gpio_pins_b (gpio_pins_b)
);
assign gpio_pins_b = gpio_reg;
reg [31:0] data;
initial begin
wait (WB.ready);
$display("Set half of the pins to outputs, other half to inputs");
WB.write32(`ADDR_GPIO_DDR, 32'hffff0000);
#1 $display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Set every even byte to '1'");
WB.write32(`ADDR_GPIO_SOPR, 32'hff00ff00);
#1 $display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Clear every even bit");
WB.write32(`ADDR_GPIO_COPR, 32'h55555555);
#1 $display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Write an arbitrary value");
WB.write32(`ADDR_GPIO_PDR, 32'hdeadbeef);
#1 $display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Force something tasty on the GPIO input pins");
gpio_reg[15:0] = 16'hcafe;
#1 $display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
#1000; // wait for a while (sync logic)
WB.read32(`ADDR_GPIO_PSR, data);
$display("Time for %x!", data[15:0]);
end
endmodule
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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