Verilog是拿来用的,不是用来学的。
这是Verilog的一份极简教程,涵盖日常设计中的绝大部分基本语法。
语法不重要,关键是实践。
完整的代码和仿真环境在github共享。
# Centos Linux release 7.2.1511
cat /etc/redhat-release
# QuestaSim-64 vlog 10.4c
vlog -version
# Verdi 2001
verdi
,
module mini_top #(
parameter NUM=8
)(
input clk,
input rst_n,
input [15 :0] i_cw,
output reg o_flag,
output [NUM-1:0] o_data_rd
);
// module instantiation
wire [15:0] cw;
wire flag;
wire [15:0] data_rd;
mini_top #(
.NUM ( 16 )
) u_DUT (
.clk ( clk ) ,
.rst_n ( rst_n ) ,
.i_cw ( cw ) ,
.o_flag ( flag ) ,
.o_data_rd ( data_rd )
);
define
定义全局常数localparam
定义局部常数include
统一管理
`define NUM_1 8'b0001_1111
`define NUM_2 8'h1F
`define NUM_3 8'd31
`define NUM_4 {4'h1, 4'b1111}
`define NUM_5 {4'h1, {4{1'b1}}}
localparam NUM_6 = 31;
localparam NUM_7 = NUM_6;
localparam NUM_8 = `NUM_1;
localparam NUM_9 = `NUM_1 + NUM_6 - 31;
wire r_enable;
wire r_start;
wire r_stop;
wire r_invert;
wire r_skip;
assign {
r_enable,
r_start,
r_stop,
r_invert,
r_skip
} = i_cw[4:0];
// reg
// combinational logic
reg flag;
always @* begin
flag = r_enable | r_skip | r_stop | r_invert;
end
// reg
// sequential logic
reg cnt_4b_is_0xa;
reg [3:0] cnt_4b;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
cnt_4b <= 4'd0;
cnt_4b_is_0xa <= 1'b0;
o_flag <= 1'b0;
end
else begin
cnt_4b <= cnt_4b + 4'd1;
cnt_4b_is_0xa <= cnt_4b==4'ha ? 1'b1 : 1'b0;
o_flag <= cnt_4b ==4'h8 ? 1'b1 : 1'b0;
end
end
// function : max
//
function [7:0] max;
input [7:0] A;
input [7:0] B;
begin
max = A < B ? B : A;
end
endfunction
wire [7:0] temp_max;
assign temp_max = max(i_din[7:0], NUM_6);
module mini_sp_ram #(
parameter ADDR_BITS=8
)(
input clk,
input [ 7:0] addr,
input [ 7:0] din,
input ce,
input we,
output reg [ 7:0] dout
);
localparam MEM_DEPTH= 1<
module mini_rom (
input clk,
input [ 7:0] addr,
output reg [ 7:0] dout
);
always @(posedge clk) begin
case(addr)
8'h00: dout <= 8'h0A;
8'h01: dout <= 8'h1A;
8'h02: dout <= 8'h2A;
8'h03: dout <= 8'h3A;
8'h04: dout <= 8'h4A;
8'h05: dout <= 8'h5A;
8'h06: dout <= 8'h6A;
8'h07: dout <= 8'h7A;
8'h08: dout <= 8'h8A;
8'h09: dout <= 8'h9A;
8'h0A: dout <= 8'hAA;
8'h0B: dout <= 8'hBA;
8'h0C: dout <= 8'hCA;
8'h0D: dout <= 8'hDA;
8'h0E: dout <= 8'hEA;
8'h0F: dout <= 8'hFA;
8'h10: dout <= 8'h50;
8'h11: dout <= 8'h51;
8'h12: dout <= 8'h52;
8'h13: dout <= 8'h53;
8'h14: dout <= 8'h54;
8'h15: dout <= 8'h55;
8'h16: dout <= 8'h56;
8'h17: dout <= 8'h57;
8'h18: dout <= 8'h58;
8'h19: dout <= 8'h59;
8'h1A: dout <= 8'h5A;
8'h1B: dout <= 8'h5B;
8'h1C: dout <= 8'h5C;
8'h1D: dout <= 8'h5D;
8'h1E: dout <= 8'h5E;
8'h1F: dout <= 8'h5F;
default: dout <= 8'hff;
endcase
end
endmodule
`timescale 1ns/10ps
task hello;
begin
$display("hello world.");
end
endtask
initial begin
hello;
end
reg clk;
reg rst_n;
initial begin
clk = 0;
end
// Be careful if CLOCK_CYCLE%2 !=0
always #(`CLOCK_CYCLE/2) clk=~clk;
// use +define+DUMP_FSDB in vsim command
// to enable fsdb file dump
//
// -pli $(VERDI_HOME)/share/PLI/MODELSIM/$PLATFORM/novas_fli.so
//
`ifdef DUMP_FSDB
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars(0,tb);
#`MAX_RUN_TIME
$finish(2);
end
`endif
// memory initilization
integer fp_dmem;
initial begin
fp_dmem = $fopen(`MEM_INIT_FILE, "r");
if(fp_dmem)
#5 $readmemh(`MEM_INIT_FILE, `MEM_INST);
else begin
$display("%s open failed.",`MEM_INIT_FILE);
$finish;
end
end
PROJ_PATH = ../..
RTL_PATH = $(PROJ_PATH)/rtl
TB_PATH = $(PROJ_PATH)/sim/tb
FILE_LIST = rtl.f
DOFILE = sim.do
TB_TOP = tb
sim:
@rm -rf work
vsim -c -do $(DOFILE)
verdi:
@verdi -nologo -f $(FILE_LIST) -top $(TB_TOP) &
clean:
@rm -rf *.ini *.fsdb *.log verdiLog transcript work
veryclean: clean
listfile:
@ls $(RTL_PATH)/*.v > $(FILE_LIST)
@ls $(TB_PATH)/*.v >> $(FILE_LIST)
vlib work
vmap work work
vlog -timescale=1ns/1ps +incdir=./ -work work \
+define+DUMP_FSDB \
-f rtl.f
vsim +notimingchecks -t 1ps -novopt -L work -l tb.log \
-pli $env(VERDI_HOME)/share/PLI/MODELSIM/LINUX64/novas_fli.so \
work.tb
run -all
更多Verilog文章,请关注微信订阅号 不忘出芯