SD-Host AHB slave 接口模块

9 篇文章 37 订阅
1 篇文章 0 订阅

在这里插入图片描述
AHB 总线接口功能模块,CPU通过驱动软件对SD HOST控制器进行访问。(内含控制寄存器,CPU通过配置寄存器,对控制器的各个模块进行控制)

功能:
1、AHB slave接口,允许CPU访问,控制sd_host的运行方式;
2、同步逻辑,SD域产生的信号同步到AHB域供软件判断;

控制寄存器介绍

DMA_CTRL_ADDR寄存器
Size:32bis
Address Offset:0x44
Read/write access:read/write

bitsnameDefinition
[0]dma_endma enable
[3:1]保留
[4]dma_direactiondma 传输方向 0:read data form ahb bus
[15:5]保留
[31:16]transfer_sizedma搬运数据大小(byte)

DMA_ADDR_ADDR寄存器
Size:32bis
Address Offset:0x40
Read/write access:read/write

bitsnameDefinition
[31:0]dma_addressdma 数据搬移时的目标地址(这里指ahb方向(slave)的地址

INT_GEN_REG_ADDR寄存器
Size:32bis
Address Offset:0x48
Read/write access:read/write

bitsnameDefinition
[0]fifo_full_int_gen
[4]fifo_empty_int_gen
[8]dma_finish_int_gen
others保留

CLR_INT_REG_ADDR寄存器
Size:32bis
Address Offset:0x4C
Read/write access:read/write

bitsnameDefinition
[0]clr_fifo_full_int
[4]clr_fifo_empty_int
[8]clr_dma_finish_int
others保留

CLOCK_CONTROL_REGISTER_ADDRR寄存器
Size:32bis
Address Offset:0x50
Read/write access:read/write

bitsnameDefinition
[2]sd_clk_enable
[15:8]sd_clk_dividersd clk 的分频系数

SOFTWARE_RESET_REGISTER_ADDR寄存器
Size:32bis
Address Offset:0x54
Read/write access:read/write

bitsnameDefinition
[0]sd_soft_reset

CLK_EN_SPEED_UP_ADDR寄存器
Size:32bis
Address Offset:0x58
Read/write access:read/write

bitsnameDefinition
[0]hw_stop_clk_en
[4]high_speed_clk

ARGUMENT_REGISTER_ADDR寄存器
Size:32bis
Address Offset:0x5C
Read/write access:read/write

bitsnameDefinition
[31:0]command_argument

COMMAND_REGISTER_ADDR寄存器
Size:32bis
Address Offset:0x60
Read/write access:read/write

bitsnameDefinition
[1:0]response_type相响应类型 无响应 普通响应 长响应
[2]data_present
[3]command_enable
[10:5]command_index

BLOCK_SIZE_REGISTER_ADDR寄存器:
Size:32bis
Address Offset:0x64
Read/write access:read/write

bitsnameDefinition
[10:0]block_size

BLOCK_COUNT_REGISTER_ADDR寄存器:
Size:32bis
Address Offset:0x68
Read/write access:read/write

bitsnameDefinition
[31:0]block_number_ahb

TRANSFER_MODE_REGISTER_ADDR寄存器:
Size:32bis
Address Offset:0x6C
Read/write access:read/write

bitsnameDefinition
[0]data_width
[1]data_direction

READ_TIMEOUT_CONTROL_REGISTER_ADDR寄存器:
Size:32bis
Address Offset:0x70
Read/write access:read/write

bitsnameDefinition
[31:0]read_to

INTERRUPT_STATUS_MASK_REGISTER_ADDR寄存器:
Size:32bis
Address Offset:0x74
Read/write access:read/write

bitsnameDefinition
[0]response_timeout_error_interrupt_mask
[1]write_data_crc_error_interrupt_mask
[2]read_data_crc_error_interrupt_mask
[3]tx_fifo_read_error_interrupt_mask
[4]rx_fifo_write_error_interrupt_mask
[5]read_to_error_interrupt_mask
[6]transfer_complete_interrupt_mask
[7]command_complete_interrupt_mask
[8]sd_fifo_empty_interrupt_mask
[9]fifo_empty_interrupt_mask
[10]fifo_full_interrupt_mask
[11]sd_fifo_full_interrupt_mask
[12]end_command_and_response_interrupt_mask
[13]dma_finish_interrupt_mask

信号描述

SignalsI/OWidthformtoDeclaration
hclkinput1AHB bus时钟信号
hrst_ninput 1 AHB bus 复位信号
hselinput1AHB bus地址decode 选中slave
hwriteinput1AHB bus1:write 0:read
htransinput1AHB bus4种 idel busy seq nonseq
hburstinput[2:0]AHB bus8种 singal incr beat4/8/16 wrap4/8/16
hwadatainput[31:0]AHB bus数据
haddrinput[31:0]AHB bus地址
hsizeinput[2:0]AHB busbus的宽度
hready_ininput1AHB bus其它slave的状态(1:其它slave IDLE 不占线)
hready_outoutput1AHB bus此slave的状态,(忙:0)给仲裁其器判断使用??
hrespoutput[1:0]AHB bus
hrdataoutput[31:0]AHB bus
dma_enoutput1DMADMA使能信号
dma_direcoutput1DMA0:写fifo(从AHB到FIFO) 1:读fifo
transfer_sizeoutput[15:0]DMA搬运数据的大小 (byte)
dma_addroutput[31:0]DMA目标地址
fifo_full_int_genoutput1中断信号产生使能(控制寄存器)
fifo_empty_int_genoutput1中断信号产生使能(控制寄存器)
dma_finish_int_genoutput1中断信号产生使能(控制寄存器)
clr_fifo_full_intoutput1
clr_fifo_empty_intoutput1清除中断信号(CLR_INT_REG_ADDR)
clr_dma_finish_intoutput1清除中断信号
clr_dma_eninput1清除dma_en 软件清零
fifo_full_intinput1fifo满中断
fifo_empty_intinput1fifo空中断
dma_finish_intinput1dma搬移结束中断
response0-3input[31:0]sd_cmd_receivecmd模块放回的命令响应
in_sd_clkinput1sd domain clk
sd_fifo_emptyinput1sd读fifo空
sd_fifo_fullinput1sd写fifo满
sd_fifo_reinput1sd读fifo使能 sd_if中没使用??
in_end_commandinput1状态:
in_end_command_and_responseinput1状态:
in_transfer_completeinput1状态:
in_send_data_crc_errorinput1状态:
in_receive_data_crc_errorinput1状态:
in_response_timeoutinput1状态:
in_cmd_current_stateinput[2:0]sd_cmd_fsm状态:当前cmd状态机状态
in_read_to_errorinput1状态:read time out
one_bk_re_endinput1sd_data_fsm状态: current_state == RECEIVE_END_BIT
sd_clk_enableoutput1sd_clksd_clk 分频使能
hw_stop_clkoutput1
sd_clk_divideroutput[7:0]sd_clk 分频系数
sd_soft_resetoutput1sd的软件复位
high_speed_clkoutput1
command_argumentoutput[31:0]命令的内容(ARGUMENT_REGISTER_ADDR)
command_indexoutput[5:0]??(COMMAND_REGISTER_ADDR)
block_sizeoutput[10:0]一次多少个block
block_lenoutput[10:0]一个block多少个byte
sd_op_finishoutput1用于清除FIFO ptr ()
block_numberoutput[31:0]
data_directionoutput1data_fsm sd-fifo data_direction1:to sd card 0:to fifo
data_widthoutput1数据位宽
read_tooutput[31:0]read time out 时间配置
irqoutput1中断信号
out_responseoutput148bit
out_longresponseoutput1136bit
cmd_fsm_readyoutput1cmd_fsmcmd fsm 启动信号
data_fsm_readyoutput1dada_fsmdata fsm 启动信号

verilog 实现

module sd_if (
		//ahb bus slave singals 
			hclk;
			hrst_n;
			hsel;
			hwrite;
			htrans;
			hburst;
			hwadata;
			haddr;
			hsize;
			hready_in;
			//out
			hready_out;
			hresp;
			hrdata;
		//--------------------------
			response0;
			response1;
			response2;
			response3;

//-- host_dma
			dma_en;
			dma_direc;
			transfer_size;
			dma_addr;

			fifo_full_int_gen;
			fifo_empty_int_gen;
			dma_finish_int_gen;
			clr_fifo_full_int;
			clr_fifo_empty_int;
			clr_dma_finish_int;
			clr_dma_en;
			fifo_full_int;
			fifo_empty_int;
			dma_finish_int;


			in_sd_clk;
			sd_fifo_empty;
			sd_fifo_full;
			sd_fifo_re;
			in_end_command;
			in_end_command_and_response;
			in_transfer_complete;
			in_send_data_crc_error;
			in_receive_data_crc_error;
			in_response_timeout;
			in_cmd_current_state;
			in_read_to_error;
			one_bk_re_end;
			sd_clk_enable;
			hw_stop_clk;
			sd_clk_divider;
			sd_soft_reset;
			high_speed_clk;
			command_argument;
			command_index;
			block_size;
			block_len;
			sd_op_finish;
			block_number;
			data_direction;
			data_width;
			read_to;
			irq;
			out_response;
			out_longresponse;
			cmd_fsm_ready;
			data_fsm_ready;
);

// AHB signals
input hclk;			
input hrst_n;
input hsel;			
input hwrite;
input   [1:0]   htrans;		//IDLE、BUSY、NONSEQ、SEQ
input   [2:0]   hburst;		//burst类型,支持4、8、16 burst,incrementing/wrapping
input   [31:0]  hwadata;
input   [31:0]  haddr;
input   [2:0]   hsize;		//8、16、32  bits this design
input 			hready_in;	//other slave is no busy

output			hready_out;
output  [1:0]   hresp;
output  [31:0]  hrdata;

//-- host_dma
output  		dma_en;		
output 			dma_direc;	
output  [15:0]  transfer_size;	//dma transfer X byte
output  [31:0]  dma_addr;

// interrupt signals generater enable
output  fifo_full_int_gen;
output	fifo_empty_int_gen;
output	dma_finish_int_gen;
//clear interrupt signals
output	clr_fifo_full_int;
output	clr_fifo_empty_int;
output	clr_dma_finish_int;

input	clr_dma_en;
input	fifo_full_int;
input	fifo_empty_int;
input	dma_finish_int;

input [31:0]	response0;
input [31:0]	response1;
input [31:0]	response2;
input [31:0]	response3;

input			in_sd_clk;
input			sd_fifo_empty;
input			sd_fifo_full;
input			sd_fifo_re;
//state register signal
input			in_end_command;
input			in_end_command_and_response;
input			in_transfer_complete;
input			in_send_data_crc_error;
input			in_receive_data_crc_error;
input			in_response_timeout;
input [2:0]		in_cmd_current_state;
input			in_read_to_error;
input			one_bk_re_end;

output			sd_clk_enable;
output			hw_stop_clk;
output [7:0]	sd_clk_divider;
output			sd_soft_reset;
output			high_speed_clk;	
	
output [31:0]	command_argument;
output [5:0]	command_index;
output [10:0]	block_size;		
output [10:0]	block_len;
output			sd_op_finish;
output [31:0]	block_number;
output			data_direction;
output			data_width;
output [31:0]	read_to;		//read timeout
output			irq;				//interrupt to interrupt controler
output			out_response;	//respobnse 48bit
output			out_longresponse;	//longresponse 136bit
output			cmd_fsm_ready;	//fsm start signal
output			data_fsm_ready;	//fsm start signal

reg			cmd_fsm_ready;
reg	[31:0]	hrdtata;
reg			sd_clk_enable;
reg	[7:0]	sd_clk_divider;
reg			sd_soft_reset;
reg			hw_stop_clk_en;
reg			high_speed_clk;
reg	[31:0]	command_argument;
reg	[5:0]	command_index;
reg 		command_enable;
reg 		data_present;		//indicate if the current command has data transfer
reg	[1:0]	response_type;
reg	[10:0]	block_size;
reg	[10:0]	block_len;
reg	[10:0]	block_len_r;
reg	[31:0]	block_number;
reg			data_direction;
reg			data_width;
reg	[31:0]	read_to;
reg			read_to_error;

reg			dma_finish_interrupt_mask;
reg			end_command_and_response_interrupt_mask;
reg			sd_fifo_empty_interrupt_mask;	//tx fifo empty interrupt mask
reg			fifo_full_interrupt_mask;		//tx fifo full interrupt mask
reg			fifo_empty_interrupt_mask;
reg			sd_fifo_full_interrupt_mask;	//rx fifo full interrupt mask
reg			command_complete_interrupt_mask;
reg			transfer_complete_interrupt_mask;
reg			read_to_error_interrupt_mask;
reg			rx_fifo_write_error_interrupt_mask;
reg			tx_fifo_read_error_interrupt_mask;
reg			read_data_crc_error_interrupt_mask;
reg			write_data_crc_error_interrupt_mask;
reg			response_timeout_error_interrupt_mask;

reg			sd_fifo_empty_r;
reg			sd_fifo_full_r;
reg			end_command;
reg			transfer_complete;
reg			send_data_crc_error;
reg			receive_data_crc_error;
reg			response_timeout;
reg			out_response;
reg			out_longresponse;
reg			end_command_and_response;

//--host_dma
reg			dma_en;
reg			dma_direc;transfer_size;
reg	[15:0]	dma_addr;
reg	[31:0]	fifo_full_int_gen;
reg			fifo_empty_int_gen;
reg			dma_finish_int_gen;
reg			clr_fifo_full_int;
reg			clr_fifo_empty_int;
reg			clr_dma_finish_int;
//-------------internal register-------------
reg 		hwrite_r;
reg [2:0]	hsize_r;
reg [2:0]	hburst_r;
reg [1:0]	htrans_r;
reg [31:0]	haddr_r;

reg 		dma_end_tp;
reg 		dma_end;
reg 		dma_end_r;
reg 		cmd_ready_pre;
reg 		hw_stop_clk;

reg [31:0]	block_number_ahb;
reg [31:0]	block_num_tp;
reg 		one_bk_re_end_tp_1;
reg 		one_bk_re_end_tp_2;
reg 		one_bk_re_end_tp_3;
reg 		cmd_state_send_tp1;
reg 		cmd_state_send_tp2;
reg 		cmd_state_send_tp3;
reg 		in_end_cmd_and_resp_tp_1;
reg 		in_end_cmd_and_resp_tp_2;
reg 		in_end_cmd_and_resp_tp_3;
reg 		sd_fifo_empty_tp1;
reg 		sd_fifo_full_tp1;
reg 		in_end_cmd_tp_1;
reg 		in_end_cmd_tp_2;
reg 		in_end_cmd_tp_3;
reg 		in_transfer_end_tp_1;
reg 		in_transfer_end_tp_2;
reg 		in_transfer_end_tp_3;
reg 		in_rd_to_err_tp_1;
reg 		in_rd_to_err_tp_2;
reg 		in_rd_to_err_tp_3;
reg 		in_send_data_crc_err_tp_1;
reg 		in_send_data_crc_err_tp_2;
reg 		in_send_data_crc_err_tp_3;
reg 		in_receive_data_crc_err_tp_1;
reg 		in_receive_data_crc_err_tp_2;
reg 		in_receive_data_crc_err_tp_3;
reg 		in_resp_timeout_tp_1;
reg 		in_resp_timeout_tp_2;
reg 		in_resp_timeout_tp_3;
reg [31:0]	response0_ahb;
reg [31:0]	response1_ahb;
reg [31:0]	response2_ahb;
reg [31:0]	response3_ahb;
reg 		cmd_state_send;
reg 		ahb_wr_reg_en;
reg 		ahb_rd_reg_en;
//----------------------------------------------------------
// Beginning of main code 
//-------------------------------------------------------------

//------------------------------------------------------
// Generate AHB hready_out and hresp signals
//------------------------------------------------------------
//sd 的工作和这边没有关系,这里只是配置寄存器,配置完就根据寄存器内容进行工作
//这里若拉低了,DMA也不能工作
assign hready_out = 1'b1;	//这里能实现单周期配置寄存器,这里没有必要拉低
assign hresp =2'b0;			//respone always OK

//----------------------------------------------------------
//register AHB bus control and addr
//-----------------------------------------------------------

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		hwrite_r 	<= 1'b0;
        hsize_r 	<= 3'b0;
        hburst_r	<= 3'b0;
        htrans_r	<= 2'b0;
        haddr_r		<= 32'b0;
	end
	//hsel decoder 选中sd host,hread_in  other slave is IDLE
	else if (hsel && hready_in)
	begin
		hwrite_r 	<= hwrite;
        hsize_r 	<= hsize;
        hburst_r	<= hburst;
        htrans_r	<= htrans;
        haddr_r		<= haddr;
	end
	else begin
		hwrite_r 	<= 1'b0;
        hsize_r 	<= 3'b0;
        hburst_r	<= 3'b0;
        htrans_r	<= 2'b0;
        haddr_r		<= 32'b0;
	end
end

//-----------------------------------------------------------
// Generate ahb_wr_reg_en and ahb_rd_reg_en
//----------------------------------------------------------
//10 NOSNSEQ  11  SEQ
//ahb_wr_reg_en 写寄存器使能,ahb_rd_reg_en 读寄存器使能
assign ahb_wr_reg_en = hready_in && hwrite_r && (htrans_r == 2'b10 | htrans_r == 2'b11);
assign ahb_rd_reg_en = hsel && hready_in && !hwrite & (htrans_r == 2'b10 | htrans_r == 2'b11);
//write use hwrite_r (打拍)地址周期打完一拍刚好对上数据周期
//read use !hwrite (没打拍)

//-------------------------------------------------------------
// Generate block_len for fifo
//------------------------------------------------------------
// delay 2 clk  (blcok_size hclk domian) 2d (block_len in_sd_clk block_len)
// 因为in_sd_clk 也是hclk 分频得到,这里可以保证不出现亚稳态??(他说的)
always @(posedge in_sd_clk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		block_len   <= 11'd200;
		block_len_r <= 11'd200;
	end
	else
	begin
		block_len_r <= block_size;
		block_len <= block_len_r;
	end
end

//--------------------------------------------------------------
//DMA control operation
//DMA_CTRL_ADDR : 	[0] dma_en
//					[4]	dma_direc
//				[31:16]	transfer_size
//		   [15:5]/[3:1]	reserved
//-------------------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		dma_en <= 1'b0;
	else if (clr_dma_en)
		dma_en <= 1'b0;
	else if (ahb_wr_reg_en & (haddr_r[7:0]) == `DMA_CTRL_ADDR)
		dma_en <= hwdata[0];
end
// dma_en 单独写(没和下面的一起),dma_en是个traig信号,只有被clr才清零

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		dma_direc <= 1'b0;
		transfer_size <= 16'b0;
		dma_addr <= 32'b0;
	end
	else if (ahb_wr_reg_en)
	begin
		case (haddr_r[7:0])
			`DMA_CTRL_ADDR : begin
				dma_direc <= hwdata[4];
				transfer_size <= hwdata[31:16];
			end
			`DMA_ADDR_ADDR:
				dma_addr <= hwdata[31:0];
		endcase
	end
end
//------------------------------------------------
// INT_GEN_REG_ADDR
//---------------------------------------------------

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		fifo_full_int_gen <= 1'b1;
		fifo_empty_int_gen <= 1'b1;
		dma_finish_int_gen <= 1'b1;
	end
	else if (ahb_wr_reg_en && (haddr_r[7:0]== `INT_GEN_REG_ADDR))
	begin
		fifo_full_int_gen <= hwdata[0];
		fifo_empty_int_gen <= hwdata[4];
		dma_finish_int_gen <= hwdata[8];
	end
end

//-------------------------------------------------------------
//CLR_INT_REG_ADDR spec
//					[0] clr_fifo_full_int
//					[4]	clr_fifo_empty_int
//					[8]	clr_dma_finish_int
//		   		 [....]	reserved
//-------------------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		clr_fifo_full_int <= 1'b0;
		clr_fifo_empty_int <= 1'b0;
		clr_dma_finish_int <= 1'b0;
	end
	else if (ahb_wr_reg_en && (haddr_r[7:0]== `CLR_INT_REG_ADDR))
	begin
		clr_fifo_full_int <= hwdata[0];
		clr_fifo_empty_int <= hwdata[4];
		clr_dma_finish_int <= hwdata[8];
	end
	else 
	begin
		clr_fifo_full_int <= 1'b0;
		clr_fifo_empty_int <= 1'b0;
		clr_dma_finish_int <= 1'b0;
	end
end

//-----------------------------------------------
// Generate DATA FSM  start signals
//------------------------------------------------
//写准备好了(有效data_present)+fifo也写满了/commoand结束了
//sd-fifo  data_direction 1:to sd card   0:to fifo
assign data_fsm_ready = data_present && 
						(data_direction ? (sd_fifo_full):(in_end_command));

always @(posedge in_sd_clk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		dma_end_tp 	<= 1'b0;
		dma_end 	<= 1'b0;
		dma_end_r 	<= 1'b0;
	end
	else 
	begin
		dma_end_tp 	<= dma_finish_int;
		dma_end 	<= dma_end_tp;
		dma_end_r 	<= dma_end;
	end
end

//sd op finish used to clear FIFO ptr
// dirction 1:写sd  0:读sd card 
//(!dma_end_r && dma_end)产生搬数据结束的脉冲
assign sd_op_finish = data_direction ? in_transfer_complete : (!dma_end_r && dma_end);

//hw stop sd_clk 
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		one_bk_re_end_tp_1 	<= 1'b0;
		one_bk_re_end_tp_2 	<= 1'b0;
		one_bk_re_end_tp_3 	<= 1'b0;
	end
	else 
	begin
		one_bk_re_end_tp_1 <= one_bk_re_end;
		one_bk_re_end_tp_2 <= one_bk_re_end_tp_1;
		one_bk_re_end_tp_3 <= one_bk_re_end_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		hw_stop_clk <= 1'b0;
	else if (!data_direction && hw_stop_clk_en)
	begin
		if (!one_bk_re_end_tp_3 && one_bk_re_end_tp_2)
		//一个block 结束脉冲,停sd clk
			hw_stop_clk <= 1'b1;
		else if (dma_finish_int)
		//dma搬数据的时候可以停时钟,搬完了就不要在停时钟了
			hw_stop_clk <= 1'b0;
	end
	else 
		hw_stop_clk <= 1'b0;
end

//-----------------------------------------------
// Generate COMMAND FSM start signals
//-----------------------------------------------
assign cmd_state_send = (in_cmd_current_state == `CMD_STATE_SEND);

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		cmd_state_send_tp1 	<= 1'b0;
		cmd_state_send_tp2 	<= 1'b0;
		cmd_state_send_tp3 	<= 1'b0;
	end
	else 
	begin
		cmd_state_send_tp1 <= cmd_state_send;
		cmd_state_send_tp2 <= cmd_state_send_tp1;
		cmd_state_send_tp3 <= cmd_state_send_tp2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		cmd_ready_pre <= 1'b0;
	else if (!cmd_state_send_tp3 && cmd_state_send_tp2)
	//已经开始发送了 cmd_ready_pre清零,下次在配的时候再发
		cmd_ready_pre <= 1'b0;
	else if (command_enable && (ahb_wr_reg_en &&(haddr_r[70] == `ARGUMENT_REGISTER_ADDR)))
		cmd_ready_pre <= 1'b1;
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		cmd_fsm_ready <= 1'b0;
	else
		cmd_fsm_ready <= cmd_ready_pre;
end
//-------------------------------
// Generate  interrupt signal
//---------------------------------------
//mask signal  mask the interrupt signal

assign irq =((dma_finish_int && !dma_finish_interrupt_mask) ||
			(end_command_and_response && !end_command_and_response_interrupt_mask) ||
			(sd_fifo_empty_r && !sd_fifo_empty_interrupt_mask) ||
			(fifo_full_int && !fifo_full_interrupt_mask) ||
			(fifo_empty_int && !fifo_empty_interrupt_mask) ||
			(sd_fifo_full_r && ! sd_fifo_full_interrupt_mask)||
			(end_command && !command_complete_interrupt_mask) ||
			(transfer_complete && !transfer_complete_interrupt_mask) ||
			(1'b0 && !rx_fifo_write_error_interrupt_mask) ||
			(1'b0 && !tx_fifo_read_error_interrupt_mask) ||
			(receive_data_crc_error && read_data_crc_error_interrupt_mask) ||
			(send_data_crc_error && !write_data_crc_error_interrupt_mask) ||
			(response_timeout && !response_timeout_error_interrupt_mask) ||
			(read_to_error && !read_to_error_interrupt_mask) );
			
//------------------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		in_end_cmd_and_resp_tp_1 	<= 1'b0;
		in_end_cmd_and_resp_tp_2 	<= 1'b0;
		in_end_cmd_and_resp_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_end_cmd_and_resp_tp_1 <= in_end_command_and_response;
		in_end_cmd_and_resp_tp_2 <= in_end_cmd_and_resp_tp_1;
		in_end_cmd_and_resp_tp_3 <= in_end_cmd_and_resp_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		end_command_and_response <= 1'b0;
	else if (cmd_ready_pre)
		end_command_and_response <= 1'b0;
	else if (!in_end_cmd_and_resp_tp_3 && in_end_cmd_and_resp_tp_2)
		end_command_and_response <= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state tx fifo empty
//------------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin	
		sd_fifo_empty_tp1 <= 1'b0;
		sd_fifo_empty_r <= 1'b0;
	end
	else begin
		sd_fifo_empty_tp1 <= sd_fifo_empty;
		sd_fifo_empty_r <= sd_fifo_empty_tp1;
	end
end

//---------------------------------------------------
// Generate interrupt state tx fifo empty
//------------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin	
		sd_fifo_full_tp1 <= 1'b0;
		sd_fifo_full_r <= 1'b0;
	end
	else begin
		sd_fifo_full_tp1 <= sd_fifo_full;
		sd_fifo_full_r <= sd_fifo_full_tp1;
	end
end

//---------------------------------------------------
// Generate interrupt command sending fifo empty
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		in_end_cmd_tp_1 	<= 1'b0;
		in_end_cmd_tp_2 	<= 1'b0;
		in_end_cmd_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_end_cmd_tp_1 <= in_end_command;
		in_end_cmd_tp_2 <= in_end_cmd_tp_1;
		in_end_cmd_tp_3 <= in_end_cmd_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		end_command <= 1'b0;
	else if (cmd_ready_pre)
		end_command <= 1'b0;
	else if (!in_end_cmd_tp_3 && in_end_cmd_tp_2)
		end_command<= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state data transfer complete
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		in_transfer_end_tp_1 	<= 1'b0;
		in_transfer_end_tp_2 	<= 1'b0;
		in_transfer_end_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_transfer_end_tp_1 <= in_transfer_complete;
		in_transfer_end_tp_2 <= in_transfer_end_tp_1;
		in_transfer_end_tp_3 <= in_transfer_end_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		transfer_complete <= 1'b0;
	else if (cmd_ready_pre)
		transfer_complete <= 1'b0;
	else if (!in_transfer_end_tp_3 && in_transfer_end_tp_2)
		transfer_complete<= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state data read_data_crc_error_interrupt_mask timeout
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n) 
	begin
		in_rd_to_err_tp_1 	<= 1'b0;
		in_rd_to_err_tp_2 	<= 1'b0;
		in_rd_to_err_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_rd_to_err_tp_1 <= in_read_to_error;
		in_rd_to_err_tp_2 <= in_rd_to_err_tp_1;
		in_rd_to_err_tp_3 <= in_rd_to_err_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		read_to_error <= 1'b0;
	else if (cmd_ready_pre)
		read_to_error <= 1'b0;
	else if (!in_rd_to_err_tp_3 && in_rd_to_err_tp_2)
		read_to_error<= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state singal sending data crc error
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n) 
	begin
		in_send_data_crc_err_tp_1 	<= 1'b0;
		in_send_data_crc_err_tp_2 	<= 1'b0;
		in_send_data_crc_err_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_send_data_crc_err_tp_1 <= in_send_data_crc_error;
		in_send_data_crc_err_tp_2 <= in_send_data_crc_err_tp_1;
		in_send_data_crc_err_tp_3 <= in_send_data_crc_err_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		send_data_crc_error <= 1'b0;
	else if (cmd_ready_pre)
		send_data_crc_error <= 1'b0;
	else if (!in_send_data_crc_err_tp_3 && in_send_data_crc_err_tp_2)
		send_data_crc_error<= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state singal receive data crc error
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n) 
	begin
		in_receive_data_crc_err_tp_1 	<= 1'b0;
		in_receive_data_crc_err_tp_2 	<= 1'b0;
		in_receive_data_crc_err_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_receive_data_crc_err_tp_1 <= in_receive_data_crc_error;
		in_receive_data_crc_err_tp_2 <= in_receive_data_crc_err_tp_1;
		in_receive_data_crc_err_tp_3 <= in_receive_data_crc_err_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		receive_data_crc_error <= 1'b0;
	else if (cmd_ready_pre)
		receive_data_crc_error <= 1'b0;
	else if (!in_receive_data_crc_err_tp_3 && in_receive_data_crc_err_tp_2)
		receive_data_crc_error<= 1'b1;
end

//---------------------------------------------------
// Generate interrupt state singal command response timeout
//---------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n) 
	begin
		in_resp_timeout_tp_1 	<= 1'b0;
		in_resp_timeout_tp_2 	<= 1'b0;
		in_resp_timeout_tp_3 	<= 1'b0;
	end
	else 
	begin
		in_resp_timeout_tp_1 <= in_resp_timeout;
		in_resp_timeout_tp_2 <= in_resp_timeout_tp_1;
		in_resp_timeout_tp_3 <= in_resp_timeout_tp_2;
	end
end

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
		response_timeout <= 1'b0;
	else if (cmd_ready_pre)
		response_timeout <= 1'b0;
	else if (!in_resp_timeout_tp_3 && in_resp_timeout_tp_2)
		response_timeout<= 1'b1;
end

//---------------------------------------------------
// Config control register
//---------------------------------------------------
always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n) 
	begin
		sd_clk_enable		<= 1'b0;
		sd_clk_divider		<= 8'b0;			
		sd_soft_reset		<= 1'b1;			
		command_argument	<= 32'b0;			
		command_index		<= 6'b0;			
		command_enable		<= 1'b0;			
		data_present		<= 1'b0;		
		response_type		<= 2'b0;			
		block_size			<= 11'd200;
		block_number_ahb	<= 32'b0;			
		data_direction		<= 1'b0;		
		data_width			<= 1'b0;					
		read_to				<= 32'hffff_ffff;		
		dma_finish_interrupt_mask				<= 1'b0;	
		end_command_and_response_interrupt_mask	<= 1'b0;		
		fifo_full_interrupt_mask                <= 1'b0;
		command_complete_interrupt_mask		    <= 1'b0;
		transfer_complete_interrupt_mask	    <= 1'b0;
		read_to_error_interrupt_mask			<= 1'b0;
		rx_fifo_write_error_interrupt_mask      <= 1'b0;
		tx_fifo_read_error_interrupt_mask       <= 1'b0;
		read_data_crc_error_interrupt_mask      <= 1'b0;
		write_data_crc_error_interrupt_mask     <= 1'b0;
		response_timeout_error_interrupt_mask   <= 1'b0;
		fifo_empty_interrupt_mask               <= 1'b0;
		sd_fifo_full_interrupt_mask             <= 1'b0;
		sd_fifo_empty_interrupt_mask            <= 1'b0;
		hw_stop_clk_en                          <= 1'b0;
		high_speed_clk                          <= 1'b0;
		
	end
	else if (ahb_wr_reg_en)
	begin 
		case (haddr_r[7:0])
		
		`CLOCK_CONTROL_REGISTER_ADDR: begin
			sd_clk_enable <= hwdata[2];
			sd_clk_divider <= hwdata[15:8];
		end
		
		`SOFTWARE_RESET_REGISTER_ADDR: begin
			sd_soft_reset <= hwdata[0];
		end
		
		`CLK_EN_SPEED_UP_ADDR: begin
			hw_stop_clk_en <= hwdata[0];
			high_speed_clk <= hwdata[4];
		end
		
		`ARGUMENT_REGISTER_ADDR : begin
			command_argument <= hwdata;
		end
		
		`COMMAND_REGISTER_ADDR : begin
			command_index <= hwdata[10:5];
			command_enable<= hwdata[3];
			data_present  <= hwdata[2];
			response_type <= hwdata[1:0];
		end
			
		`BLOCK_SIZE_REGISTER_ADDR: begin
			block_size <= hwdata[10:0];
		end
		
		`BLOCK_COUNT_REGISTER_ADDR: begin
			block_number_ahb <= hwdata [31:0];
		end
		
		`TRANSFER_MODE_REGISTER_ADDR : begin
			data_direction <= hwdata[1];
			data_width <= hwdata[0];
		end
		
		`READ_TIMEOUT_CONTROL_REGISTER_ADDR: begin
			read_to <= hwdata[31:0];
		end
		
		`INTERRUPT_STATUS_MASK_REGISTER_ADDR: begin
			dma_finish_interrupt_mask				<= hwdata[13];
			end_command_and_response_interrupt_mask	<= hwdata[12];
			sd_fifo_full_interrupt_mask             <= hwdata[11];
			fifo_full_interrupt_mask                <= hwdata[10];
			fifo_empty_interrupt_mask               <= hwdata[9];
			sd_fifo_empty_interrupt_mask            <= hwdata[8;
			command_complete_interrupt_mask		    <= hwdata[7];
			transfer_complete_interrupt_mask	    <= hwdata[6];
		    read_to_error_interrupt_mask			<= hwdata[5];
		    rx_fifo_write_error_interrupt_mask      <= hwdata[4];
            tx_fifo_read_error_interrupt_mask       <= hwdata[3];
            read_data_crc_error_interrupt_mask      <= hwdata[2];
            write_data_crc_error_interrupt_mask     <= hwdata[1];
            response_timeout_error_interrupt_mask   <= hwdata[0];
        end
		endcase
	end
end

//response0-3 sd clk domain to ahb clk domain
//these data are generated in CMD_STATE_RECEIVE of cmd_current_state
//end_command_and_response can become the sync enable

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		response0_ahb <= 32'h0;
		response1_ahb <= 32'h0;
		response2_ahb <= 32'h0;
		response3_ahb <= 32'h0;
	end
	else if (!in_end_cmd_and_resp_tp_3 && in_end_cmd_and_resp_tp_2)
	begin
		response0_ahb <= response0;
		response1_ahb <= response1;
		response2_ahb <= response2;
		response3_ahb <= response3;
	end
end

//----------------------------------------------------------
// Read state register
//-----------------------------------------------------------
always @(posedge hclk or negedge hrst_n)
begin 
	if (!hrst_n)
		hrdata <= 32'b0;
	else if (ahb_rd_reg_en)
	begin
		case (haddr[7:0])
		`CLOCK_CONTROL_REGISTER_ADDR:
			hrdata <= {16'b0,sd_clk_divider,5'b0,sd_clk_enable,2'b0};
		`SOFTWARE_RESET_REGISTER_ADDR:
			hrdata <= {31'b0,sd_soft_reset};
		`CLK_EN_SPEED_UP_ADDR:
			hrdata <= {27'b0,high_speed_clk,3'b0,hw_stop_clk_en};
		`ARGUMENT_REGISTER_ADDR:
			hrdata <= command_argument;
		`COMMAND_REGISTER_ADDR:
			hrdata <= {21'b0,command_index,1'b0,command_enable,data_present,response_type};
		`BLOCK_SIZE_REGISTER_ADDR:
			hrdata <= {21'b0,block_size};
		`BLOCK_COUNT_REGISTER_ADDR:
			hrdata <= block_number_ahb;
		`TRANSFER_MODE_REGISTER_ADDR:
			hrdata <= {30'b0,data_direction,data_width};
		`READ_TIMEOUT_CONTROL_REGISTER_ADDR:
			hrdata <= read_to;
		`DMA_ADDR_ADDR :
			hrdata <= dma_addr;
		`DMA_CTRL_ADDR:
			hrdata <= {transfer_size,11'b0,dma_direc,3'b0,dma_en};
		`INT_GEN_REG_ADDR:
			hrdata <= {23'b0,dma_finish_int_gen,3'b0,fifo_empty_int_gen,3'b0,fifo_full_int_gen};
		`CLR_INT_REG_ADDR:
			hrdata <= {23'b0,clr_fifo_empty_int,3'b0,clr_fifo_full_int,3'b0,clr_dma_finish_int};
		`RESPONSE0_REGISTER_ADDR:
			hrdata <= response0_ahb;
		`RESPONSE1_REGISTER_ADDR:
			hrdata <= response1_ahb;
		`RESPONSE2_REGISTER_ADDR:
			hrdata <= response2_ahb;
		`RESPONSE3_REGISTER_ADDR:
			hrdata <= response3_ahb;
		`INTERRUPT_STATUS_REGISTER_ADDR:
		begin
			hrdata <= {
						18'b0,
						dma_finish_int,
						end_command_and_response,
						sd_fifo_empty_r,
						fifo_full_int,
						fifo_empty_int,
						sd_fifo_full_r,
						end_command,
						transfer_complete,
						read_to_error,
						1'b0,
						1'b0,
						receive_data_crc_error,
						send_data_crc_error,
						response_timeout};
		end
		default : hrdata <= 32'h0;
		endcase
	end
end

//-------------------------------------------------
always @(posedge in_sd_clk or neged  hrst_n) begin
	if (!hrst_n)
	begin
		block_num_tp <= 32'h0;
		block_number <= 32'g0;
	end
	else begin
		block_num_tp <= block_number_ahb;
		block_number <= block_num_tp;
	end
end

endmodule

学习总结

1、软硬件协同工作的设计思想;

通过配置控制寄存器(软件配置),来控制模块的工作运行(硬件工作)。同时硬件在运行过程中产生各种标志信号、状态信号可以写入状态寄存器供软件进行查询。

配置寄存器示例:

always @(posedge hclk or negedge hrst_n) begin
	if (!hrst_n)
	begin
		dma_direc <= 1'b0;
		transfer_size <= 16'b0;
		dma_addr <= 32'b0;
	end
	else if (ahb_wr_reg_en)
	begin
		case (haddr_r[7:0])
			`DMA_CTRL_ADDR : begin
				dma_direc <= hwdata[4];
				transfer_size <= hwdata[31:16];
			end
			`DMA_ADDR_ADDR:
				dma_addr <= hwdata[31:0];
		endcase
	end
end

2、单bit信号的跨时钟域处理、脉冲信号的同步:

信号在跨时钟域传输时会存在亚稳态的问题,单bit信号可以通过2级寄存器同步的方式大大降低亚问题出现概率(理论上不可完全消除)。

脉冲信号的同步:
1、信号通过2级寄存器同步后得到signal_r2再多打一拍signal_r3,再将signal_r3取反结果和signal_r2相与得到signal在新时钟域下的脉冲信号。

2、补充:脉冲同步器(更加通用可靠)
a.慢时钟域到快时钟域
(1) 将 src_clk 时钟域的输入脉冲转换为 src_clk 时钟域的电平信号 src_state;
(2) 对 src_data 电平信号进行打拍(一般可打 2 拍)同步到 dst_clk 时钟域;
(3) 对 dst_clk 时钟域的电平信号进行边沿检测,产生 dst_clk 时钟域的脉冲;
在这里插入图片描述
部分代码:

always @(posedge src_clk or negedge src_rst_n) 
begin     
	if(src_rst_n == 1'b0)        
		src_state   <= 1'b0 ;     
	else if (src_pulse)          
		src_state   <= ~src_state ; 
end   

always @(posedge dst_clk or negedge dst_rst_n) 
begin 
	if(dst_rst_n == 1'b0)         
		begin             
			state_dly1  <= 1'b0 ;             
			state_dly2  <= 1'b0 ;             
			dst_state   <= 1'b0 ;         
		end     
	else         
		begin             
			state_dly1  <= src_state ;             
			state_dly2  <= state_dly1;             
			dst_state   <= state_dly2;         
		end 
	end   

assign dst_pulse = dst_state ^ state_dly2 ; 

b.快时钟域到慢时钟域
将快时钟域脉冲信号同步至慢时钟域可能存在以下问题:

源时钟域中的第一个脉冲和第二个脉冲间隔过短,第一个脉冲未完成同步,第 二脉冲又将状态清空,导致最终脉冲同步丢失。
在这里插入图片描述
于是需要引入异步握手机制,保证每个脉冲都同步成功,同步成功 后再进行下一个脉冲同步。握手原理如下: sync_req: 源时钟域同步请求信号,高电平表示当前脉冲需要同步; sync_ack: 目的时钟域应答信号,高电平表示当前已收到同步请求;

完整同步过程分为以下 4 个步骤:
(1) 同步请求产生;当同步器处于空闲(即上一次已同步完成)时,源同步脉 冲到达时产生同步请求信号 sync_req;
(2) 同步请求信号 sync_req 同步到目的时钟域,目的时钟域产生脉冲信号并将 产生应答信号 sync_ack;
(3) 同步应答信号 sync_ack 同步到源时钟域,源时钟域检测到同步应答信号 sync_ack 后,清除同步请求信号;
(4) 目的时钟域检测到 sync_req 撤销后,清除 sync_ack 应答;源时钟域将到 sync_ack 清除后,认为一次同步完成,可以同步下一个脉冲。

module HANDSHAKE_PULSE_SYNC     ( 
        src_clk         , //source clock          
        src_rst_n       , //source clock reset (0: reset)        
        src_pulse       , //source clock pulse in         
        src_sync_fail   , //source clock sync state: 1 clock pulse if sync fail.         
        dst_clk         , //destination clock          
        dst_rst_n       , //destination clock reset (0:reset)         
        dst_pulse       //destination pulse out     );   
//PARA   DECLARATION 

//INPUT  DECLARATION 
input               src_clk     ; //source clock  
input               src_rst_n   ; //source clock reset (0: reset) 
input               src_pulse   ; //source clock pulse in 
 
input               dst_clk     ; //destination clock  
input               dst_rst_n   ; //destination clock reset (0:reset) 
 
//OUTPUT DECLARATION 
output              src_sync_fail   ; //source clock sync state: 1 clock pulse if sync fail. 
output              dst_pulse       ; //destination pulse out 
 
//INTER  DECLARATION
wire                dst_pulse       ; wire                src_sync_idle   ; reg                 src_sync_fail   ; reg                 src_sync_req    ; reg                 src_sync_ack    ; reg                 ack_state_dly1  ; reg                 ack_state_dly2  ; reg                 req_state_dly1  ; reg                 req_state_dly2  ; reg                 dst_req_state   ; reg                 dst_sync_ack    ; 
 
//--========================MODULE SOURCE CODE==========================-- 
 
 
//--=========================================-- 
// DST Clock : 
// 1. generate src_sync_fail;  
// 2. generate sync req  
// 3. sync dst_sync_ack //--=========================================-- 
assign src_sync_idle = ~(src_sync_req | src_sync_ack ); 
 
//report an error if src_pulse when sync busy ; 
always @(posedge src_clk or negedge src_rst_n) 
begin     
	if(src_rst_n == 1'b0)         
		src_sync_fail   <= 1'b0 ;     
	else if (src_pulse & (~src_sync_idle))          
		src_sync_fail   <= 1'b1 ;     
	else          
		src_sync_fail   <= 1'b0 ; 
end 
 
//set sync req if src_pulse when sync idle ; 
always @(posedge src_clk or negedge src_rst_n) begin     if(src_rst_n == 1'b0)         src_sync_req    <= 1'b0 ;     else if (src_pulse & src_sync_idle)          src_sync_req    <= 1'b1 ;     else if (src_sync_ack)         src_sync_req    <= 1'b0 ; end 
 
always @(posedge src_clk or negedge src_rst_n) begin     if(src_rst_n == 1'b0)         begin             ack_state_dly1  <= 1'b0 ;             ack_state_dly2  <= 1'b0 ;             src_sync_ack    <= 1'b0 ;                  end         else         begin             ack_state_dly1  <= dst_sync_ack     ;             ack_state_dly2  <= ack_state_dly1   ;             src_sync_ack    <= ack_state_dly2   ;                  end         end 
 
//--=========================================-- 
// DST Clock : 
// 1. sync src sync req  
// 2. generate dst pulse 
// 3. generate sync ack 
//--=========================================-- 
always @(posedge dst_clk or negedge dst_rst_n) 
begin     
	if(dst_rst_n == 1'b0) begin             
		req_state_dly1  <= 1'b0 ;             
		req_state_dly2  <= 1'b0 ;             
		dst_req_state   <= 1'b0 ;         
	end     
	else   begin             
		req_state_dly1  <= src_sync_req     ;             
		req_state_dly2  <= req_state_dly1   ;             
		dst_req_state   <= req_state_dly2   ;         
	end 
end 
 
//Rising Edge of dst_state generate a dst_pulse; 
assign dst_pulse = (~dst_req_state) & req_state_dly2 ;  
 
//set sync ack when src_req = 1 , clear it when src_req = 0 ; 
always @(posedge dst_clk or negedge dst_rst_n) 
begin     
	if(dst_rst_n == 1'b0)         
		dst_sync_ack    <= 1'b0;     
	else if (req_state_dly2)           
		dst_sync_ack    <= 1'b1;     
	else           
		dst_sync_ack    <= 1'b0; 
end 
 
endmodule

3、屏蔽信号的使用

通过添加屏蔽信号,可以配置是否要使用某些信号。

例如对于此设计中的中断请求信号,其中对于各种中断状态可以通过配置相应的屏蔽信号选择只有发生其中的一部分中断会产生中断请求信号,而被屏蔽的中断状态不会产生中断请求:

assign irq =((dma_finish_int && !dma_finish_interrupt_mask) ||
			(end_command_and_response && !end_command_and_response_interrupt_mask) ||
			(sd_fifo_empty_r && !sd_fifo_empty_interrupt_mask) ||
			(fifo_full_int && !fifo_full_interrupt_mask) ||
			(fifo_empty_int && !fifo_empty_interrupt_mask) ||
			(sd_fifo_full_r && ! sd_fifo_full_interrupt_mask)||
			(end_command && !command_complete_interrupt_mask) ||
			(transfer_complete && !transfer_complete_interrupt_mask) ||
			(1'b0 && !rx_fifo_write_error_interrupt_mask) ||
			(1'b0 && !tx_fifo_read_error_interrupt_mask) ||
			(receive_data_crc_error && read_data_crc_error_interrupt_mask) ||
			(send_data_crc_error && !write_data_crc_error_interrupt_mask) ||
			(response_timeout && !response_timeout_error_interrupt_mask) ||
			(read_to_error && !read_to_error_interrupt_mask) );
  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个简单的Verilog代码,实现了一个DMA控制器,其中包含一个DMA通道,支持1 x AXI master接口和1 x AHB slave接口异步: ```verilog module dma_controller( input logic clk, input logic rst, input logic [31:0] axi_m_addr, input logic [31:0] axi_m_data, input logic [31:0] axi_m_wstrb, input logic axi_m_valid, output logic axi_m_ready, output logic [31:0] ahb_s_addr, output logic [31:0] ahb_s_data, output logic ahb_s_write, output logic ahb_s_sel, input logic ahb_s_ack, input logic [31:0] dma_src_addr, input logic [31:0] dma_dst_addr, input logic [31:0] dma_len, input logic dma_start, input logic dma_enable, output logic dma_done ); // DMA状态机的状态定义 typedef enum logic [1:0] { IDLE, READ_AXI, WRITE_AHB, DONE } dma_state_t; dma_state_t dma_state; logic [31:0] dma_counter; always_ff @(posedge clk) begin if (rst) begin dma_state <= IDLE; dma_counter <= 0; ahb_s_addr <= 0; ahb_s_data <= 0; ahb_s_write <= 0; ahb_s_sel <= 0; dma_done <= 0; end else begin case (dma_state) IDLE: begin if (dma_start && dma_enable) begin dma_state <= READ_AXI; end end READ_AXI: begin if (axi_m_valid && axi_m_ready) begin ahb_s_addr <= dma_dst_addr; ahb_s_data <= axi_m_data; ahb_s_write <= 1; ahb_s_sel <= 1; dma_counter <= dma_len - 1; dma_state <= WRITE_AHB; end end WRITE_AHB: begin if (ahb_s_ack) begin ahb_s_addr <= ahb_s_addr + 4; ahb_s_data <= 0; ahb_s_write <= 0; ahb_s_sel <= 0; dma_counter <= dma_counter - 1; if (dma_counter == 0) begin dma_state <= DONE; end else begin dma_state <= READ_AXI; end end end DONE: begin dma_done <= 1; dma_state <= IDLE; end endcase end end assign axi_m_ready = (dma_state == READ_AXI); endmodule ``` 在这个代码中,我们定义了一个包含状态机的DMA控制器,它通过AXI master接口读取数据并将其写入AHB slave接口。当DMA控制器收到开始传输信号时,它将进入状态机并开始执行传输。 在状态机的“IDLE”状态下,DMA控制器等待传输开始信号。当收到该信号时,它将进入“READ_AXI”状态,开始从AXI master接口读取数据。 在“READ_AXI”状态下,DMA控制器将等待AXI master接口的数据有效信号。一旦数据有效,它将使用AHB slave接口将数据写入目标地址,并将计数器设置为传输长度减1。然后,它将进入“WRITE_AHB”状态,等待AHB slave接口的确认信号。 在“WRITE_AHB”状态下,DMA控制器将等待AHB slave接口的确认信号。一旦确认,它将递增目标地址和计数器,并检查是否已传输完所有数据。如果是,则进入“DONE”状态,否则返回“READ_AXI”状态并继续传输。 在“DONE”状态下,DMA控制器将设置传输完成信号并返回“IDLE”状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值