此工程是串轉並行數據的實驗
- do文件模板(自動仿真文件)
Modelsim do 文件的自動化仿真
1.1 建立庫
1.2 映射庫到物理目錄
1.3 編譯源文件
1.4 啓動仿真器
1.5 執行仿真
#此處是註釋
#退出當前仿真功能
quit -sim
#清楚命令行顯示信息
.main clear
#建立一個lib庫
vlib ./lib
#在lib中建立一個work
vlib ./lib/work
#映射邏輯庫名,將邏輯庫名映射庫路徑中
vmap work ./lib/work
#編譯指令 編譯源文件
vlog -work work ./tb_ex_shift_reg.v
vlog -work work ./../design/*.v
# 以上爲編譯指令 */
#啓動仿真器
vsim -voptargs=+acc work.tb_ex_shift_reg
#-divider 分隔符
add wave -divider {tb_111}
# 添加觀察項
add wave tb_ex_shift_reg/lvds_d
add wave tb_ex_shift_reg/o_lvds_d
add wave tb_ex_shift_reg/i_30
add wave tb_ex_shift_reg/lvds_clock
add wave tb_ex_shift_reg/rst_n
# *號代表通配符
add wave -divider {ex_shift_reg_instaa}
add wave tb_ex_shift_reg/ex_shift_reg_inst/*
run 100us
- tb激勵文件
注意:readmemb命令符的使用
`timescale 1ns/1ns //單位時標聲明 1ns是單位
module tb_ex_shift_reg();
reg lvds_clock;
reg rst_n;
reg [0:0] mem1x16 [15:0]; //這是聲明memory變量,第一個[]是位寬,第二個[]是深度.
reg lvds_d = 0;
wire [7:0] o_lvds_d = 0;
reg [3:0] i_30;
initial begin
lvds_clock = 0;
rst_n = 0;
#90
rst_n = 1;
end
always #10 lvds_clock <= ~lvds_clock;
// 在根目錄中建立了data.txt文件
initial begin
$readmemb ("./data.txt",mem1x16); // readmemb命令符,這個最後b爲二進制,也可以是h(16進制)
end
ex_shift_reg ex_shift_reg_inst(
.lvds_clk (lvds_clock),
.rst_n (rst_n),
.lvds_d (lvds_d),
.o_lvds_d (o_lvds_d)
);
initial begin
#100
lvds_send_d();
end
task lvds_send_d();
integer i;
begin
for (i=0; i<=255; i=i+1)
begin
@(posedge lvds_clock);
lvds_d <= mem1x16[i[3:0]];
i_30 <= i[3:0];
end
end
endtask
endmodule
- tata.txt
注意此文件是放在sim文件夾中
1
0
1
0
1
0
1
0
1
0
0
0
1
0
0
0
- 串轉並行數據的源文件
注:lvds數據轉並行
module ex_shift_reg(
input wire lvds_clk,
input wire rst_n,
input wire lvds_d,
output reg [7:0] o_lvds_d
};
reg [7:0] shift_reg; // 用戶存儲我們的串轉並的數據;
reg [2:0] s_cnt;
reg s_flag;
reg s_flag_dly1,s_flag_dly2,s_flag_dly3;
// 位拼接符{7'b1010_00,3'b010} ---> 10'b1010_000_010 等效的;
// 注意左移和右移的用法
always @(posedge lvds_clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
shift_reg <= 'd0;
end
else begin
//shift_reg <= {shift_reg[6:0],lvds_d}; // 左移
shift_reg <= {lvds_d,shift_reg[7:1]}; // 右移
end
end
// 第一個時鐘週期{0000_000lvds_d1}
// 第二個時鐘週期{0000_00lvds_d1 lvds_d2}
// .....
// 第八個時鐘週期{lvds_d1 d2 ... d8}
always @(posedge lvds_clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
s_cnt <= 'd0;
end
else begin
s_cnt <= s_cnt + 1'b1;
end
end
always @(s_cnt) //()內爲敏感列表,如何寫全敏感列表,條件列表裏的所有變量,以及賦值語句右邊的所有變量
if (s_cnt == 3'd7)
s_flag <= 1'b1;
else
s_flag <= 1'b0; //這個分支條件一定要寫全,不然生產鎖存器,鎖存器在fpga中是很危險的
always @(posedge lvds_clk or posedge rst_n) begin
if (rst_n == 1'b0) begin
o_lvds_d <= 'd0;
end
else if (s_flag_dly3 == 1'b1) begin
o_lvds_d <= shift_reg;
end
end
// 延時打拍的用法
always @(posedge lvds_clk)
{s_flag_dly3,s_flag_dly2,s_flag_dly1} <= {s_flag_dly2,s_flag_dly1,s_flag};
endmodule