Browse Source

new files (SPI)

ikari 14 years ago
parent
commit
be0fde297d
5 changed files with 968 additions and 0 deletions
  1. 52 0
      src/fpga_spi.c
  2. 10 0
      src/fpga_spi.h
  3. 118 0
      verilog/sd2snes/avr_cmd.v
  4. 643 0
      verilog/sd2snes/main_tf2.v
  5. 145 0
      verilog/sd2snes/spi.v

+ 52 - 0
src/fpga_spi.c

@@ -0,0 +1,52 @@
+// insert cool lengthy disclaimer here
+/*
+	fpga_spi.c: SPI functions for SRAM interfacing and mapper config
+
+	SPI commands
+
+	cmd		param		function	
+   =============================================
+	00		bb[hh[ll]]	set address to 0xbbhhll
+	2s		-			set SRAM size to s
+	3m		-			set mapper to m
+						0=HiROM, 1=LoROM
+	80		-			read with increment
+	81		-			read w/o increment
+	90		{xx}*		write xx with increment
+	91		{xx}*		write xx w/o increment
+	
+*/
+
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+#include "avrcompat.h"
+#include "fpga.h"
+#include "config.h"
+#include "uart.h"
+#include "spi.h"
+#include "fpga_spi.h"
+
+void spi_fpga(void) {
+	SPI_SS_HIGH();
+	FPGA_SS_LOW();
+}
+
+void spi_sd(void) {
+	FPGA_SS_HIGH();
+	SPI_SS_LOW();
+}
+
+void fpga_spi_init(void) {
+	DDRC = _BV(PC7);
+	FPGA_SS_HIGH();
+}
+
+void set_avr_addr(uint32_t address) {
+	spi_fpga();
+	spiTransferByte(0x00);
+	spiTransferByte((address>>16)&0xff);
+	spiTransferByte((address>>8)&0xff);
+	spiTransferByte((address)&0xff);
+	spi_sd();
+}
+

+ 10 - 0
src/fpga_spi.h

@@ -0,0 +1,10 @@
+// insert cool lengthy disclaimer here
+
+#define FPGA_SS_HIGH()	do {PORTC |= _BV(PC7);} while (0)
+#define FPGA_SS_LOW()	do {PORTC &= ~_BV(PC7);} while (0)
+
+void fpga_spi_init(void);
+void fpga_spi_test(void);
+void spi_fpga(void);
+void spi_sd(void);
+void set_avr_addr(uint32_t);

+ 118 - 0
verilog/sd2snes/avr_cmd.v

