Top files describe the hierarchy and connectivity of an HDLmaker design. In it's simplest form the top file is just a list of components. The default signal name is the component's pin name so for designs where no renaming is required the Top file consists of barely more than a component list.
Basic Top File
In it's most basic form the HDLmaker top file requires only a #module statement, to specify the module name, a #include of a pin file and one or more #insert statements to instantiate components, The default signal naming conventions is to use the component pin names as the signal names. In this example we instantiate a single 32 bit register. The design consists of the top file basic.top, the pin file basic.pin and a single component, dregce32 which can be found in either dregce32.v or dregce32.vhd depending on the target language.
basic.top
#module "basic";
#include "basic.pin";
#insert "dregce32.v";
basic.pin
#nopadring
#pins
d[31:0] type = in;
q[31:0] type = out;
sysclk type = in;
gblreset type = in;
ce type = in;
#endpins
Shown below are the Verilog and VHDL outputs of HDLmaker for the basic.top design. HDLmaker uses the file extension to determine the source format of a file, i.e. .v for Verilog, .vhd for VHDL, .top for a top file, .pin for a pin file, .cnet for a concise netlist and so forth. The source file is then translated into the target language, Verilog or VHDL in this case, and the component is instantiated. If the source file is an HDLmaker file, i.e. top or pin, a target file is generated. If the source file is already in the target language it is used directly. If the source and target formats are different then HDLmaker first searches for the equivalent file in the target language and uses that file, or if no equivalent file is found it translates the source file into the target language. HDLmaker has a crude VHDL to Verilog translator built in, it has no Verilog to VHDL translator. In this example dregce32 is available in both Verilog and VHDL so HDLmaker was able to substitute dregce32.vhd for dregce32.v.
basic.v
module basic(
ce,
d,
gblreset,
q,
sysclk
);
//-- IO Declarations
input ce;
input [31:0] d;
input gblreset;
output [31:0] q;
input sysclk;
//-- Signal Declarations
//-- Component Instance dregce32_1
dregce32 dregce32_1
(
.ce (ce),
.d ({d[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({q[31:0]})
);
endmodule
basic.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity basic is
port (
ce_pin :in std_logic;
d_pin :in std_logic_vector (31 downto 0);
gblreset_pin :in std_logic;
q_pin :buffer std_logic_vector (31 downto 0);
sysclk_pin :in std_logic
);
end basic;
architecture BEHAVIOR of basic is
component dregce32
port (
sysclk,ce,gblreset : in std_logic ;
d : in std_logic_vector (31 downto 0);
q : buffer std_logic_vector (31 downto 0)
);
end component;
--// signals begin here
signal ce : std_logic;
signal d : std_logic_vector (31 downto 0);
signal gblreset : std_logic;
signal q : std_logic_vector (31 downto 0);
signal sysclk : std_logic;
begin
dregce32_1: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 0) => d (31 downto 0),
q (31 downto 0) => q (31 downto 0)
);
end;
Simple Connections
HDLmaker uses connect statements to attach wires to pins. The connect statements need only be used if the signal name and the pin name differs. The next example instantiates three registers in a row. HDLmaker insert statements begin with the #insert keyword followed by the component name, followed by a comma separated list of optional arguments and finally terminated with a ;.
basic_connect.top
#module "basic_connect";
#include "basic.pin";
#insert "dregce32.v",
connect q[31:0] = reg_a[31:0];
#insert "dregce32.v",
connect d[31:0] = reg_a[31:0],
connect q[31:0] = reg_b[31:0];
#insert "dregce32.v",
connect d[31:0] = reg_b[31:0];
basic_connect.v
module basic_connect(
ce,
d,
gblreset,
q,
sysclk
);
//-- IO Declarations
input ce;
input [31:0] d;
input gblreset;
output [31:0] q;
input sysclk;
//-- Signal Declarations
wire [31:0] reg_a;
wire [31:0] reg_b;
//-- Component Instance dregce32_1
dregce32 dregce32_1
(
.ce (ce),
.d ({d[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({reg_a[31:0]})
);
//-- Component Instance dregce32_2
dregce32 dregce32_2
(
.ce (ce),
.d ({reg_a[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({reg_b[31:0]})
);
//-- Component Instance dregce32_3
dregce32 dregce32_3
(
.ce (ce),
.d ({reg_b[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({q[31:0]})
);
endmodule
basic_connect.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity basic_connect is
port (
ce_pin :in std_logic;
d_pin :in std_logic_vector (31 downto 0);
gblreset_pin :in std_logic;
q_pin :buffer std_logic_vector (31 downto 0);
sysclk_pin :in std_logic
);
end basic_connect;
architecture BEHAVIOR of basic_connect is
component dregce32
port (
sysclk,ce,gblreset : in std_logic ;
d : in std_logic_vector (31 downto 0);
q : buffer std_logic_vector (31 downto 0)
);
end component;
--// signals begin here
signal ce : std_logic;
signal d : std_logic_vector (31 downto 0);
signal gblreset : std_logic;
signal q : std_logic_vector (31 downto 0);
signal reg_a : std_logic_vector (31 downto 0);
signal reg_b : std_logic_vector (31 downto 0);
signal sysclk : std_logic;
begin
dregce32_1: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 0) => d (31 downto 0),
q (31 downto 0) => reg_a (31 downto 0)
);
dregce32_2: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 0) => reg_a (31 downto 0),
q (31 downto 0) => reg_b (31 downto 0)
);
dregce32_3: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 0) => reg_b (31 downto 0),
q (31 downto 0) => q (31 downto 0)
);
end;
Shuffled Connections
HDLmaker can handle arbitrary signal ordering. The numbering of a bus can be in any order and direction. HDLmaker will unshuffle it so that Verilog or VHDL can handle it. The example below illustrates this:
basic_shuffle.top
#module "basic_shuffle";
#include "basic.pin";
#insert "dregce32.v",
connect q[31:0] = reg_a[31:0];
#insert "dregce32.v",
connect d[31:0] = reg_a[31:8,4:7,0,3,1,2];
connect q[31:0] = q[31:0];
basic_shuffle.v
module basic_shuffle(
ce,
d,
gblreset,
q,
sysclk
);
//-- IO Declarations
input ce;
input [31:0] d;
input gblreset;
output [31:0] q;
input sysclk;
//-- Signal Declarations
wire [31:0] reg_a;
//-- Component Instance dregce32_1
dregce32 dregce32_1
(
.ce (ce),
.d ({d[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({reg_a[31:0]})
);
//-- Component Instance dregce32_2
dregce32 dregce32_2
(
.ce (ce),
.d ({reg_a[31:8],reg_a[4],reg_a[5],reg_a[6],reg_a[7],reg_a[0],reg_a[3],reg_a[1],reg_a[2]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({q[31:0]})
);
endmodule
basic_shuffle.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity basic_shuffle is
port (
ce_pin :in std_logic;
d_pin :in std_logic_vector (31 downto 0);
gblreset_pin :in std_logic;
q_pin :buffer std_logic_vector (31 downto 0);
sysclk_pin :in std_logic
);
end basic_shuffle;
architecture BEHAVIOR of basic_shuffle is
component dregce32
port (
sysclk,ce,gblreset : in std_logic ;
d : in std_logic_vector (31 downto 0);
q : buffer std_logic_vector (31 downto 0)
);
end component;
--// signals begin here
signal ce : std_logic;
signal d : std_logic_vector (31 downto 0);
signal gblreset : std_logic;
signal q : std_logic_vector (31 downto 0);
signal reg_a : std_logic_vector (31 downto 0);
signal sysclk : std_logic;
begin
dregce32_1: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 0) => d (31 downto 0),
q (31 downto 0) => reg_a (31 downto 0)
);
dregce32_2: dregce32
port map (
sysclk => sysclk,
ce => ce,
gblreset => gblreset,
d (31 downto 8) => reg_a (31 downto 8),
d(7) => reg_a(4),
d(6) => reg_a(5),
d(5) => reg_a(6),
d(4) => reg_a(7),
d(3) => reg_a(0),
d(2) => reg_a(3),
d(1) => reg_a(1),
d(0) => reg_a(2),
q (31 downto 0) => q (31 downto 0)
);
end;
File Name Override
HDLmaker assumes that a module or entity named foo is found in a file called foo.v or foo.vhd. The file argument to the insert command overrides this. In the following example the module description is found in reg_components.v, or in reg_components.vhd.
#insert "dregce32",file = "reg_components.v";
Verilog Parameters
HDLmaker can pass parameter values to Verilog modules. VHDL Generics are not supported. Parameters are passed by name just as connections are. The following example illustrates the use of the parameter argument:
param.top
#module "param";
#include "basic.pin";
#insert "dregce.v",
parameter WIDTH = 32,
connect q[31:0] = reg_a[31:0];
#insert "dregce.v",
parameter WIDTH = 16,
connect d[15:0] = reg_a[15:0],
connect q[15:0] = q[15:0];
#insert "dregce.v",
parameter WIDTH = 16,
connect d[15:0] = reg_a[31:16],
connect q[15:0] = q[31:16];
param.v
module param(
ce,
d,
gblreset,
q,
sysclk
);
//-- IO Declarations
input ce;
input [31:0] d;
input gblreset;
output [31:0] q;
input sysclk;
//-- Signal Declarations
wire [31:0] reg_a;
//-- Component Instance dregce_w32_1 {#Parameters W32}
dregce dregce_w32_1
(
.ce (ce),
.d ({d[31:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({reg_a[31:0]})
);
defparam dregce_w32_1.WIDTH = 32;
//-- Component Instance dregce_w16_1 {#Parameters W16}
dregce dregce_w16_1
(
.ce (ce),
.d ({reg_a[15:0]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({q[15:0]})
);
defparam dregce_w16_1.WIDTH = 16;
//-- Component Instance dregce_w16_2 {#Parameters W16}
dregce dregce_w16_2
(
.ce (ce),
.d ({reg_a[31:16]}),
.gblreset (gblreset),
.sysclk (sysclk),
.q ({q[31:16]})
);
defparam dregce_w16_2.WIDTH = 16;
endmodule
Hierarchical Designs
HDLMaker handles an unlimited number of hierarchical levels. Top file may instantiate other top files, as shown below:
#insert "sub_level.top",
connect ce = ce[0]
connect d[31:0] = data[31:0];
HDLmaker recurses down the tree and evaluates each level of the design. Connections to top file are made in the same way as connections to Verilog or VHDL modules/entities. Parameters are handled differently. Instead of using the parameter command, HDLmaker passes the values of it's variables down the tree. The language section describes the care and feeding of HDLmaker variables.
#module:
Specifies the name of the module. If no #module statement is included then the top file's name is used, i.e. if the top file is "foo.top" then the module name will be "foo";
#module "file_name";
#part_type,#package,#speed:
Specifies the part type,package type and speed, for example:
#part_type "4013E";
#package "pq240";
#speed "-3";
#part_type "board"; Specifies a PC board, causes all of the non-IO pins to be included,
i.e. vcc, gnd, jtag, init ...
#company:
Specifies the company name for use in the copyright line inserted into generated files
#company "Polybus Systems Corp, Westford, MA";
#engineer:
Specifies the engineer's name for use in the comments inserted into the generated code
#engineer "B. Joshua Rosen";
#directory:
Specifies the VHDL working directory.
#directory "work";
#maxfan:
This is a Synplicity directive, sets the max fan out limit. The default is a soft limit of 100.
To set a soft fan out limit do the following:
#maxfan 16;
If a hard limit is desired add the word "hard" to the line;
#maxfan 25 hard;
#synplicity:
This is a Synplicity directive, places the quoted string into the synplicity project file
#synplicity "set_option -default_enum_encoding onehot";
#include
Directly includes the text of the file. If the file is a .pin file then the pad ring and entity declarations are automaticcaly generated. An #include of a pin file is required.
#include "file_name.pin";
#insert,#insert_upcase:
Insert an instance of a component. The extension specifies the source type. insert_upcase is similiar to insert except that in verilog synthesys mode the component name is upper cased.
#insert "foo.top"; Generates a VHDL file from the .top file and inserts it.
#insert "foo.vhd"; Insert a vhdl file.
#insert_compare
Builds a module that contains the specified component and comparison logic for all of the module's outputs. The compare module is inserted into the file instead of the specified component. The purpose of insert_compare is to allow to different implementations of a module to be compared, for example a gate level and an RTL version.
#insert "foo.top";
#insert_compare "foo_gate.v",
connect cmp_clk = sysclk,
connect cmp_rst = gblreset;
The comparison logic is clocked with the signal cmp_clk and reset with the signal cmp_rst. These signals must be connected to a clock and a high true reset signal from your design.
#insert_script
Inserts the component into all relevant scripts and make files (like #insert) but does not instantiate it
#insert_script "foo.vhd";
#insert_string
Inserts an arbitrary string into the code. For example,
#insert_string "`ifdef foo";
The argument may be any HDLmaker expression. If you want to include a ; then you must use a backslash,
#insert_string "assign a = b\;";
#add_package
Adds packages to all script files.
#add_package "my_package.vhd";
#add_package "my_library.v";
#add_sim_package
Adds packages to all simulation script files.
#add_package "my_package.vhd";
#add_package "my_library.v";
#add_syn_package
Adds packages to all synthesys script files.
#add_package "my_package.vhd";
#add_package "my_library.v";
#clock
#clock specifies a clock period, thefault is nanoseconds. The #clock command generates timing constraints for Precision, Synplify and for the Xilinx place and route tools.
The old format, which is still supported, has the form #clock "clk_name" period; where the period is specified in nanoseconds.
#clock "sysclk" 10;
A new more flexible form of the clock statement has been added as of release 6.8.1. The new form is
#clock clk_name, period or frequency, [units], [syn,par];
All arguments may be HDLmaker expressions. The first argument is the clock name, the second is either the period or the frequency, the third optional argument is the units (ns,ps,mhz,ghz), and the 4th optional argument is
a syn (synthesis only) or par (place and route only). If the 4th argument is omitted then the clock constraint is applied to both synthesis and place and route.
#clock "x_clk", 7800, "ps";
#clock "y_clk", 150, "mhz";
#clock "q_clk", 8;
#clock "z_clk_in", 10, "ns", "par";
#clock "z_clk_buff", 8, "ns", "syn";
In the first example the clock period is expressed in ps, in the second the clock speed is expressed as mhz. In the 3rd example the clock period uses the default unit of ns. In the 4th example the clock constraint applies to the place and route tool only, in the 5th it applies to the systhesis tool only.
There are two reasons for using different constraints at synthesis time, one is to influence the behavior of the synthesis tool by applying tighter or looser constraints, and the second is because different tools want the clock constraint applied at different points in the clock tree. For example the Xilinx tools prefer that clock constraints be applied at the input of the DCM whereas Synplify wants it on the outputs of the clock buffers.
#dont_touch
SUpported for Precision only, inserts a dont_touch pragma into the code.
#dont_touch "startup_1";
#timespec,#timegrp
These are Xilinx timespec directives. The example shown below specifies that the clock to RAM setup is 30 ns.
#timespec="FROM:FFS:TO:RAMS=30";
Time specs may also use expressions , the syntax for is:
#timespec from_expression,to_expression,time_expression,priority_expression (optional);
example:
#timespec "foo_a" + i, "bar_a" + j, k, l;
where i,j,k and l are variables.
example:
#timespec foo, "FFS", 20, 1;
In this example only foo is a variable, "FFS" is the Xilinx name for all flipflops, 20 and 1, mean 20 ns and priority 1;
#tnm_net
#tnm_inst
#tnm_pin
These are Xilinx timing name directives. The example shown groups together all signals named areg* (areg_0,areg_1...) in the datapath_1 module. This is used in conjunction with the #timespec directive.
#tnm_net "areg" "datapath_1/areg*";
places the following into the ucf
NET "datapath_1/areg*" TNM="areg";
Expressions may be used as follows:
#tnm_net path_name_expression, path_expression;
#tnm_inst path_name_expression, path_expression;
#tnm_pin path_name_expression, path_expression;
example:
#tnm_inst "tms_iff", "obuft_" $ name $ "_pads_1/scan_tms_iff" ;
where name is a variable.
#no_timespecs
Stop Synopsys from emitting time specs in the SXNF files. #no_timespecs is the same as
#synopsys "xnfout_constraints_per_endpoint = 0"
#input_setup
Specify an input setup constraint to Synopsys
#input_setup "pin_name" "clock_name" 20;
This is equivalent to:
#synopsys "set_input_delay -clock clock_name -max 20 pin_name";
#input_hold
Specify an input hold constraint to Synopsys
#input_hold "pin_name" "clock_name" 20;
This is equivalent to:
#synopsys "set_input_delay -clock clock_name -min 20 pin_name";
#black_box
This is a Synplicity directive. It is similiar to the Synopsys #dont_touch command.
Hdlmaker also uses the black_box directive to exclude modules from Synopsys Make
files.
#black_box "startup";
#state_machine
Sets the Synplicity FSM compiler switch on.
#resource_sharing_off
Sets the Synplicity resource sharing switch off, the default is on
#pipe_off
Sets the Synplicity resource pipe switch off, the default is on
#write_verilog,#write_vhdl
Sets the write verilog or vhdl option in Synplicity
#boundary_optimization
Synopsys derective, enables logic optimization across hierarchical boundaries. #flatten takes precedence over #boundary_optimization.
#flatten
Forces Synopsys to flatten the design
#synopsys
This allows you to add arbitrary commands to the Synopsys .job file
#synopsys "xnfout_constraints_per_endpoints = 0"
#syn_directive
Add synthesys directives to the module or entity. For example the Synplicity directive syn_sharing
#syn_directive "syn_sharing" "off";
Will produce the following results in Verilog and VHDL
//verilog
module dreg(
d,
q,
sysclk
) /* syn_sharing = "off" */ ;
//-- IO Declarations
input [7:0] d;
output [7:0] q;
input sysclk;
--vhdl
entity dreg is
port (
d :in std_logic_vector (7 downto 0);
q :buffer std_logic_vector (7 downto 0);
sysclk :in std_logic
);
end dreg;
architecture BEHAVIOR of dreg is
attribute syn_sharing of behavior : architecture is "off";
#xst_directive
Specify and XST directive. Example,
#xst_directive "keep_hierarchy","dblbus_interface_1","false";
#buffer
Specify the type of output used for VHDL
#buffer "out";
#buffer "inout";
#buffer "buffer"; -- this is the default
#locate
Insert placement constraints into the appropriate constraint file (.cst file for the old ppr Xilinx tool, .pcf file for the new Xilinx place and route tool).
#locate "fdc_1","clb_r1c1";
#priority
Insert a prioritize command to PAR into the pcf file. Prioritize is used to up the priority of a signal to the place and route software.
#priority "rxvalid" 90;
Valid priority levels run from 1 to 99 (highest priority). The default priority is 3.
#timescale
Insert Verilog `timescale command
#timescale "1 ns/1 ps";
Inserts the following
`timescale 1 ns/1 ps
#uselib
Insert Verilog uselib command
#uselib "/tools/xilinx/xact-5.2.1-verilog/verilog4000e";
Inserts the following
`uselib dir=/tools/xilinx/xact-5.2.1-verilog/verilog4000e libext=.v
#casesensitive
Allow case sensitive Verilog code, the default is to downcase everything. The env variableHDLMAKER_ALLOW_CASE_SENS can also be used.
#allowtrailingnumbers
Allow bus and signal names to end in a number, the default is to append _bus to any bus name that ends
in a number and to turn individual signals that end in a number into members of a bus.
The env variable HDL_TRAILING_NUM also can be used. The valid values for the variable are
0
|
Don't allow trailing numbers
|
FALSE
|
Don't allow trailing numbers
|
1
|
Allow trailing numbers on buses
|
TRUE
|
Allow trailing numbers on buses
|
BUS
|
Allow trailing numbers on buses
|
2
|
Allow trailing numbers on individual signals
|
SIGNAL
|
Allow trailing numbers on individual signals
|
3
|
Allow trailing numbers on both
|
BOTH
|
Allow trailing numbers on both
|
#allowtrailingnumbers "BUS";
#allowtrailingnumbers "SIGNAL";
#allowtrailingnumbers "BOTH";
#use_defparam
Hdlmaker can pass parameters to a Verilog module using either defparam or by passing them as ordered arguments. The default is defparam, to use the argument syntax do
#use_defparam 0
or use the HDLMAKER_USE_DEFPARAM env variable.
Examples:
#use_defparam 1;
#insert "srfifo_ctrl.v",
#parameter WIDTH = 32;
Generates:
srfifo_ctrl srfifo_ctrl_w32_1
(
);
defparam srfifo_ctrl_w32_1.WIDTH = 32;
#use_defparam 0;
#insert "srfifo_ctrl.v",
#parameter WIDTH = 32;
Will generate
srfifo_ctrl #(32) srfifo_ctrl_w32_1
(
);
#initial
#initial is used to insert a Verilog initial block into an HDLmaker generated Verilog file. HDLmaker takes the text between the parenthesis and places it in an initial block in the Verilog file.
HDLmaker top file #initial statement:
#initial (
$dumpfile("sys.vcd");
$dumpvars(0,sys.rework_1.U1);
$dumpvars(0,sys.rework_1.U2);
$dumpvars(0,sys.rework_1.U3);
$dumpvars(0,sys.rework_1.U4);
$dumpvars(0,sys.rework_1.U6);
);
HDLmaker generated Verilog initial block:
initial begin
$dumpfile("sys.vcd");
$dumpvars(0,sys.rework_1.U1);
$dumpvars(0,sys.rework_1.U2);
$dumpvars(0,sys.rework_1.U3);
$dumpvars(0,sys.rework_1.U4);
$dumpvars(0,sys.rework_1.U6);
end
#fplan
Floorplan command for use with Xilinx FPGAs. The #fplan is used to place FFs, DLLs, BUFGs, Block RAM. The syntax is
For CLB components,
#fplan component path, row, col, slice (optional);
For CLKDLLs, BUFGs, Block RAMs. Multipliers
#fplan component path, type, x, y;// Virtex 2, Spartan3
#fplan component path, type, row, col, slice;// Spartan 2
Legal types are,
bufg,ramb4,ramb16,buft,bufe,dll,dcm,mult18x18.
Examples:
#fplan "alu_1/acc[0]", 12, 13;
#fplan "alu_1/acc[1]", 14,15,1;
#fplan "alu_1/acc[1]", "slice", 4,5; // For virtex2 and 2p devices this specifies slice instead of CLB
#fplan "clkdll_1", "dll", 2;
#fplan "bufg_1", "bufg", 2;
#fplan "dcache_1/ramb4_s8_s16_1", "ramb4",7,1;
#fplan "dcache_1/ramb4_s8_s16_2", "ramb4",6,1;
Area