Commit 9d19b097 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

Initial wbgen2 uploaded.

parent 2d957fc1
This diff is collapsed.
This is the initial version of wbgen2. Requires Lua 5.1.4+. Enjoy it :)
There is still some stuff to do:
- add RAMs and FIFOs
- add C code generator
- add documentation generator
- CONSTANT registers
\ No newline at end of file
These examples show various uses of wbgen2.
Run "run.do" in Modelsim to start the simulation.
\ No newline at end of file
This diff is collapsed.
-------------------------------------------------------------------------------
-- Title : A sample GPIO port (wbgen2 example)
-- Project :
-------------------------------------------------------------------------------
-- File : gpio_port.vhdl
-- Author : T.W.
-- Company :
-- Created : 2010-02-22
-- Last update: 2010-02-22
-- Platform :
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2010 T.W.
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-02-22 1.0 slayer Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
library work;
entity gpio_port is
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(2 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
-- our port :)
gpio_pins_b : inout std_logic_vector(31 downto 0)
);
end gpio_port;
architecture syn of gpio_port is
component wb_slave_gpio_port
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(2 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
gpio_ddr_o : out std_logic_vector(31 downto 0);
gpio_psr_i : in std_logic_vector(31 downto 0);
gpio_pdr_o : out std_logic_vector(31 downto 0);
gpio_pdr_wr_o : out std_logic;
gpio_sopr_o : out std_logic_vector(31 downto 0);
gpio_sopr_wr_o : out std_logic;
gpio_copr_o : out std_logic_vector(31 downto 0);
gpio_copr_wr_o : out std_logic);
end component;
signal gpio_ddr : std_logic_vector(31 downto 0);
signal gpio_psr : std_logic_vector(31 downto 0);
signal gpio_pdr : std_logic_vector(31 downto 0);
signal gpio_pdr_wr : std_logic;
signal gpio_sopr : std_logic_vector(31 downto 0);
signal gpio_sopr_wr : std_logic;
signal gpio_copr : std_logic_vector(31 downto 0);
signal gpio_copr_wr : std_logic;
-- regsiter containing current output state
signal gpio_reg : std_logic_vector(31 downto 0);
-- registers for synchronization of input pins
signal gpio_pins_sync1 : std_logic_vector(31 downto 0);
signal gpio_pins_sync0 : std_logic_vector(31 downto 0);
begin -- syn
wb_slave : wb_slave_gpio_port
port map (
rst_n_i => rst_n_i,
wb_clk_i => wb_clk_i,
wb_addr_i => wb_addr_i,
wb_data_i => wb_data_i,
wb_data_o => wb_data_o,
wb_cyc_i => wb_cyc_i,
wb_sel_i => wb_sel_i,
wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i,
wb_ack_o => wb_ack_o,
gpio_ddr_o => gpio_ddr,
gpio_psr_i => gpio_pins_sync1,
gpio_pdr_o => gpio_pdr,
gpio_pdr_wr_o => gpio_pdr_wr,
gpio_sopr_o => gpio_sopr,
gpio_sopr_wr_o => gpio_sopr_wr,
gpio_copr_o => gpio_copr,
gpio_copr_wr_o => gpio_copr_wr);
process (wb_clk_i, rst_n_i)
begin -- process
if(rst_n_i = '0') then
gpio_reg <= (others => '0');
elsif rising_edge(wb_clk_i) then
if(gpio_pdr_wr = '1') then -- write operation to "PDR" register -
-- set the new values of GPIO outputs
gpio_reg <= gpio_pdr;
end if;
if(gpio_sopr_wr = '1') then -- write to "SOPR" reg - set ones
for i in 0 to 31 loop
if(gpio_sopr(i) = '1') then
gpio_reg(i) <= '1';
end if;
end loop;
end if;
if(gpio_copr_wr = '1') then -- write to "COPR" reg - set zeros
for i in 0 to 31 loop
if(gpio_copr(i) = '1') then
gpio_reg(i) <= '0';
end if;
end loop;
end if;
end if;
end process;
-- synchronizing process for input pins
synchronize_input_pins : process (wb_clk_i, rst_n_i)
begin -- process
if(rst_n_i = '0') then
gpio_pins_sync0 <= (others => '0');
gpio_pins_sync1 <= (others => '0');
elsif rising_edge(wb_clk_i) then
gpio_pins_sync0 <= gpio_pins_b;
gpio_pins_sync1 <= gpio_pins_sync0;
end if;
end process;
-- generate the tristate buffers for I/O pins
gen_tristates : for i in 0 to 31 generate
gpio_pins_b(i) <= gpio_reg(i) when gpio_ddr(i) = '1' else 'Z';
end generate gen_tristates;
end syn;
-- here comes our peripheral definition
peripheral {
-- short (human-readable) name for the peripheral.
name = "GPIO Port";
-- a longer description, if you want
description = "A sample 32-bit general-purpose bidirectional I/O port, explaining how to use SLV and PASS-THROUGH registers.";
-- name of the target VHDL entity to be generated
hdl_entity = "wb_slave_gpio_port";
-- prefix for all the generated ports belonging to our peripheral
prefix = "gpio";
-- Pin direction register. Readable and writable from the bus, readable from the device.
reg {
name = "Pin direction register";
description = "A register defining the direction of the GPIO potr pins.";
prefix = "ddr";
-- a single, anonymous field (no prefix) of type SLV.
field {
name = "Pin directions";
description = "Each bit in this register defines the direction of corresponding pin of the GPIO port. 1 means the pin is an OUTPUT, 0 means the pin is an INPUT";
-- there is (deliberately) no prefix defined for this field. Since we have only one field in the register "ddr", we can omit the prefix - wbgen2 will produce signal names
-- containing only prefixes of the peripheral and the parent register.
-- type of our field - std_logic_vector
type = SLV;
-- size - we want 32-bits wide port :)
size = 32;
-- the field will be readable/writable from the Wishbone bus
access_bus = READ_WRITE;
-- .. and readable from the peripheral
access_dev = READ_ONLY;
};
};
-- Pin input state register. Readable the bus, writable from the device.
reg {
name = "Pin input state register";
description = "A register containing the current state of input pins.";
prefix = "psr";
-- a single, anonymous field (no prefix) of type SLV.
field {
name = "Pin input state";
description = "Each bit in this register reflects the state of corresponding GPIO port pin.";
-- no prefix here as well (see above)
-- type of our field - std_logic_vector
type = SLV;
-- size - we want 32-bits wide port :)
size = 32;
-- the field will be readable from the Wishbone bus
access_bus = READ_ONLY;
-- .. and writable from the peripheral
access_dev = WRITE_ONLY;
};
};
-- Port output register. Shows how to use PASS-THROUGH regs
reg {
name = "Port output register";
description = "Register containing the output pin state.";
prefix = "pdr";
-- a single, anonymous field (no prefix) of type PASS-THROUGH.
field {
name = "Port output value";
-- the description isn't really necessary here :)
-- description = "Writing '1' sets the corresponding GPIO pin to '1'";
-- type of our field - PASS_THROUGH. In this mode, the slave core is not storing the register value. Instead it provides the raw value
-- (taken from the wishbone data input) and a strobe signal, asserted for single clock cycle upon write operation to the register.
-- The wishbone data input will be fed directly to gpio_pdr_o and each write operation to this register will generate a single-cycle positive
-- pulse on gpio_pdr_wr_o signal.
type = PASS_THROUGH;
size = 32;
-- access flags don't apply for the PASS-THROUGH regsiters, so we can omit them.
};
};
-- Set output register. Shows how to use PASS-THROUGH regs
reg {
name = "Set output pin register";
description = "Writing '1' sets the corresponding GPIO pin to '1'";
prefix = "sopr";
-- Our driver developer would want these two (SOPR and COPR) registers' addresses to be aligned to multiple of 4 :)
align = 4;
field {
name = "Set output pin register";
type = PASS_THROUGH;
size = 32;
};
};
-- Clear output register. Designed identically as the previous reg.
reg {
name = "Clear output pin register";
description = "Writing '1' clears the corresponding GPIO pin";
prefix = "copr";
field {
name = "Clear output pin register";
type = PASS_THROUGH;
size = 32;
};
};
};
`define ADDR_GPIO_DDR 3'h0
`define ADDR_GPIO_PSR 3'h1
`define ADDR_GPIO_PDR 3'h2
`define ADDR_GPIO_SOPR 3'h4
`define ADDR_GPIO_COPR 3'h5
vlib work
../../wbgen2.lua gpio_port.wb -vo ./output/wb_slave_gpio_port.vhdl --gen-vlog-constants ./output/vlog_constants.v
vcom ./output/wb_slave_gpio_port.vhdl
vcom ./gpio_port.vhdl
vlog ./testbench.v
vsim work.main
radix -hexadecimal
do wave.do
run 15us
wave zoomfull
`timescale 1ns/1ps
`define wbclk_period 100
`include "output/vlog_constants.v"
module main;
reg clk=1;
reg rst=0;
always #(`wbclk_period/2) clk <= ~clk;
initial #1000 rst <= 1;
`include "wishbone_stuff.v"
wire [31:0] gpio_pins_b;
reg [31:0] gpio_reg = 32'bz;
gpio_port dut(
.rst_n_i (rst),
.wb_clk_i (clk),
.wb_addr_i (wb_addr[2:0]),
.wb_data_i (wb_data_o),
.wb_data_o (wb_data_i),
.wb_cyc_i (wb_cyc),
.wb_sel_i (wb_sel),
.wb_stb_i (wb_stb),
.wb_we_i (wb_we),
.wb_ack_o (wb_ack),
.gpio_pins_b (gpio_pins_b)
);
assign gpio_pins_b = gpio_reg;
reg[31:0] data;
integer i;
initial begin
#2001; // wait until the DUT is reset
$display("Set half of the pins to outputs, other half to inputs");
wb_write(`ADDR_GPIO_DDR, 32'hffff0000);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Set every even byte to '1'");
wb_write(`ADDR_GPIO_SOPR, 32'hff00ff00);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Clear every even bit");
wb_write(`ADDR_GPIO_COPR, 32'h55555555);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Write an arbitrary value");
wb_write(`ADDR_GPIO_PDR, 32'hdeadbeef);
$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;
delay_cycles(1);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
delay_cycles(10); // wait for a while for the sync logic
wb_read(`ADDR_GPIO_PSR, data);
$display("Time for %x!", data[15:0]);
end
endmodule
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -format Logic /main/dut/rst_n_i
add wave -noupdate -format Logic /main/dut/wb_clk_i
add wave -noupdate -format Literal /main/dut/wb_addr_i
add wave -noupdate -format Literal /main/dut/wb_data_i
add wave -noupdate -format Literal /main/dut/wb_data_o
add wave -noupdate -format Logic /main/dut/wb_cyc_i
add wave -noupdate -format Logic /main/dut/wb_sel_i
add wave -noupdate -format Logic /main/dut/wb_stb_i
add wave -noupdate -format Logic /main/dut/wb_we_i
add wave -noupdate -format Logic /main/dut/wb_ack_o
add wave -noupdate -format Literal /main/dut/gpio_pins_b
add wave -noupdate -format Literal /main/dut/gpio_ddr
add wave -noupdate -format Literal /main/dut/gpio_psr
add wave -noupdate -format Literal /main/dut/gpio_pdr
add wave -noupdate -format Logic /main/dut/gpio_pdr_wr
add wave -noupdate -format Literal /main/dut/gpio_sopr
add wave -noupdate -format Logic /main/dut/gpio_sopr_wr
add wave -noupdate -format Literal /main/dut/gpio_copr
add wave -noupdate -format Logic /main/dut/gpio_copr_wr
add wave -noupdate -format Literal /main/dut/gpio_reg
add wave -noupdate -format Literal /main/dut/gpio_pins_sync1
add wave -noupdate -format Literal /main/dut/gpio_pins_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/rst_n_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_clk_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_addr_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_o
add wave -noupdate -format Logic /main/dut/wb_slave/wb_cyc_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_sel_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_stb_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_we_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_ack_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_async_clk_i
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_ddr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_psr_i
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_pdr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_sopr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_copr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_ddr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s2
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_psr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_in_progress
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/wb_ack_regbank
add wave -noupdate -format Literal /main/dut/wb_slave/ack_cntr
add wave -noupdate -format Logic /main/dut/wb_slave/ack_in_progress
add wave -noupdate -format Logic /main/dut/wb_slave/tmpbit
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_out_int
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {0 ps} 0}
configure wave -namecolwidth 333
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 {0 ps} {15750 ns}
reg [31:0] wb_addr, wb_data_o, tmp;
wire [31:0] wb_data_i;
wire wb_ack;
reg wb_sel =0, wb_cyc=0, wb_stb=0, wb_we= 0;
task delay_cycles;
input [31:0] n;
begin
#(n * `wbclk_period);
end
endtask // delay_cycles
task wb_write;
input[31:0] addr;
input [31:0] data;
begin
$display("WB write: addr %x, data %x", addr, data);
wb_sel=1;
wb_stb=1;
wb_cyc=1;
wb_addr = addr;
wb_data_o=data;
wb_we = 1;
delay_cycles(1);
while(wb_ack == 0)
delay_cycles(1);
delay_cycles(1);
wb_cyc = 0;
wb_sel=0;
wb_we=0;
wb_stb=0;
end
endtask // wb_write
task wb_read;
input[31:0] addr;
output [31:0] data;
begin
wb_sel=1;
wb_stb=1;
wb_cyc=1;
wb_addr = addr;
wb_data_o=data;
wb_we = 0;
delay_cycles(1);
while(wb_ack == 0)
delay_cycles(1);
data = wb_data_i;
delay_cycles(1);
wb_cyc = 0;
wb_sel=0;
wb_we=0;
wb_stb=0;
end
endtask // wb_read
-------------------------------------------------------------------------------
-- Title : A sample GPIO port with asynchronous clock (wbgen2 example)
-- Project :
-------------------------------------------------------------------------------
-- File : gpio_port_async.vhdl
-- Author : T.W.
-- Company :
-- Created : 2010-02-22
-- Last update: 2010-02-22
-- Platform :
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2010 T.W.
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-02-22 1.0 slayer Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
library work;
entity gpio_port_async is
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(2 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
-- our port :)
gpio_clk_i: in std_logic; -- asynchronous clock for the GPIO port
gpio_pins_b : inout std_logic_vector(31 downto 0)
);
end gpio_port_async;
architecture syn of gpio_port_async is
component wb_slave_gpio_port_async
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(2 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
gpio_async_clk_i : in std_logic;
gpio_ddr_o : out std_logic_vector(31 downto 0);
gpio_psr_i : in std_logic_vector(31 downto 0);
gpio_pdr_o : out std_logic_vector(31 downto 0);
gpio_pdr_wr_o : out std_logic;
gpio_sopr_o : out std_logic_vector(31 downto 0);
gpio_sopr_wr_o : out std_logic;
gpio_copr_o : out std_logic_vector(31 downto 0);
gpio_copr_wr_o : out std_logic);
end component;
signal gpio_ddr : std_logic_vector(31 downto 0);
signal gpio_psr : std_logic_vector(31 downto 0);
signal gpio_pdr : std_logic_vector(31 downto 0);
signal gpio_pdr_wr : std_logic;
signal gpio_sopr : std_logic_vector(31 downto 0);
signal gpio_sopr_wr : std_logic;
signal gpio_copr : std_logic_vector(31 downto 0);
signal gpio_copr_wr : std_logic;
-- regsiter containing current output state
signal gpio_reg : std_logic_vector(31 downto 0);
-- registers for synchronization of input pins
signal gpio_pins_sync1 : std_logic_vector(31 downto 0);
signal gpio_pins_sync0 : std_logic_vector(31 downto 0);
begin -- syn
wb_slave : wb_slave_gpio_port_async
port map (
rst_n_i => rst_n_i,
wb_clk_i => wb_clk_i,
wb_addr_i => wb_addr_i,
wb_data_i => wb_data_i,
wb_data_o => wb_data_o,
wb_cyc_i => wb_cyc_i,
wb_sel_i => wb_sel_i,
wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i,
wb_ack_o => wb_ack_o,
gpio_async_clk_i => gpio_clk_i,
gpio_ddr_o => gpio_ddr,
gpio_psr_i => gpio_pins_sync1,
gpio_pdr_o => gpio_pdr,
gpio_pdr_wr_o => gpio_pdr_wr,
gpio_sopr_o => gpio_sopr,
gpio_sopr_wr_o => gpio_sopr_wr,
gpio_copr_o => gpio_copr,
gpio_copr_wr_o => gpio_copr_wr);
process (gpio_clk_i, rst_n_i)
begin -- process
if(rst_n_i = '0') then
gpio_reg <= (others => '0');
elsif rising_edge(gpio_clk_i) then
if(gpio_pdr_wr = '1') then -- write operation to "PDR" register -
-- set the new values of GPIO outputs
gpio_reg <= gpio_pdr;
end if;
if(gpio_sopr_wr = '1') then -- write to "SOPR" reg - set ones
for i in 0 to 31 loop
if(gpio_sopr(i) = '1') then
gpio_reg(i) <= '1';
end if;
end loop;
end if;
if(gpio_copr_wr = '1') then -- write to "COPR" reg - set zeros
for i in 0 to 31 loop
if(gpio_copr(i) = '1') then
gpio_reg(i) <= '0';
end if;
end loop;
end if;
end if;
end process;
-- synchronizing process for input pins
synchronize_input_pins : process (gpio_clk_i, rst_n_i)
begin -- process
if(rst_n_i = '0') then
gpio_pins_sync0 <= (others => '0');
gpio_pins_sync1 <= (others => '0');
elsif rising_edge(gpio_clk_i) then
gpio_pins_sync0 <= gpio_pins_b;
gpio_pins_sync1 <= gpio_pins_sync0;
end if;
end process;
-- generate the tristate buffers for I/O pins
gen_tristates : for i in 0 to 31 generate
gpio_pins_b(i) <= gpio_reg(i) when gpio_ddr(i) = '1' else 'Z';
end generate gen_tristates;
end syn;
-- this is no different from "gpio_port" example, except all the registers use gpio_async_clk_i clock input.
-- here comes our peripheral definition
peripheral {
-- short (human-readable) name for the peripheral.
name = "GPIO Port";
-- a longer description, if you want
description = "A sample 32-bit general-purpose bidirectional I/O port, explaining how to use SLV and PASS-THROUGH registers. This time in asynchronous mode!";
-- name of the target VHDL entity to be generated
hdl_entity = "wb_slave_gpio_port_async";
-- prefix for all the generated ports belonging to our peripheral
prefix = "gpio";
-- Pin direction register. Readable and writable from the bus, readable from the device.
reg {
name = "Pin direction register";
description = "A register defining the direction of the GPIO potr pins.";
prefix = "ddr";
-- a single, anonymous field (no prefix) of type SLV.
field {
name = "Pin directions";
description = "Each bit in this register defines the direction of corresponding pin of the GPIO port. 1 means the pin is an OUTPUT, 0 means the pin is an INPUT";
-- there is (deliberately) no prefix defined for this field. Since we have only one field in the register "ddr", we can omit the prefix - wbgen2 will produce signal names
-- containing only prefixes of the peripheral and the parent register.
-- type of our field - std_logic_vector
type = SLV;
-- size - we want 32-bits wide port :)
size = 32;
-- the field will be readable/writable from the Wishbone bus
access_bus = READ_WRITE;
-- .. and readable from the peripheral
access_dev = READ_ONLY;
-- our asynchronous clock :)
clock = "gpio_async_clk_i";
};
};
-- Pin input state register. Readable the bus, writable from the device.
reg {
name = "Pin input state register";
description = "A register containing the current state of input pins.";
prefix = "psr";
-- a single, anonymous field (no prefix) of type SLV.
field {
name = "Pin input state";
description = "Each bit in this register reflects the state of corresponding GPIO port pin.";
-- no prefix here as well (see above)
-- type of our field - std_logic_vector
type = SLV;
-- size - we want 32-bits wide port :)
size = 32;
-- the field will be readable from the Wishbone bus
access_bus = READ_ONLY;
-- .. and writable from the peripheral
access_dev = WRITE_ONLY;
clock = "gpio_async_clk_i";
};
};
-- Port output register. Shows how to use PASS-THROUGH regs
reg {
name = "Port output register";
description = "Register containing the output pin state.";
prefix = "pdr";
-- a single, anonymous field (no prefix) of type PASS-THROUGH.
field {
name = "Port output value";
-- the description isn't really necessary here :)
-- description = "Writing '1' sets the corresponding GPIO pin to '1'";
-- type of our field - PASS_THROUGH. In this mode, the slave core is not storing the register value. Instead it provides the raw value
-- (taken from the wishbone data input) and a strobe signal, asserted for single clock cycle upon write operation to the register.
-- The wishbone data input will be fed directly to gpio_pdr_o and each write operation to this register will generate a single-cycle positive
-- pulse on gpio_pdr_wr_o signal.
type = PASS_THROUGH;
size = 32;
-- access flags don't apply for the PASS-THROUGH regsiters, so we can omit them.
clock = "gpio_async_clk_i";
};
};
-- Set output register. Shows how to use PASS-THROUGH regs
reg {
name = "Set output pin register";
description = "Writing '1' sets the corresponding GPIO pin to '1'";
prefix = "sopr";
-- Our driver developer would want these two (SOPR and COPR) registers' addresses to be aligned to multiple of 4 :)
align = 4;
field {
name = "Set output pin register";
type = PASS_THROUGH;
size = 32;
clock = "gpio_async_clk_i";
};
};
-- Clear output register. Designed identically as the previous reg.
reg {
name = "Clear output pin register";
description = "Writing '1' clears the corresponding GPIO pin";
prefix = "copr";
field {
name = "Clear output pin register";
type = PASS_THROUGH;
size = 32;
clock = "gpio_async_clk_i";
};
};
};
`define ADDR_GPIO_DDR 3'h0
`define ADDR_GPIO_PSR 3'h1
`define ADDR_GPIO_PDR 3'h2
`define ADDR_GPIO_SOPR 3'h4
`define ADDR_GPIO_COPR 3'h5
vlib work
../../wbgen2.lua gpio_port_async.wb -vo ./output/wb_slave_gpio_port_async.vhdl --gen-vlog-constants ./output/vlog_constants.v
vcom ./output/wb_slave_gpio_port_async.vhdl
vcom ./gpio_port_async.vhdl
vlog ./testbench.v
vsim work.main
radix -hexadecimal
do wave.do
run 15us
wave zoomfull
`timescale 1ns/1ps
`define wbclk_period 100
`define clk_async_period 71
`include "output/vlog_constants.v"
module main;
reg clk=1;
reg clk_async = 1;
reg rst=0;
always #(`wbclk_period) clk<=~clk;
always #(`clk_async_period/2) clk_async <= ~clk_async;
initial #1000 rst <= 1;
`include "wishbone_stuff.v"
wire [31:0] gpio_pins_b;
reg [31:0] gpio_reg = 32'bz;
gpio_port_async dut(
.rst_n_i (rst),
.wb_clk_i (clk),
.wb_addr_i (wb_addr[2:0]),
.wb_data_i (wb_data_o),
.wb_data_o (wb_data_i),
.wb_cyc_i (wb_cyc),
.wb_sel_i (wb_sel),
.wb_stb_i (wb_stb),
.wb_we_i (wb_we),
.wb_ack_o (wb_ack),
.gpio_clk_i (clk_async),
.gpio_pins_b (gpio_pins_b)
);
assign gpio_pins_b = gpio_reg;
reg[31:0] data;
integer i;
initial begin
#2001; // wait until the DUT is reset
$display("Set half of the pins to outputs, other half to inputs");
wb_write(`ADDR_GPIO_DDR, 32'hffff0000);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Set every even byte to '1'");
wb_write(`ADDR_GPIO_SOPR, 32'hff00ff00);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Clear every even bit");
wb_write(`ADDR_GPIO_COPR, 32'h55555555);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
$display("Write an arbitrary value");
wb_write(`ADDR_GPIO_PDR, 32'hdeadbeef);
$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;
delay_cycles(1);
$display("Pins state: %b (%x)", gpio_pins_b, gpio_pins_b);
delay_cycles(10); // wait for a while for the sync logic
wb_read(`ADDR_GPIO_PSR, data);
$display("Time for %x!", data[15:0]);
end
endmodule
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -format Logic /main/dut/rst_n_i
add wave -noupdate -format Logic /main/dut/wb_clk_i
add wave -noupdate -format Literal /main/dut/wb_addr_i
add wave -noupdate -format Literal /main/dut/wb_data_i
add wave -noupdate -format Literal /main/dut/wb_data_o
add wave -noupdate -format Logic /main/dut/wb_cyc_i
add wave -noupdate -format Logic /main/dut/wb_sel_i
add wave -noupdate -format Logic /main/dut/wb_stb_i
add wave -noupdate -format Logic /main/dut/wb_we_i
add wave -noupdate -format Logic /main/dut/wb_ack_o
add wave -noupdate -format Literal /main/dut/gpio_pins_b
add wave -noupdate -format Literal /main/dut/gpio_ddr
add wave -noupdate -format Literal /main/dut/gpio_psr
add wave -noupdate -format Literal /main/dut/gpio_pdr
add wave -noupdate -format Logic /main/dut/gpio_pdr_wr
add wave -noupdate -format Literal /main/dut/gpio_sopr
add wave -noupdate -format Logic /main/dut/gpio_sopr_wr
add wave -noupdate -format Literal /main/dut/gpio_copr
add wave -noupdate -format Logic /main/dut/gpio_copr_wr
add wave -noupdate -format Literal /main/dut/gpio_reg
add wave -noupdate -format Literal /main/dut/gpio_pins_sync1
add wave -noupdate -format Literal /main/dut/gpio_pins_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/rst_n_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_clk_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_addr_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_i
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_o
add wave -noupdate -format Logic /main/dut/wb_slave/wb_cyc_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_sel_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_stb_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_we_i
add wave -noupdate -format Logic /main/dut/wb_slave/wb_ack_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_async_clk_i
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_ddr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_psr_i
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_pdr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_sopr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_copr_o
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_o
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_ddr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_ddr_swb_s2
add wave -noupdate -format Literal /main/dut/wb_slave/gpio_psr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_in_progress
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_psr_lwb_s2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_pdr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_sopr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_int
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_int_delay
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync0
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync1
add wave -noupdate -format Logic /main/dut/wb_slave/gpio_copr_wr_sync2
add wave -noupdate -format Logic /main/dut/wb_slave/wb_ack_regbank
add wave -noupdate -format Literal /main/dut/wb_slave/ack_cntr
add wave -noupdate -format Logic /main/dut/wb_slave/ack_in_progress
add wave -noupdate -format Logic /main/dut/wb_slave/tmpbit
add wave -noupdate -format Literal /main/dut/wb_slave/wb_data_out_int
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {0 ps} 0}
configure wave -namecolwidth 333
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 {0 ps} {46187117 ps}
reg [31:0] wb_addr, wb_data_o, tmp;
wire [31:0] wb_data_i;
wire wb_ack;
reg wb_sel =0, wb_cyc=0, wb_stb=0, wb_we= 0;
task delay_cycles;
input [31:0] n;
begin
#(n * `wbclk_period);
end
endtask // delay_cycles
task wb_write;
input[31:0] addr;
input [31:0] data;
begin
$display("WB write: addr %x, data %x", addr, data);
wb_sel=1;
wb_stb=1;
wb_cyc=1;
wb_addr = addr;
wb_data_o=data;
wb_we = 1;
delay_cycles(1);
while(wb_ack == 0)
delay_cycles(1);
delay_cycles(1);
wb_cyc = 0;
wb_sel=0;
wb_we=0;
wb_stb=0;
end
endtask // wb_write
task wb_read;
input[31:0] addr;
output [31:0] data;
begin
wb_sel=1;
wb_stb=1;
wb_cyc=1;
wb_addr = addr;
wb_data_o=data;
wb_we = 0;
delay_cycles(1);
while(wb_ack == 0)
delay_cycles(1);
data = wb_data_i;
delay_cycles(1);
wb_cyc = 0;
wb_sel=0;
wb_we=0;
wb_stb=0;
end
endtask // wb_read
#!/usr/bin/lua
wbgen2_version="0.3"
wbgen2_libdir="/home/slayer/wbgen2-dev"
device_family="altera_cyclone3";
dofile(wbgen2_libdir.."/wbgen_common.lua");
dofile(wbgen2_libdir.."/wbgen_vhdl.lua");
dofile(wbgen2_libdir.."/wbgen_regbank.lua");
dofile(wbgen2_libdir.."/wbgen_rams.lua");
function chk_nil(p,s)
if(p == nil) then
die(s.." expected.");
end
return p;
end
function parse_args(arg)
local n=1;
if(arg[1] == nil) then
print("wbgen2 version "..wbgen2_version);
print("(c) Tomasz Wlostowski/CERN BE-Co-HT 2010");
print("");
print("usage: "..arg[0].." input_file.wb -t target -vo output.vhdl -co output.c -do output.html [additional options]");
print("where target is the target FPGA architecture [altera/xilinx]");
print("");
print("Additional options: ");
print("--gen-reg-constants - generates VHDL constants containing addresses of all registers. Useful for writing testbenches.");
print("--gen-vlog-constants file.v - generates Verilog constants containing addresses of all registers and writes them to file.v. Useful for writing testbenches.");
print("");
os.exit(0);
end
input_wb_file = arg[1];
vhdl_gen_reg_constants = false;
vlog_gen_reg_constants = false;
n=2;
while(arg[n] ~= nil) do
local sw = arg[n];
if(sw == "-vo") then
output_vhdl_file = chk_nil(arg[n+1], "VHDL output filename expected");
n=n+2;
elseif(sw == "-co") then
output_c_file = chk_nil(arg[n+1], "C header output filename expected");
n=n+2;
elseif(sw == "--gen-reg-constants") then
vhdl_gen_reg_constants = true;
n=n+1;
elseif(sw == "--gen-vlog-constants") then
output_vlog_constants_file = chk_nil(arg[n+1],"Verilog constants filename expected");
vlog_gen_reg_constants = true;
n=n+2;
else
n=n+1;
end
end
end
parse_args(arg);
dofile(input_wb_file);
if(periph == nil) then die ("missing peripheral declaration"); end
foreach_reg(
function(reg)
reg.total_size=0;
reg.current_offset=0;
end
);
foreach_field( fix_prefix );
foreach_field( fix_access );
foreach_reg( fix_prefix );
periph = fix_prefix(periph);
foreach_field(calc_size);
foreach_reg(check_max_size);
foreach_field(calc_field_offsets);
--foreach_field(function(reg, field) print
foreach_reg(calc_address_sizes);
assign_addresses();
--foreach_reg(gen_vhdl_signals);
--foreach_reg(gen_vhdl_constants);
gen_vhdl_code(output_vhdl_file);
if(vlog_gen_reg_constants) then
gen_vlog_constants(output_vlog_constants_file);
end
#!/usr/bin/lua
-- bus properties
DATA_BUS_WIDTH = 32;
SYNC_CHAIN_LENGTH = 3;
-- constant definitions (block types)
TYPE_PERIPH = 1;
TYPE_REG = 2;
TYPE_FIELD = 3;
TYPE_FIFO = 4;
TYPE_ENUM = 5;
TYPE_RAM = 6;
-- FIFO register flags
FIFO_FULL = 0x1;
FIFO_EMPTY = 0x2;
FIFO_ALMOST_FULL = 0x4;
FIFO_ALMOST_EMPTY = 0x8;
FIFO_CLEAR = 0x10;
FIFO_COUNT = 0x20;
-- field access flags
READ_ONLY = 0x1;
READ_WRITE = 0x2;
WRITE_ONLY = 0x4;
SET_ON_WRITE = 0x8;
RESET_ON_WRITE = 0x10;
-- field types
MONOSTABLE = 0x1;
BIT = 0x2;
SLV = 0x4;
SIGNED = 0x8;
UNSIGNED = 0x10;
ENUM = 0x20;
PASS_THROUGH = 0x40;
LOAD_INT = 1;
LOAD_EXT = 2;
ACC_RO_WO = 1;
ACC_WO_RO = 2;
ACC_RW_RW = 3;
ACC_RW_RO = 4;
FROM_WB = 1;
TO_WB = 2;
function peripheral(x) x['__type']=TYPE_PERIPH; periph = x; return x; end
function reg(x) x['__type']=TYPE_REG; return x; end
function field(x) x['__type']=TYPE_FIELD; return x; end
function fifo_reg(x) x['__type']=TYPE_FIFO; return x; end
function ram(x) x['__type']=TYPE_RAM; return x; end
function enum(x) x['__type']=TYPE_ENUM; return x; end
function range2bits(range)
local min = range[1];
local max = range[2];
local msize;
if(math.abs(min) > math.abs(max)) then
msize = math.abs(min);
else
msize = math.abs(max);
end
local logsize = math.ceil(math.log(msize) / math.log(2));
if(min < 0) then
logsize = logsize + 1;
end
return logsize;
end
function calc_size(field, reg)
if(field.type == MONOSTABLE or field.type == BIT) then
-- print('got bit');
field.size = 1;
elseif (field.type == SLV) then
-- print('got slv');
if(field.size == nil) then
die("no size declared for SLV-type field '".. field.name.."'");
end
elseif (field.type == SIGNED or field.type == UNSIGNED) then
-- print("got signed/USIGNED");
if(field.range == nil and field.size == nil) then
die("no range nor size declared for SIGNED/UNSIGNED-type field '".. field.name.."'");
end
if(field.size == nil) then
local nbits = range2bits(field.range);
if(nbits == nil) then
die("misdeclared range for SIGNED/UNSIGNED-type field '".. field.name.."'");
end
field.size = nbits;
end
elseif(field.type == ENUM) then
die("ENUM-type fields are not yet supported. Sorry :(");
end
reg.total_size = reg.total_size + field.size;
end
function foreach_field(func)
for i,v in pairs(periph) do
if(type(v) == 'table') then
if(v.__type ~= nil and (v.__type == TYPE_REG or v.__type == TYPE_FIFO or v.__type == TYPE_RAM)) then
for j,field in pairs(v) do
if (type(field) == 'table' and field.__type == TYPE_FIELD) then
func(field, v, periph);
end
end
end
end
end
end
function foreach_subfield(reg, func)
for j,field in pairs(reg) do
if (type(field) == 'table' and field.__type == TYPE_FIELD) then
func(field, reg);
end
end
end
function foreach_reg(func)
for i,v in pairs(periph) do
if(type(v) == 'table') then
if(v.__type ~= nil and (v.__type == TYPE_REG or v.__type == TYPE_FIFO or v.__type == TYPE_RAM)) then
func(v);
end
end
end
end
function align(field, offset)
local a;
if(field.align == nil) then
a=1;
else
a=field.align;
end
local newofs = a * math.floor((offset + a - 1) / a);
return newofs;
end
function calc_field_offsets(field, reg)
local ofs = reg.current_offset;
ofs = align(field, ofs);
-- print ("field "..field.name.." offset: "..ofs);
reg.current_offset = ofs + field.size;
field.offset = ofs;
if( reg.__type == TYPE_REG and reg.current_offset > DATA_BUS_WIDTH ) then
die ("Total size of register '"..reg.name.."' ("..reg.current_offset..") exceeds data bus width ("..DATA_BUS_WIDTH..")");
end
-- print ("field ", field.name, "align: ", align);
end
function die(s)
print ("Error: "..s);
os.exit(-1);
end
function match(var, values)
local i,v;
for i,v in pairs(values) do
if(var==v) then return true; end
end
return false;
end
function csel(cond, tr, fl)
if(cond) then
return tr;
else
return fl;
end
end
function flag_set(where, flag)
local i,v;
for i,v in pairs(where)do
if(v == flag) then return true; end
end
return false;
end
function fix_prefix(obj)
if(obj.c_prefix == nil or obj.hdl_prefix==nil) then
if(obj.prefix == nil and obj.__type ~= TYPE_FIELD) then
die ("No C/HDL prefix nor default prefix defined for field/reg/peripheral '"..obj.name.."'");
end
obj.c_prefix = obj.prefix;
obj.hdl_prefix = obj.prefix;
return obj;
end
return obj;
end
function default_access(field, mytype, acc_bus, acc_dev)
if(field.type == mytype) then
if(field.access_bus == nil) then
field.access_bus = acc_bus;
end
if(field.access_dev == nil) then
field.access_dev = acc_dev;
end
end
end
function fix_access(field, reg)
if(reg.__type == TYPE_REG) then
default_access(field, BIT, READ_WRITE, READ_ONLY);
default_access(field, SLV, READ_WRITE, READ_ONLY);
default_access(field, SIGNED, READ_WRITE, READ_ONLY);
default_access(field, UNSIGNED, READ_WRITE, READ_ONLY);
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);
if(field.access ~= nil) then
return;
end
if(field.access_bus == READ_ONLY and field.access_dev == WRITE_ONLY) then
field.access = ACC_RO_WO;
elseif (field.access_bus == WRITE_ONLY and field.access_dev == READ_ONLY) then
field.access = ACC_WO_RO;
elseif (field.access_bus == READ_WRITE and field.access_dev == READ_WRITE) then
field.access = ACC_RW_RW;
elseif (field.access_bus == READ_WRITE and field.access_dev == READ_ONLY) then
field.access = ACC_RW_RO;
else
die ("Illegal access flags combination for field '"..field.name.."' in register '"..reg.name.."'");
end
end
end
function check_max_size(reg)
if(reg.total_size > DATA_BUS_WIDTH and reg.__type == TYPE_REG) then
die ("register ", reg.name, " size exceeds data bus witdh (", DATA_BUS_WIDTH, " bits)");
end
end
all_regs_size = 0;
max_ram_addr_bits = 0;
block_bits = 0;
num_rams = 0;
function log2 (x)
return math.floor(math.log(x) / math.log(2));
end
function log2up (x)
return math.ceil(math.log(x) / math.log(2));
end
function is_power_of_2(x)
for i=1,24 do
if(x == math.pow(2, i)) then return true; end
end
return false;
end
function calc_address_sizes(reg)
if(reg.__type == TYPE_REG) then
-- for ordinary registers - just count them
all_regs_size = align(reg, all_regs_size) + 1;
elseif (reg.__type == TYPE_FIFO) then
-- for FIFOS:
-- size of all FIFO fields (rounded up to multiple of 32 bits) + 1 extra FIFO control register
fifo_size = math.floor((reg.total_size + DATA_BUS_WIDTH - 1) / DATA_BUS_WIDTH) + 1;
all_regs_size = all_regs_size + fifo_size;
reg.num_fifo_regs = fifo_size;
else
-- for rams:
if(not is_power_of_2(reg.size)) then die ("RAM '"..reg.name.."': memory size must be a power of 2"); end
print("RAM: "..reg.size.." entries");
if (reg.wrap_bits == nil) then
reg.wrap_bits = 0;
end
reg.addr_bits = log2(reg.size * math.pow(2, reg.wrap_bits));
print("RAM: address size "..reg.addr_bits);
if(max_ram_addr_bits < reg.addr_bits) then
max_ram_addr_bits = reg.addr_bits;
end
if(reg.width > DATA_BUS_WIDTH) then
die("RAM '"..reg.name.."' data width exceeds WB data bus width");
end
reg.select_bits = num_rams + 1;
num_rams = num_rams + 1;
end
regbank_address_bits = log2up (all_regs_size);
-- print("all_regs: "..all_regs_size);
end
function assign_addresses()
local block_bits = math.max(max_ram_addr_bits, log2up(all_regs_size));
local num_blocks = num_rams;
local i = 0;
if(all_regs_size > 0) then
num_blocks = num_blocks + 1;
end
local select_bits = log2up (num_blocks);
print("Total bits per block: "..block_bits..", select bits: "..select_bits);
foreach_reg(function(reg)
if(reg.__type==TYPE_REG) then
reg.base = align(reg, i);
i=reg.base+1;
print("base "..reg.name.." = "..reg.base);
elseif(reg.__type == TYPE_FIFO) then
reg.base = i;
i=i+reg.num_fifo_regs;
print("fifo base "..reg.name.." = "..reg.base);
end
end );
address_bus_width = block_bits + select_bits;
address_bus_select_bits = select_bits;
end
function find_max(table, field)
local mval = 0;
local i,v;
for i,v in pairs(table) do if(type(v) == 'table' and v[field]~=nil and v[field] > mval) then mval = v[field]; end end
return mval;
end
function table_join(table_out, table_in)
local i,v;
if(table_in == nil) then return; end
for i,v in pairs(table_in) do
table.insert(table_out, v);
end
end
function tree_2_table(entry)
local tab = {};
foreach_reg(function(reg)
if(reg[entry] ~= nil) then
if(type(reg[entry]) == 'table') then
table_join(tab, reg[entry]);
else
table.insert(tab, reg[entry]);
end
end
foreach_subfield(reg, function(field, reg)
if(field[entry] ~= nil) then
if(type(field[entry]) == 'table') then
table_join(tab, field[entry]);
else
table.insert(tab, field[entry]);
end
end
end);
end);
return tab;
end
function remove_duplicates(t)
local i=1,v,j;
while(t[i] ~= nil) do
for j=1,i-1 do if(t[j]==t[i]) then table.remove(t, i); i=i-1; end end
i=i+1;
end
end
\ No newline at end of file
#!/usr/bin/lua
function gen_vhdl_ramcode(ram)
local prefix = string.lower(periph.hdl_prefix.."_"..ram.hdl_prefix);
-- generate the RAM-related ports
ram.ports = { port (SLV, ram.addr_bits - ram.wrap_bits, "in", prefix.."_addr_i", "Ports for RAM: "..ram.name ) };
if(match(ram.access_dev, {READ_ONLY, READ_WRITE})) then
table_join(ram.ports, { port(SLV, ram.width, "out", prefix.."_data_o") });
end
if(match(ram.access_dev, {WRITE_ONLY, READ_WRITE})) then
table_join(ram.ports, { port(SLV, ram.width, "in", prefix.."_data_i"),
port(BIT, 0, "in", prefix.."_we_i") });
end
local raminst = vhdl_new_instance();
end
function gen_vhdl_rams()
foreach_reg(function(reg) if(reg.__type == TYPE_RAM) then gen_vhdl_ramcode(reg); end end);
end
\ No newline at end of file
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