@@ -0,0 +1,118 @@
+`timescale 1ns / 1ps
+//////////////////////////////////////////////////////////////////////////////////
+// Company: 
+// Engineer: 
+// 
+// Create Date:    21:57:50 08/25/2009 
+// Design Name: 
+// Module Name:    avr_cmd 
+// Project Name: 
+// Target Devices: 
+// Tool versions: 
+// Description: 
+//
+// Dependencies: 
+//
+// Revision: 
+// Revision 0.01 - File Created
+// Additional Comments: 
+//
+//////////////////////////////////////////////////////////////////////////////////
+module avr_cmd(
+    input clk,
+    input cmd_ready,
+    input param_ready,
+    input [7:0] cmd_data,
+    input [7:0] param_data,
+    output [3:0] avr_mapper,
+    output [3:0] avr_sram_size,
+    output avr_read,
+    output avr_write,
+    output [7:0] avr_data_out,
+    input [7:0] avr_data_in,
+    output [7:0] spi_data_out,
+    input [31:0] spi_byte_cnt,
+    input [2:0] spi_bit_cnt,
+    output [23:0] addr_out,
+    output [3:0] mapper,
+    input endmessage,
+    input startmessage
+    );
+
+reg [3:0] MAPPER_BUF;
+reg [3:0] SRAM_SIZE_BUF;
+reg AVR_READ_BUF;
+reg AVR_WRITE_BUF;
+reg [23:0] ADDR_OUT_BUF;
+reg [7:0] AVR_DATA_OUT_BUF;
+reg [7:0] AVR_DATA_IN_BUF;
+reg [1:0] avr_nextaddr_buf;
+wire avr_nextaddr;
+
+assign spi_data_out = AVR_DATA_IN_BUF;
+
+initial begin
+   ADDR_OUT_BUF = 0;
+end
+
+always @(posedge clk) begin
+   if (cmd_ready) begin
+      case (cmd_data[7:4])
+         4'h2:
+            SRAM_SIZE_BUF <= cmd_data[3:0];
+         4'h3:
+            MAPPER_BUF <= cmd_data[3:0];
+         4'h8:
+            AVR_DATA_IN_BUF <= avr_data_in;
+      endcase
+   end else if (param_ready) begin
+      case (cmd_data[7:4])
+         4'h0:
+            case (spi_byte_cnt)
+               32'h2: begin
+                  ADDR_OUT_BUF[23:16] <= param_data;
+                  ADDR_OUT_BUF[15:0] <= 16'b0;
+               end
+               32'h3:
+                  ADDR_OUT_BUF[15:8] <= param_data;
+               32'h4:
+                  ADDR_OUT_BUF[7:0] <= param_data;
+            endcase
+         4'h8:
+            AVR_DATA_IN_BUF <= avr_data_in;
+         4'h9:
+            AVR_DATA_OUT_BUF <= param_data;
+      endcase
+   end
+   if (avr_nextaddr & (cmd_data[7:5] == 3'h4) && (cmd_data[0]) && (spi_byte_cnt > (32'h0+2*cmd_data[4])))
+      ADDR_OUT_BUF <= ADDR_OUT_BUF + 1;
+end
+
+always @(posedge clk) begin
+   if (spi_bit_cnt == 3'h0)
+      avr_nextaddr_buf <= {avr_nextaddr_buf[0], 1'b1};
+   else
+      avr_nextaddr_buf <= {avr_nextaddr_buf[0], 1'b0};
+end
+
+always @(posedge clk) begin
+   if (spi_bit_cnt == 3'h1 & (cmd_data[7:4] == 4'h9) & (spi_byte_cnt > 32'h1))
+      AVR_WRITE_BUF <= 1'b0;
+   else
+      AVR_WRITE_BUF <= 1'b1;
+   
+   if ((spi_bit_cnt == 3'h7) & (cmd_data[7:4] == 4'h8) & (spi_byte_cnt > 32'h0))
+      AVR_READ_BUF <= 1'b0;
+   else
+      AVR_READ_BUF <= 1'b1;      
+end
+
+assign avr_nextaddr = avr_nextaddr_buf == 2'b01;
+assign avr_read = AVR_READ_BUF;
+assign avr_write = AVR_WRITE_BUF;
+assign addr_out = ADDR_OUT_BUF;
+assign avr_data_out = AVR_DATA_OUT_BUF;
+assign avr_mapper = MAPPER_BUF;
+assign avr_sram_size = SRAM_SIZE_BUF;
+
+endmodule

+ 643 - 0
verilog/sd2snes/main_tf2.v

@@ -0,0 +1,643 @@
+`timescale 1ns / 1ps
+
+////////////////////////////////////////////////////////////////////////////////
+// Company: 
+// Engineer:
+//
+// Create Date:   00:20:33 07/14/2009
+// Design Name:   main
+// Module Name:   /home/ikari/prj/sd2snes/verilog/sd2snes/main_tf2.v
+// Project Name:  sd2snes
+// Target Device:  
+// Tool versions:  
+// Description: 
+//
+// Verilog Test Fixture created by ISE for module: main
+//
+// Dependencies:
+// 
+// Revision:
+// Revision 0.01 - File Created
+// Additional Comments:
+// 
+////////////////////////////////////////////////////////////////////////////////
+
+module main_tf2;
+
+	// Inputs
+	reg CLKIN;
+	reg [23:0] SNES_ADDR;
+	reg SNES_READ;
+	reg SNES_WRITE;
+	reg SNES_CS;
+	reg SNES_CPU_CLK;
+	reg SNES_REFRESH;
+	reg SPI_MOSI;
+	reg SPI_SS;
+	reg SPI_SCK;
+	reg AVR_ENA;
+
+	// Outputs
+	wire SNES_DATABUS_OE;
+	wire SNES_DATABUS_DIR;
+	wire [19:0] SRAM_ADDR;
+	wire [3:0] ROM_SEL;
+	wire SRAM_OE;
+	wire SRAM_WE;
+	wire SPI_MISO;
+	wire MODE;
+	wire SPI_LSB;
+   wire SRAM_BHE;
+   wire SRAM_BLE;
+   
+	// Bidirs
+	wire [7:0] SNES_DATA;
+	wire SNES_IRQ;
+	wire [15:0] SRAM_DATA;
+
+   reg [15:0] SRAM_DATA_BUF;
+	// Instantiate the Unit Under Test (UUT)
+	main uut (
+		.CLKIN(CLKIN), 
+		.SNES_ADDR(SNES_ADDR), 
+		.SNES_READ(SNES_READ), 
+		.SNES_WRITE(SNES_WRITE), 
+		.SNES_CS(SNES_CS), 
+		.SNES_DATA(SNES_DATA), 
+		.SNES_CPU_CLK(SNES_CPU_CLK), 
+		.SNES_REFRESH(SNES_REFRESH), 
+		.SNES_IRQ(SNES_IRQ),
+      .IRQ_DIR(IRQ_DIR),
+		.SNES_DATABUS_OE(SNES_DATABUS_OE), 
+		.SNES_DATABUS_DIR(SNES_DATABUS_DIR), 
+		.SRAM_DATA(SRAM_DATA), 
+		.SRAM_ADDR(SRAM_ADDR), 
+		.SRAM_CE2(ROM_SEL), 
+		.SRAM_OE(SRAM_OE), 
+		.SRAM_WE(SRAM_WE), 
+		.SPI_MOSI(SPI_MOSI), 
+		.SPI_MISO(SPI_MISO), 
+		.SPI_SS(SPI_SS), 
+		.SPI_SCK(SPI_SCK), 
+		.AVR_ENA(AVR_ENA), 
+      .SRAM_BHE(SRAM_BHE),
+      .SRAM_BLE(SRAM_BLE)
+	);
+
+	initial begin
+		// Initialize Inputs
+		CLKIN = 0;
+		SNES_ADDR = 0;
+		SNES_READ = 1;
+		SNES_WRITE = 1;
+		SNES_CS = 0;
+		SNES_CPU_CLK = 0;
+		SNES_REFRESH = 0;
+		SPI_MOSI = 0;
+		SPI_SS = 1;
+		SPI_SCK = 0;
+		AVR_ENA = 0;
+
+		// Wait 100 ns for global reset to finish
+		#100;
+      // Wait for DCM to stabilize
+      #5000;
+		// Add stimulus here
+		// Add stimulus here
+      SPI_SS = 0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #100 SPI_SS=1;
+      #200;
+      SPI_SS=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+      SPI_SS=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      #100 SPI_SS=1;
+      #200;
+      SPI_SS=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_SS=1;
+      #200;
+      
+      /*
+       * READ TEST
+       */
+       AVR_ENA=1;
+      SPI_SS=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #100;
+      #100;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_SS=1;
+      #300;
+      SPI_SS=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;      
+      #200;
+      SPI_SS=1;
+      AVR_ENA=1;
+      #280;
+  		// Initialize Inputs
+		SNES_ADDR = 24'h223456;
+		SNES_READ = 1;
+		SNES_WRITE = 1;
+		SNES_CS = 0;
+		AVR_ENA = 1;
+      SRAM_DATA_BUF = 8'hff;
+		// Wait for global reset to finish
+		#276;
+      SNES_ADDR <= 24'h123456;
+      SNES_READ <= 0;
+      #176;
+      SNES_READ <= 1;
+      #100;      
+      SNES_WRITE <= 0;
+      #176;
+      SNES_WRITE <= 1;
+      #100;
+      SNES_READ <= 0;
+      #276;
+//      AVR_READ <= 1;
+		// Add stimulus here
+      SPI_SS = 0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #200;
+
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=0;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      SPI_MOSI=1;
+      #100 SPI_SCK=1;
+      #100 SPI_SCK=0;
+      #100 SPI_SS=1;
+      #200;
+
+
+	end
+   always begin
+      #23 CLKIN = ~CLKIN;
+   end
+   always begin
+      #150 SNES_READ = ~SNES_READ;
+   end
+   
+endmodule
+

