📄 vspi.v
字号:
reg [7:0] shift_reg; wire shift_clk; wire shift_clk_negedge; // negative edge of SCKwire shift_negative_edge_nxt; reg shift_negative_edge; wire shift_datain; wire shift_dataout; reg slvsel_r1; reg slvsel_r2; reg slvsel_r3; // synchronizerswire spi_go; // begin a transfer// slave select registerreg [7:0] ssel; // status registerwire [7:0] status; // TX has completed, TX_RUN will go lowwire tx_end; reg tx_run; // tx is runningwire tx_start; // -------------------------------------------------------------reg tx_start_r1; // ---------ARCHITECTURE rtl-----------// required for synopsys// # bits in a byteassign mosio = mosie_lcl == 1'b 1 & open_drain == 1'b 0 ? shift_dataout : 1'b 0; // drive low when open drain enabled.assign mosie = open_drain == 1'b 0 ? mosie_lcl : mosie_lcl == 1'b 1 & shift_dataout == 1'b 0 ? 1'b 1 : 1'b 0; assign misoo = misoe_lcl == 1'b 1 & open_drain == 1'b 0 ? shift_dataout : 1'b 0; // drive low when open drain enabled.assign misoe = open_drain == 1'b 0 ? misoe_lcl : misoe_lcl == 1'b 1 & shift_dataout == 1'b 0 ? 1'b 1 : 1'b 0; assign misoe_lcl = master_mode == 1'b 0 & slvsel == 1'b 1 ? 1'b 1 : 1'b 0; // spi_go initiates a transfer - A write to the DOUT reg in master// mode ignore the CPU write if we're already running.assign mosie_lcl = master_mode == 1'b 1 ? 1'b 1 : 1'b 0; assign spi_go = chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 00 & tx_run == 1'b 0 & slvsel_r3 == 1'b 0 ? 1'b 1 : 1'b 0; // -----------Shift register----------------always @(posedge clk) begin : sr_proc if (rst == 1'b 1) begin shift_reg <= 8'b 00000000; // sync reset end else begin if (spi_go == 1'b 1)// don't reload while running begin shift_reg <= datain; // load with data from CPU end else if (shift_clk == 1'b 1 ) begin shift_reg <= {shift_reg[6:0], shift_datain}; end end end// --------Hold time register--------------always @(posedge clk)// negative edge pipeline DFF begin : neg_proc if (rst == 1'b 1) begin shift_negative_edge <= 1'b 0; // sync reset end else if (shift_clk_negedge == 1'b 1 ) begin shift_negative_edge <= shift_negative_edge_nxt; end else if (spi_go == 1'b 1 ) begin shift_negative_edge <= datain[7]; // preload for phase=0 mode end endassign shift_negative_edge_nxt = phase == 1'b 1 ? shift_reg[7] : master_mode == 1'b 1 ? misoi : mosii; // add in the negative edge dff on phase=1assign shift_dataout = phase == 1'b 1 ? shift_negative_edge : shift_reg[7]; // insert the neg DFF in phase=0assign shift_datain = phase == 1'b 0 ? shift_negative_edge : master_mode == 1'b 1 ? misoi : mosii; // -------------TX run------------------// this bit is active while a transmit is runningalways @(posedge clk) begin : tr_proc if (rst == 1'b 1) begin tx_run <= 1'b 0; // sync reset end else begin if (tx_start == 1'b 1) begin tx_run <= 1'b 1; end else if (tx_end == 1'b 1 ) begin tx_run <= 1'b 0; end end end// -----------Bit counter for master mode----------------always @(posedge clk) begin : bc_proc if (rst == 1'b 1)// sync reset begin bit_ctr <= 3'b 000; end else begin if (tx_start == 1'b 1) begin bit_ctr <= ssel[7:5]; end else if (shift_clk == 1'b 1 ) begin bit_ctr <= bit_ctr - 1'b 1; end end end// bit counterassign tx_end = master_mode == 1'b 1 & bit_ctr == 3'b 001 & shift_clk == 1'b 1 & tx_run == 1'b 1 ? 1'b 1 : 1'b 0; assign tx_start = master_mode == 1'b 1 & spi_go == 1'b 1 ? 1'b 1 : 1'b 0; // -------Control Register----------------------always @(posedge clk) begin : gjr_proc if (rst == 1'b 1)// sync reset begin ctl_reg <= 8'b 00000000; end else begin if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 01)// load begin ctl_reg <= datain; end end end// map the control register to more meaningfull namesassign master_mode = ctl_reg[1]; assign open_drain = ctl_reg[2]; assign polck = ctl_reg[3]; assign phase = ctl_reg[4]; assign sel_clk = ctl_reg[6:5]; // -------Slave Select Register-------------------------always @(posedge clk) begin : s_proc if (rst == 1'b 1)// sync reset begin ssel <= 8'b 00000000; end else begin if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 11)// load begin ssel <= datain; end end endassign slvselo = ssel[4:0]; // drive the portassign slvsele = master_mode; // -------Collision flag bit---------------------------always @(posedge clk) begin : cf_proc if (rst == 1'b 1) begin col_flag <= 1'b 0; end else begin if (master_mode == 1'b 1 & slvsel_r3 == 1'b 1) begin col_flag <= 1'b 1; end else if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 10 & datain[5] == 1'b 1 ) begin col_flag <= 1'b 0; end end end// -------OFLOw flag bit------------------------------always @(posedge clk) begin : o_proc if (rst == 1'b 1) begin oflow <= 1'b 0; end else begin if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 00 & (tx_run == 1'b 1 | slvsel_r3 == 1'b 1))// write to DOUT// and we're busy begin oflow <= 1'b 1; end else if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 10 & datain[6] == 1'b 1 ) begin oflow <= 1'b 0; end end end// -------IRQ flag bit------------------------------always @(posedge clk) begin : elr_proc if (rst == 1'b 1) begin irq_flag <= 1'b 0; end else begin if (tx_end == 1'b 1 | slvsel_r2 == 1'b 0 & slvsel_r3 == 1'b 1) begin irq_flag <= 1'b 1; end else if (chip_sel == 1'b 1 & write == 1'b 1 & addr == 2'b 10 & datain[7] == 1'b 1 ) begin irq_flag <= 1'b 0; end end endassign irq = irq_flag & ctl_reg[7]; // gate with the IRQENB bit.// --------------various pipeline flops---------always @(posedge clk) begin : flops_proc slvsel_r3 <= slvsel_r2; slvsel_r2 <= slvsel_r1; // synchronizers slvsel_r1 <= slvsel; sck_r3 <= sck_r2; sck_r2 <= sck_r1; // synchronizers// select the desired polarity of the slave clk sck_r1 <= ~scki ^ polck; tx_start_r1 <= tx_start; end// --------------clock divider for clk generation-------// create a 2x clock which creates 2 pulses.// One for each edge of SCK.always @(posedge clk) begin : dvd_proc if (~(tx_run == 1'b 1 & master_mode == 1'b 1) | tx_end == 1'b 1)// divider only runs when sending data begin dvd_ctr <= 5'b 00000; dvd2 <= 1'b 0; end else begin if (dvd_ctr == 5'b 00000) begin if (sel_clk == 2'b 00) begin dvd_ctr <= 5'b 00011; end else if (sel_clk == 2'b 01 ) begin dvd_ctr <= 5'b 00111; end else if (sel_clk == 2'b 10 ) begin dvd_ctr <= 5'b 01111; end else begin dvd_ctr <= 5'b 11111; end if (tx_start_r1 == 1'b 0) begin dvd2 <= ~dvd2; end end else begin dvd_ctr <= dvd_ctr - 1'b 1; end end end// dvdassign dvd_zero = dvd_ctr == 5'b 00000 ? 1'b 1 : 1'b 0; // TX_START_R1 prevents data from shifting on the first// clock in POLCK=1 mode which we don't want.We only get// 7 clocks otherwise.assign shift_clk = master_mode == 1'b 1 ? dvd_zero & dvd2 & tx_run & ~tx_start_r1 : sck_r2 & ~sck_r3; // dataout multiplexor for register readback// assemble the bits that make up the status registerassign shift_clk_negedge = master_mode == 1'b 1 ? dvd_zero & ~dvd2 & tx_run : ~sck_r2 & sck_r3; assign status = {irq_flag, oflow, col_flag, 3'b 000, tx_run, slvsel_r3}; assign scke = master_mode; assign scko = dvd2 ^ polck; assign dataout = addr == 2'b 00 ? shift_reg : addr == 2'b 01 ? ctl_reg : addr == 2'b 10 ? status : addr == 2'b 11 ? ssel : 8'b xxxxxxxx; endmodule // module vspi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -