Slvcodec
Generate conversions to/from VHDL types and std_logic_vector. Generate python-based tests.
Install / Use
/learn @benreynwar/SlvcodecREADME
slvcodec
NOTE This project is not well maintained. I'm making occasional bug fixes since I'm still using it for a project but I don't recommand it for new projects. I would recommend building something on top of one of the solid python vhdl parsing projects that has come out sinced I create this.
slvcodec is a tool that analyzes VHDL and generates:
-
Functions to convert arbitrary VHDL types to and from std_logic_vector.
-
Generate testbenches for entities that read inputs from a file, and write outputs to a file.
-
Utilities so that unit tests for VHDL code can easily to be written in python.
Generation of functions to convert to and from std_logic_vector
Here's an example VHDL package.
.. code:: vhdl
library ieee;
use ieee.numeric_std.all;
package complex is
constant FIXED_WIDTH: natural := 8;
subtype fixed_t is unsigned(FIXED_WIDTH-1 downto 0);
type complex_t is record
real: fixed_t;
imag: fixed_t;
end record;
type array_of_complex is array(natural range <>) of complex_t;
end package;
The following python script is used to generate a helper package that contains functions to convert the types to and from std_logic_vector.
.. code:: python
import os
from slvcodec import filetestbench_generator
thisdir = os.path.dirname(__file__)
def make_slvcodec_package():
complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')
directory = os.path.join(thisdir, 'generated')
os.mkdir(directory)
filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])
if __name__ == '__main__':
make_slvcodec_package()
Here is what the generated VHDL looks like.
.. code:: vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.complex.all;
use work.slvcodec.all;
package complex_slvcodec is
function to_slvcodec (constant data: array_of_complex) return std_logic_vector;
function from_slvcodec (constant slv: std_logic_vector) return array_of_complex;
constant fixed_t_slvcodecwidth: natural := fixed_width;
constant complex_t_slvcodecwidth: natural := 2*fixed_width;
function to_slvcodec (constant data: complex_t) return std_logic_vector;
function from_slvcodec (constant slv: std_logic_vector) return complex_t;
end package;
package body complex_slvcodec is
function to_slvcodec (constant data: array_of_complex) return std_logic_vector is
constant W: natural := complex_t_slvcodecwidth;
constant N: natural := data'length;
variable slv: std_logic_vector(N*W-1 downto 0);
begin
for ii in 0 to N-1 loop
slv((ii+1)*W-1 downto ii*W) := to_slvcodec(data(ii));
end loop;
return slv;
end function;
function from_slvcodec (constant slv: std_logic_vector) return array_of_complex is
constant W: natural := complex_t_slvcodecwidth;
constant N: natural := slv'length/W;
variable mapped: std_logic_vector(slv'length-1 downto 0);
variable output: array_of_complex(N-1 downto 0);
begin
mapped := slv;
for ii in 0 to N-1 loop
output(ii) := from_slvcodec(mapped((ii+1)*W-1 downto ii*W));
end loop;
return output;
end function;
function to_slvcodec (constant data: complex_t) return std_logic_vector is
constant W0: natural := 0;
constant W1: natural := W0 + fixed_width;
constant W2: natural := W1 + fixed_width;
variable slv: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);
begin
slv(W1-1 downto W0) := to_slvcodec(data.real);
slv(W2-1 downto W1) := to_slvcodec(data.imag);
return slv;
end function;
function from_slvcodec (constant slv: std_logic_vector) return complex_t is
constant W0: natural := 0;
constant W1: natural := W0 + fixed_width;
constant W2: natural := W1 + fixed_width;
variable data: complex_t;
variable mapped: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);
begin
mapped := slv;
data.real := from_slvcodec(mapped(W1-1 downto W0));
data.imag := from_slvcodec(mapped(W2-1 downto W1));
return data;
end function;
end package body;
Generation of file-based testbenches
Here's an example entity that just returns the magnitude squared of a complex data type that we defined earlier.
.. code:: vhdl
library ieee;
use ieee.numeric_std.all;
use work.complex.all;
entity complex_mag2 is
port (
i: in complex_t;
o: out unsigned(FIXED_WIDTH+1-1 downto 0)
);
end entity;
architecture arch of complex_mag2 is
signal real2: signed(FIXED_WIDTH*2-1 downto 0);
signal imag2: signed(FIXED_WIDTH*2-1 downto 0);
signal mag2: unsigned(FIXED_WIDTH*2-1 downto 0);
signal scaled_mag2: unsigned(FIXED_WIDTH+1-1 downto 0);
begin
real2 <= i.real * i.real;
imag2 <= i.imag * i.imag;
mag2 <= unsigned(real2) + unsigned(imag2);
scaled_mag2 <= mag2(FIXED_WIDTH*2-1-1 downto FIXED_WIDTH-2);
o <= scaled_mag2;
end architecture;
We can use slvcodec to generate a testbench that reads input data from a file, and writes output data to another file.
.. code:: python
import os
from slvcodec import filetestbench_generator
thisdir = os.path.dirname(__file__)
def make_slvcodec_package():
complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')
directory = os.path.join(thisdir, 'generated')
os.mkdir(directory)
slvcodec_files = filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])
return slvcodec_files
def make_complex_mag2_testbench():
base_filenames = [
os.path.join(thisdir, 'complex_pkg.vhd'),
os.path.join(thisdir, 'complex_mag2.vhd'),
]
slvcodec_fns = make_slvcodec_package()
with_slvcodec_fns = base_filenames + slvcodec_fns
directory = os.path.join(thisdir, 'generated')
generated_fns, generated_wrapper_fns, resolved = filetestbench_generator.prepare_files(
directory=directory, filenames=with_slvcodec_fns,
top_entity='complex_mag2')
return generated_fns
if __name__ == '__main__':
make_complex_mag2_testbench()
This will generate the following VHDL testbench.
.. code:: vhdl
library ieee;
use ieee.std_logic_1164.all;
use work.slvcodec.all;
use ieee.numeric_std.all;
use work.complex.all;
use work.complex_slvcodec.all;
entity complex_mag2_tb is
generic (
CLOCK_PERIOD: time := 10 ns;
RUNNER_CFG: string;
OUTPUT_PATH: string
);
end entity;
architecture arch of complex_mag2_tb is
type t_input is
record
i: complex_t;
end record;
type t_output is
record
o: unsigned((1+fixed_width)-1 downto 0);
end record;
constant t_input_slvcodecwidth: natural := 2*fixed_width;
function to_slvcodec (constant data: t_input) return std_logic_vector;
function from_slvcodec (constant slv: std_logic_vector) return t_input;
function to_slvcodec (constant data: t_input) return std_logic_vector is
constant W0: natural := 0;
constant W1: natural := W0 + 2*fixed_width;
variable slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
begin
slv(W1-1 downto W0) := to_slvcodec(data.i);
return slv;
end function;
function from_slvcodec (constant slv: std_logic_vector) return t_input is
constant W0: natural := 0;
constant W1: natural := W0 + 2*fixed_width;
variable data: t_input;
variable mapped: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
begin
mapped := slv;
data.i := from_slvcodec(mapped(W1-1 downto W0));
return data;
end function;
constant t_output_slvcodecwidth: natural := (1+fixed_width);
function to_slvcodec (constant data: t_output) return std_logic_vector;
function from_slvcodec (constant slv: std_logic_vector) return t_output;
function to_slvcodec (constant data: t_output) return std_logic_vector is
constant W0: natural := 0;
constant W1: natural := W0 + (1+fixed_width);
variable slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
begin
slv(W1-1 downto W0) := to_slvcodec(data.o);
return slv;
end function;
function from_slvcodec (constant slv: std_logic_vector) return t_output is
constant W0: natural := 0;
constant W1: natural := W0 + (1+fixed_width);
variable data: t_output;
variable mapped: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
begin
mapped := slv;
data.o := from_slvcodec(mapped(W1-1 downto W0));
return data;
end function;
signal input_data: t_input;
signal output_data: t_output;
signal input_slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
signal output_slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
signal clk: std_logic;
signal read_clk: std_logic;
signal write_clk: std_logic;
begin
input_data <= from_slvcodec(input_slv);
output_slv <= to_slvcodec(output_data);
file_reader: entity work.ReadFile
generic map(FILENAME => OUTPUT_PATH & "/indata.dat",
PASSED_RUNNER_CFG => RUNNER_CFG,
WIDTH => t_input_sl
Related Skills
node-connect
350.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
350.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
350.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
