OpenCores
URL https://opencores.org/ocsvn/simple_spi/simple_spi/trunk

Subversion Repositories simple_spi

[/] [simple_spi/] [trunk/] [rtl/] [verilog/] [simple_spi_top.v] - Rev 6

Go to most recent revision | Compare with Previous | Blame | View Log

/////////////////////////////////////////////////////////////////////
////                                                             ////
////  OpenCores                    MC68HC11E based SPI interface ////
////                                                             ////
////  Author: Richard Herveille                                  ////
////          richard@asics.ws                                   ////
////          www.asics.ws                                       ////
////                                                             ////
/////////////////////////////////////////////////////////////////////
////                                                             ////
//// Copyright (C) 2002 Richard Herveille                        ////
////                    richard@asics.ws                         ////
////                                                             ////
//// This source file may be used and distributed without        ////
//// restriction provided that this copyright statement is not   ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer.////
////                                                             ////
////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
//// POSSIBILITY OF SUCH DAMAGE.                                 ////
////                                                             ////
/////////////////////////////////////////////////////////////////////
 
//  CVS Log
//
//  $Id: simple_spi_top.v,v 1.3 2003-01-09 16:47:59 rherveille Exp $
//
//  $Date: 2003-01-09 16:47:59 $
//  $Revision: 1.3 $
//  $Author: rherveille $
//  $Locker:  $
//  $State: Exp $
//
// Change History:
//               $Log: not supported by cvs2svn $
//               Revision 1.2  2003/01/07 13:29:52  rherveille
//               Changed SPR bits coding.
//
//               Revision 1.1.1.1  2002/12/22 16:07:15  rherveille
//               Initial release
//
//
 
 
 
//
// Motorola MC68HC11E based SPI interface
//
// Currently only MASTER mode is supported
//
 