+ 145 - 0
verilog/sd2snes/spi.v

@@ -0,0 +1,145 @@
+`timescale 1ns / 1ps
+//////////////////////////////////////////////////////////////////////////////////
+// Company: 
+// Engineer: 
+// 
+// Create Date:    21:16:09 07/10/2009 
+// Design Name: 
+// Module Name:    spi 
+// Project Name: 
+// Target Devices: 
+// Tool versions: 
+// Description: 
+//
+// Dependencies: 
+//
+// Revision: 
+// Revision 0.01 - File Created
+// Additional Comments:
+//
+
+//////////////////////////////////////////////////////////////////////////////////
+module spi(input clk,
+           input SCK,
+           input MOSI,
+           output MISO,
+           input SSEL,
+           output LED,
+           output cmd_ready,
+           output param_ready,
+           output [7:0] cmd_data,
+           output [7:0] param_data,
+           output endmessage,
+           output startmessage,
+           input [7:0] input_data,
+           output [31:0] byte_cnt,
+           output [2:0] bit_cnt);
+           
+reg [7:0] cmd_data_r;
+reg [7:0] param_data_r;
+
+// sync SCK to the FPGA clock using a 3-bits shift register
+reg [2:0] SCKr;  always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
+wire SCK_risingedge = (SCKr[2:1]==2'b01);  // now we can detect SCK rising edges
+wire SCK_fallingedge = (SCKr[2:1]==2'b10);  // and falling edges
+
+// same thing for SSEL
+reg [2:0] SSELr;  always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
+wire SSEL_active = ~SSELr[1];  // SSEL is active low
+wire SSEL_startmessage = (SSELr[2:1]==2'b10);  // message starts at falling edge
+wire SSEL_endmessage = (SSELr[2:1]==2'b01);  // message stops at rising edge
+assign endmessage = SSEL_endmessage;
+assign startmessage = SSEL_startmessage;
+
+// and for MOSI
+reg [1:0] MOSIr;  always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
+wire MOSI_data = MOSIr[1];
+
+// we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come in
+reg [2:0] bitcnt;
+reg [31:0] byte_cnt_r;
+
+reg byte_received;  // high when a byte has been received
+reg [7:0] byte_data_received;
+
+assign bit_cnt = bitcnt;
+
+always @(posedge clk)
+begin
+  if(~SSEL_active) begin
+    bitcnt <= 3'b000;
+  end else   
+  if(SCK_risingedge)
+  begin
+    bitcnt <= bitcnt + 3'b001;
+
+    // implement a shift-left register (since we receive the data MSB first)
+    byte_data_received <= {byte_data_received[6:0], MOSI_data};
+  end
+end
+
+always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
+
+// we use the LSB of the data received to control an LED
+reg LEDr;
+
+always @(posedge clk) begin
+   if(~SSEL_active)
+       byte_cnt_r <= 16'h0000;    
+   else if(byte_received) begin
+      LEDr <= byte_data_received[0];
+      byte_cnt_r <= byte_cnt_r + 16'h0001;
+   end
+end
+assign LED = LEDr;
+
+reg [7:0] byte_data_sent;
+
+reg [7:0] cnt;
+always @(posedge clk) begin
+   if(SSEL_startmessage) cnt<=cnt+8'h1;  // count the messages
+end
+
+always @(posedge clk) begin
+   if(SSEL_active) begin
+     if(SSEL_startmessage)
+       byte_data_sent <= cnt;  // first byte sent in a message is the message count
+     else
+     if(SCK_fallingedge) begin
+       if(bitcnt==3'b000)
+         byte_data_sent <= input_data; // after that, we send whatever we get
+       else
+         byte_data_sent <= {byte_data_sent[6:0], 1'b0};
+     end
+   end
+end
+
+assign MISO = SSEL_active ? byte_data_sent[7] : 1'bZ;  // send MSB first
+
+reg cmd_ready_r;
+reg param_ready_r;
+reg cmd_ready_r2;
+reg param_ready_r2;
+assign cmd_ready = cmd_ready_r;
+assign param_ready = param_ready_r;
+assign cmd_data = cmd_data_r;
+assign param_data = param_data_r;
+assign byte_cnt = byte_cnt_r;
+
+always @(posedge clk) cmd_ready_r2 = byte_received && byte_cnt_r == 32'h0;
+always @(posedge clk) param_ready_r2 = byte_received && byte_cnt_r > 32'h0;
+always @(posedge clk) begin
+   if (SSEL_startmessage)
+      cmd_data_r <= 8'h00;
+   else if(cmd_ready_r2)
+      cmd_data_r <= byte_data_received;
+   else if(param_ready_r2)
+      param_data_r <= byte_data_received;
+   
+end
+always @(posedge clk) begin
+   cmd_ready_r <= cmd_ready_r2;
+   param_ready_r <= param_ready_r2;
+end
+
+endmodule