|
这边简单举个例子, 我们在规划 FPGA 时, 有时因为 pin 脚数不够使用, 或希望保留多些 pin 脚留作他用等因素, 会把原本需要比较多 port 的沟通接口, 化简为类似 I2C 的传输方式.. 又传输的资料没有需要像 I2C 一样多或复杂, 这时可以依我们的需求来规划这边的架构, 以下传输端的架构因而产生
(这边是先规划 block diagram => timing diagram => coding => simulation 看是不是符合所想要的时序)
module ext_pll_ctrl
(
// system input
osc_50,
rstn,
// device 1
clk1_set_wr,
clk1_set_rd,
// device 2
clk2_set_wr,
clk2_set_rd,
// device 3
clk3_set_wr,
clk3_set_rd,
// setting trigger
conf_wr, // 1T 50MHz
conf_rd, // 1T 50MHz
// status
conf_ready,
rd_data_ready, // 1T 50MHz
// 2-wire interface
max_sclk,
max_sdat
);
//=======================================================
// Port declarations
//=======================================================
// system input
input osc_50;
input rstn;
// device 1
input [3:0] clk1_set_wr;
output [3:0] clk1_set_rd;
// device 2
input [3:0] clk2_set_wr;
output [3:0] clk2_set_rd;
// device 3
input [3:0] clk3_set_wr;
output [3:0] clk3_set_rd;
// setting trigger
input conf_wr;
input conf_rd;
// status
output conf_ready;
output rd_data_ready;
// 2-wire interface
output max_sclk;
inout max_sdat;
//=======================================================
// Parameter declarations
//=======================================================
//=======================================================
// Signal declarations
//=======================================================
reg conf_ready;
reg rd_data_ready;
reg conf_wr_p2s;
wire [13:0] conf_data;
reg [4:0] conf_counter;
reg conf_end;
reg p2s;
reg s2p_act_pre;
reg [1:0] s2p_act;
reg [11:0] s2p;
reg sclk;
reg sclk_mask;
//=======================================================
// Structural coding
//=======================================================
assign clk1_set_rd = s2p[3:0];
assign clk2_set_rd = s2p[7:4];
assign clk3_set_rd = s2p[11:8];
assign max_sclk = sclk || (sclk_mask ? ~osc_50 : 1'b0);
assign max_sdat = (s2p_act_pre || s2p_act[1]) ? 1'bz : p2s;
assign conf_data = conf_wr_p2s ? {2'b10, clk3_set_wr, clk2_set_wr, clk1_set_wr} : 14'hfff;
//--- config status ---//
always @ (posedge osc_50 or negedge rstn)
if(!rstn)
conf_ready <= 1'b1;
else if (conf_wr || conf_rd)
begin
conf_ready <= 1'b0;
conf_wr_p2s <= conf_wr;
end
else if (conf_end)
conf_ready <= 1'b1;
//--- config counter ---//
always @ (posedge osc_50 or negedge rstn)
if(!rstn)
conf_counter <= 5'b0;
else if (conf_ready)
conf_counter <= 5'b0;
else
conf_counter <= conf_counter + 1;
//--- p2s convert ---//
always @ (posedge osc_50 or negedge rstn)
if (!rstn)
begin
sclk <= 1'b1; p2s <= 1'b1; sclk_mask <= 1'b0; conf_end <= 1'b0; s2p_act_pre <= 1'b0;
end
else
case (conf_counter)
5'd1 : p2s <= 1'b0;
5'd2 : sclk <= 1'b0;
5'd3 : begin p2s <= conf_data[13]; sclk_mask <= 1'b1; end
5'd4 : begin p2s <= conf_data[12]; s2p_act_pre <= !conf_wr_p2s; end
5'd5 : p2s <= conf_data[11];
5'd6 : p2s <= conf_data[10];
5'd7 : p2s <= conf_data[9];
5'd8 : p2s <= conf_data[8];
5'd9 : p2s <= conf_data[7];
5'd10 : p2s <= conf_data[6];
5'd11 : p2s <= conf_data[5];
5'd12 : p2s <= conf_data[4];
5'd13 : p2s <= conf_data[3];
5'd14 : p2s <= conf_data[2];
5'd15 : p2s <= conf_data[1];
5'd16 : begin p2s <= conf_data[0]; s2p_act_pre <= 1'b0; end
5'd17 : begin sclk <= 1'b0; p2s <= 1'b0; sclk_mask <= 1'b0; end
5'd18 : sclk <= 1'b1;
5'd19 : begin p2s <= 1'b1; conf_end <= 1'b1; end
default : begin sclk <= 1'b1; p2s <= 1'b1; sclk_mask <= 1'b0; conf_end <= 1'b0; s2p_act_pre <= 1'b0; end
endcase
//--- s2p convert ---//
always @ (posedge max_sclk)
if (s2p_act[0])
s2p <= {s2p[10:0], max_sdat};
always @ (posedge osc_50 or negedge rstn)
if (!rstn)
begin
s2p_act <= 2'b0;
rd_data_ready <= 1'b0;
end
else
begin
s2p_act <= {s2p_act[0], s2p_act_pre};
if (s2p_act[1] && !s2p_act[0])
rd_data_ready <= 1'b1;
else
rd_data_ready <= 1'b0;
end
endmodule |
|