系统芯片设计笔记 fifo&watchdog

串并转换

串并转换一般用来各种低速通信协议中,比如UART, SPI, I2C等。
UART的传输速率有9600,38400,191200等,K级别,CPU频率是M级别,串并转换可以作为数据缓冲模块,提高数据传输效率

wire data_out;
reg [7:0] temp;
always @(posedge clk or negedge rstn) begin
  if(!rstn)
    temp <= 8'h0;
  else if(load)
    temp <= data_in;
  else if(en)
    temp <= {temp[6:0], 1'b0};
  else
    temp <= temp;
end
assign data_out = temp[7];
// 并转串,比如CPU给uart发送串行数据,1bit,1bit发送
input wire data_in;
  temp <= {temp[6:0], data_in};
// 串转并

FIFO&FILO

FIFO通常用在通信双方数据传输速率不匹配的情况下,硬件实现。
FILO与软件中的堆栈类型,完成入栈和出栈操作,一般采用软件方式实现。

FIFO分为同步fifo和异步fifo,异步fifo指的是读写时钟域的速率不同,当读写时钟速率差越大,所需fifo的深度越小,反之,深度越大。同步fifo指的是读写时钟速率相同,仅仅完成的是数据搬移工作,比如DMA的工作,在DMA控制器内部有一个同步的fifo作为数据缓冲,可以提高数据传输的速率。

此外,为了设计方便,FIFO的输入和输出位宽一般是相同的,如果不相同,要通过上文提到的串并转换方法进行位宽的调整。

  1. 同步fifo_demo
module fifo_sync #(
  parameter   DATA_WIDTH = 32,
  parameter   RAM_DEPTH  = 8,
  parameter   RAM_ADDR   = 3
)(
  input                        clk,
  input                        rstn,

  input                        wr_en,
  input       [DATA_WIDTH-1:0] wr_data,
  input                        rd_en,
  output  reg [DATA_WIDTH-1:0] rd_data,

  output  reg                  fifo_full,
  output  reg                  fifo_empyt
);

reg [DATA_WIDTH-1:0] ram[RAM_DEPTH];
reg [RAM_ADDR-1:0]   wr_ptr, rd_ptr;
reg [RAM_ADDR-1:0]   counter;

integer i;
always @(posedge clk or negedge rstn) begin
  if(!rstn) begin 
    for(i=0;i<RAM_DEPTH)    
      ram[i] <= 0;
  end
  else if(!fifo_full & wr_en)
    ram[wr_ptr] <= wr_data;
end

always @(*) begin  // comb logic
  if(!rstn) begin 
    rd_data = 0; 
  end
  else if(rd_en & !fifo_empyt)
    rd_data = ram[rd_ptr];
  else
    rd_data = 0;
end

always @(posedge clk or negedge rstn) begin
  if(!rstn) begin 
    wr_ptr <= 0;
  end
  else if(wr_en & ~fifo_full)
    wr_ptr <= wr_ptr + 1'b1;
end

always @(posedge clk or negedge rstn) begin
  if(!rstn) begin 
    rd_ptr <= 0;
  end
  else if(rd_en & ~fifo_empyt)
    rd_ptr <= rd_ptr + 1'b1;
end

always @(posedge clk or negedge rstn) begin
  if(!rstn) begin 
    counter <= 'h0;
  end
  else if(wr_ptr && !fifo_full)
    counter <= counter + 1'b1;
  else if(rd_ptr && !fifo_empyt)
    counter <= counter - 1'b1;
end

always @(*)
  if(counter == RAM_DEPTH-1)
    fifo_full = 1;
  else 
    fifo_full = 0;

always @(*)
  if(counter == 0)
    fifo_empyt = 1;
  else 
    fifo_empyt = 0;

endmodule
  1. 异步fifo的demo
 /*********************************************************************
 * Author           : liu
 * Last modified    : 2023-04-11 22:24
 * Filename         : asyn_fifo.v
 * Description      : 
 * ******************************************************************/
module asyn_fifo(
  input			 rstn,

  input          wr_clk,
  input  [31:0]  wr_data,
  input          wr_en,
  
  input          rd_clk,
  input			 rd_en,
  output  [31:0] rd_data,

  output		 fifo_full,
  output	     fifo_empty
);

// generate meomory 
// 32 * 16bit 
// depath : 32
// width : 16
  reg [31:0] memory[0:15];

