MDIO接口FPGA代码

MDIO 接口Verilog 代码

支持 clause 22 标准
其中start 标志至少需要保持两个mdc时钟,可以参考后面的仿真文件

module	MDIO
(
	input	rst,
	input	clk,
	
	output reg mdc,
	inout	mdio,
	input                start      ,   //开始传输标志  高电平有效,结束传输后拉低
   input  [1:0]         opcode     ,
   input  [4:0]         phy_addr   ,   //phy address
   input  [4:0]         reg_addr   ,   //phy register address
   input  [15:0]        write_data ,   //write smi data
    
   output reg [15:0]    phy_reg    ,   //read smi data
   output reg           transfer_end   //write or read finished
	
);


reg mdio_oe,mdio_out;
wire mdio_in;

assign mdio = mdio_oe ? mdio_out : 1'bz ;// MDIO数据输出或高阻, 0-READ,1-WRITE
assign mdio_in = mdio;


//产生MDC 时钟
parameter NUM=49;  //50M/100=500k
reg [5:0] cnt;
always @(posedge clk or negedge rst)
begin
	if(!rst)
	begin
		cnt<=0;
		mdc<=0;
	end
	else if (cnt==NUM)
	begin
		cnt<=0;
		mdc<=mdc+1;
	end
	else
	begin
		cnt<=cnt+1;
	end
end


//数据流,上升沿有效
parameter preamble=8'b00000001;
parameter st=		 8'b00000010;
parameter op=      8'b00000100;
parameter phyad=   8'b00001000;
parameter regad=   8'b00010000;
parameter ta=      8'b00100000;
parameter data=    8'b01000000;
parameter idle=    8'b10000000;


//检测上升沿,产生开始传输脉冲
reg start_next;
wire start_edge;
always @(posedge mdc or negedge rst)
begin
	if(!rst)
	begin
		start_next<=0;
	end
	else 
		start_next<=start;
end

assign start_edge=!start_next & start;


//状态转移
reg [7:0] state,state_next;

always @(posedge mdc or negedge rst )
begin
	if(!rst)
	begin
		state<=idle;
	end 
	else if(start_edge)
		begin
			state<=preamble;
			
		end
		
	else
		state<=state_next;
end


//接口数据缓存
reg [1:0] st_code;          //mdio start code
reg [1:0] ta_code ;          //mdio write code
reg [1:0] op_code;
reg [4:0] regaddr;
reg [4:0] phyaddr; 
reg [15:0] writedata;



reg [7:0] counter;
always @(posedge mdc or negedge rst)
begin
	if(!rst)
	begin 
		counter<=0;
	end
	else if(counter==64)
	begin
		counter<=0;
		transfer_end<=1;
	end
	else if(state!=idle)
	begin
		transfer_end<=0;
		counter<=counter+1;
	end
		
end


