From be0fde297d83331b61d1e5de11bade14dabdc004 Mon Sep 17 00:00:00 2001 From: ikari Date: Fri, 4 Sep 2009 10:56:59 +0200 Subject: [PATCH] new files (SPI) --- src/fpga_spi.c | 52 +++ src/fpga_spi.h | 10 + verilog/sd2snes/avr_cmd.v | 118 +++++++ verilog/sd2snes/main_tf2.v | 643 +++++++++++++++++++++++++++++++++++++ verilog/sd2snes/spi.v | 145 +++++++++ 5 files changed, 968 insertions(+) create mode 100644 src/fpga_spi.c create mode 100644 src/fpga_spi.h create mode 100644 verilog/sd2snes/avr_cmd.v create mode 100644 verilog/sd2snes/main_tf2.v create mode 100644 verilog/sd2snes/spi.v diff --git a/src/fpga_spi.c b/src/fpga_spi.c new file mode 100644 index 0000000..41d6ce9 --- /dev/null +++ b/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 +#include +#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(); +} + diff --git a/src/fpga_spi.h b/src/fpga_spi.h new file mode 100644 index 0000000..40a7d71 --- /dev/null +++ b/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); diff --git a/verilog/sd2snes/avr_cmd.v b/verilog/sd2snes/avr_cmd.v new file mode 100644 index 0000000..e06fd62 --- /dev/null +++ b/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 diff --git a/verilog/sd2snes/main_tf2.v b/verilog/sd2snes/main_tf2.v new file mode 100644 index 0000000..7a48010 --- /dev/null +++ b/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 + diff --git a/verilog/sd2snes/spi.v b/verilog/sd2snes/spi.v new file mode 100644 index 0000000..a233363 --- /dev/null +++ b/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