⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simple_spi_top.v

📁 摩托罗拉SPI通信sourcecode,对于程序开发的人来说,写底层的东西,一定要看
💻 V
字号:
//
// Motorola MC68HC11E based SPI interface
//
// Currently only MASTER mode is supported
//

// synopsys translate_off
`include "timescale.v"
// synopsys translate_on

module spi_top(
// 8bit APB bus slave interface
    input  wire       pclk,         // clock
    input  wire       prst,         // reset (asynchronous active low)
    input  wire       psel,        	// select slave device and a data transfer required //
    input  wire       penable,      // penable
    input  wire [1:0] paddr,        // address
    input  wire       pwrite,       // write enable
    input  wire [7:0] pwdata,       // data input
    output reg  [7:0] prdata,       // data output

    output reg        inta_o,       // interrupt output

// SPI port
    output reg        sck_o,        // serial clock output
    output wire       mosi_o,       // MasterOut SlaveIN
    input  wire       miso_i        // MasterIn SlaveOut
);

reg  [7:0] spcr;       // Serial Peripheral Control Register ('HC11 naming)
wire [7:0] spsr;       // Serial Peripheral Status register ('HC11 naming)
reg  [7:0] sper;       // Serial Peripheral Extension register
reg  [7:0] treg, rreg; // Transmit/Receive register

// fifo signals
wire [7:0] rfdout;
reg        wfre, rfwe;
wire       rffull, rfempty;
wire [7:0] wfdout;
wire       wffull, wfempty;

// misc signals
wire       tirq;     // transfer interrupt (selected number of transfers done)
wire       wfov;     // write fifo overrun (writing while fifo full)
reg  [1:0] state;    // statemachine state
reg  [2:0] bcnt;
reg     	  ack;      // normal bus termination
	
// APB interface
wire reg_we  = psel & pwrite;      // APB write access

// pwdata
always @(posedge pclk or negedge prst)
    if (~prst)
    begin
        spcr <= #1 8'h10;  // set master bit
        sper <= #1 8'h00;
    end
    else if ( reg_we )
    begin
        if (paddr == 2'b00)
            spcr <= #1 pwdata | 8'h10; // always set master bit

        if (paddr == 2'b11)
            sper <= #1 pwdata;
    end

// write fifo
wire wfwe = psel & paddr == 2'b10 & penable &  pwrite;
wire rfre = psel & paddr == 2'b10 & penable & ~pwrite;

assign wfov = wfwe & wffull;

// prdata
always @( paddr or spcr or spsr or rfdout or sper )
    case(paddr) // synopsys full_case parallel_case
    2'b00: prdata <= #1 spcr;
    2'b01: prdata <= #1 spsr;
    2'b10: prdata <= #1 rfdout;
    2'b11: prdata <= #1 sper;
    endcase

// decode Serial Peripheral Control Register
wire       spie = spcr[7];   // Interrupt enable bit
wire       spe  = spcr[6];   // System Enable bit
wire       dwom = spcr[5];   // Port D Wired-OR Mode Bit
wire       mstr = spcr[4];   // Master Mode Select Bit
wire       cpol = spcr[3];   // Clock Polarity Bit
wire       cpha = spcr[2];   // Clock Phase Bit
wire [1:0] spr  = spcr[1:0]; // Clock Rate Select Bits

// decode Serial Peripheral Extension Register
wire [1:0] icnt = sper[7:6]; // interrupt on transfer count
wire [1:0] spre = sper[1:0]; // extended clock rate select

wire [3:0] espr = {spre, spr};

// generate status register
wire wr_spsr = reg_we & (paddr == 2'b01);

reg spif;
always @(posedge pclk)
    if (~spe) spif <= #1 1'b0;
    else      spif <= #1 ( tirq | spif ) & ~(wr_spsr & pwdata[7]);

reg wcol;
always @(posedge pclk)
    if (~spe) wcol <= #1 1'b0;
    else      wcol <= #1 (wfov | wcol) & ~(wr_spsr & pwdata[6]);

assign spsr[7]   = spif;
assign spsr[6]   = wcol;
assign spsr[5:4] = 2'b00;
assign spsr[3]   = wffull;
assign spsr[2]   = wfempty;
assign spsr[1]   = rffull;
assign spsr[0]   = rfempty;
  

// generate IRQ output (inta_o)
always @(posedge pclk)
    inta_o <= #1 spif & spie;

// hookup read/write buffer fifo
fifo4 #(8)
    rfifo(
    .clk   ( pclk    ),
    .rst   ( prst    ),
    .clr   ( ~spe    ),
    .din   ( treg    ),
    .we    ( rfwe    ),
    .dout  ( rfdout  ),
    .re    ( rfre    ),
    .full  ( rffull  ),
    .empty ( rfempty )
    ),

    wfifo(
    .clk   ( pclk   ),
    .rst   ( prst   ),
    .clr   ( ~spe    ),
    .din   ( pwdata   ),
    .we    ( wfwe    ),
    .dout  ( wfdout  ),
    .re    ( wfre    ),
    .full  ( wffull  ),
    .empty ( wfempty )
    );

// generate clk divider
reg [11:0] clkcnt;
always @(posedge pclk)
    if( spe & (|clkcnt & |state) )
        clkcnt <= #1 clkcnt - 11'h1;
    else
        case (espr) // synopsys full_case parallel_case
        4'b0000: clkcnt <= #1 12'h0;   // 2   -- original M68HC11 coding
        4'b0001: clkcnt <= #1 12'h1;   // 4   -- original M68HC11 coding
        4'b0010: clkcnt <= #1 12'h7;   // 16  -- original M68HC11 coding
        4'b0011: clkcnt <= #1 12'hf;   // 32  -- original M68HC11 coding
        4'b0100: clkcnt <= #1 12'h3;   // 8
        4'b0101: clkcnt <= #1 12'h1f;  // 64
        4'b0110: clkcnt <= #1 12'h3f;  // 128
        4'b0111: clkcnt <= #1 12'h7f;  // 256
        4'b1000: clkcnt <= #1 12'hff;  // 512
        4'b1001: clkcnt <= #1 12'h1ff; // 1024
        4'b1010: clkcnt <= #1 12'h3ff; // 2048
        4'b1011: clkcnt <= #1 12'h7ff; // 4096
        endcase
 
// generate clock enable signal
wire ena = ~| clkcnt;

// transfer statemachine
always @(posedge pclk)
    if (~spe)
    begin
        state <= #1 2'b00; // idle
        bcnt  <= #1 3'h0;
        treg  <= #1 8'h00;
        wfre  <= #1 1'b0;
        rfwe  <= #1 1'b0;
        sck_o <= #1 1'b0;
    end
    else
    begin
        wfre <= #1 1'b0;
        rfwe <= #1 1'b0;

        case (state) //synopsys full_case parallel_case
        2'b00: // idle state
        begin
            bcnt  <= #1 3'h7;   // set transfer counter
            treg  <= #1 wfdout; // load transfer register
            sck_o <= #1 cpol;   // set sck

            if (~wfempty) begin
                wfre  <= #1 1'b1;
                state <= #1 2'b01;
                if (cpha) sck_o <= #1 ~sck_o;
            end
        end

        2'b01: // clock-phase2, next data
        if (ena) begin
            sck_o <= #1 ~sck_o;
            state <= #1 2'b11;
        end

        2'b11: // clock phase1
        if (ena) begin
            treg <= #1 {treg[6:0], miso_i};
            bcnt <= #1 bcnt -3'h1;

            if (~|bcnt) begin
                state <= #1 2'b00;
                sck_o <= #1 cpol;
                rfwe  <= #1 1'b1;
            end
            else begin
                state <= #1 2'b01;
                sck_o <= #1 ~sck_o;
            end
        end

        2'b10: state <= #1 2'b00;
        endcase
    end

assign mosi_o = treg[7];

// count number of transfers (for interrupt generation)
reg [1:0] tcnt; // transfer count
always @(posedge pclk)
    if (~spe)
        tcnt <= #1 icnt;
    else if (rfwe) // rfwe gets asserted when all bits have been transfered
        if (|tcnt) tcnt <= #1 tcnt - 2'h1;
        else       tcnt <= #1 icnt;

assign tirq = ~| tcnt & rfwe;

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -