从零开始学习FPGA(模块文件)

一,引言

此篇为笔者第一次学习FPGA技术,在学习此技术之前,有基础的电路分析,数电,模电,c语言,人工智能理论基础,此次的学习方式为跟随项目组老师先学习基础再进行项目实践重现项目开发过程。

二,verilog语言基础

模块声明

module xx(

input xx,           //默认不占资源的是wire线

input reg  xx ,    //reg声明寄存器

output xx,

output reg xx

);

endmodule

localparam     //状态机声明

parameter INTERVAL_TIME = 28'd5000_0000;  //设定参数
//状态名 编号
localparam   S0 = 2'b00;  //本地化参数
localparam   S1 = 2'b01;
localparam   S2 = 2'b10;
localparam   S3 = 2'b11;

三,基础寄存器实现以及基础功能实现

module logic_exer(      //模块声明
  input clk,   //时钟信号
  input rst_n,
  input [7:0]theta,
  input wire [7:0]a_i,  //输入信号   //wire是一条线(不占资源)
  input wire [7:0]b_i,
  output reg [9:0]sin_o,
  output [7:0]c_o,
  output shift_o,
  output  b_o,   //输出信号 
  output reg [3:0]led
);

//reg [27:0]count;   //[9:0]是线宽,10bit 2^10==1024

parameter INTERVAL_TIME = 28'd5000_0000;  //设定参数
//状态名 编号
localparam   S0 = 2'b00;  //本地化参数
localparam   S1 = 2'b01;
localparam   S2 = 2'b10;
localparam   S3 = 2'b11;

reg [27:0]count;   //[9:0]是线宽,10bit 2^10==1024

reg [1:0] current_state;
reg [1:0] next_state;

wire work;
assign work=1'b1;

1.状态机三段式写法

//三段式写法
//第一段:刷新curren_state
always @(posedge clk or negedge rst_n)
 if(~rst_n)
  current_state<=S0;
 else
  current_state <= next_state;

//第二段
always @(*)   //组合电路的另一种写法 求next_state
 case(current_state)
  S0:
   if (count == INTERVAL_TIME-1'b1)
    next_state <= S1;
  S1:
   if (count == INTERVAL_TIME-1'b1)
    next_state <= S2;
  S2:
   if (count == INTERVAL_TIME-1'b1)
    next_state <= S3;
  S3:
   if (count == INTERVAL_TIME-1'b1)
    next_state <= S0;
 default: next_state <= S0;
 endcase

 //第三段 if or case
 always@(posedge clk or negedge rst_n)begin
 if (~rst_n)
 led<=4'b0000;
 else
 if (work==1'b1)begin
  if(current_state == S0)begin
   led[3:0] <= 4'b0001;
  end
  else if(current_state == S1)begin
   led[3:0] <= 4'b0010;
  end
  else if(current_state == S2)begin
   led[3:0] <= 4'b0100;
  end
  else if(current_state == S3)begin
   led[3:0] <= 4'b1000;
  end
 end
  
 end

2.D触发器

//第一个d触发器
always @(posedge clk)       //上升触发时钟信号   //always是申请一个时序逻辑电路
b_t0<=a_i[0];   //d触发器表达式

//第二个d触发器,吧输出再于输入延迟一个时钟信号单位
always @(posedge clk)       //上升触发时钟信号    //@表示触发条件的意思
b_t<=b_t0;   //d触发器表达式

3.计数器

//计数器  
always @(posedge clk or negedge rst_n)begin
 if(~rst_n)
   count<=28'd0;
 else
  if(count<INTERVAL_TIME)    //用减一的方法让计数准确
   count<=count+1'b1;
  else   //在10的时候置零
   count<=28'd0;
end

4.移位寄存器

always @(posedge clk)begin
if(count==0)   //在满足count这个条件时下一个条件data刷新
   //reg_shift<={reg_shift[6:0],reg_shift[7]};    //语句中的逗号是拼接前后,第一位到最后一位,其余的往前移动一位
   reg_shift<={reg_shift[0],reg_shift[7:1]};      //所有向后移位移位
end

assign shift_o = reg_shift[0];  //把reg_shift[0]赋予shift_o

4.译码器(2种写法)

//译码器,用if来实现
always @(posedge clk)begin
if (theta==10'd0)
  sin_o<=10'd12;
else if(theta==10'd1)
  sin_o<=10'd23;
else if(theta==10'd2)
  sin_o<=10'd16;
else if(theta==10'd3)
  sin_o<=10'd15;
else if(theta==10'd4)
  sin_o<=10'd28;
else if(theta==10'd5)
  sin_o<=10'd66;
else if(theta==10'd6)
  sin_o<=10'd42;
else if(theta==10'd7)
  sin_o<=10'd11;
else if(theta==10'd8)
  sin_o<=10'd15;
else if(theta==10'd9)
  sin_o<=10'd66;
end

//译码器 查找表(sin查找表),用case来实现
always @(posedge clk)begin
  case(theta)
    8'd0 : sin_o<=10'd0;
    8'd1 : sin_o<=10'd1;
    8'd2 : sin_o<=10'd2;
    8'd3 : sin_o<=10'd3;
    8'd4 : sin_o<=10'd4;
    8'd5 : sin_o<=10'd5;
    8'd6 : sin_o<=10'd6;
    8'd7 : sin_o<=10'd7;
    8'd8 : sin_o<=10'd8;
    8'd09 : sin_o<=10'd9;
    8'd10 : sin_o<=10'd10;
    8'd11 : sin_o<=10'd11;
    8'd12 : sin_o<=10'd12;
    8'd13 : sin_o<=10'd13;
    //0到90度,查表
    default:sin_o<=8'd0;
  endcase
 end

5.延迟机

reg a_r[2:0];

always@(posedge clk)begin

  a_r[0]<=a_i;
  a_r[1]<=a_r[0];
  a_r[2]<=a_r[1];
  
end

endmodule

三,tb

代码仿真使用modelsim软件,在仿真前需要先编辑tb测试文件,添加所需输入信号,并应用对应仿真模块。

`timescale  1ns/1ns  //设定时间基准

module gpu_tb();

reg clk = 1'b0; //模拟时钟,注意开始时给时钟信号设定初始值
reg [7:0]a_i,b_i;
reg [7:0]theta;

wire [7:0]c_o;
wire shift_o;
wire b_o;
wire [9:0]sin_o;

always #10 clk = ~clk; //#是延迟符号,20ns  //此处生成一个模拟的时钟信号

//起一个线程
initial begin

theta = 8'd3;
a_i = 8'd2;
b_i = 8'd3;  //设定ab_i的初始值

//a_i = 1'b0;    //1'是位宽 b0是二进制的0
//#40   //延时40ns
//a_i = 1'b1;
//#60
//a_i = 1'b0;

end

/*
genvar i;
generate
 for (i=0;i<10;i+1)begin
logic_exer #(
.INTERVAL_TIME(28'd10)
)
end
endgenerate
*/

logic_inst(
 .clk(clk),
 .a_i(a_i),
 .b_o(b_o),
 .b_i(b_i),
 .c_o(c_o),
 .shift_o(shift_o),
 .theta(theta),
 .sin_o(sin_o)
);    
endmodule

//软件环境制作一个时钟

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值