Main / Hdl
Design Tips
Handy tool for converting VHDL to Verilog here: https://github.com/ldoolitt/vhd2vl VHDL NotesVHDL is NOT case sensitive. VHDL files often start with library inclusions like: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; library unisim; use unisim.vcomponents.all; These IEEE libraries include definitions for std_logic and std_logic_vectors, which are arrays of bits. A whole bunch of functions are described that can be used with these data types, like and, nand, or, xor, etc. You can define a single bit std_logic_vector: std_logic_vector(0 to 0) There are two ways to put sub-blocks into your architecture. You can either put a component declaration at the top of your arch and then instantiate it in the body, or you can instantiate an entity in the body that is in the work library using entity : work.foo. Since there are no macros per se in VHDL, for conditional inclusion of blocks of logic use generics and generates. A generic is included in the entity above the ports: generic (name : type); port(...); Optionally, a constant can be assigned by adding a := value after the type. Generate statementsThen, conditionally build some logic with a generate: foobar_gen : if DEBUG or FOO_TYPE = "superfoo" generate foobar_proc : process begin wait until (foo_clk = '1'); if (foo_rst = '1') then ... end if; end process foobar_proc; end generate foobar_gen; It appears to nest a conditional, you must separate into two clauses. Also, note that in compile the validity of the inner statements are checked regardless of the outer statement and this can result in warnings. foo_gen : if foo_g = "yayfoo" generate bar_gen : for i in 0 to 2 generate In other words, the VHDL generate statement does not accomplish "conditional compilation". The contained statements are always compiled, but if the conditional is false, they are not elaborated (in SW terms, they are not "linked"). Any statements must be legal VHDL, and all referenced objects must exist. So you can't get away with invalid code inside a generate statement even if the conditions aren't met to generate it. Conditional use of configurationsThere doesn't seem to be a clean way to do this (i.e. no 'else' for generates, etc) so we must instantiate in code a component for each potential component. Of course it only gets created if the conditional passes during sim/synth. Here's an example of this, also throwing in some complication in that there are many of these foo guys sharing the foo_wrapper and they need an index into specific bit positions of a shared vector. Hence the for loop. foo_gen : for i in 1 to 1 generate begin rock_gen : if music_g = "rock" generate for rock : foo_wrapper USE CONFIGURATION work.rock_c; begin rock : foo_wrapper generic map... ... end generate rock_gen; roll_gen : if music_g /= "roll" generate for roll : foo_wrapper USE CONFIGURATION work.roll_c; begin roll : foo_wrapper generic map... ... end generate roll_gen; end generate foo_gen; You cannot concatenate bits together in a port map value assignment, but you can separate the port name as needed. To assign your array ports to all zeroes, use ( (others => '0'), (others => '0') ) or (others => ( others => '0') ) VerilogLearning Sites: Header filesVerilog header files have the extension .vh and they are included with `include "filename.vh" Here is a template for a vh file with an inclusion protection and illustrating the way to define macros. You can also build functions in these. `ifndef _FILENAME_VH_ `define _FILENAME_VH_ `define FOO 42 `endif SignsIn Verilog a reg contains binary data, signed vs unsigned is just a matter of interpretation. The bit values stay the same, subtraction and addition are always performed using two's complement. Assigning all ones to a bus of variable widthwire foo; assign foo = {32{1'b1}}; assign foo = ~0; Either way should work. Abtraction LevelsBehavioral level (highest) Register-Transfer Level Gate Level (lowest) Does using <signal_name>'RIGHT mean the last bit on the right of the signal? Conditional ProcessesYou can actually put always blocks inside of if statements, which presumably gates them and they are only active under certain conditions (more research needed). Edgesposedge and negedge are functions. If one signal in the sensitivity list uses them, then all signals must. Parameterized ModulesYou can create a module "template" that will let you set up and use variable values for things like signal widths, whenever you instantiate said module. module foobar #(PARAM1=42, PARAM2=42) ( //blah blah ); endmodule Syntax TipsCreating a module template. Ports can be in any order, and is a list of names only, with direction defined inside definition body. module <module_type> ( <portlist> ); : type name(ports); end module always @(*) begin asks the compiler to build the sensitivity list for you based on what's inside the block. = is used for blocking assignments, while <= is used for non-blocking assignments. This helps in generating combinational or sequential logic. The blocking assignment blocks the next assignment from occurring until the current one is complete. It's counter-intuitive, because the blocking assignments happen faster given that they are not waiting on anything except wire time. Therefore blocking assignments makes sense for combinational logic, but non-blocking assignments make sense for sequential logic. reg vs wire Crossing Clock Domains//--------------------------local clock domain------------------ // Verilog Example: // crossing transaction ACK from remote state machine to local state machine // always @(posedge local_clk) begin if (reset) begin remote_ack_local_reg1 <= 1'b0 ; remote_ack_local_reg2 <= 1'b0 ; remote_ack_local <= 1'b0 ; end else begin remote_ack_local_reg1 <= remote_ack ; remote_ack_local_reg2 <= remote_ack_local_reg1 ; remote_ack_local <= !remote_ack_local_reg2 && remote_ack_local_reg1 ; end end How about another? In this case we are interested in the level, and when the input signal de-asserts. //--------------------------remote clock domain------------------ // Verilog Example: crossing the REQ from local state machine to the // remote state machine // always @(posedge remote_clk) begin if (reset_rem) begin local_req_remote_reg1 <= 1'b0 ; local_req_remote_reg2 <= 1'b0 ; local_req_remote_start <= 1'b0 ; local_req_remote_end <= 1'b0 ; end else begin local_req_remote_reg1 <= local_req_remote ; local_req_remote_reg2 <= local_req_remote_reg1 ; local_req_remote_start <= !local_req_remote_reg2 && local_req_remote_reg1 ; local_req_remote_end <= !local_req_remote_reg1 && local_req_remote_reg2 ; end end Parameters Vs MacrosThe tick ` is used for macros, not parameters. So when you use something like `define VAR, then you reference `VAR but with parameter WIDTH = 5 then you just reference WIDTH in the code. Functions and TasksTasks can include time delays, but functions cannot as they are combinational only. So functions cannot call tasks, but can call other functions. Tasks can have multiple outputs, but functions have only one output. Variables declared within are local, but can modify global variables. Oddly, a function is required to have at least one input. A function name is also assigned within the function as the return value. For example: function integer log2; input [31:0] value; for (log2 = 0; value > 0; log2 = log2 + 1) value = value >> 1; endfunction Here's an example function to generate a large field of data for your testbench: function [DATA_BITS-1:0] count_fill; input useless; integer i; integer start_data; begin start_data = 32'h01010101; count_fill = 0; for ( i=0; i < 128; i = i+1 ) begin count_fill = (count_fill << BITS ) | start_data; start_data = start_data+ 32'h01010101; end end endfunction Verilog SimulationTimingThe `timescale directive is NOT synthesizable. It is to tell the simulation how time is defined (i.e. what does #1 mean?) and is specified with <time_unit>/<time_precison> as in `timescale 1ns/1ns'. The latter indicates how delay values are rounded in simulation. The time units available are s/ms/us/ns/ps/fs. WhileA while statement executes the code within it repeatedly if the condition it is assigned to check returns true. While loops are not normally used for synthesizable models, but they are used in test benches. InitialAn initial block, as the name suggests, is executed only once when simulation starts. This is useful in writing test benches. If we have multiple initial blocks, then all of them are executed at the beginning of simulation. initial begin clk = 0; reset = 0; req_0 = 0; req_1 = 0; end Note that the commands inside execute sequentially, so delays are compounding even when applied to different signals. In this example, the enable happens 60 time units after start, not 20. initial begin enable = 1'b0; reset = 1'b0; #20 reset = 1'b1; #20 reset = 1'b0; #20 enable = 1'b1; end SystemVerilogNet variables are static type, which is global scope and fixed size throughout simulation. Dynamic types are Class, Queue, Associative Array and do not have a fixed size but vary during run. Note that Verilog does not have an enum, but SV does. However, SV is not allowed for a top level RTL module by Vivado. In SV you are allowed to put function definitions at global scope, but this is not allowed for Verilog. If you try Vivado will give you this error: root scope declaration is not allowed in verilog 95/2K mode. Note that Verilog does not have the import instruction, while SV does. If you don't have the right file type assigned, Vivado will only give you a stupidly useless "syntax error" failure note instead of pointing out the real problem. DeclarationsSome online examples show declarations of ints inside an initial begin block, but the Vivado 2017 compiler won't actually let you do this. Must be outside the block. Glossary
Verilog-specific
importAn import function let's you bring in stuff from other "packages". Here's the syntax: import axi_vip_pkg::* Mixed-Language GotchasWhen instantiating VHDL in Verilog, only the following VHDL data types are supported: bit, bit_vector, std_logic, std_ulogic, std_logic_vector, std_ulogic_vector. See chapter 9 of UG901 for details of Vivado mixed language support. Cannot use the VHDL integer data type for simulation. |