// wr&rd ptr gray
  reg  [4:0]  wr_ptr;
  reg  [4:0]  wr_ptr_gray;
  reg  [4:0]  wr_ptr_gray_r;
  reg  [4:0]  wr_ptr_gray_rr;
  wire [4:0]  wr_ptr_bin2gray;

  reg  [4:0]  rd_ptr;
  reg  [4:0]  rd_ptr_gray;
  reg  [4:0]  rd_ptr_gray_r;
  reg  [4:0]  rd_ptr_gray_rr;
  wire [4:0]  rd_ptr_bin2gray;

  integer i;
  always @(posedge wr_clk or negedge rstn) begin
	if(!rstn) begin
	  for(i=0;i<15;i=i+1)
		memory[i] <= 32'h0;
	end else if(wr_en && !fifo_full) begin
	  memory[wr_ptr] <= wr_data;
	end
  end
  
  // read domain
  always @(posedge rd_clk or negedge rstn) begin
	if(!rstn)  
	  rd_ptr <= 5'h0;
	else if(rd_en && !fifo_empty) 
	  rd_ptr <= rd_ptr + 1'b1;
  end

  // reg to write clk domain 
  assign rd_ptr_bin2gray = (rd_ptr>>1)^(rd_ptr);
  always @(posedge rd_clk or negedge rstn) begin 
    if(!rstn) 
      rd_ptr_gray <= 0;
    else 
      rd_ptr_gray <= rd_ptr_bin2gray;
  end

  assign rd_data = memory[rd_ptr[3:0]];

  always @(posedge rd_clk or negedge rstn) begin 
	if(!rstn) begin
	  wr_ptr_gray_r  <= wr_ptr_gray;  
	  wr_ptr_gray_rr <= wr_ptr_gray_r;  
	end else begin
	  wr_ptr_gray_r  <= wr_ptr_gray;  
	  wr_ptr_gray_rr <= wr_ptr_gray_r;  
	end
  end

  // write domain
  always @(posedge wr_clk or negedge rstn) begin
	if(!rstn) begin 
	  wr_ptr <= 5'h0;
	end
	else if(wr_en && !fifo_full) begin
	  wr_ptr <= wr_ptr + 1'b1;
	end
  end

  assign wr_ptr_bin2gray = (wr_ptr>>1)^(wr_ptr);

  // reg to read clk domain 
  always @(posedge wr_clk or negedge rstn) begin 
	if(!rstn) 
	  wr_ptr_gray <= 0;
	else
	  wr_ptr_gray <= wr_ptr_bin2gray;
  end

  always @(posedge wr_clk or negedge rstn) begin 
	if(!rstn) begin
	  rd_ptr_gray_r  <= rd_ptr_gray;  
	  rd_ptr_gray_rr <= rd_ptr_gray_r;  
	end	else begin
	  rd_ptr_gray_r  <= rd_ptr_gray;  
	  rd_ptr_gray_rr <= rd_ptr_gray_r;  
	end
  end

  assign fifo_empty = wr_ptr_gray_rr == rd_ptr_gray;
  assign fifo_full  = (rd_ptr_gray_rr[4] != wr_ptr_gray[4])&&(rd_ptr_gray_rr[3] != wr_ptr_gray[3])&&(rd_ptr_gray_rr[2:0] == wr_ptr_gray[2:0]);

endmodule

watchdog(硬件实现)

满足第一个预置数,向CPU发起中断,请求对watchdog计数清零,如果等到预置数1+预置数2还没有等到清零信号,说明系统跑飞了,则发起全局复位信号,对系统进行复位。

module wtd(
  input clk,
  input rstn,
  input clear,
  input [7:0] preload1,
  input [7:0] preload2,
  
  output reg  done,
  output reg  reset 
);

reg [7:0] cnt;
always @(posedge clk or negedge rstn) begin
  if(!rstn)
    cnt <= 8'h0;
  else if(clear)
    cnt <= 8'h0;
  else if(cnt <= preload1 + preload2)
    cnt <= cnt + 8'h1;
  else
    cnt <= cnt;
end

always @(posedge clk or negedge rstn) begin
  if(!rstn)
    done <= 1'b0;
  else if(clear)
    done <= 1'b0;
  else if(cnt == preload1)
    done <= 1'b1;
end

always @(posedge clk or negedge rstn) begin
  if(!rstn)
    reset <= 1'b0; 
  else if(cnt == preload1 + preload2)
    reset <= 1'b1;
end
endmodule

对于硬件寄存器的访问,有两种方式:

  1. 硬件直接访问
  2. 通过软件方式间接访问
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值