📄 spi.v
字号:
`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Author: Till Harbaum <till@harbaum.org>// Create Date: 20:12:16 08/24/2006 // Project Name: spi2cf// Target Devices: xc9572xl// Tool versions: Webpack ISE 8.2// Description: SPI to CF converter for use with Prism2 WLAN CF card// URL: http://www.harbaum.org/till/spi2cf// License: GPL////////////////////////////////////////////////////////////////////////////////////// CPLD version number`define VERSION 16'h0106`define VERSION_HI (`VERSION >> 8)`define VERSION_LO (`VERSION & 255)// commands`define GET_ID 0`define SET_ADDR 1`define REG_READ 2 `define REG_WRITE 3`define IO_READ 4`define IO_WRITE 5`define MEM_READ 6`define MEM_WRITE 7module spi(SS, SCK, SIN, EN, SOUT, INT, CFRST, LED, ADDRESS, DATA, REG, CE, OE, WE, IORD, IOWR, CD); // interface to avr input SS; input SCK; input SIN; input EN; output SOUT; output INT; // interface to cf card output [10:0] ADDRESS; inout [7:0] DATA; output CE, OE, REG, WE; output CFRST; output LED; output IORD, IOWR; input CD; // used to store incoming command reg [2:0] cmd_reg; // to determine end of byte reg [2:0] bit_counter; // keep track of transmission reg [1:0] state; reg addr_inc; // address latch reg [15:0] address_reg; // only 11 actually are used as address lines reg [7:0] data_reg; reg [7:0] data_out_reg; reg cf_ce, cf_reg, cf_oe, cf_we; reg cf_iord, cf_iowr; // output shift register reg [7:0] out_reg;
reg [7:0] data_in_reg; wire cmd_internal; wire cmd_cf_write, cmd_cf_read; // count bits to determine and of a byte // reset counter if always @(negedge SCK or posedge SS) begin // clear state if not selected if (SS) begin bit_counter <= 0; state <= 0; end // count bits and bytes else begin bit_counter <= bit_counter + 1; if(bit_counter == 7) begin // one byte completed, advance state. state // goes: 0->1->2->3->2->3->2... state[0] <= !state[0]; state[1] <= state[0] || state[1]; end end end // process the flag indicating that the address auto increment is enabled always @(posedge SCK or posedge SS) begin // clear state if not selected if (SS) begin addr_inc <= 0; end else begin // enable auto address modes in all modes that cause cf data transfers // (these are all but the internal commands SET_ADDR and GET_ID) if(!cmd_internal) if(bit_counter == 7) if(cmd_cf_read || (cmd_cf_write && state >= 1)) addr_inc <= 1; end end // shift command in always @(posedge SCK) begin // default state: no access cf_reg <= 1; cf_ce <= 1; cf_oe <= 1; cf_iord <= 1; cf_iowr <= 1; cf_we <= 1; // latch address register, this is not shifted, since this // way we won't see glitches e.g. in the reset line built by // the address register bit 15 during address loads if(cmd_reg == `SET_ADDR) begin if(state == 1) address_reg[7-bit_counter] <= SIN; if(state == 2) address_reg[15-bit_counter] <= SIN; end if((addr_inc) && (bit_counter == 7)) begin // address register bits 13 and 14 determine the address mode // and bits 0..10 actually are addresses case( address_reg[12:11] ) // toggle odd/even byte address 1: address_reg[0] <= !address_reg[0]; // increment byte 2: address_reg[10:0] <= address_reg[10:0] + 1; // increment word 3: address_reg[10:0] <= address_reg[10:0] + 2; endcase end // permanently shift data in data_reg = { data_reg[6:0], SIN };
// and permanently latch the data from the data bus if(bit_counter == 7)
data_in_reg <= DATA;
// command phase: shift three command bits in if( (state == 0) && (bit_counter < 3) ) cmd_reg <= { cmd_reg[1:0], SIN }; // read is active already in state 1, the data will then be sent via spi // in the next state if( cmd_cf_read && (((state == 0)&&(bit_counter == 7)) ||(state >= 1) )) begin cf_ce <= 0; // register select if(( cmd_reg == `REG_READ ) || (cmd_reg == `IO_READ)) cf_reg <= 0; // enable read signals if ( bit_counter < 7) begin if( cmd_reg == `REG_READ ) cf_oe <= 0; if( cmd_reg == `IO_READ ) cf_iord <= 0; end end // write starts in state 2 since its delayed by one after input if( cmd_cf_write && (((state == 1)&&(bit_counter == 7)) ||(state >= 2) )) begin cf_ce <= 0; // register select if(( cmd_reg == `REG_WRITE ) || (cmd_reg == `IO_WRITE)) cf_reg <= 0; // enable write signals if ( bit_counter < 7) begin if( cmd_reg == `REG_WRITE && bit_counter < 6) cf_we <= 0; if( cmd_reg == `IO_WRITE ) cf_iowr <= 0; end end end // shift result out on negative edge to have it valid on positive always @(negedge SCK) begin // latch data for output if(bit_counter == 7) begin data_out_reg <= data_reg; // these are the only two cases where the out_reg is latched. this // means that this byte can be returned during a command transfer. this // is necessary to be able to fetch the last byte in a read phase by // issuing e.g. the get_id command. if( cmd_reg == `GET_ID ) begin if(state[0]) begin // msb is "card is present" bit out_reg[7] <= CD; out_reg[6:0] <= `VERSION_HI; end else out_reg <= `VERSION_LO; end if( cmd_cf_read ) out_reg <= data_in_reg; end else out_reg <= { out_reg[6:0], 1'b0 }; end // internal wires assign cmd_internal = ((cmd_reg == `GET_ID) || (cmd_reg == `SET_ADDR)); assign cmd_cf_read = ((cmd_reg == `REG_READ) || (cmd_reg == `MEM_READ) || (cmd_reg == `IO_READ)); assign cmd_cf_write = ((cmd_reg == `REG_WRITE) || (cmd_reg == `MEM_WRITE) || (cmd_reg == `IO_WRITE)); // drive outputs assign SOUT = (!SS)?out_reg[7]:1'bz; assign ADDRESS = address_reg[10:0]; // 12:11 are used internally for auto address assign LED = address_reg[13]; // 13 is LED output, 14 is unused assign CFRST = address_reg[15]; // 15 is reset // drive control signals assign CE = cf_ce; assign REG = cf_reg; assign OE = cf_oe; assign WE = cf_we; assign IORD = cf_iord; assign IOWR = cf_iowr; assign INT = 1; // INT isn't used yet, tie to VCC // drive data lines if a write command is scheduled, if chip is selected and // if we are in state 2 or 3 (data is being written) and within bits 2 to 7 // (cf card is selected) assign DATA = (cmd_cf_write && (state >= 2))? data_out_reg : 8'hzz;endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -