板间通讯avalon总线转16bit并行总线用于通用寄存器读写

发布于:2024-12-18 ⋅ 阅读:(61) ⋅ 点赞:(0)

1,本模块主要用于实现master端avalon总线转16bit并行总线,slave端恢复成avalon总线,实现板间通信。
板间总线接口如下:

    output              emif_clk     ,
    output reg          emif_wr_rd    ,      //0-rd      1-wr
    output reg          emif_addr_data,      //0-data    1-addr
    output reg [7:0]    emif_data_tx ,
    input      [7:0]    emif_data_rx 

数据位宽可以根据需要扩展32bit、64bit
如果硬件支持的话也可以数据线用inout,省掉8跟线

2,master端avalon_to_16bit_no_addr.v

module avalon_to_16bit_no_addr (
    input           clk             ,
    input           rst             ,

    input       [7:0]   M_AVALON_address           ,
    input               M_AVALON_read              ,
    output reg  [31:0]  M_AVALON_readdata          ,
    output reg          M_AVALON_readdatavalid     ,
    // output reg          M_AVALON_waitrequest       ,
    input               M_AVALON_write             ,
    input       [31:0]  M_AVALON_writedata         ,

    output              emif_clk     ,
    output reg          emif_wr_rd    ,      //0-rd      1-wr
    output reg          emif_addr_data,      //0-data    1-addr
    output reg [7:0]    emif_data_tx ,
    input      [7:0]    emif_data_rx 
);

    reg         M_AVALON_write_delay  ;
    reg         M_AVALON_read_delay   ;
    reg [15:0]  M_AVALON_writedata_r  ;   //缓存数据

    reg [7:0]   emif_data_rx_r0;

    reg [8:0]   cur_state;
    reg [8:0]   next_state;

    reg [2:0]   delay_cnt = 3'b0;

	localparam IDLE 			=  9'b0_0000_0001;//001
	localparam WR_REG_WR_ADDR	=  9'b0_0000_0010;//002
	localparam WR_REG_WR_DATA1	=  9'b0_0000_0100;//004
	localparam WR_REG_WR_DATA2 	=  9'b0_0000_1000;//008
    localparam RD_REG_WR_ADDR 	=  9'b0_0001_0000;//010
    localparam RD_REG_RD_DELAY1 =  9'b0_0010_0000;//020
    // localparam RD_REG_RD_DELAY2 =  9'b0_0100_0000;//040
	localparam RD_REG_RD_DATA1	=  9'b0_1000_0000;//080
	localparam RD_REG_RD_DATA2	=  9'b1_0000_0000;//100



    assign  emif_clk = clk;

    always@(posedge clk) begin
        M_AVALON_write_delay	    <=  M_AVALON_write		;
        M_AVALON_read_delay	    <=  M_AVALON_read		;
    end

//上升沿跳变下降沿接收
    always @ (negedge clk )begin
        emif_data_rx_r0   <= emif_data_rx;
	end

	always @ (posedge clk or posedge rst)begin
		if (rst) 
			cur_state  <= IDLE;
		else 
			cur_state <= next_state;
	end

    always@(*)begin
        case(cur_state)									
            IDLE:begin				
                if(M_AVALON_write_delay == 1'b0 && M_AVALON_write == 1'b1)            //写寄存器
                    next_state = WR_REG_WR_ADDR;		
                else if(M_AVALON_read_delay == 1'b0 && M_AVALON_read == 1'b1)       //读寄存器
                    next_state = RD_REG_WR_ADDR;	
                else 
                    next_state = IDLE;		
            end					

/************************写寄存器***************************/
            WR_REG_WR_ADDR:begin				
                    next_state = WR_REG_WR_DATA1;		
            end

            WR_REG_WR_DATA1:begin				
                    next_state = WR_REG_WR_DATA2;		
            end

            WR_REG_WR_DATA2:begin				
                    next_state = IDLE;		
            end