// synopsys translate_off
`include "timescale.v"
// synopsys translate_on
 
module simple_spi_top(
  clk_i, rst_i, cyc_i, stb_i, adr_i, we_i, dat_i, dat_o, ack_o,
  inta_o,
  sck_o, mosi_o, miso_i
);
 
  //
  // Inputs & outputs
  //
 
  // 8bit WISHBONE bus slave interface
  input        clk_i;         // clock
  input        rst_i;         // reset (asynchronous active low)
  input        cyc_i;         // cycle
  input        stb_i;         // strobe
  input  [1:0] adr_i;         // address
  input        we_i;          // write enable
  input  [7:0] dat_i;         // data output
  output [7:0] dat_o;         // data input
  output       ack_o;         // normal bus termination
  output       inta_o;        // interrupt output
 
  // SPI port
  output       sck_o;         // serial clock output
  output       mosi_o;        // MasterOut SlaveIN
  input        miso_i;        // MasterIn SlaveOut
 
  //
  // Module body
  //
  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;       // Transfer register
 
  // fifo signals
  wire [7:0] rfdout;
  reg        wfre, rfwe;
  wire       rfre, rffull, rfempty;
  wire [7:0] wfdin, wfdout;
  wire       wfwe, wffull, wfempty;
 
  // misc signals
  wire tirq;     // transfer interrupt (selected number of transfers done)
  wire wfov;     // write fifo overrun (writing while fifo full)
  reg  state;    // statemachine state
  reg  ena_mosi; // mosi_o clock-enable
  reg [2:0] bcnt;
 
  //
  // Wishbone interface
  wire wb_acc = cyc_i & stb_i;       // WISHBONE access
  wire wb_wr  = wb_acc & we_i;       // WISHBONE write access
 
  // dat_i
  always @(posedge clk_i or negedge rst_i)
    if (~rst_i)
      begin
          spcr <= #1 8'h10;  // set master bit
          sper <= #1 8'h00;
      end
    else if (wb_wr)
      begin
        if (adr_i == 2'b00)
          spcr <= #1 dat_i | 8'h10; // always set master bit
 
        if (adr_i == 2'b11)
          sper <= #1 dat_i;
      end
 
  // write fifo
  assign wfwe = wb_acc & (adr_i == 2'b10) & ack_o &  we_i;
  assign wfov = wfwe & wffull;
 
  // dat_o
  reg [7:0] dat_o;
  always @(posedge clk_i)
    case(adr_i) // synopsys full_case parallel_case
      2'b00: dat_o <= #1 spcr;
      2'b01: dat_o <= #1 spsr;
      2'b10: dat_o <= #1 rfdout;
      2'b11: dat_o <= #1 sper;
    endcase
 
  // read fifo
  assign rfre = wb_acc & (adr_i == 2'b10) & ack_o & ~we_i;
 
  // ack_o
  reg ack_o;
  always @(posedge clk_i or negedge rst_i)
    if (~rst_i)
      ack_o <= #1 1'b0;
    else
      ack_o <= #1 wb_acc & !ack_o;
 
  // 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 = wb_wr & (adr_i == 2'b01);
 
  reg spif;
  always @(posedge clk_i)
    if (~spe)
      spif <= #1 1'b0;
    else
      spif <= #1 (tirq | spif) & ~(wr_spsr & dat_i[7]);
 
  reg wcol;
  always @(posedge clk_i)
    if (~spe)
      wcol <= #1 1'b0;
    else
      wcol <= #1 (wfov | wcol) & ~(wr_spsr & dat_i[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)
  reg inta_o;
  always @(posedge clk_i)
    inta_o <= #1 spif & spie;
 
  //
  // hookup read/write buffer fifo
  fifo4 #(8)
  rfifo(
	.clk   ( clk_i   ),
	.rst   ( rst_i   ),
	.clr   ( ~spe    ),
	.din   ( treg    ),
	.we    ( rfwe    ),
	.dout  ( rfdout  ),
	.re    ( rfre    ),
	.full  ( rffull  ),
	.empty ( rfempty )
  ),
  wfifo(
	.clk   ( clk_i   ),
	.rst   ( rst_i   ),
	.clr   ( ~spe    ),
	.din   ( dat_i   ),
	.we    ( wfwe    ),
	.dout  ( wfdout  ),
	.re    ( wfre    ),
	.full  ( wffull  ),
	.empty ( wfempty )
  );
 
  //
  // generate clk divider
  reg [10:0] clkcnt;
  always @(posedge clk_i)
    if(~spe)
        clkcnt <= #1 11'h0;
    else if (|clkcnt & state)
        clkcnt <= #1 clkcnt - 11'h1;
    else
        case (espr) // synopsys full_case parallel_case
          4'b0000: clkcnt <= #1 11'h0;   // 2   -- original M68HC11 coding
          4'b0001: clkcnt <= #1 11'h1;   // 4   -- original M68HC11 coding
          4'b0010: clkcnt <= #1 11'h7;   // 16  -- original M68HC11 coding
          4'b0011: clkcnt <= #1 11'hf;   // 32  -- original M68HC11 coding
          4'b0100: clkcnt <= #1 11'h3;   // 8
          4'b0101: clkcnt <= #1 11'h1f;  // 64
          4'b0110: clkcnt <= #1 11'h3f;  // 128
          4'b0111: clkcnt <= #1 11'h7f;  // 256
          4'b1000: clkcnt <= #1 11'hff;  // 512
          4'b1001: clkcnt <= #1 11'h1ff; // 1024
          4'b1010: clkcnt <= #1 11'h3ff; // 2048
          4'b1011: clkcnt <= #1 11'h7ff; // 4096
        endcase
 
  // generate internal SCK
  reg sck;
  always @(posedge clk_i)
    if (~spe)
      sck <= #1 1'b0;
    else
      sck <= #1 sck ^ ~(|clkcnt);
 
  // generate SCK_O
  reg sck_o;
  always @(posedge clk_i)
    sck_o <= #1 sck ^ cpol;
 
  // generate clock-enable signal
  reg ena;
  always @(posedge clk_i)
    ena <= #1 ~(|clkcnt) & (~sck ^ cpha);
 
  // generate ena_mosi (clock data in)
  reg hold_ena;
  always @(posedge clk_i or negedge rst_i)
    if(~rst_i)
      hold_ena <= #1 1'b0;
    else
      hold_ena <= state & (ena | hold_ena) & ~ena_mosi;
 
  always @(posedge clk_i)
    ena_mosi <= #1 ~(|clkcnt) & hold_ena;
 
  // store miso
  reg smiso;
  always @(posedge clk_i)
    if(ena)
      smiso <= #1 miso_i;
 
  // transfer statemachine
  //reg [2:0] bcnt; // bit count
  always @(posedge clk_i)
    if (~spe)
      begin
          state <= #1 1'b0; // idle
          bcnt  <= #1 3'h0;
          treg  <= #1 8'h00;
          wfre  <= #1 1'b0;
          rfwe  <= #1 1'b0;
      end
    else
      begin
         wfre <= #1 1'b0;
         rfwe <= #1 1'b0;
 
         if(~state) // idle
         begin
             bcnt <= #1 3'h7;   // set transfer counter
             treg <= #1 wfdout; // load transfer register
             if (~wfempty)
             begin
                 state <= #1 1'b1; // goto transfer state
                 wfre  <= #1 1'b1;
             end
         end
 
         if(state & ena_mosi)
         begin
             treg <= #1 {treg[6:0], smiso}; //miso_i};
             bcnt <= #1 bcnt -3'h1;
             if (~|bcnt)
             begin
                 state <= #1 1'b0; // goto idle state
                 rfwe  <= #1 1'b1;
             end
         end
      end
 
  assign mosi_o = treg[7];
 
 
  // count number of transfers (for interrupt generation)
  reg [1:0] tcnt; // transfer count
  always @(posedge clk_i)
    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
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.