always @(negedge mdc)
begin
	state_next<=state;
	case(state)
	preamble: 
		begin
			st_code<= 2'b01 ; 
			ta_code<= 2'b10 ;
			op_code<=opcode;//缓存
			regaddr<=reg_addr;
			phyaddr<=phy_addr;
			writedata<=write_data;
			mdio_oe<=1;
			mdio_out<=1;
			if(counter==31)
				begin
					state_next<=st;
				end
		end
	st:
		begin
			mdio_oe<=1;
			mdio_out<=st_code[1];
			st_code<=st_code<<1;
			if(counter==33)
				begin
					state_next<=op;
				end
		end
	op:
		begin
			mdio_oe<=1;
			mdio_out<=op_code[1];
			op_code<=op_code<<1;
			if(counter==35)
				begin
					state_next<=phyad;
				end
		end
	phyad:
		begin
			mdio_oe<=1;
			mdio_out<=phyaddr[4];
			phyaddr<=phyaddr<<1;
			if(counter==40)
				begin
					state_next<=regad;
				end
		end
	regad:
		begin
			mdio_oe<=1;
			mdio_out<=regaddr[4];
			regaddr<=regaddr<<1;
			if(counter==45)
				begin
					state_next<=ta;
				end
		end
	ta:
		begin
			if(opcode==2'b10)
			begin
				mdio_oe<=0;
				if(counter==47)
				begin
					state_next<=data;
				end
			end
			if(opcode==2'b01)
			begin
				mdio_oe<=1;
				mdio_out<=ta_code[1];
				ta_code<=ta_code<<1;
				if(counter==47)
				begin
					state_next<=data;
				end
			end
		end
	data:
		begin
			if(opcode==2'b10)//读取
			begin
				mdio_oe<=0;
				//读取放到外面;
				if(counter==63)
				begin
					state_next<=idle;
				end
			end
			if(opcode==2'b01)//写入
			begin
				mdio_oe<=1;
				mdio_out<=writedata[15];
				writedata<=writedata<<1;
				if(counter==63)
				begin
					state_next<=idle;
				end
			end
		end
	idle:
		begin
			mdio_oe<=0;
				if(counter==64)
				begin
					state_next<=idle;
				end
		end
	default:
		begin
			state_next<=idle;
		end
	
endcase
end	
//读取数据
always @(posedge mdc or negedge rst )
begin
	if(!rst)
	begin
		phy_reg<=0;
	end
	else if(state_next==data )
	begin
		phy_reg<={phy_reg[14:0],mdio_in};
	end
	else 
		phy_reg<=phy_reg;
end

endmodule	

仿真文件

`timescale   1 ns / 1 ps

module tb;

reg  clk;
reg  rst;

wire mdc;
wire 	mdio;
reg start      ;   //开始传输标志  高电平有效,结束传输后拉低
reg   [1:0]         opcode     ;
reg   [4:0]         phy_addr   ;   //phy address
reg   [4:0]         reg_addr   ;   //phy register address
reg   [15:0]        write_data ;   //write smi data
    
wire [15:0]    phy_reg    ;   //read smi data
wire          transfer_end ;  //write or read finished 





initial
begin
		rst=0;
		start=0;
		phy_addr=5'b10101;
		reg_addr=5'b01010;
		opcode=2'b01;        //10 读取   01  写入
		write_data=16'h5a5a;
//		mdio_data=16'ha5a5;
	#10 rst=1;
	    clk=1;
	#80 start=1; 
	#150000 start=0;
	#4000 start=1; 
	#150000 start=0;	 
	#4000 start=1; 
	#150000 start=0;	 
		
end


always #10 clk<=~clk;



//读取逻辑验证
//reg [15:0] mdio_data;
//reg mdio_out;
//reg mdio_en;
//
//assign mdio=mdio_en ? mdio_out : 1'bz;
//reg [7:0] counter;
//always @(posedge mdc or negedge rst)
//begin
//	if(!rst)
//	begin
//		counter<=0;
//	end
//	else if(start)
//		if(counter==64)
//			counter<=0;
//		else 
//			counter <=counter+1;
//	else 
//		counter<=0;
//	
//end


//always @(negedge mdc)
//begin
//	case(counter)
//			48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64:
//				begin
//					mdio_en<=1;
//					mdio_out<=mdio_data[15];
//					mdio_data<={mdio_data[14:0],1'b0};
//				end
//	endcase
//end






MDIO  MDIO_INST
(
	.rst(rst),
	.clk(clk),
	
	.mdc(mdc),
	.mdio(mdio),
	.start (start)     ,   //开始传输标志  高电平有效,结束传输后拉低
   .opcode  (opcode)   ,
   .phy_addr (phy_addr)  ,   //phy address
   .reg_addr (reg_addr)  ,   //phy register address
   .write_data (write_data),   //write smi data
    
   .phy_reg  (phy_reg)  ,   //read smi data
   .transfer_end (transfer_end)  //write or read finished
	
);

endmodule 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值