SPI offloading -> 5x loading speed (needs code cleanup)

This commit is contained in:
ikari 2009-12-22 03:06:26 +01:00
parent b37fc1b846
commit 63febb92c6
15 changed files with 508 additions and 82 deletions

View File

@ -80,6 +80,8 @@ DRESULT disk_getinfo(BYTE drv, BYTE page, void *buffer);
void disk_init(void);
uint8_t SD_SPI_OFFLOAD;
/* Will be set to DISK_ERROR if any access on the card fails */
enum diskstates { DISK_CHANGED = 0, DISK_REMOVED, DISK_OK, DISK_ERROR };

View File

@ -60,6 +60,7 @@
#include "ff.h" /* FatFs declarations */
#include "diskio.h" /* Include file for user provided disk functions */
#include "uart.h"
#include "fpga.h"
/*--------------------------------------------------------------------------
@ -1603,8 +1604,12 @@ FRESULT f_read (
cc = btr / SS(fs); /* When left bytes >= SS(fs), */
if (cc) { /* Read maximum contiguous sectors directly */
if (cc > fp->csect) cc = fp->csect;
if(SPI_OFFLOAD) {
SD_SPI_OFFLOAD = 1;
}
if (disk_read(fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
goto fr_error;
SD_SPI_OFFLOAD = 0;
fp->csect -= (BYTE)(cc - 1);
fp->curr_sect += cc - 1;
rcnt = cc * SS(fs);
@ -1619,10 +1624,13 @@ FRESULT f_read (
}
}
SPI_OFFLOAD = 0;
return FR_OK;
fr_error: /* Abort this file due to an unrecoverable error */
fp->flag |= FA__ERROR;
SPI_OFFLOAD = 0;
SD_SPI_OFFLOAD = 0;
return FR_RW_ERROR;
}

View File

@ -55,6 +55,10 @@ void fpga_init() {
DDRD |= _BV(PD3) | _BV(PD4); // PD3, PD4 are outputs
DDRA = ~_BV(PA3); // PA3 is input <- DONE
DDRB |= _BV(PB2); // DMA_CTRL preinit
PORTB |= _BV(PB2);
SPI_OFFLOAD=0;
set_cclk(0); // initial clk=0
}
@ -64,7 +68,7 @@ int fpga_get_done(void) {
void fpga_postinit() {
DDRA |= _BV(PA0) | _BV(PA1) | _BV(PA2) | _BV(PA4) | _BV(PA5) | _BV(PA6); // MAPPER+NEXTADDR output
DDRB |= _BV(PB2) | _BV(PB1) | _BV(PB0); // turn PB2 into output, enable AVR_BANK
DDRB |= _BV(PB1) | _BV(PB0); // turn PB2 into output, enable AVR_BANK
DDRD |= _BV(PD7); // turn PD7 into output
}

View File

@ -20,6 +20,7 @@ void set_avr_addr_en(uint8_t val);
void set_avr_mapper(uint8_t val);
void set_avr_bank(uint8_t val);
uint8_t SPI_OFFLOAD;
#define FPGA_TEST_TOKEN (0xa5)

View File

@ -48,6 +48,7 @@
#include "spi.h"
#include "avrcompat.h"
#include "filetypes.h"
#include "sdcard.h"
void writetest(void) {
// HERE BE LIONS, GET IN THE CAR
@ -116,12 +117,6 @@ void poison_memory(void) {
}
#endif
void avr_goto_addr(const uint32_t val) {
AVR_ADDR_RESET();
for(uint32_t i=0; i<val; i++) {
AVR_NEXTADDR();
}
}
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)
int main(void) __attribute__((OS_main));
#endif
@ -189,7 +184,41 @@ restart:
uint16_t mem_dir_id = sram_readshort(SRAM_DIRID);
uint32_t mem_magic = sram_readlong(SRAM_SCRATCHPAD);
while(0) {
SD_SPI_OFFLOAD=1;
sd_read(0, file_buf, 32L, 1);
// sram_writeblock((void*)file_buf, 0, 0x200);
sram_hexdump(0,0x10);
uart_putc('+');
}
/* here be strange monsters */
while(0){
// uint16_t hurdur1 = 0, hurdur2 = 0;
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
PORTB |= _BV(PB2);
DDRB |= _BV(PB2);
PORTB &= ~_BV(PB2);
DDRB &= ~_BV(PB7); // tristate SCK
PORTB |= _BV(PB2);
DDRB &= ~_BV(PB2);
while(!(PINB & _BV(PB2))) {
}
DDRB |= _BV(PB7);
_delay_ms(1);
// dprintf("hurdur1=%d hurdur2=%d\n", hurdur1, hurdur2);
}
if((mem_magic != 0x12345678) || (mem_dir_id != saved_dir_id)) {
uint16_t curr_dir_id = scan_dir(fs_path, 0, 0); // generate files footprint
dprintf("curr dir id = %x\n", curr_dir_id);
@ -207,7 +236,7 @@ restart:
save_sram((uint8_t*)"/sd2snes/sd2snes.db", endaddr-SRAM_DB_ADDR, SRAM_DB_ADDR);
save_sram((uint8_t*)"/sd2snes/sd2snes.dir", direndaddr-(SRAM_DIR_ADDR), SRAM_DIR_ADDR);
dprintf("done\n");
sram_hexdump(SRAM_DB_ADDR, 0x400);
// sram_hexdump(SRAM_DB_ADDR, 0x400);
} else {
dprintf("saved dir id = %x\n", saved_dir_id);
dprintf("different card, consistent db, loading db...\n");
@ -229,10 +258,14 @@ restart:
led_pwm();
// sram_hexdump(0, 0x200);
uart_putc('(');
load_rom((uint8_t*)"/sd2snes/menu.bin");
set_rom_mask(0x3fffff); // force mirroring off
uart_putc(')');
uart_putcrlf();
// sram_hexdump(0, 0x200);
// save_sram((uint8_t*)"/sd2snes/dump", 65536, 0);
sram_writebyte(0, SRAM_CMD_ADDR);
@ -256,6 +289,7 @@ restart:
set_avr_ena(0);
dprintf("Selected name: %s\n", file_lfn);
load_rom(file_lfn);
// save_sram((uint8_t*)"/sd2snes/test.smc", romprops.romsize_bytes, 0);
if(romprops.ramsize_bytes) {
strcpy(strrchr((char*)file_lfn, (int)'.'), ".srm");
dprintf("SRM file: %s\n", file_lfn);
@ -281,7 +315,6 @@ restart:
uint8_t snes_reset_prev=0, snes_reset_now=0, snes_reset_state=0;
uint16_t reset_count=0;
while(fpga_test() == FPGA_TEST_TOKEN) {
dprintf("%02X\n", fpga_test());
snes_reset_now=get_snes_reset();
if(snes_reset_now) {
if(!snes_reset_prev) {

View File

@ -124,7 +124,7 @@ void sram_writeblock(void* buf, uint32_t addr, uint16_t size) {
}
uint32_t load_rom(uint8_t* filename) {
uint8_t dummy;
// uint8_t dummy;
set_avr_bank(0);
UINT bytes_read;
DWORD filesize;
@ -132,18 +132,25 @@ uint32_t load_rom(uint8_t* filename) {
file_open(filename, FA_READ);
filesize = file_handle.fsize;
smc_id(&romprops);
dprintf("no nervous breakdown beyond this point! or else!\n");
if(file_res) {
uart_putc('?');
uart_putc(0x30+file_res);
return 0;
}
f_lseek(&file_handle, romprops.offset);
spi_none();
for(;;) {
SPI_OFFLOAD=1;
spi_none();
bytes_read = file_read();
spi_none();
if (file_res || !bytes_read) break;
spi_fpga();
if(!(count++ % 8)) {
// toggle_busy_led();
bounce_busy_led();
uart_putc('.');
}
/* spi_fpga();
spiTransferByte(0x91); // write w/ increment
if(!(count++ % 8)) {
// toggle_busy_led();
@ -156,7 +163,7 @@ uint32_t load_rom(uint8_t* filename) {
loop_until_bit_is_set(SPSR, SPIF);
dummy = SPDR;
}
spiTransferByte(0x00); // dummy tx for increment+write pulse
spiTransferByte(0x00); // dummy tx for increment+write pulse */
}
file_close();
spi_none();

View File

@ -60,6 +60,7 @@
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/crc16.h>
#include <util/delay.h>
#include "config.h"
#include "avrcompat.h"
#include "crc7.h"
@ -308,6 +309,8 @@ static void sdInit(const uint8_t card) {
uint8_t i;
uint16_t counter;
SD_SPI_OFFLOAD = 0;
counter = 0xffff;
do {
// Prepare for ACMD, send CMD55: APP_CMD
@ -557,24 +560,46 @@ DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
// Get data
crc = 0;
// Initiate data exchange over SPI
SPDR = 0xff;
for (i=0; i<512; i++) {
// Wait until data has been received
loop_until_bit_is_set(SPSR, SPIF);
tmp = SPDR;
// Transmit the next byte while we store the current one
if(SD_SPI_OFFLOAD) {
// uart_putc('O');
PORTB |= _BV(PB2);
DDRB |= _BV(PB2);
PORTB &= ~_BV(PB2);
PORTB |= _BV(PB2);
PORTB &= ~_BV(PB7);
DDRB &= ~_BV(PB7); // tristate SCK
// SPCR=0;
DDRB &= ~_BV(PB2);
_delay_us(1);
loop_until_bit_is_set(PINB, PB2);
DDRB |= _BV(PB2);
// SPCR=0b01010000;
SD_SPI_OFFLOAD = 0;
deselectCard(drv);
DDRB |= _BV(PB7);
return RES_OK;
SPDR = 0xff;
*(buffer++) = tmp;
} else {
// Initiate data exchange over SPI
SPDR = 0xff;
for (i=0; i<512; i++) {
// Wait until data has been received
loop_until_bit_is_set(SPSR, SPIF);
tmp = SPDR;
// Transmit the next byte while we store the current one
SPDR = 0xff;
*(buffer++) = tmp;
#ifdef CONFIG_SD_DATACRC
crc = _crc_xmodem_update(crc, tmp);
crc = _crc_xmodem_update(crc, tmp);
#endif
}
}
// Wait until the first CRC byte is received
loop_until_bit_is_set(SPSR, SPIF);
// Check CRC
recvcrc = (SPDR << 8) + spiTransferByte(0xff);
#ifdef CONFIG_SD_DATACRC
@ -586,7 +611,6 @@ DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
continue;
}
#endif
break;
}
deselectCard(drv);

View File

@ -38,7 +38,13 @@ module avr_cmd(
input endmessage,
input startmessage,
output [23:0] saveram_mask_out,
output [23:0] rom_mask_out
output [23:0] rom_mask_out,
// SPI "DMA" extension
input spi_dma_ovr,
input spi_dma_nextaddr,
input [7:0] spi_dma_sram_data,
input spi_dma_sram_we
);
reg [3:0] MAPPER_BUF;
@ -50,6 +56,8 @@ reg [7:0] AVR_DATA_OUT_BUF;
reg [7:0] AVR_DATA_IN_BUF;
reg [1:0] avr_nextaddr_buf;
wire avr_nextaddr;
wire spi_dma_nextaddr_trig;
reg [2:0] spi_dma_nextaddr_r;
reg [1:0] SRAM_MASK_IDX;
reg [23:0] SAVERAM_MASK;
@ -59,17 +67,15 @@ assign spi_data_out = AVR_DATA_IN_BUF;
initial begin
ADDR_OUT_BUF = 0;
spi_dma_nextaddr_r = 0;
end
// command interpretation
always @(posedge clk) begin
if (cmd_ready) begin
case (cmd_data[7:4])
4'h3:
MAPPER_BUF <= cmd_data[3:0];
// 4'h8:
// AVR_DATA_IN_BUF <= avr_data_in;
// 4'hF:
// TODO AVR_DATA_IN_BUF <= 8'hA5;
endcase
end else if (param_ready) begin
case (cmd_data[7:4])
@ -102,16 +108,15 @@ always @(posedge clk) begin
32'h4:
SAVERAM_MASK[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'h1+cmd_data[4])))
if (spi_dma_nextaddr_trig | (avr_nextaddr & (cmd_data[7:5] == 3'h4) && (cmd_data[0]) && (spi_byte_cnt > (32'h1+cmd_data[4]))))
ADDR_OUT_BUF <= ADDR_OUT_BUF + 1;
end
// value fetch during last SPI bit
always @(posedge clk) begin
if (spi_bit_cnt == 3'h7)
if (cmd_data[7:4] == 4'hF)
@ -120,6 +125,7 @@ always @(posedge clk) begin
AVR_DATA_IN_BUF <= avr_data_in;
end
// nextaddr pulse generation
always @(posedge clk) begin
if (spi_bit_cnt == 3'h0)
avr_nextaddr_buf <= {avr_nextaddr_buf[0], 1'b1};
@ -127,23 +133,33 @@ always @(posedge clk) begin
avr_nextaddr_buf <= {avr_nextaddr_buf[0], 1'b0};
end
assign spi_dma_nextaddr_trig = (spi_dma_nextaddr_r[2:1] == 2'b01);
always @(posedge clk) begin
spi_dma_nextaddr_r <= {spi_dma_nextaddr_r[1:0], spi_dma_nextaddr};
end
// r/w pulse
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;
// Read pulse is two spi cycles to ensure that the value
// is ready in the 2nd cycle in AVR master mode
if ((spi_bit_cnt == 3'h6 || 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
// trigger for nextaddr
assign avr_nextaddr = avr_nextaddr_buf == 2'b01;
assign avr_read = AVR_READ_BUF;
assign avr_write = AVR_WRITE_BUF;
assign avr_write = spi_dma_ovr ? spi_dma_sram_we : AVR_WRITE_BUF;
assign addr_out = ADDR_OUT_BUF;
assign avr_data_out = AVR_DATA_OUT_BUF;
assign avr_data_out = spi_dma_ovr ? spi_dma_sram_data : AVR_DATA_OUT_BUF;
assign avr_mapper = MAPPER_BUF;
assign avr_sram_size = SRAM_SIZE_BUF;
assign rom_mask_out = ROM_MASK;

View File

@ -40,7 +40,6 @@ NET "SNES_CPU_CLK" IOSTANDARD = LVCMOS33;
NET "SNES_REFRESH" IOSTANDARD = LVCMOS33;
NET "SPI_MISO" IOSTANDARD = LVCMOS33;
NET "SPI_MOSI" IOSTANDARD = LVCMOS33;
NET "SPI_SCK" IOSTANDARD = LVCMOS33;
NET "AVR_ENA" LOC = P58;
NET "CLKIN" LOC = P125;
NET "IRQ_DIR" LOC = P40;
@ -187,5 +186,7 @@ NET "SRAM_DATA[8]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[9]" IOSTANDARD = LVCMOS33;
NET "SRAM_OE" IOSTANDARD = LVCMOS33;
NET "SRAM_WE" IOSTANDARD = LVCMOS33;
TEMPERATURE = 60 C;
VOLTAGE = 1.25 V;
NET "SPI_DMA_CTRL" LOC = P41;
NET "SPI_DMA_CTRL" IOSTANDARD = LVCMOS33;
NET "SPI_SCK" IOSTANDARD = LVCMOS33;
NET "SPI_SCK" PULLDOWN;

View File

@ -46,10 +46,11 @@ module main(
/* AVR signals */
input SPI_MOSI,
output SPI_MISO,
inout SPI_MISO,
input SPI_SS,
input SPI_SCK,
input AVR_ENA
inout SPI_SCK,
input AVR_ENA,
inout SPI_DMA_CTRL
/* debug */
//output DCM_IN_STOPPED,
@ -69,13 +70,15 @@ wire [7:0] AVR_OUT_DATA;
wire [3:0] MAPPER;
wire [23:0] SAVERAM_MASK;
wire [23:0] ROM_MASK;
wire [23:0] spi_dma_addr;
wire [7:0] spi_dma_sram_data;
wire spi_dma_trig = SPI_DMA_CTRL;
spi snes_spi(.clk(CLK2),
.MOSI(SPI_MOSI),
.MISO(SPI_MISO),
.SSEL(SPI_SS),
.SCK(SPI_SCK),
.LED(SPI_LSB),
.cmd_ready(spi_cmd_ready),
.param_ready(spi_param_ready),
.cmd_data(spi_cmd_data),
@ -84,7 +87,10 @@ spi snes_spi(.clk(CLK2),
.startmessage(spi_startmessage),
.input_data(spi_input_data),
.byte_cnt(spi_byte_cnt),
.bit_cnt(spi_bit_cnt)
.bit_cnt(spi_bit_cnt),
.spi_dma_sck(spi_dma_sck),
.spi_dma_ovr(spi_dma_ovr)
);
avr_cmd snes_avr_cmd(
@ -106,10 +112,27 @@ avr_cmd snes_avr_cmd(
.endmessage(spi_endmessage),
.startmessage(spi_startmessage),
.saveram_mask_out(SAVERAM_MASK),
.rom_mask_out(ROM_MASK)
.rom_mask_out(ROM_MASK),
.spi_dma_ovr(spi_dma_ovr),
.spi_dma_nextaddr(spi_dma_nextaddr),
.spi_dma_sram_data(spi_dma_sram_data),
.spi_dma_sram_we(spi_dma_sram_we)
);
//wire [7:0] DCM_STATUS;
spi_dma snes_spi_dma(
.clk(CLK2),
.spi_dma_ovr(spi_dma_ovr), // to spi, avr_cmd
.spi_dma_miso(SPI_MISO), // to spi
.spi_dma_sck(spi_dma_sck), // to spi
.spi_dma_trig(spi_dma_trig), // from avr
.spi_dma_nextaddr(spi_dma_nextaddr), // to avr_cmd?
.spi_dma_sram_data(spi_dma_sram_data), // to avr_cmd?
.spi_dma_sram_we(spi_dma_sram_we), // to avr_cmd?
.spi_dma_done(spi_dma_done) // to avr
);
assign SPI_DMA_CTRL = spi_dma_ovr ? 1'b0 : 1'bZ;
// dcm1: dfs 4x
my_dcm snes_dcm(.CLKIN(CLKIN),

View File

@ -46,7 +46,6 @@ module main_tf2;
wire SRAM_WE;
wire SPI_MISO;
wire MODE;
wire SPI_LSB;
wire SRAM_BHE;
wire SRAM_BLE;

View File

@ -69,6 +69,22 @@
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="spi_dma.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="Implementation"/>
<association xil_pn:name="BehavioralSimulation"/>
</file>
<file xil_pn:name="tf_spi_dma.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="PostTranslateSimulation"/>
<association xil_pn:name="PostMapSimulation"/>
<association xil_pn:name="PostRouteSimulation"/>
</file>
<file xil_pn:name="tf_main_3.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="PostTranslateSimulation"/>
<association xil_pn:name="PostMapSimulation"/>
<association xil_pn:name="PostRouteSimulation"/>
</file>
</files>
<properties>
@ -92,9 +108,9 @@
<property xil_pn:name="Optimization Effort" xil_pn:value="High"/>
<property xil_pn:name="Optimization Strategy (Cover Mode)" xil_pn:value="Balanced"/>
<property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="true"/>
<property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Module|main_tf2"/>
<property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Module|tf_main_3"/>
<property xil_pn:name="PROP_DesignName" xil_pn:value="sd2snes"/>
<property xil_pn:name="PROP_PostParSimTop" xil_pn:value="Module|main_tf2"/>
<property xil_pn:name="PROP_PostParSimTop" xil_pn:value="Module|tf_main_3"/>
<property xil_pn:name="Package" xil_pn:value="tq144"/>
<property xil_pn:name="Place &amp; Route Effort Level (Overall)" xil_pn:value="High"/>
<property xil_pn:name="Placer Effort Level (Overrides Overall Level)" xil_pn:value="High"/>
@ -104,8 +120,8 @@
<property xil_pn:name="Register Duplication" xil_pn:value="On"/>
<property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="5"/>
<property xil_pn:name="Router Effort Level (Overrides Overall Level)" xil_pn:value="High"/>
<property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="Module|main_tf2"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="Module|main_tf2"/>
<property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="Module|tf_main_3"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="Module|tf_main_3"/>
<property xil_pn:name="Selected Simulation Source Node" xil_pn:value="uut"/>
<property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)"/>
<property xil_pn:name="Speed Grade" xil_pn:value="-4"/>

View File

@ -20,11 +20,10 @@
//////////////////////////////////////////////////////////////////////////////////
module spi(input clk,
input SCK,
inout SCK,
input MOSI,
output MISO,
inout MISO,
input SSEL,
output LED,
output cmd_ready,
output param_ready,
output [7:0] cmd_data,
@ -33,15 +32,41 @@ module spi(input clk,
output startmessage,
input [7:0] input_data,
output [31:0] byte_cnt,
output [2:0] bit_cnt);
output [2:0] bit_cnt,
// spi "DMA" extension
input spi_dma_sck,
input spi_dma_ovr);
reg [7:0] cmd_data_r;
reg [7:0] param_data_r;
// sync SCK to the FPGA clock using a 3-bits shift register
// SCK is an OUTPUT in "DMA" mode
reg [2:0] spi_dma_ovr_r;
reg [9:0] spi_dma_leadout_cnt;
reg spi_dma_leadout;
initial begin
spi_dma_ovr_r = 3'b000;
spi_dma_leadout_cnt <= 10'b0000000000;
end
always @(posedge clk) spi_dma_ovr_r <= {spi_dma_ovr_r[1:0], spi_dma_ovr};
wire spi_dma_ovr_falling = (spi_dma_ovr_r[1:0] == 2'b10);
always @(posedge clk) begin
if (spi_dma_ovr_falling) begin
spi_dma_leadout <= 1;
spi_dma_leadout_cnt <= 0;
end else begin
if(spi_dma_leadout_cnt == 100)
spi_dma_leadout <= 0;
if(spi_dma_leadout)
spi_dma_leadout_cnt <= spi_dma_leadout_cnt + 1;
end
end
assign SCK = spi_dma_ovr ? spi_dma_sck : spi_dma_leadout ? 1'b0 : 1'bZ;
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
wire SCK_risingedge = spi_dma_ovr ? 0 : (SCKr[2:1]==2'b01); // now we can detect SCK rising edges
wire SCK_fallingedge = spi_dma_ovr ? 0 : (SCKr[2:1]==2'b10); // and falling edges
// same thing for SSEL
reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
@ -55,7 +80,7 @@ assign startmessage = SSEL_startmessage;
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
// bit count for one SPI byte + byte count for the message
reg [2:0] bitcnt;
reg [31:0] byte_cnt_r;
@ -66,44 +91,32 @@ 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
if(~SSEL_active) begin
bitcnt <= 3'b000;
end
else if(SCK_risingedge) begin
bitcnt <= bitcnt + 3'b001;
// shift received data into the register
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;
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
byte_data_sent <= 8'h5A; // dummy byte
else
if(SCK_fallingedge) begin
if(bitcnt==3'b000)
@ -114,7 +127,8 @@ always @(posedge clk) begin
end
end
assign MISO = SSEL_active ? byte_data_sent[7] : 1'bZ; // send MSB first
// Slave out is an INPUT in "DMA" mode
assign MISO = spi_dma_ovr ? 1'bZ : SSEL_active ? byte_data_sent[7] : 1'bZ; // send MSB first
reg cmd_ready_r;
reg param_ready_r;
@ -128,6 +142,8 @@ 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;
// fill registers
always @(posedge clk) begin
if (SSEL_startmessage)
cmd_data_r <= 8'h00;
@ -135,8 +151,9 @@ always @(posedge clk) begin
cmd_data_r <= byte_data_received;
else if(param_ready_r2)
param_data_r <= byte_data_received;
end
// delay ready signals by one clock (why did I do this again...)
always @(posedge clk) begin
cmd_ready_r <= cmd_ready_r2;
param_ready_r <= param_ready_r2;

143
verilog/sd2snes/spi_dma.v Normal file
View File

@ -0,0 +1,143 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 22:18:56 12/20/2009
// Design Name:
// Module Name: spi_dma
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module spi_dma(
input clk,
output spi_dma_ovr,
input spi_dma_miso,
output spi_dma_sck,
input spi_dma_trig,
output spi_dma_nextaddr,
output [7:0] spi_dma_sram_data,
output spi_dma_sram_we,
output spi_dma_done
);
reg spi_dma_sram_we_r;
reg spi_dma_done_r;
reg spi_dma_ovr_r;
reg spi_dma_nextaddr_r;
reg [7:0] spi_dma_sram_data_r;
reg [3:0] spi_dma_bitcnt; // extra bits
reg [9:0] spi_dma_bytecnt;
reg [3:0] spi_dma_clkcnt;
reg [3:0] spi_dma_sck_int_r;
reg [5:0] spi_dma_trig_r;
reg [1:0] spi_dma_miso_r;
reg spi_dma_sck_out_r;
reg spi_dma_sck_out_r2;
initial begin
spi_dma_clkcnt <= 4'b0000;
spi_dma_bitcnt <= 4'b1110;
spi_dma_bytecnt <= 10'b0000000000;
spi_dma_nextaddr_r <= 1'b0;
spi_dma_sram_we_r <= 1'b1;
spi_dma_done_r <= 1'b1;
spi_dma_sck_int_r <= 4'b0000;
spi_dma_trig_r <= 6'b000000;
spi_dma_ovr_r <= 1'b0;
spi_dma_sck_out_r <= 1'b0;
spi_dma_sck_out_r2 <= 1'b0;
end
// synthesize clock
wire spi_dma_sck_int = spi_dma_clkcnt[1];
assign spi_dma_sck = spi_dma_sck_out_r & spi_dma_sck_out_r2;
always @(posedge clk) begin
spi_dma_clkcnt <= spi_dma_clkcnt + 1;
spi_dma_sck_int_r <= {spi_dma_sck_int_r[2:0], spi_dma_sck_int};
spi_dma_trig_r <= {spi_dma_trig_r[4:0], spi_dma_trig};
spi_dma_miso_r <= {spi_dma_miso_r[0], spi_dma_miso};
end
wire spi_dma_trig_rising = (spi_dma_trig_r[5:1] == 5'b00011);
wire spi_dma_trig_falling = (spi_dma_trig_r[5:1] == 5'b11100);
wire spi_dma_sck_rising = (spi_dma_sck_int_r[1:0] == 2'b01);
wire spi_dma_sck_falling = (spi_dma_sck_int_r[1:0] == 2'b10);
wire spi_dma_sck_rising2 = (spi_dma_sck_int_r[1:0] == 2'b01);
wire spi_dma_sck_falling2 = (spi_dma_sck_int_r[1:0] == 2'b10);
assign spi_dma_nextaddr = spi_dma_nextaddr_r;
assign spi_dma_sram_data = spi_dma_sram_data_r;
assign spi_dma_sram_we = spi_dma_sram_we_r;
assign spi_dma_done = spi_dma_done_r;
assign spi_dma_ovr = spi_dma_ovr_r;
always @(posedge clk) begin
if (spi_dma_trig_falling & !spi_dma_ovr_r) begin
spi_dma_done_r <= 0;
spi_dma_ovr_r <= 1;
end else if (spi_dma_bitcnt == 0 && spi_dma_bytecnt == 512) begin
spi_dma_done_r <= 1;
spi_dma_ovr_r <= 0;
end
end
always @(posedge clk) begin
if(spi_dma_sck_falling)
spi_dma_sck_out_r2 <= 0;
else if(spi_dma_sck_rising)
spi_dma_sck_out_r2 <= 1;
end
always @(posedge clk) begin
if (spi_dma_sck_rising & spi_dma_ovr_r & spi_dma_bitcnt < 8)
spi_dma_sram_data_r <= {spi_dma_sram_data_r[6:0], spi_dma_miso};
end
always @(posedge clk) begin
if(spi_dma_sck_rising & spi_dma_ovr_r) begin
if (spi_dma_bitcnt < 8) begin
spi_dma_sck_out_r <= 1;
spi_dma_bitcnt <= spi_dma_bitcnt + 1;
end else if (spi_dma_bitcnt == 8) begin
spi_dma_sck_out_r <= 0;
spi_dma_bitcnt <= spi_dma_bitcnt + 1;
spi_dma_sram_we_r <= 0;
end else if (spi_dma_bitcnt == 9) begin
spi_dma_sck_out_r <= 0;
spi_dma_sram_we_r <= 1;
spi_dma_bytecnt <= spi_dma_bytecnt + 1;
spi_dma_bitcnt <= 10;
end else if (spi_dma_bitcnt == 10) begin
spi_dma_nextaddr_r <= 1;
spi_dma_bitcnt <= spi_dma_bitcnt + 1;
end else if (spi_dma_bitcnt == 11) begin
spi_dma_nextaddr_r <= 0;
spi_dma_bitcnt <= spi_dma_bitcnt + 1;
end else if (spi_dma_bitcnt == 12) begin
spi_dma_bitcnt <= 0;
end else if (spi_dma_bitcnt == 4'b1101) begin
spi_dma_sck_out_r <= 0;
spi_dma_bitcnt <= 4'b1110;
end else if (spi_dma_bitcnt == 4'b1110) begin
spi_dma_bitcnt <= spi_dma_bitcnt + 1;
end else if (spi_dma_bitcnt == 4'b1111) begin
spi_dma_bitcnt <= 0;
end
end else if (spi_dma_sck_rising & !spi_dma_ovr_r) begin
spi_dma_bitcnt <= 4'b1101;
spi_dma_bytecnt <= 10'b0000000000;
end
end
endmodule

132
verilog/sd2snes/tf_main_3.v Normal file
View File

@ -0,0 +1,132 @@
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 04:03:25 12/21/2009
// Design Name: main
// Module Name: /home/ikari/prj/sd2snes/verilog/sd2snes/tf_main_3.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 tf_main_3;
// 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 AVR_ENA;
// Outputs
wire SNES_DATABUS_OE;
wire SNES_DATABUS_DIR;
wire IRQ_DIR;
wire [19:0] SRAM_ADDR;
wire [3:0] SRAM_CE2;
wire SRAM_OE;
wire SRAM_WE;
wire SRAM_BHE;
wire SRAM_BLE;
// Bidirs
wire [7:0] SNES_DATA;
wire SNES_IRQ;
wire [15:0] SRAM_DATA;
wire SPI_MISO;
wire SPI_SCK;
wire SPI_DMA_CTRL;
reg SPI_DMA_CTRLdir;
reg SPI_DMA_CTRLr;
reg SPI_MISOdir;
reg SPI_MISOr;
// 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),
.SNES_DATABUS_OE(SNES_DATABUS_OE),
.SNES_DATABUS_DIR(SNES_DATABUS_DIR),
.IRQ_DIR(IRQ_DIR),
.SRAM_DATA(SRAM_DATA),
.SRAM_ADDR(SRAM_ADDR),
.SRAM_CE2(SRAM_CE2),
.SRAM_OE(SRAM_OE),
.SRAM_WE(SRAM_WE),
.SRAM_BHE(SRAM_BHE),
.SRAM_BLE(SRAM_BLE),
.SPI_MOSI(SPI_MOSI),
.SPI_MISO(SPI_MISO),
.SPI_SS(SPI_SS),
.SPI_SCK(SPI_SCK),
.AVR_ENA(AVR_ENA),
.SPI_DMA_CTRL(SPI_DMA_CTRL)
);
initial begin
// Initialize Inputs
CLKIN = 0;
SNES_ADDR = 0;
SNES_READ = 0;
SNES_WRITE = 0;
SNES_CS = 0;
SNES_CPU_CLK = 0;
SNES_REFRESH = 0;
SPI_MOSI = 0;
SPI_SS = 0;
AVR_ENA = 0;
SPI_DMA_CTRLr = 1;
SPI_DMA_CTRLdir = 0;
SPI_MISOr = 0;
SPI_MISOdir = 0;
// Wait 100 ns for global reset to finish
#100;
#600; // dcm?
// Add stimulus here
SPI_DMA_CTRLr = 1;
SPI_DMA_CTRLdir = 1;
#100 SPI_DMA_CTRLr = 0;
#100 SPI_DMA_CTRLr = 1'bZ;
SPI_DMA_CTRLdir = 0;
SPI_MISOdir = 1;
#260 SPI_MISOr = 1;
#80 SPI_MISOr = 0;
#80 SPI_MISOr = 0;
#80 SPI_MISOr = 1;
#80 SPI_MISOr = 0;
#80 SPI_MISOr = 1;
#80 SPI_MISOr = 0;
#80 SPI_MISOr = 1;
end
assign SPI_DMA_CTRL = SPI_DMA_CTRLdir ? SPI_DMA_CTRLr : 1'bZ;
assign SPI_MISO = SPI_MISOdir ? SPI_MISOr : 1'bZ;
always #35 CLKIN = ~CLKIN;
endmodule