/************************读寄存器***************************/
            RD_REG_WR_ADDR:begin				
                    next_state = RD_REG_RD_DELAY1;		
            end

            RD_REG_RD_DELAY1:begin		
                if(delay_cnt == 3'd4)            //读等待   //回读的相位差除了对端数据处理相位,还有隔离芯片引入的相位差,因此这里是个测量值。随隔离芯片性能调整
                    next_state = RD_REG_RD_DATA1;			
                else 
                    next_state = RD_REG_RD_DELAY1;		
            end

            RD_REG_RD_DATA1:begin				
                    next_state = RD_REG_RD_DATA2;		
            end

            RD_REG_RD_DATA2:begin				
                    next_state = IDLE;		
            end

/***************************************************/
            default:begin					
                next_state = IDLE;	
            end
        endcase
    end

    always@(posedge clk) begin
        if(cur_state == RD_REG_RD_DELAY1)
            delay_cnt <= delay_cnt + 3'b1;
        else
            delay_cnt <= 3'd0   ;
    end


    always@(posedge clk or posedge rst)begin
        if(rst) begin
            emif_wr_rd       <= 1'b0             ;   //读状态
            emif_addr_data   <= 1'b0             ;   //数据状态 
            emif_data_tx     <= 8'b0             ;
            M_AVALON_writedata_r       <= 16'b0          ;
        end
        else begin
            M_AVALON_writedata_r        <= 16'b0    ;
            M_AVALON_readdatavalid      <= 1'b0     ;

            case(cur_state)									
                IDLE:begin				
                    emif_wr_rd       <= 1'b0             ;   //读状态
                    emif_addr_data   <= 1'b0             ;   //数据状态 
                    emif_data_tx     <= 8'b0             ;
                    M_AVALON_writedata_r       <= 16'b0            ;
                    M_AVALON_readdata           <= 32'h0            ;
                end					

    /************************写寄存器***************************/
                WR_REG_WR_ADDR:begin				
                    emif_wr_rd       <= 1'b1             ;   //写
                    emif_addr_data   <= 1'b1             ;   //地址
                    emif_data_tx     <= M_AVALON_address ;   //发送地址
                    M_AVALON_writedata_r       <= M_AVALON_writedata[15:0];   //缓存数据
                end

                WR_REG_WR_DATA1:begin				
                    emif_wr_rd              <= 1'b1                         ;   //写
                    emif_addr_data          <= 1'b0                         ;   //数据
                    emif_data_tx            <= M_AVALON_writedata_r[7:0]    ;   //发送第一个8bit
                    M_AVALON_writedata_r    <= M_AVALON_writedata_r         ;   
                end

                WR_REG_WR_DATA2:begin				
                    emif_wr_rd              <= 1'b1                ;   //写
                    emif_addr_data          <= 1'b0                ;   //数据
                    emif_data_tx            <= M_AVALON_writedata_r[15:8];   //发送第二个8bit
                    M_AVALON_writedata_r    <= 16'b0             ;  
                end
    /************************读寄存器***************************/
                RD_REG_WR_ADDR:begin				
                    emif_wr_rd       <= 1'b1             ;   //写
                    emif_addr_data   <= 1'b1             ;   //地址
                    emif_data_tx     <= M_AVALON_address ;   //发送地址

                end

                RD_REG_RD_DELAY1:begin		                            //等一拍		
                    emif_wr_rd                  <= 1'b0             ;   //读
                    emif_addr_data              <= 1'b0             ;   //数据
                    emif_data_tx                <= 8'b0             ;   //发送数据
                    M_AVALON_readdata           <= 32'h0            ;   //先读低8bit
                end

                RD_REG_RD_DATA1:begin				
                    emif_wr_rd                  <= 1'b0             ;   //读
                    emif_addr_data              <= 1'b0             ;   //数据
                    emif_data_tx                <= 8'b0             ;   //发送数据
                    M_AVALON_readdata           <= {8'b0, emif_data_rx_r0}     ;   //先读低8bit
                end

                RD_REG_RD_DATA2:begin				
                    emif_wr_rd              <= 1'b0             ;   //读
                    emif_addr_data          <= 1'b0             ;   //数据
                    emif_data_tx            <= 8'b0             ;   //发送数据
                    M_AVALON_readdata       <= {emif_data_rx_r0, M_AVALON_readdata[7:0]}     ;   //再读高8bit
                    M_AVALON_readdatavalid  <= 1'b1             ;
                end

    /***************************************************/
                default:begin					
                    emif_wr_rd              <= 1'b0             ;   //读状态
                    emif_addr_data          <= 1'b0             ;   //数据状态 
                    emif_data_tx            <= 8'b0             ;
                    M_AVALON_writedata_r    <= 16'b0          ;
                end
            endcase
        end
    end

endmodule

3,slave端恢复avalon总线并读写寄存器

module reg_control (

    input               rst        ,

    output              emif_clk_w   ,   //emif_clk
    input               emif_clk     ,
    input               emif_wr_rd    ,      //0-rd      1-wr
    input               emif_addr_data,      //0-data    1-addr
    input       [7:0]   emif_data_tx ,
    output reg  [7:0]   emif_data_rx ,

    //软件控制的GPIO
    output reg [15:0]   pod_gpio_reg60 = 16'd0  ,
    output reg [15:0]   pod_gpio_reg61 = 16'd3  ,
    input      [15:0]   pid_gpio_reg62          ,
    output reg [15:0]   pod_gpio_reg63 = 16'd0  


);
    parameter FPGA_VERSION		= 16'd118 ;

    wire    emif_clk_IBUFG;

    //通信总线进来以后首先打两拍
    reg         emif_wr_rd_r0, emif_wr_rd_r1;      //0-rd      1-wr
    reg         emif_addr_data_r0, emif_addr_data_r1;      //0-data    1-addr
    reg [7:0]   emif_data_tx_r0, emif_data_tx_r1;

    reg [7:0]   cur_state;
    reg [7:0]   next_state;

	localparam IDLE 			    =  8'b0000_0001;//001
	localparam STATE_2ST_BYTE	    =  8'b0000_0010;//002
	localparam STATE_3ST_BYTE_WR	=  8'b0000_0100;//004
	localparam STATE_3ST_BYTE_RD 	=  8'b0000_1000;//008
	// localparam RD_REG_RD_DATA1	=  8'b0001_0000;//010
	// localparam RD_REG_RD_DATA2	=  8'b0010_0000;//020

    reg [7:0]       reg_addr;
    reg [15:0]      wr_reg_value;
    reg             wr_reg_flag;
    reg             rd_reg_flag;        //一个脉冲,用于读清操作
    wire [15:0]      rd_reg_value;
    reg  [15:0]      rd_reg_value_r;    //记录rd_reg_value的值,防止打高8bit的时候值变了

    IBUFG CLK_U0(
        .I  (emif_clk),
        .O  (emif_clk_IBUFG)
    );

    BUFG CLK_U1(
        .I  (emif_clk_IBUFG),
        .O  (emif_clk_w)
    );


/**************************总线转换****************************/
//上升沿跳变下降沿接收
	always @ (negedge emif_clk_w )begin
        emif_wr_rd_r0   <= emif_wr_rd;
        emif_wr_rd_r1   <= emif_wr_rd_r0;

        emif_addr_data_r0   <= emif_addr_data;
        emif_addr_data_r1   <= emif_addr_data_r0;

        emif_data_tx_r0   <= emif_data_tx;
        emif_data_tx_r1   <= emif_data_tx_r0;
	end

	always @ (posedge emif_clk_w or posedge rst)begin
		if (rst) 
			cur_state  <= IDLE;
		else 
			cur_state <= next_state;
	end

    always@(*)begin
        case(cur_state)									
            IDLE:begin				
                if(emif_wr_rd_r0 == 1'b1 && emif_addr_data_r0 == 1'b1)            //写地址,不区分是写操作的写地址还是读操作的写地址
                    next_state = STATE_2ST_BYTE;		
                else 
                    next_state = IDLE;		
            end		

            STATE_2ST_BYTE:begin		
                if(emif_wr_rd_r0 == 1'b1 && emif_addr_data_r0 == 1'b0)            //写数据
                    next_state = STATE_3ST_BYTE_WR;		
                else if(emif_wr_rd_r0 == 1'b0 && emif_addr_data_r0 == 1'b0)       //读数据
                    next_state = STATE_3ST_BYTE_RD;		
                else		                                                //其它位为非法状态
                    next_state = IDLE;		
            end			

            //写寄存器
            STATE_3ST_BYTE_WR:begin				
                    next_state = IDLE;		
            end

            //读寄存器
            STATE_3ST_BYTE_RD:begin				
                    next_state = IDLE;		
            end

            default:begin					
                next_state = IDLE;	
            end
        endcase
    end


    always@(posedge emif_clk_w or posedge rst)begin
        if(rst) begin
            reg_addr        <= 8'b0     ;
            wr_reg_value    <= 16'b0    ;
            wr_reg_flag     <= 1'b0     ;
            rd_reg_flag     <= 1'b0     ;
            emif_data_rx    <= 8'b0     ;
        end
        else begin
            rd_reg_flag     <= 1'b0     ;
            case(cur_state)									
                IDLE:begin				
                    reg_addr        <= emif_data_tx_r0    ;        //发过来的第一个字节是地址
                    wr_reg_value    <= 16'b0    ;
                    wr_reg_flag     <= 1'b0     ;
                    emif_data_rx    <= 8'b0   ;
                end		

                STATE_2ST_BYTE:begin				//不判断是读还是写操作
                    wr_reg_value    <= {8'b0, emif_data_tx_r0}     ;        //缓存发过来的第二byte,发过来的第二个字节是低8bit数据
                    emif_data_rx    <=  rd_reg_value[7:0]       ;       //发送读数据的低8bit
                    rd_reg_value_r  <=  rd_reg_value            ;       //记录rd_reg_value的值,防止打高8bit的时候值变了
                end			

                //写寄存器
                STATE_3ST_BYTE_WR:begin				
                    wr_reg_value    <= {emif_data_tx_r0, wr_reg_value[7:0]}    ;        //发过来的第二个字节是低8bit数据
                    wr_reg_flag     <= 1'b1     ;
                end
                //读寄存器
                STATE_3ST_BYTE_RD:begin				
                    emif_data_rx    <=  rd_reg_value_r[15:8]   ;
                    rd_reg_flag     <=  1'b1     ;
                end

                default:begin					
                    emif_data_rx    <=  8'b0   ;
                end
            endcase
        end
    end


/************************写寄存器***************************/
//读写寄存器需要保持一致
    always@(posedge emif_clk_w )begin
        if(wr_reg_flag) begin
            case(reg_addr)									
                8'h60 : pod_gpio_reg60      <= wr_reg_value     ;
                8'h61 : pod_gpio_reg61      <= wr_reg_value     ;
                8'h63 : pod_gpio_reg63      <= wr_reg_value     ;

                default:begin					
                end
            endcase
        end
    end

/************************读寄存器***************************/
    assign  rd_reg_value =  (reg_addr == 8'h01) ? FPGA_VERSION :                    //r  FPGA版本号
                            (reg_addr == 8'h60) ? pod_gpio_reg60    :
                            (reg_addr == 8'h61) ? pod_gpio_reg61    :
                            (reg_addr == 8'h62) ? pid_gpio_reg62    :
                            (reg_addr == 8'h63) ? pod_gpio_reg63    :
                            16'b0;



endmodule

4,master端0x74寄存器写0x1234波形
在这里插入图片描述
5,master端0x74寄存器读到0x1234波形
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到