mk2 fw wip
This commit is contained in:
parent
64453e2fdf
commit
fa28f6035e
@ -55,7 +55,7 @@ TARGET = $(OBJDIR)/sd2snes
|
||||
|
||||
|
||||
# List C source files here. (C dependencies are automatically generated.)
|
||||
SRC = main.c ff.c ccsbcs.c clock.c uart.c power.c led.c timer.c printf.c sdcard.c spi.c fileops.c rtc.c fpga.c
|
||||
SRC = main.c ff.c ccsbcs.c clock.c uart.c power.c led.c timer.c printf.c sdcard.c spi.c fileops.c rtc.c fpga.c fpga_spi.c snes.c smc.c memory.c crc16.c filetypes.c faulthandler.c sort.c
|
||||
|
||||
|
||||
# List Assembler source files here.
|
||||
@ -218,6 +218,9 @@ program: bin
|
||||
debug: bin
|
||||
openocd -f openocd-usb.cfg -f lpc1754.cfg
|
||||
|
||||
reset:
|
||||
openocd -f openocd-usb.cfg -f lpc1754.cfg -f reset.cfg
|
||||
|
||||
# Display size of file.
|
||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||
ELFSIZE = $(SIZE) -A $(TARGET).elf
|
||||
|
||||
17
src/config.h
17
src/config.h
@ -1,6 +1,8 @@
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
#define IN_AHBRAM __attribute__ ((section(".ahbram")))
|
||||
|
||||
#define SDCARD_DETECT (1)
|
||||
#define SDCARD_WP (0)
|
||||
#define SD_SUPPLY_VOLTAGE (1L<<21) /* 3.3V - 3.4V */
|
||||
@ -15,4 +17,19 @@
|
||||
#define CONFIG_UART_TX_BUF_SHIFT 5
|
||||
#define CONFIG_UART_BAUDRATE 921600
|
||||
#define CONFIG_UART_DEADLOCKABLE
|
||||
|
||||
#define SPI_SD 1
|
||||
#define SPI_FPGA 0
|
||||
|
||||
#define SSP_CLK_DIVISOR_FAST 4
|
||||
#define SSP_CLK_DIVISOR_SLOW 250
|
||||
#define SSP_CLK_DIVISOR_FPGA_FAST 6
|
||||
#define SSP_CLK_DIVISOR_FPGA_SLOW 16
|
||||
|
||||
#define SNES_RESET_REG LPC_GPIO1
|
||||
#define SNES_RESET_BIT 29
|
||||
// Rev.B: 26
|
||||
|
||||
#define QSORT_MAXELEM 1024
|
||||
|
||||
#endif
|
||||
|
||||
51
src/crc16.c
Normal file
51
src/crc16.c
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* \file stdout
|
||||
* Functions and types for CRC checks.
|
||||
*
|
||||
* Generated on Tue Jun 30 23:02:59 2009,
|
||||
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
|
||||
* using the configuration:
|
||||
* Width = 16
|
||||
* Poly = 0x8005
|
||||
* XorIn = 0x0000
|
||||
* ReflectIn = True
|
||||
* XorOut = 0x0000
|
||||
* ReflectOut = True
|
||||
* Algorithm = bit-by-bit-fast
|
||||
* Direct = True
|
||||
*****************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include "crc16.h"
|
||||
/**
|
||||
* Update the crc value with new data.
|
||||
*
|
||||
* \param crc The current crc value.
|
||||
* \param data Pointer to a buffer of \a data_len bytes.
|
||||
* \param data_len Number of bytes in the \a data buffer.
|
||||
* \return The updated crc value.
|
||||
*****************************************************************************/
|
||||
crc_t crc16_update(crc_t crc, const unsigned char *data, size_t data_len)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t bit;
|
||||
unsigned char c;
|
||||
|
||||
while (data_len--) {
|
||||
c = *data++;
|
||||
for (i = 0x01; i & 0xff; i <<= 1) {
|
||||
bit = (crc & 0x8000 ? 1 : 0);
|
||||
if (c & i) {
|
||||
bit ^= 1;
|
||||
}
|
||||
crc <<= 1;
|
||||
if (bit) {
|
||||
crc ^= 0x8005;
|
||||
}
|
||||
}
|
||||
crc &= 0xffff;
|
||||
}
|
||||
return crc & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
54
src/crc16.h
Normal file
54
src/crc16.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* \file stdout
|
||||
* Functions and types for CRC checks.
|
||||
*
|
||||
* Generated on Tue Jun 30 23:02:56 2009,
|
||||
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
|
||||
* using the configuration:
|
||||
* Width = 16
|
||||
* Poly = 0x8005
|
||||
* XorIn = 0x0000
|
||||
* ReflectIn = True
|
||||
* XorOut = 0x0000
|
||||
* ReflectOut = True
|
||||
* Algorithm = bit-by-bit-fast
|
||||
* Direct = True
|
||||
*****************************************************************************/
|
||||
#ifndef __STDOUT__
|
||||
#define __STDOUT__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The definition of the used algorithm.
|
||||
*****************************************************************************/
|
||||
#define CRC_ALGO_BIT_BY_BIT_FAST 1
|
||||
|
||||
/**
|
||||
* The type of the CRC values.
|
||||
*
|
||||
* This type must be big enough to contain at least 16 bits.
|
||||
*****************************************************************************/
|
||||
typedef uint16_t crc_t;
|
||||
|
||||
/**
|
||||
* Update the crc value with new data.
|
||||
*
|
||||
* \param crc The current crc value.
|
||||
* \param data Pointer to a buffer of \a data_len bytes.
|
||||
* \param data_len Number of bytes in the \a data buffer.
|
||||
* \return The updated crc value.
|
||||
*****************************************************************************/
|
||||
crc_t crc16_update(crc_t crc, const unsigned char *data, size_t data_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* closing brace for extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __STDOUT__ */
|
||||
|
||||
20
src/faulthandler.c
Normal file
20
src/faulthandler.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "uart.h"
|
||||
|
||||
void HardFault_Handler(void) {
|
||||
printf("HFSR: %lx\n", SCB->HFSR);
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
void MemManage_Handler(void) {
|
||||
printf("MemManage - CFSR: %lx; MMFAR: %lx\n", SCB->CFSR, SCB->MMFAR);
|
||||
}
|
||||
|
||||
void BusFault_Handler(void) {
|
||||
printf("BusFault - CFSR: %lx; BFAR: %lx\n", SCB->CFSR, SCB->BFAR);
|
||||
}
|
||||
|
||||
void UsageFault_Handler(void) {
|
||||
printf("UsageFault - CFSR: %lx; BFAR: %lx\n", SCB->CFSR, SCB->BFAR);
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
#ifndef FILEOPS_H
|
||||
#define FILEOPS_H
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "ff.h"
|
||||
|
||||
BYTE file_buf[512];
|
||||
|
||||
@ -26,8 +26,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/delay.h>
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "filetypes.h"
|
||||
@ -37,13 +35,14 @@
|
||||
#include "crc16.h"
|
||||
#include "memory.h"
|
||||
#include "led.h"
|
||||
#include "sort.h"
|
||||
|
||||
uint16_t scan_flat(const char* path) {
|
||||
DIR dir;
|
||||
FRESULT res;
|
||||
FILINFO fno;
|
||||
fno.lfn = NULL;
|
||||
res = f_opendir(&dir, (unsigned char*)path);
|
||||
fno.lfname = NULL;
|
||||
res = f_opendir(&dir, (TCHAR*)path);
|
||||
uint16_t numentries = 0;
|
||||
if (res == FR_OK) {
|
||||
for (;;) {
|
||||
@ -60,7 +59,7 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
FILINFO fno;
|
||||
FRESULT res;
|
||||
uint8_t len;
|
||||
unsigned char* fn;
|
||||
TCHAR* fn;
|
||||
static unsigned char depth = 0;
|
||||
static uint16_t crc;
|
||||
static uint32_t db_tgt;
|
||||
@ -81,10 +80,11 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
next_subdir_tgt = SRAM_DIR_ADDR;
|
||||
this_dir_tgt = SRAM_DIR_ADDR;
|
||||
parent_tgt = 0;
|
||||
dprintf("root dir @%lx\n", dir_tgt);
|
||||
printf("root dir @%lx\n", dir_tgt);
|
||||
}
|
||||
|
||||
fno.lfn = file_lfn;
|
||||
fno.lfsize = 255;
|
||||
fno.lfname = (TCHAR*)file_lfn;
|
||||
numentries=0;
|
||||
for(pass = 0; pass < 2; pass++) {
|
||||
if(pass) {
|
||||
@ -95,24 +95,24 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
if(next_subdir_tgt > dir_end) {
|
||||
dir_end = next_subdir_tgt;
|
||||
}
|
||||
dprintf("path=%s depth=%d ptr=%lx entries=%d parent=%lx next subdir @%lx\n", path, depth, db_tgt, numentries, parent_tgt, next_subdir_tgt /*dir_tgt_next*/);
|
||||
printf("path=%s depth=%d ptr=%lx entries=%d parent=%lx next subdir @%lx\n", path, depth, db_tgt, numentries, parent_tgt, next_subdir_tgt /*dir_tgt_next*/);
|
||||
// _delay_ms(50);
|
||||
if(mkdb) {
|
||||
dprintf("d=%d Saving %lX to Address %lX [end]\n", depth, 0L, next_subdir_tgt - 4);
|
||||
printf("d=%d Saving %lx to Address %lx [end]\n", depth, 0L, next_subdir_tgt - 4);
|
||||
// _delay_ms(50);
|
||||
sram_writelong(0L, next_subdir_tgt - 4);
|
||||
}
|
||||
}
|
||||
res = f_opendir(&dir, (unsigned char*)path);
|
||||
res = f_opendir(&dir, (TCHAR*)path);
|
||||
if (res == FR_OK) {
|
||||
if(pass && parent_tgt && mkdb) {
|
||||
// write backlink to parent dir
|
||||
// switch to next bank if record does not fit in current bank
|
||||
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt)+sizeof(len)+4))&0xffff)) {
|
||||
dprintf("switch! old=%lx ", db_tgt);
|
||||
printf("switch! old=%lx ", db_tgt);
|
||||
db_tgt &= 0xffff0000;
|
||||
db_tgt += 0x00010000;
|
||||
dprintf("new=%lx\n", db_tgt);
|
||||
printf("new=%lx\n", db_tgt);
|
||||
}
|
||||
sram_writelong((parent_tgt-SRAM_MENU_ADDR), db_tgt);
|
||||
sram_writebyte(0, db_tgt+sizeof(next_subdir_tgt));
|
||||
@ -123,7 +123,7 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
}
|
||||
len = strlen((char*)path);
|
||||
for (;;) {
|
||||
toggle_busy_led();
|
||||
toggle_read_led();
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res != FR_OK || fno.fname[0] == 0) {
|
||||
if(pass) {
|
||||
@ -131,8 +131,8 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
fn = *fno.lfn ? fno.lfn : fno.fname;
|
||||
// dprintf("%s\n", fn);
|
||||
fn = *fno.lfname ? fno.lfname : fno.fname;
|
||||
// printf("%s\n", fn);
|
||||
// _delay_ms(100);
|
||||
if (*fn == '.') continue;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
@ -144,7 +144,7 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
if(mkdb) {
|
||||
uint16_t pathlen = strlen(path);
|
||||
// write element pointer to current dir structure
|
||||
dprintf("d=%d Saving %lX to Address %lX [dir]\n", depth, db_tgt, dir_tgt);
|
||||
printf("d=%d Saving %lx to Address %lx [dir]\n", depth, db_tgt, dir_tgt);
|
||||
// _delay_ms(50);
|
||||
sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
|
||||
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt_save, sizeof(dir_tgt_save));
|
||||
@ -153,12 +153,12 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
// - path name
|
||||
// - pointer to sub dir structure
|
||||
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2))&0xffff)) {
|
||||
dprintf("switch! old=%lx ", db_tgt);
|
||||
printf("switch! old=%lx ", db_tgt);
|
||||
db_tgt &= 0xffff0000;
|
||||
db_tgt += 0x00010000;
|
||||
dprintf("new=%lx\n", db_tgt);
|
||||
printf("new=%lx\n", db_tgt);
|
||||
}
|
||||
dprintf(" Saving dir descriptor to %lX, tgt=%lX, path=%s\n", db_tgt, next_subdir_tgt, path);
|
||||
printf(" Saving dir descriptor to %lx tgt=%lx, path=%s\n", db_tgt, next_subdir_tgt, path);
|
||||
// _delay_ms(100);
|
||||
sram_writelong((next_subdir_tgt-SRAM_MENU_ADDR), db_tgt);
|
||||
sram_writebyte(len+1, db_tgt+sizeof(next_subdir_tgt));
|
||||
@ -189,20 +189,20 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
case TYPE_SMC:
|
||||
// XXX file_open_by_filinfo(&fno);
|
||||
// XXX if(file_res){
|
||||
// XXX dprintf("ZOMG NOOOO %d\n", file_res);
|
||||
// XXX printf("ZOMG NOOOO %d\n", file_res);
|
||||
// XXX _delay_ms(30);
|
||||
// XXX }
|
||||
// XXX smc_id(&romprops);
|
||||
// XXX file_close();
|
||||
// _delay_ms(30);
|
||||
// write element pointer to current dir structure
|
||||
// dprintf("d=%d Saving %lX to Address %lX [file]\n", depth, db_tgt, dir_tgt);
|
||||
// printf("d=%d Saving %lX to Address %lX [file]\n", depth, db_tgt, dir_tgt);
|
||||
// _delay_ms(50);
|
||||
if((db_tgt&0xffff) > ((0x10000-(sizeof(romprops) + sizeof(len) + pathlen + 1))&0xffff)) {
|
||||
dprintf("switch! old=%lx ", db_tgt);
|
||||
printf("switch! old=%lx ", db_tgt);
|
||||
db_tgt &= 0xffff0000;
|
||||
db_tgt += 0x00010000;
|
||||
dprintf("new=%lx\n", db_tgt);
|
||||
printf("new=%lx\n", db_tgt);
|
||||
}
|
||||
sram_writelong((db_tgt-SRAM_MENU_ADDR), dir_tgt);
|
||||
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt, sizeof(db_tgt));
|
||||
@ -220,23 +220,23 @@ uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
||||
break;
|
||||
}
|
||||
path[len]=0;
|
||||
// dprintf("%s ", path);
|
||||
// printf("%s ", path);
|
||||
// _delay_ms(30);
|
||||
}
|
||||
} else {
|
||||
unsigned char* sfn = fno.fname;
|
||||
TCHAR* sfn = fno.fname;
|
||||
while(*sfn != 0) {
|
||||
crc += crc16_update(crc, sfn++, 1);
|
||||
crc += crc16_update(crc, (unsigned char*)sfn++, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// dprintf("%s/%s\n", path, fn);
|
||||
// printf("%s/%s\n", path, fn);
|
||||
// _delay_ms(50);
|
||||
}
|
||||
}
|
||||
} else uart_putc(0x30+res);
|
||||
}
|
||||
// dprintf("%x\n", crc);
|
||||
// printf("%x\n", crc);
|
||||
// _delay_ms(50);
|
||||
sram_writelong(db_tgt, SRAM_DB_ADDR+4);
|
||||
sram_writelong(dir_end, SRAM_DB_ADDR+8);
|
||||
@ -248,7 +248,7 @@ SNES_FTYPE determine_filetype(char* filename) {
|
||||
char* ext = strrchr(filename, '.');
|
||||
if(ext == NULL)
|
||||
return TYPE_UNKNOWN;
|
||||
if(!strcasecmp_P(ext+1, PSTR("SMC"))) {
|
||||
if(!strcasecmp(ext+1, "SMC")) {
|
||||
return TYPE_SMC;
|
||||
}/* later
|
||||
if(!strcasecmp_P(ext+1, PSTR("SRM"))) {
|
||||
@ -271,3 +271,25 @@ FRESULT get_db_id(uint16_t* id) {
|
||||
}
|
||||
return file_res;
|
||||
}
|
||||
|
||||
int get_num_dirent(uint32_t addr) {
|
||||
int result = 0;
|
||||
while(sram_readlong(addr+result*4)) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void sort_all_dir(uint32_t endaddr) {
|
||||
uint32_t entries = 0;
|
||||
uint32_t current_base = SRAM_DIR_ADDR;
|
||||
while(current_base<(endaddr)) {
|
||||
while(sram_readlong(current_base+entries*4)) {
|
||||
entries++;
|
||||
}
|
||||
printf("sorting dir @%lx, entries: %ld\n", current_base, entries);
|
||||
sort_dir(current_base, entries);
|
||||
current_base += 4*entries + 4;
|
||||
entries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,10 @@ typedef enum {
|
||||
char fs_path[256];
|
||||
SNES_FTYPE determine_filetype(char* filename);
|
||||
//uint32_t scan_fs();
|
||||
uint16_t scan_flat(const char* path);
|
||||
uint16_t scan_dir(char* path, char mkdb, uint32_t this_subdir_tgt);
|
||||
FRESULT get_db_id(uint16_t*);
|
||||
int get_num_dirent(uint32_t addr);
|
||||
void sort_all_dir(uint32_t endaddr);
|
||||
|
||||
#endif
|
||||
|
||||
152
src/fpga.c
Normal file
152
src/fpga.c
Normal file
@ -0,0 +1,152 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
fpga.c: FPGA (re)configuration
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
FPGA pin mapping
|
||||
================
|
||||
CCLK P0.11 out
|
||||
PROG_B P1.10 out
|
||||
INIT_B P2.9 in
|
||||
DIN P2.8 out
|
||||
DONE P0.22 in
|
||||
*/
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "bits.h"
|
||||
|
||||
#include "fpga.h"
|
||||
#include "fpga_spi.h"
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "sdcard.h"
|
||||
#include "diskio.h"
|
||||
#include "integer.h"
|
||||
#include "ff.h"
|
||||
#include "fileops.h"
|
||||
// XXX #include "fpga_spi.h"
|
||||
#include "spi.h"
|
||||
#include "led.h"
|
||||
#include "timer.h"
|
||||
|
||||
/*DWORD get_fattime(void) {
|
||||
return 0L;
|
||||
}*/
|
||||
void fpga_set_prog_b(uint8_t val) {
|
||||
if(val)
|
||||
BITBAND(PROGBREG->FIOSET, PROGBBIT) = 1;
|
||||
else
|
||||
BITBAND(PROGBREG->FIOCLR, PROGBBIT) = 1;
|
||||
}
|
||||
|
||||
void fpga_set_cclk(uint8_t val) {
|
||||
if(val)
|
||||
BITBAND(CCLKREG->FIOSET, CCLKBIT) = 1;
|
||||
else
|
||||
BITBAND(CCLKREG->FIOCLR, CCLKBIT) = 1;
|
||||
}
|
||||
|
||||
int fpga_get_initb() {
|
||||
return BITBAND(INITBREG->FIOPIN, INITBBIT);
|
||||
}
|
||||
|
||||
void fpga_init() {
|
||||
/* mainly GPIO directions */
|
||||
BITBAND(CCLKREG->FIODIR, CCLKBIT) = 1; /* CCLK */
|
||||
BITBAND(DONEREG->FIODIR, DONEBIT) = 0; /* DONE */
|
||||
BITBAND(PROGBREG->FIODIR, PROGBBIT) = 1; /* PROG_B */
|
||||
BITBAND(DINREG->FIODIR, DINBIT) = 1; /* DIN */
|
||||
BITBAND(INITBREG->FIODIR, INITBBIT) = 0; /* INIT_B */
|
||||
|
||||
LPC_GPIO2->FIOMASK1 = 0;
|
||||
|
||||
SPI_OFFLOAD=0;
|
||||
fpga_set_cclk(0); /* initial clk=0 */
|
||||
}
|
||||
|
||||
int fpga_get_done(void) {
|
||||
return BITBAND(LPC_GPIO0->FIOPIN, 22);
|
||||
}
|
||||
|
||||
void fpga_postinit() {
|
||||
LPC_GPIO2->FIOMASK1 = 0;
|
||||
}
|
||||
|
||||
void fpga_pgm(uint8_t* filename) {
|
||||
int MAXRETRIES = 10;
|
||||
int retries = MAXRETRIES;
|
||||
do {
|
||||
fpga_set_prog_b(0);
|
||||
uart_putc('P');
|
||||
fpga_set_prog_b(1);
|
||||
while(!fpga_get_initb());
|
||||
LPC_GPIO2->FIOMASK1 = ~(BV(0));
|
||||
uart_putc('p');
|
||||
|
||||
UINT bytes_read;
|
||||
|
||||
// open configware file
|
||||
file_open(filename, FA_READ);
|
||||
if(file_res) {
|
||||
uart_putc('?');
|
||||
uart_putc(0x30+file_res);
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bytes_read = file_read();
|
||||
if (file_res || bytes_read == 0) break; // error or eof
|
||||
for(int i=0; i<bytes_read; i++) {
|
||||
FPGA_SEND_BYTE_SERIAL(file_buf[i]);
|
||||
}
|
||||
}
|
||||
file_close();
|
||||
} while (!fpga_get_done() && retries--);
|
||||
if(!fpga_get_done()) {
|
||||
printf("FPGA failed to configure after %d tries.\n", MAXRETRIES);
|
||||
delay_ms(50);
|
||||
led_panic();
|
||||
}
|
||||
printf("FPGA configured\n");
|
||||
fpga_postinit();
|
||||
}
|
||||
|
||||
void set_mcu_ovr(uint8_t val) {
|
||||
if(!val) { // shared mode
|
||||
FPGA_SPI_SLOW();
|
||||
SET_MCU_OVR();
|
||||
// Disable SPI double speed mode -> clock = f/4
|
||||
// XXX SPSR = 0;
|
||||
printf("SPI slow\n");
|
||||
} else { // mcu only
|
||||
FPGA_SPI_FAST();
|
||||
CLR_MCU_OVR();
|
||||
// Enable SPI double speed mode -> clock = f/2
|
||||
// XXX SPSR = _BV(SPI2X);
|
||||
printf("SPI fast\n");
|
||||
}
|
||||
}
|
||||
|
||||
74
src/fpga.h
Normal file
74
src/fpga.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
fpga.h: FPGA (re)configuration
|
||||
*/
|
||||
|
||||
#ifndef FPGA_H
|
||||
#define FPGA_H
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "bits.h"
|
||||
|
||||
void fpga_set_prog_b(uint8_t val);
|
||||
void fpga_set_cclk(uint8_t val);
|
||||
int fpga_get_initb(void);
|
||||
|
||||
void fpga_init(void);
|
||||
uint8_t fpga_test(void);
|
||||
void fpga_postinit(void);
|
||||
void fpga_pgm(uint8_t* filename);
|
||||
|
||||
void set_mcu_ovr(uint8_t val);
|
||||
|
||||
|
||||
uint8_t SPI_OFFLOAD;
|
||||
|
||||
#define CCLKREG LPC_GPIO0
|
||||
#define PROGBREG LPC_GPIO1
|
||||
#define INITBREG LPC_GPIO2
|
||||
#define DINREG LPC_GPIO2
|
||||
#define DONEREG LPC_GPIO0
|
||||
|
||||
#define CCLKBIT (11)
|
||||
#define PROGBBIT (10)
|
||||
#define INITBBIT (9)
|
||||
#define DINBIT (8)
|
||||
#define DONEBIT (22)
|
||||
|
||||
|
||||
#define FPGA_TEST_TOKEN (0xa5)
|
||||
|
||||
// some macros for bulk transfers (faster)
|
||||
#define FPGA_SEND_BYTE_SERIAL(data) do {SET_FPGA_DIN(data>>7); CCLK();\
|
||||
SET_FPGA_DIN(data>>6); CCLK(); SET_FPGA_DIN(data>>5); CCLK();\
|
||||
SET_FPGA_DIN(data>>4); CCLK(); SET_FPGA_DIN(data>>3); CCLK();\
|
||||
SET_FPGA_DIN(data>>2); CCLK(); SET_FPGA_DIN(data>>1); CCLK();\
|
||||
SET_FPGA_DIN(data); CCLK();} while (0)
|
||||
#define SET_CCLK() do {BITBAND(LPC_GPIO0->FIOSET, 11) = 1;} while (0)
|
||||
#define CLR_CCLK() do {BITBAND(LPC_GPIO0->FIOCLR, 11) = 1;} while (0)
|
||||
#define CCLK() do {SET_CCLK(); CLR_CCLK();} while (0)
|
||||
#define SET_MCU_OVR() do {BITBAND(LPC_GPIO2->FIOSET, 8) = 1;} while (0)
|
||||
#define CLR_MCU_OVR() do {BITBAND(LPC_GPIO2->FIOCLR, 8) = 1;} while (0)
|
||||
#define SET_FPGA_DIN(data) do {LPC_GPIO2->FIOPIN1 = data;} while (0)
|
||||
#endif
|
||||
99
src/fpga_spi.c
Normal file
99
src/fpga_spi.c
Normal file
@ -0,0 +1,99 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
fpga_spi.h: functions for SPI ctrl, SRAM interfacing and feature configuration
|
||||
*/
|
||||
/*
|
||||
|
||||
SPI commands
|
||||
|
||||
cmd param function
|
||||
=============================================
|
||||
00 bb[hh[ll]] set address to 0xbb0000, 0xbbhh00, or 0xbbhhll
|
||||
10 bbhhll set SNES input address mask to 0xbbhhll
|
||||
20 bbhhll set SRAM address mask to 0xbbhhll
|
||||
3m - set mapper to m
|
||||
0=HiROM, 1=LoROM, 2=ExHiROM, 7=Menu
|
||||
80 - read with increment
|
||||
81 - read w/o increment
|
||||
90 {xx}* write xx with increment
|
||||
91 {xx}* write xx w/o increment
|
||||
F0 - receive test token (to see if FPGA is alive)
|
||||
|
||||
*/
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "bits.h"
|
||||
#include "fpga.h"
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "spi.h"
|
||||
#include "fpga_spi.h"
|
||||
#include "timer.h"
|
||||
|
||||
void fpga_spi_init(void) {
|
||||
spi_init(SPI_SPEED_FPGA_FAST, SPI_FPGA);
|
||||
}
|
||||
|
||||
void set_mcu_addr(uint32_t address) {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x00);
|
||||
FPGA_TX_BYTE((address>>16)&0xff);
|
||||
FPGA_TX_BYTE((address>>8)&0xff);
|
||||
FPGA_TX_BYTE((address)&0xff);
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void set_saveram_mask(uint32_t mask) {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x20);
|
||||
FPGA_TX_BYTE((mask>>16)&0xff);
|
||||
FPGA_TX_BYTE((mask>>8)&0xff);
|
||||
FPGA_TX_BYTE((mask)&0xff);
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void set_rom_mask(uint32_t mask) {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x10);
|
||||
FPGA_TX_BYTE((mask>>16)&0xff);
|
||||
FPGA_TX_BYTE((mask>>8)&0xff);
|
||||
FPGA_TX_BYTE((mask)&0xff);
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void set_mapper(uint8_t val) {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x30 | (val & 0x0f));
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
uint8_t fpga_test() {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0xF0); // TEST
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
uint8_t result = FPGA_RX_BYTE();
|
||||
FPGA_DESELECT();
|
||||
return result;
|
||||
}
|
||||
|
||||
59
src/fpga_spi.h
Normal file
59
src/fpga_spi.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
fpga_spi.h: functions for SPI ctrl, SRAM interfacing and feature configuration
|
||||
*/
|
||||
|
||||
#ifndef _FPGA_SPI_H
|
||||
#define _FPGA_SPI_H
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "bits.h"
|
||||
|
||||
#define FPGA_SS_BIT 16
|
||||
#define FPGA_SS_REG LPC_GPIO0
|
||||
|
||||
#define FPGA_SELECT() do {FPGA_TX_SYNC(); BITBAND(FPGA_SS_REG->FIOCLR, FPGA_SS_BIT) = 1;} while (0)
|
||||
#define FPGA_DESELECT() do {FPGA_TX_SYNC(); BITBAND(FPGA_SS_REG->FIOSET, FPGA_SS_BIT) = 1;} while (0)
|
||||
|
||||
#define FPGA_TX_SYNC() spi_tx_sync(SPI_FPGA)
|
||||
#define FPGA_TX_BYTE(x) spi_tx_byte(x, SPI_FPGA)
|
||||
#define FPGA_RX_BYTE() spi_rx_byte(SPI_FPGA)
|
||||
#define FPGA_TXRX_BYTE(x) spi_txrx_byte(x, SPI_FPGA)
|
||||
#define FPGA_TX_BLOCK(x,y) spi_tx_block(x,y,SPI_FPGA)
|
||||
#define FPGA_RX_BLOCK(x,y) spi_rx_block(x,y,SPI_FPGA)
|
||||
|
||||
#define FPGA_SPI_FAST() spi_set_speed(SPI_SPEED_FPGA_FAST, SPI_FPGA)
|
||||
#define FPGA_SPI_SLOW() spi_set_speed(SPI_SPEED_FPGA_SLOW, SPI_FPGA)
|
||||
|
||||
void fpga_spi_init(void);
|
||||
void fpga_spi_test(void);
|
||||
void spi_fpga(void);
|
||||
void spi_sd(void);
|
||||
void spi_none(void);
|
||||
void set_mcu_addr(uint32_t);
|
||||
void set_saveram_mask(uint32_t);
|
||||
void set_rom_mask(uint32_t);
|
||||
void set_mapper(uint8_t val);
|
||||
|
||||
#endif
|
||||
16
src/led.c
16
src/led.c
@ -6,6 +6,8 @@
|
||||
#include "led.h"
|
||||
|
||||
int led_rdyledstate = 0;
|
||||
int led_readledstate = 0;
|
||||
int led_writeledstate = 0;
|
||||
|
||||
void rdyled(unsigned int state) {
|
||||
BITBAND(LPC_GPIO2->FIODIR, 0) = state;
|
||||
@ -14,6 +16,12 @@ void rdyled(unsigned int state) {
|
||||
|
||||
void readled(unsigned int state) {
|
||||
BITBAND(LPC_GPIO2->FIODIR, 1) = state;
|
||||
led_readledstate = state;
|
||||
}
|
||||
|
||||
void writeled(unsigned int state) {
|
||||
BITBAND(LPC_GPIO2->FIODIR, 2) = state;
|
||||
led_writeledstate = state;
|
||||
}
|
||||
|
||||
void led_clkout32(uint32_t val) {
|
||||
@ -31,6 +39,14 @@ void toggle_rdy_led() {
|
||||
rdyled(~led_rdyledstate);
|
||||
}
|
||||
|
||||
void toggle_read_led() {
|
||||
readled(~led_readledstate);
|
||||
}
|
||||
|
||||
void toggle_write_led() {
|
||||
writeled(~led_writeledstate);
|
||||
}
|
||||
|
||||
void led_panic() {
|
||||
while(1) {
|
||||
LPC_GPIO2->FIODIR |= BV(0) | BV(1) | BV(2);
|
||||
|
||||
@ -4,9 +4,12 @@
|
||||
#define _LED_H
|
||||
|
||||
void readled(unsigned int state);
|
||||
void writeled(unsigned int state);
|
||||
void rdyled(unsigned int state);
|
||||
void led_clkout32(uint32_t val);
|
||||
void toggle_rdy_led(void);
|
||||
void toggle_read_led(void);
|
||||
void toggle_write_led(void);
|
||||
void led_panic(void);
|
||||
|
||||
#endif
|
||||
|
||||
215
src/main.c
215
src/main.c
@ -1,4 +1,5 @@
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "clock.h"
|
||||
#include "uart.h"
|
||||
@ -11,6 +12,12 @@
|
||||
#include "sdcard.h"
|
||||
#include "fileops.h"
|
||||
#include "fpga.h"
|
||||
#include "fpga_spi.h"
|
||||
#include "filetypes.h"
|
||||
#include "memory.h"
|
||||
#include "snes.h"
|
||||
#include "led.h"
|
||||
#include "sort.h"
|
||||
|
||||
#define EMC0TOGGLE (3<<4)
|
||||
#define MR0R (1<<1)
|
||||
@ -23,21 +30,31 @@ volatile enum diskstates disk_state;
|
||||
int main(void) {
|
||||
LPC_GPIO2->FIODIR = BV(0) | BV(1) | BV(2);
|
||||
LPC_GPIO1->FIODIR = 0;
|
||||
uint32_t p1;
|
||||
LPC_GPIO0->FIODIR = BV(16);
|
||||
|
||||
/* connect UART3 on P0[25:26] + SSP1 on P0[6:9] + MAT3.0 on P0[10] */
|
||||
LPC_PINCON->PINSEL1=(0xf<<18);
|
||||
LPC_PINCON->PINSEL0=BV(13) | BV(15) | BV(17) | BV(19) | BV(20) | BV(21);
|
||||
/* connect UART3 on P0[25:26] + SSP0 on P0[15:18] SSP1 on P0[6:9] + MAT3.0 on P0[10] */
|
||||
LPC_PINCON->PINSEL1 = BV(18) | BV(19) | BV(20) | BV(21) /* UART3 */
|
||||
| BV(3) | BV(5); /* SSP0 (FPGA) except SS */
|
||||
LPC_PINCON->PINSEL0 = BV(31) /* SSP0 */
|
||||
| BV(13) | BV(15) | BV(17) | BV(19) /* SSP1 (SD) */
|
||||
| BV(20) | BV(21); /* MAT3.0 */
|
||||
|
||||
/* enable pull-downs for CIC data lines */
|
||||
LPC_PINCON->PINMODE3 = BV(18) | BV(19) | BV(20) | BV(21);
|
||||
clock_disconnect();
|
||||
|
||||
snes_init();
|
||||
snes_reset(1);
|
||||
power_init();
|
||||
timer_init();
|
||||
uart_init();
|
||||
spi_init(SPI_SPEED_SLOW);
|
||||
sd_init();
|
||||
fpga_spi_init();
|
||||
spi_preinit(SPI_FPGA);
|
||||
spi_preinit(SPI_SD);
|
||||
/* do this last because the peripheral init()s change PCLK dividers */
|
||||
clock_init();
|
||||
|
||||
sd_init();
|
||||
fpga_spi_init();
|
||||
delay_ms(10);
|
||||
printf("\n\nsd2snes mk.2\n============\ncpu clock: %d Hz\n", CONFIG_CPU_FREQUENCY);
|
||||
file_init();
|
||||
@ -57,12 +74,194 @@ int main(void) {
|
||||
LPC_TIM3->MCR=MR0R;
|
||||
LPC_TIM3->MR0=1;
|
||||
LPC_TIM3->TCR=1;
|
||||
uart_puts("hurr durr derpderpderp\n");
|
||||
fpga_init();
|
||||
fpga_pgm((uint8_t*)"/sd2snes/main.bit");
|
||||
restart:
|
||||
rdyled(1);
|
||||
readled(0);
|
||||
writeled(0);
|
||||
set_mcu_ovr(1); // exclusive mode
|
||||
|
||||
*fs_path=0;
|
||||
uint16_t saved_dir_id;
|
||||
get_db_id(&saved_dir_id);
|
||||
|
||||
uint16_t mem_dir_id = sram_readshort(SRAM_DIRID);
|
||||
uint32_t mem_magic = sram_readlong(SRAM_SCRATCHPAD);
|
||||
|
||||
if((mem_magic != 0x12345678) || (mem_dir_id != saved_dir_id)) {
|
||||
uint16_t curr_dir_id = scan_dir(fs_path, 0, 0); // generate files footprint
|
||||
printf("curr dir id = %x\n", curr_dir_id);
|
||||
if((get_db_id(&saved_dir_id) != FR_OK) // no database?
|
||||
|| saved_dir_id != curr_dir_id) { // files changed? // XXX
|
||||
printf("saved dir id = %x\n", saved_dir_id);
|
||||
printf("rebuilding database...");
|
||||
curr_dir_id = scan_dir(fs_path, 1, 0); // then rebuild database
|
||||
sram_writeblock(&curr_dir_id, SRAM_DB_ADDR, 2);
|
||||
uint32_t endaddr, direndaddr;
|
||||
sram_readblock(&endaddr, SRAM_DB_ADDR+4, 4);
|
||||
sram_readblock(&direndaddr, SRAM_DB_ADDR+8, 4);
|
||||
printf("%lx %lx\n", endaddr, direndaddr);
|
||||
printf("sorting database...");
|
||||
sort_all_dir(direndaddr);
|
||||
printf("done\n");
|
||||
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);
|
||||
printf("done\n");
|
||||
// sram_hexdump(SRAM_DB_ADDR, 0x400);
|
||||
} else {
|
||||
printf("saved dir id = %x\n", saved_dir_id);
|
||||
printf("different card, consistent db, loading db...\n");
|
||||
load_sram((uint8_t*)"/sd2snes/sd2snes.db", SRAM_DB_ADDR);
|
||||
load_sram((uint8_t*)"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR);
|
||||
}
|
||||
// save_sram((uint8_t*)"/debug.smc", 0x400000, 0);
|
||||
// uart_putc('[');
|
||||
// load_sram((uint8_t*)"/test.srm", SRAM_SAVE_ADDR);
|
||||
// uart_putc(']');
|
||||
|
||||
sram_writeshort(curr_dir_id, SRAM_DIRID);
|
||||
sram_writelong(0x12345678, SRAM_SCRATCHPAD);
|
||||
} else {
|
||||
printf("same card, loading db...\n");
|
||||
load_sram((uint8_t*)"/sd2snes/sd2snes.db", SRAM_DB_ADDR);
|
||||
load_sram((uint8_t*)"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR);
|
||||
}
|
||||
|
||||
uart_putc('(');
|
||||
load_rom((uint8_t*)"/sd2snes/menu.bin", SRAM_MENU_ADDR);
|
||||
set_rom_mask(0x3fffff); // force mirroring off
|
||||
set_mapper(0x7); // menu mapper XXX
|
||||
uart_putc(')');
|
||||
uart_putcrlf();
|
||||
// sram_hexdump(0x7ffff0, 0x10);
|
||||
// sram_hexdump(0, 0x400);
|
||||
// save_sram((uint8_t*)"/sd2snes/dump", 65536, 0);
|
||||
|
||||
sram_writebyte(0, SRAM_CMD_ADDR);
|
||||
|
||||
set_mcu_ovr(0);
|
||||
|
||||
printf("SNES GO!\n");
|
||||
snes_reset(0);
|
||||
|
||||
uint8_t cmd = 0;
|
||||
printf("test sram\n");
|
||||
while(!sram_reliable()) uart_puts("DERP");
|
||||
printf("ok\n");
|
||||
|
||||
/* uint8_t *teststring=(uint8_t*)"Wer das liest ist doof! 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
uint8_t testbuf[80];
|
||||
while(1) {
|
||||
sram_writeblock(teststring, 0xd00000, 61);
|
||||
sram_readblock(testbuf, 0xd00000, 61);
|
||||
testbuf[60]=0;
|
||||
printf("%p %s\n",testbuf, (char*)testbuf);
|
||||
} */
|
||||
|
||||
while(!cmd) {
|
||||
cmd=menu_main_loop();
|
||||
switch(cmd) {
|
||||
case SNES_CMD_LOADROM:
|
||||
get_selected_name(file_lfn);
|
||||
// snes_reset(1);
|
||||
set_mcu_ovr(1);
|
||||
printf("Selected name: %s\n", file_lfn);
|
||||
load_rom(file_lfn, SRAM_ROM_ADDR);
|
||||
// save_sram((uint8_t*)"/sd2snes/test.smc", romprops.romsize_bytes, 0);
|
||||
if(romprops.ramsize_bytes) {
|
||||
strcpy(strrchr((char*)file_lfn, (int)'.'), ".srm");
|
||||
printf("SRM file: %s\n", file_lfn);
|
||||
load_sram(file_lfn, SRAM_SAVE_ADDR);
|
||||
} else {
|
||||
printf("No SRAM\n");
|
||||
}
|
||||
set_mcu_ovr(0);
|
||||
snes_reset(1);
|
||||
delay_ms(100);
|
||||
snes_reset(0);
|
||||
break;
|
||||
case SNES_CMD_SETRTC:
|
||||
break;
|
||||
default:
|
||||
printf("unknown cmd: %d\n", cmd);
|
||||
cmd=0; // unknown cmd: stay in loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("cmd was %x, going to snes main loop\n", cmd);
|
||||
cmd=0;
|
||||
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) {
|
||||
snes_reset_now=get_snes_reset();
|
||||
if(snes_reset_now) {
|
||||
if(!snes_reset_prev) {
|
||||
printf("RESET BUTTON DOWN\n");
|
||||
snes_reset_state=1;
|
||||
// reset reset counter
|
||||
reset_count=0;
|
||||
}
|
||||
} else {
|
||||
if(snes_reset_prev) {
|
||||
printf("RESET BUTTON UP\n");
|
||||
snes_reset_state=0;
|
||||
}
|
||||
}
|
||||
if(snes_reset_state) {
|
||||
delay_ms(10);
|
||||
reset_count++;
|
||||
} else {
|
||||
sram_reliable();
|
||||
snes_main_loop();
|
||||
}
|
||||
if(reset_count>100) {
|
||||
reset_count=0;
|
||||
set_mcu_ovr(1);
|
||||
snes_reset(1);
|
||||
delay_ms(100);
|
||||
if(romprops.ramsize_bytes && fpga_test() == 0xa5) {
|
||||
writeled(1);
|
||||
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
|
||||
writeled(0);
|
||||
}
|
||||
delay_ms(1000);
|
||||
goto restart;
|
||||
}
|
||||
snes_reset_prev = snes_reset_now;
|
||||
}
|
||||
// FPGA TEST FAIL. PANIC.
|
||||
led_panic();
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
||||
void teststuff(void) {
|
||||
uint8_t i=0, data;
|
||||
uint32_t p1;
|
||||
sram_writebyte(0x5e, 0);
|
||||
sram_writebyte(0x6f, 1);
|
||||
sram_writelong(0x3451451e, 4);
|
||||
sram_hexdump(0x0, 0x10);
|
||||
sram_hexdump(0x620000, 0x200);
|
||||
|
||||
while(i<10) {
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0xff);
|
||||
FPGA_TX_BYTE(0xff);
|
||||
data=FPGA_TXRX_BYTE(i);
|
||||
FPGA_DESELECT();
|
||||
printf("%x %x\n", i, data);
|
||||
i++;
|
||||
}
|
||||
while(1) {
|
||||
// if((data=fpga_test())!=0xa5) printf("Unexpected FPGA test token 0x%x\n", data);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
p1 = LPC_GPIO1->FIOPIN;
|
||||
BITBAND(LPC_GPIO2->FIOPIN, 1) = (p1 & BV(29))>>29;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
329
src/memory.c
Normal file
329
src/memory.c
Normal file
@ -0,0 +1,329 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
memory.c: RAM operations
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "fpga.h"
|
||||
#include "crc16.h"
|
||||
#include "ff.h"
|
||||
#include "fileops.h"
|
||||
#include "spi.h"
|
||||
#include "fpga_spi.h"
|
||||
#include "led.h"
|
||||
#include "smc.h"
|
||||
#include "memory.h"
|
||||
#include "snes.h"
|
||||
#include "timer.h"
|
||||
|
||||
char* hex = "0123456789ABCDEF";
|
||||
|
||||
void sram_hexdump(uint32_t addr, uint32_t len) {
|
||||
static uint8_t buf[16];
|
||||
uint32_t ptr;
|
||||
for(ptr=0; ptr < len; ptr += 16) {
|
||||
sram_readblock((void*)buf, ptr+addr, 16);
|
||||
uart_trace(buf, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void sram_writebyte(uint8_t val, uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91); // WRITE
|
||||
FPGA_TX_BYTE(val);
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
uint8_t sram_readbyte(uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81); // READ
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
uint8_t val = FPGA_TXRX_BYTE(0x00);
|
||||
FPGA_DESELECT();
|
||||
return val;
|
||||
}
|
||||
|
||||
void sram_writeshort(uint16_t val, uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91); // WRITE
|
||||
FPGA_TX_BYTE(val&0xff); // 7-0
|
||||
FPGA_TX_BYTE((val>>8)&0xff); // 15-8
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void sram_writelong(uint32_t val, uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91); // WRITE
|
||||
FPGA_TX_BYTE(val&0xff); // 7-0
|
||||
FPGA_TX_BYTE((val>>8)&0xff); // 15-8
|
||||
FPGA_TX_BYTE((val>>16)&0xff); // 23-15
|
||||
FPGA_TX_BYTE((val>>24)&0xff); // 31-24
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
uint16_t sram_readshort(uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81);
|
||||
FPGA_TX_BYTE(0x00);
|
||||
|
||||
uint32_t val = FPGA_TXRX_BYTE(0x00);
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<8);
|
||||
FPGA_DESELECT();
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t sram_readlong(uint32_t addr) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81);
|
||||
FPGA_TX_BYTE(0x00);
|
||||
uint32_t val = FPGA_TXRX_BYTE(0x00);
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<8);
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<16);
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<24);
|
||||
FPGA_DESELECT();
|
||||
return val;
|
||||
}
|
||||
|
||||
void sram_readlongblock(uint32_t* buf, uint32_t addr, uint16_t count) {
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81);
|
||||
FPGA_TX_BYTE(0x00);
|
||||
uint16_t i=0;
|
||||
while(i<count) {
|
||||
uint32_t val = (uint32_t)FPGA_TXRX_BYTE(0x00)<<24;
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<16);
|
||||
val |= ((uint32_t)FPGA_TXRX_BYTE(0x00)<<8);
|
||||
val |= FPGA_TXRX_BYTE(0x00);
|
||||
buf[i++] = val;
|
||||
}
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void sram_readblock(void* buf, uint32_t addr, uint16_t size) {
|
||||
uint16_t count=size;
|
||||
uint8_t* tgt = buf;
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81); // READ
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
while(count--) {
|
||||
*(tgt++) = FPGA_TXRX_BYTE(0x00);
|
||||
}
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
void sram_writeblock(void* buf, uint32_t addr, uint16_t size) {
|
||||
uint16_t count=size;
|
||||
uint8_t* src = buf;
|
||||
set_mcu_addr(addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91); // WRITE
|
||||
while(count--) {
|
||||
FPGA_TX_BYTE(*src++);
|
||||
}
|
||||
FPGA_TX_BYTE(0x00); // dummy
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
|
||||
uint32_t load_rom(uint8_t* filename, uint32_t base_addr) {
|
||||
// uint8_t dummy;
|
||||
UINT bytes_read;
|
||||
DWORD filesize;
|
||||
UINT count=0;
|
||||
file_open(filename, FA_READ);
|
||||
filesize = file_handle.fsize;
|
||||
smc_id(&romprops);
|
||||
set_mcu_addr(base_addr);
|
||||
printf("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);
|
||||
FPGA_DESELECT();
|
||||
for(;;) {
|
||||
// SPI_OFFLOAD=1;
|
||||
bytes_read = file_read();
|
||||
if (file_res || !bytes_read) break;
|
||||
if(!(count++ % 32)) {
|
||||
toggle_read_led();
|
||||
// bounce_busy_led();
|
||||
uart_putc('.');
|
||||
}
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91); // write w/ increment
|
||||
if(!(count++ % 8)) {
|
||||
// toggle_busy_led();
|
||||
// bounce_busy_led();
|
||||
uart_putc('.');
|
||||
}
|
||||
for(int j=0; j<bytes_read; j++) {
|
||||
FPGA_TX_BYTE(file_buf[j]);
|
||||
/* SPDR = file_buf[j];
|
||||
loop_until_bit_is_set(SPSR, SPIF);
|
||||
dummy = SPDR;*/
|
||||
}
|
||||
FPGA_TX_BYTE(0x00); // dummy tx for increment+write pulse */
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
file_close();
|
||||
set_mapper(romprops.mapper_id);
|
||||
printf("rom header map: %02x; mapper id: %d\n", romprops.header.map, romprops.mapper_id);
|
||||
|
||||
uint32_t rammask;
|
||||
uint32_t rommask;
|
||||
|
||||
if(filesize > (romprops.romsize_bytes + romprops.offset)) {
|
||||
romprops.romsize_bytes <<= 1;
|
||||
}
|
||||
|
||||
if(romprops.header.ramsize == 0) {
|
||||
rammask = 0;
|
||||
} else {
|
||||
rammask = romprops.ramsize_bytes - 1;
|
||||
}
|
||||
rommask = romprops.romsize_bytes - 1;
|
||||
printf("ramsize=%x rammask=%lx\nromsize=%x rommask=%lx\n", romprops.header.ramsize, rammask, romprops.header.romsize, rommask);
|
||||
set_saveram_mask(rammask);
|
||||
set_rom_mask(rommask);
|
||||
|
||||
return (uint32_t)filesize;
|
||||
}
|
||||
|
||||
uint32_t load_sram(uint8_t* filename, uint32_t base_addr) {
|
||||
set_mcu_addr(base_addr);
|
||||
UINT bytes_read;
|
||||
DWORD filesize;
|
||||
file_open(filename, FA_READ);
|
||||
filesize = file_handle.fsize;
|
||||
if(file_res) return 0;
|
||||
for(;;) {
|
||||
bytes_read = file_read();
|
||||
if (file_res || !bytes_read) break;
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x91);
|
||||
for(int j=0; j<bytes_read; j++) {
|
||||
FPGA_TX_BYTE(file_buf[j]);
|
||||
}
|
||||
FPGA_TX_BYTE(0x00); // dummy tx
|
||||
FPGA_DESELECT();
|
||||
}
|
||||
file_close();
|
||||
return (uint32_t)filesize;
|
||||
}
|
||||
|
||||
|
||||
void save_sram(uint8_t* filename, uint32_t sram_size, uint32_t base_addr) {
|
||||
uint32_t count = 0;
|
||||
uint32_t num = 0;
|
||||
|
||||
FPGA_DESELECT();
|
||||
file_open(filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if(file_res) {
|
||||
uart_putc(0x30+file_res);
|
||||
}
|
||||
while(count<sram_size) {
|
||||
set_mcu_addr(base_addr+count);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81); // read
|
||||
FPGA_TX_BYTE(0); // dummy
|
||||
for(int j=0; j<sizeof(file_buf); j++) {
|
||||
file_buf[j] = FPGA_TXRX_BYTE(0x00);
|
||||
count++;
|
||||
}
|
||||
FPGA_DESELECT();
|
||||
num = file_write();
|
||||
if(file_res) {
|
||||
uart_putc(0x30+file_res);
|
||||
}
|
||||
}
|
||||
file_close();
|
||||
}
|
||||
|
||||
|
||||
uint32_t calc_sram_crc(uint32_t base_addr, uint32_t size) {
|
||||
uint8_t data;
|
||||
uint32_t count;
|
||||
uint16_t crc;
|
||||
crc=0;
|
||||
crc_valid=1;
|
||||
set_mcu_addr(base_addr);
|
||||
FPGA_SELECT();
|
||||
FPGA_TX_BYTE(0x81);
|
||||
FPGA_TX_BYTE(0x00);
|
||||
for(count=0; count<size; count++) {
|
||||
data = FPGA_TXRX_BYTE(0x00);
|
||||
if(get_snes_reset()) {
|
||||
crc_valid = 0;
|
||||
break;
|
||||
}
|
||||
crc += crc16_update(crc, &data, 1);
|
||||
}
|
||||
FPGA_DESELECT();
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint8_t sram_reliable() {
|
||||
uint16_t score=0;
|
||||
uint32_t val;
|
||||
// uint32_t val = sram_readlong(SRAM_SCRATCHPAD);
|
||||
uint8_t result = 0;
|
||||
/* while(score<SRAM_RELIABILITY_SCORE) {
|
||||
if(sram_readlong(SRAM_SCRATCHPAD)==val) {
|
||||
score++;
|
||||
} else {
|
||||
set_pwr_led(0);
|
||||
score=0;
|
||||
}
|
||||
}*/
|
||||
for(uint16_t i = 0; i < SRAM_RELIABILITY_SCORE; i++) {
|
||||
val=sram_readlong(SRAM_SCRATCHPAD);
|
||||
if(val==0x12345678) {
|
||||
score++;
|
||||
// } else {
|
||||
// dprintf("i=%d val=%08lX\n", i, val);
|
||||
}
|
||||
}
|
||||
if(score<SRAM_RELIABILITY_SCORE) {
|
||||
result = 0;
|
||||
// dprintf("score=%d\n", score);
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
rdyled(result);
|
||||
return result;
|
||||
}
|
||||
63
src/memory.h
Normal file
63
src/memory.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
memory.h: RAM operations
|
||||
*/
|
||||
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
|
||||
#define SRAM_ROM_ADDR (0x000000L)
|
||||
#define SRAM_SAVE_ADDR (0xE00000L)
|
||||
|
||||
#define SRAM_MENU_ADDR (0xE00000L)
|
||||
#define SRAM_DB_ADDR (0xE20000L)
|
||||
#define SRAM_DIR_ADDR (0xE10000L)
|
||||
#define SRAM_CMD_ADDR (0xFF1004L)
|
||||
#define SRAM_PARAM_ADDR (0xFF1000L)
|
||||
#define SRAM_MENU_SAVE_ADDR (0xFF0000L)
|
||||
#define SRAM_SCRATCHPAD (0xFFFF00L)
|
||||
#define SRAM_DIRID (0xFFFFF0L)
|
||||
#define SRAM_RELIABILITY_SCORE (0x100)
|
||||
|
||||
uint32_t load_rom(uint8_t* filename, uint32_t base_addr);
|
||||
uint32_t load_sram(uint8_t* filename, uint32_t base_addr);
|
||||
void sram_hexdump(uint32_t addr, uint32_t len);
|
||||
uint8_t sram_readbyte(uint32_t addr);
|
||||
uint16_t sram_readshort(uint32_t addr);
|
||||
uint32_t sram_readlong(uint32_t addr);
|
||||
void sram_writebyte(uint8_t val, uint32_t addr);
|
||||
void sram_writeshort(uint16_t val, uint32_t addr);
|
||||
void sram_writelong(uint32_t val, uint32_t addr);
|
||||
void sram_readblock(void* buf, uint32_t addr, uint16_t size);
|
||||
void sram_readlongblock(uint32_t* buf, uint32_t addr, uint16_t count);
|
||||
void sram_writeblock(void* buf, uint32_t addr, uint16_t size);
|
||||
void save_sram(uint8_t* filename, uint32_t sram_size, uint32_t base_addr);
|
||||
uint32_t calc_sram_crc(uint32_t base_addr, uint32_t size);
|
||||
uint8_t sram_reliable(void);
|
||||
|
||||
#include "smc.h"
|
||||
snes_romprops_t romprops;
|
||||
#endif
|
||||
@ -179,6 +179,7 @@ static int internal_nprintf(void (*output_function)(char c), const char *fmt, va
|
||||
output_function('x');
|
||||
width -= 2;
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
flags |= FLAG_UNSIGNED;
|
||||
break;
|
||||
|
||||
40
src/sdcard.c
40
src/sdcard.c
@ -184,7 +184,7 @@ static uint8_t wait_for_response(uint8_t expected) {
|
||||
tick_t timeout = getticks() + HZ/2;
|
||||
|
||||
while (time_before(getticks(), timeout)) {
|
||||
uint8_t byte = spi_rx_byte();
|
||||
uint8_t byte = spi_rx_byte(1);
|
||||
|
||||
if (expected == 0 && byte != 0)
|
||||
return 1;
|
||||
@ -199,7 +199,7 @@ static uint8_t wait_for_response(uint8_t expected) {
|
||||
static void deselectCard(uint8_t card) {
|
||||
// Send 8 clock cycles
|
||||
set_sd_led(0);
|
||||
spi_rx_byte();
|
||||
spi_rx_byte(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,15 +244,15 @@ static int sendCommand(const uint8_t card,
|
||||
#endif
|
||||
|
||||
// Transfer command
|
||||
spi_tx_byte(0x40+command);
|
||||
spi_tx_byte(0x40+command, 1);
|
||||
uint32_t tmp = swap_word(parameter);
|
||||
spi_tx_block(&tmp, 4);
|
||||
spi_tx_byte(crc);
|
||||
spi_tx_block(&tmp, 4, 1);
|
||||
spi_tx_byte(crc, 1);
|
||||
|
||||
// Wait for a valid response
|
||||
timeout = getticks() + HZ/2;
|
||||
do {
|
||||
i = spi_rx_byte();
|
||||
i = spi_rx_byte(1);
|
||||
} while (i & 0x80 && time_before(getticks(), timeout));
|
||||
|
||||
#ifdef CONFIG_TWINSD
|
||||
@ -291,7 +291,7 @@ static uint8_t extendedInit(const uint8_t card) {
|
||||
}
|
||||
|
||||
// No error, continue SDHC initialization
|
||||
spi_rx_block(&answer, 4);
|
||||
spi_rx_block(&answer, 4, 1);
|
||||
answer = swap_word(answer);
|
||||
deselectCard(card);
|
||||
|
||||
@ -420,16 +420,16 @@ printf("sd_initialize\n");
|
||||
* IEC lines tied to SPI, so I moved it here to resolve the
|
||||
* conflict.
|
||||
*/
|
||||
spi_init(SPI_SPEED_SLOW);
|
||||
spi_init(SPI_SPEED_SLOW, 1);
|
||||
disk_state = DISK_ERROR;
|
||||
|
||||
cardtype[drv] = 0;
|
||||
|
||||
set_sd_led(0);
|
||||
|
||||
// Send 80 clks
|
||||
// Send 8000 clks
|
||||
for (counter=0; counter<1000; counter++) {
|
||||
spi_tx_byte(0xff);
|
||||
spi_tx_byte(0xff, 1);
|
||||
}
|
||||
|
||||
// Reset card
|
||||
@ -455,7 +455,7 @@ printf("sd_initialize\n");
|
||||
} while (i > 1 && counter-- > 0);
|
||||
|
||||
if (counter > 0) {
|
||||
spi_rx_block(&answer, 4);
|
||||
spi_rx_block(&answer, 4, 1);
|
||||
answer = swap_word(answer);
|
||||
|
||||
// See if the card likes our supply voltage
|
||||
@ -501,7 +501,7 @@ printf("sd_initialize\n");
|
||||
}
|
||||
|
||||
// Thats it!
|
||||
spi_set_speed(SPI_SPEED_FAST);
|
||||
spi_set_speed(SPI_SPEED_FAST, 1);
|
||||
disk_state = DISK_OK;
|
||||
return sd_status(drv);
|
||||
}
|
||||
@ -554,9 +554,9 @@ DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
|
||||
|
||||
#ifdef CONFIG_SD_BLOCKTRANSFER
|
||||
/* Transfer data first, calculate CRC afterwards */
|
||||
spi_rx_block(buffer, 512);
|
||||
spi_rx_block(buffer, 512, 1);
|
||||
|
||||
recvcrc = spi_rx_byte() << 8 | spi_rx_byte();
|
||||
recvcrc = spi_rx_byte(1) << 8 | spi_rx_byte(1);
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
crc = crc_xmodem_block(0, buffer, 512);
|
||||
#endif
|
||||
@ -653,10 +653,10 @@ DRESULT sd_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) {
|
||||
}
|
||||
|
||||
// Send data token
|
||||
spi_tx_byte(0xfe);
|
||||
spi_tx_byte(0xfe, 1);
|
||||
|
||||
// Send data
|
||||
spi_tx_block(buffer, 512);
|
||||
spi_tx_block(buffer, 512, 1);
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
crc = crc_xmodem_block(0, buffer, 512);
|
||||
#else
|
||||
@ -664,11 +664,11 @@ DRESULT sd_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) {
|
||||
#endif
|
||||
|
||||
// Send CRC
|
||||
spi_tx_byte(crc >> 8);
|
||||
spi_tx_byte(crc & 0xff);
|
||||
spi_tx_byte(crc >> 8, 1);
|
||||
spi_tx_byte(crc & 0xff, 1);
|
||||
|
||||
// Get and check status feedback
|
||||
status = spi_rx_byte();
|
||||
status = spi_rx_byte(1);
|
||||
|
||||
// Retry if neccessary
|
||||
if ((status & 0x0F) != 0x05) {
|
||||
@ -725,7 +725,7 @@ DRESULT sd_getinfo(BYTE drv, BYTE page, void *buffer) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
spi_rx_block(buf, 18);
|
||||
spi_rx_block(buf, 18, 1);
|
||||
deselectCard(drv);
|
||||
|
||||
if (cardtype[drv] & CARD_SDHC) {
|
||||
|
||||
@ -29,6 +29,11 @@
|
||||
|
||||
#include "diskio.h"
|
||||
|
||||
#define SD_TX_BYTE(x) spi_tx_byte(x, SPI_SD);
|
||||
#define SD_RX_BYTE(x) spi_rx_byte(x, SPI_SD);
|
||||
#define SD_TX_BLOCK(x,y) spi_tx_block(x,y, SPI_SD);
|
||||
#define SD_RX_BLOCK(x,y) spi_rx_block(x,y, SPI_SD);
|
||||
|
||||
/* These functions are weak-aliased to disk_... */
|
||||
void sd_init(void);
|
||||
DSTATUS sd_status(BYTE drv);
|
||||
|
||||
173
src/smc.c
Normal file
173
src/smc.c
Normal file
@ -0,0 +1,173 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
smc.c: SMC file related operations
|
||||
*/
|
||||
|
||||
#include "fileops.h"
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "smc.h"
|
||||
|
||||
uint32_t hdr_addr[6] = {0xffb0, 0x101b0, 0x7fb0, 0x81b0, 0x40ffb0, 0x4101b0};
|
||||
uint8_t countAllASCII(uint8_t* data, int size) {
|
||||
uint8_t res = 0;
|
||||
do {
|
||||
size--;
|
||||
if(data[size] >= 0x20 && data[size] <= 0x7e) {
|
||||
res++;
|
||||
}
|
||||
} while (size);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t countAllJISX0201(uint8_t* data, int size) {
|
||||
uint8_t res = 0;
|
||||
do {
|
||||
size--;
|
||||
if((data[size] >= 0x20 && data[size] <= 0x7e)
|
||||
||(data[size] >= 0xa1 && data[size] <= 0xdf)) {
|
||||
res++;
|
||||
}
|
||||
} while (size);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t isFixed(uint8_t* data, int size, uint8_t value) {
|
||||
uint8_t res = 1;
|
||||
do {
|
||||
size--;
|
||||
if(data[size] != value) {
|
||||
res = 0;
|
||||
}
|
||||
} while (size);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t checkChksum(uint16_t cchk, uint16_t chk) {
|
||||
uint32_t sum = cchk + chk;
|
||||
uint8_t res = 0;
|
||||
if(sum==0x0000ffff) {
|
||||
res = 0x10;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void smc_id(snes_romprops_t* props) {
|
||||
uint8_t score, maxscore=1, score_idx=2; // assume LoROM
|
||||
|
||||
snes_header_t* header = &(props->header);
|
||||
|
||||
for(uint8_t num = 0; num < 6; num++) {
|
||||
if(!file_readblock(header, hdr_addr[num], sizeof(snes_header_t))
|
||||
|| file_res) {
|
||||
// dprintf("uh oh... %d\n", file_res);
|
||||
// _delay_ms(30);
|
||||
score = 0;
|
||||
} else {
|
||||
score = smc_headerscore(header)/(1+(num&1));
|
||||
if((file_handle.fsize & 0x2ff) == 0x200) {
|
||||
if(num&1) {
|
||||
score+=20;
|
||||
} else {
|
||||
score=0;
|
||||
}
|
||||
} else {
|
||||
if(!(num&1)) {
|
||||
score+=20;
|
||||
} else {
|
||||
score=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// dprintf("%d: offset = %lX; score = %d\n", num, hdr_addr[num], score);
|
||||
// _delay_ms(100);
|
||||
if(score>=maxscore) {
|
||||
score_idx=num;
|
||||
maxscore=score;
|
||||
}
|
||||
}
|
||||
|
||||
if(score_idx & 1) {
|
||||
props->offset = 0x200;
|
||||
} else {
|
||||
props->offset = 0;
|
||||
}
|
||||
|
||||
// restore the chosen one
|
||||
// dprintf("winner is %d\n", score_idx);
|
||||
// _delay_ms(30);
|
||||
file_readblock(header, hdr_addr[score_idx], sizeof(snes_header_t));
|
||||
switch(header->map & 0xef) {
|
||||
case 0x20:
|
||||
props->mapper_id = 1;
|
||||
break;
|
||||
case 0x21:
|
||||
props->mapper_id = 0;
|
||||
break;
|
||||
case 0x25:
|
||||
props->mapper_id = 2;
|
||||
break;
|
||||
default: // invalid/unsupported mapper, use header location
|
||||
switch(score_idx) {
|
||||
case 0:
|
||||
case 1:
|
||||
props->mapper_id = 0;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
props->mapper_id = 1;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
props->mapper_id = 2;
|
||||
break;
|
||||
default:
|
||||
props->mapper_id = 1; // whatever
|
||||
}
|
||||
}
|
||||
if(header->romsize == 0 || header->romsize > 13) {
|
||||
header->romsize = 13;
|
||||
}
|
||||
props->ramsize_bytes = (uint32_t)1024 << header->ramsize;
|
||||
props->romsize_bytes = (uint32_t)1024 << header->romsize;
|
||||
props->expramsize_bytes = (uint32_t)1024 << header->expramsize;
|
||||
// dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
|
||||
if(props->ramsize_bytes > 32768 || props->ramsize_bytes < 2048) {
|
||||
props->ramsize_bytes = 0;
|
||||
}
|
||||
// dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
|
||||
f_lseek(&file_handle, 0);
|
||||
}
|
||||
|
||||
uint8_t smc_headerscore(snes_header_t* header) {
|
||||
uint8_t score=0;
|
||||
score += countAllASCII(header->maker, sizeof(header->maker));
|
||||
score += countAllASCII(header->gamecode, sizeof(header->gamecode));
|
||||
score += isFixed(header->fixed_00, sizeof(header->fixed_00), 0x00);
|
||||
score += countAllJISX0201(header->name, sizeof(header->name));
|
||||
score += 3*isFixed(&header->fixed_33, sizeof(header->fixed_33), 0x33);
|
||||
score += checkChksum(header->cchk, header->chk);
|
||||
return score;
|
||||
}
|
||||
|
||||
62
src/smc.h
Normal file
62
src/smc.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* sd2snes - SD card based universal cartridge for the SNES
|
||||
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
||||
AVR firmware portion
|
||||
|
||||
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
||||
See sdcard.c|h, config.h.
|
||||
|
||||
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
||||
see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
smc.h: SMC file structures
|
||||
*/
|
||||
|
||||
#ifndef SMC_H
|
||||
#define SMC_H
|
||||
|
||||
typedef struct _snes_header {
|
||||
uint8_t maker[2]; // 0xB0
|
||||
uint8_t gamecode[4]; // 0xB2
|
||||
uint8_t fixed_00[7]; // 0xB6
|
||||
uint8_t expramsize; // 0xBD
|
||||
uint8_t specver; // 0xBE
|
||||
uint8_t carttype2; // 0xBF
|
||||
uint8_t name[21]; // 0xC0
|
||||
uint8_t map; // 0xD5
|
||||
uint8_t carttype; // 0xD6
|
||||
uint8_t romsize; // 0xD7
|
||||
uint8_t ramsize; // 0xD8
|
||||
uint8_t destcode; // 0xD9
|
||||
uint8_t fixed_33; // 0xDA
|
||||
uint8_t ver; // 0xDB
|
||||
uint16_t cchk; // 0xDC
|
||||
uint16_t chk; // 0xDE
|
||||
} snes_header_t;
|
||||
|
||||
typedef struct _snes_romprops {
|
||||
uint16_t offset; // start of actual ROM image
|
||||
uint8_t mapper_id; // FPGA mapper
|
||||
uint8_t pad1; // for alignment
|
||||
uint32_t expramsize_bytes; // ExpRAM size in bytes
|
||||
uint32_t ramsize_bytes; // CartRAM size in bytes
|
||||
uint32_t romsize_bytes; // ROM size in bytes (rounded up)
|
||||
snes_header_t header; // original header from ROM image
|
||||
} snes_romprops_t;
|
||||
|
||||
void smc_id(snes_romprops_t*);
|
||||
uint8_t smc_headerscore(snes_header_t*);
|
||||
|
||||
#endif
|
||||
45
src/snes.c
45
src/snes.c
@ -24,8 +24,8 @@
|
||||
snes.c: SNES hardware control and monitoring
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "avrcompat.h"
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include "bits.h"
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "snes.h"
|
||||
@ -38,8 +38,9 @@
|
||||
uint8_t initloop=1;
|
||||
uint32_t saveram_crc, saveram_crc_old;
|
||||
void snes_init() {
|
||||
DDRD |= _BV(PD5); // PD5 = RESET_DIR
|
||||
DDRD |= _BV(PD6); // PD6 = RESET
|
||||
/* put reset level on reset pin */
|
||||
BITBAND(SNES_RESET_REG->FIOCLR, SNES_RESET_BIT) = 1;
|
||||
/* reset the SNES */
|
||||
snes_reset(1);
|
||||
}
|
||||
|
||||
@ -49,15 +50,7 @@ void snes_init() {
|
||||
* state: put SNES in reset state when 1, release when 0
|
||||
*/
|
||||
void snes_reset(int state) {
|
||||
if(state) {
|
||||
DDRD |= _BV(PD6); // /RESET pin -> out
|
||||
PORTD &= ~_BV(PD6); // /RESET = 0
|
||||
PORTD |= _BV(PD5); // RESET_DIR = 1;
|
||||
} else {
|
||||
PORTD &= ~_BV(PD5); // RESET_DIR = 0;
|
||||
DDRD &= ~_BV(PD6); // /RESET pin -> in
|
||||
PORTD |= _BV(PD6); // /RESET = pullup
|
||||
}
|
||||
BITBAND(SNES_RESET_REG->FIODIR, SNES_RESET_BIT) = state;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -66,9 +59,7 @@ void snes_reset(int state) {
|
||||
* returns: 1 when reset, 0 when not reset
|
||||
*/
|
||||
uint8_t get_snes_reset() {
|
||||
// DDRD &= ~_BV(PD6); // /RESET pin -> in
|
||||
// PORTD &= ~_BV(PD5); // RESET_DIR (external buffer) = 0
|
||||
return !(PIND & _BV(PD6));
|
||||
return !BITBAND(SNES_RESET_REG->FIOPIN, SNES_RESET_BIT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -99,25 +90,23 @@ void snes_main_loop() {
|
||||
samecount++;
|
||||
}
|
||||
if(diffcount>=1 && samecount==5) {
|
||||
uart_putc('U');
|
||||
uart_puthexshort(saveram_crc);
|
||||
uart_putcrlf();
|
||||
set_busy_led(1);
|
||||
printf("SaveRAM CRC: 0x%04lx; saving\n", saveram_crc);
|
||||
writeled(1);
|
||||
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
|
||||
set_busy_led(0);
|
||||
writeled(0);
|
||||
didnotsave=0;
|
||||
}
|
||||
if(didnotsave>50) {
|
||||
printf("periodic save (sram contents keep changing...)\n");
|
||||
diffcount=0;
|
||||
uart_putc('V');
|
||||
set_busy_led(1);
|
||||
writeled(1);
|
||||
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
|
||||
didnotsave=0;
|
||||
set_busy_led(0);
|
||||
writeled(0);
|
||||
}
|
||||
saveram_crc_old = saveram_crc;
|
||||
}
|
||||
dprintf("crc_valid=%d sram_valid=%d diffcount=%ld samecount=%ld, didnotsave=%ld\n", crc_valid, sram_valid, diffcount, samecount, didnotsave);
|
||||
printf("crc_valid=%d sram_valid=%d diffcount=%ld samecount=%ld, didnotsave=%ld\n", crc_valid, sram_valid, diffcount, samecount, didnotsave);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,7 +118,7 @@ uint8_t menu_main_loop() {
|
||||
sram_writebyte(0, SRAM_CMD_ADDR);
|
||||
while(!cmd) {
|
||||
if(!get_snes_reset()) {
|
||||
while(!sram_reliable());
|
||||
while(!sram_reliable())printf("hurr\n");;
|
||||
cmd = sram_readbyte(SRAM_CMD_ADDR);
|
||||
}
|
||||
if(get_snes_reset()) {
|
||||
@ -140,7 +129,7 @@ uint8_t menu_main_loop() {
|
||||
}
|
||||
|
||||
void get_selected_name(uint8_t* fn) {
|
||||
uint32_t addr = sram_readlong(SRAM_FD_ADDR);
|
||||
dprintf("fd addr=%lX\n", addr);
|
||||
uint32_t addr = sram_readlong(SRAM_PARAM_ADDR);
|
||||
printf("fd addr=%lx\n", addr);
|
||||
sram_readblock(fn, addr+0x41+SRAM_MENU_ADDR, 256);
|
||||
}
|
||||
|
||||
@ -26,6 +26,10 @@
|
||||
|
||||
#ifndef SNES_H
|
||||
#define SNES_H
|
||||
|
||||
#define SNES_CMD_LOADROM (1)
|
||||
#define SNES_CMD_SETRTC (2)
|
||||
|
||||
uint8_t crc_valid;
|
||||
|
||||
void snes_init(void);
|
||||
|
||||
125
src/sort.c
Normal file
125
src/sort.c
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "uart.h"
|
||||
#include "memory.h"
|
||||
#include "sort.h"
|
||||
|
||||
/*
|
||||
heap sort algorithm for data located outside RAM
|
||||
addr: start address of pointer table
|
||||
i: index (in 32-bit elements)
|
||||
heapsize: size of heap (in 32-bit elements)
|
||||
*/
|
||||
|
||||
uint32_t stat_getstring = 0;
|
||||
static char sort_str1[21], sort_str2[21];
|
||||
uint32_t ptrcache[QSORT_MAXELEM] IN_AHBRAM;
|
||||
|
||||
/* get element from pointer table in external RAM*/
|
||||
uint32_t sort_get_elem(uint32_t base, unsigned int index) {
|
||||
return sram_readlong(base+4*index);
|
||||
}
|
||||
|
||||
/* put element from pointer table in external RAM */
|
||||
void sort_put_elem(uint32_t base, unsigned int index, uint32_t elem) {
|
||||
sram_writelong(elem, base+4*index);
|
||||
}
|
||||
|
||||
/* compare strings pointed to by elements of pointer table */
|
||||
int sort_cmp_idx(uint32_t base, unsigned int index1, unsigned int index2) {
|
||||
uint32_t elem1, elem2;
|
||||
elem1 = sort_get_elem(base, index1);
|
||||
elem2 = sort_get_elem(base, index2);
|
||||
return sort_cmp_elem((void*)&elem1, (void*)&elem2);
|
||||
}
|
||||
|
||||
int sort_cmp_elem(const void* elem1, const void* elem2) {
|
||||
uint32_t el1 = *(uint32_t*)elem1;
|
||||
uint32_t el2 = *(uint32_t*)elem2;
|
||||
sort_getstring_for_dirent(sort_str1, el1);
|
||||
sort_getstring_for_dirent(sort_str2, el2);
|
||||
//sort_getlong_for_dirent(sort_long1, elem1);
|
||||
//sort_getlong_for_dirent(sort_long2, elem2);
|
||||
// printf("i1=%d i2=%d elem1=%lx elem2=%lx ; compare %s --- %s\n", index1, index2, elem1, elem2, sort_str1, sort_str2);
|
||||
|
||||
if ((el1 & 0x80000000) && !(el2 & 0x80000000)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(el1 & 0x80000000) && (el2 & 0x80000000)) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
uint16_t cmp_i;
|
||||
for(cmp_i=0; cmp_i<8 && sort_long1[cmp_i] == sort_long2[cmp_i]; cmp_i++);
|
||||
if(cmp_i==8) {
|
||||
return 0;
|
||||
}
|
||||
return sort_long1[cmp_i]-sort_long2[cmp_i];*/
|
||||
return strcasecmp(sort_str1, sort_str2);
|
||||
}
|
||||
|
||||
/* get truncated string from database */
|
||||
void sort_getstring_for_dirent(char *ptr, uint32_t addr) {
|
||||
stat_getstring++;
|
||||
if(addr & 0x80000000) {
|
||||
/* is directory link, name offset 6 */
|
||||
sram_readblock(ptr, addr+0x6+SRAM_MENU_ADDR, 20);
|
||||
} else {
|
||||
/* is file link, name offset 65 */
|
||||
sram_readblock(ptr, addr+0x41+SRAM_MENU_ADDR, 20);
|
||||
}
|
||||
ptr[20]=0;
|
||||
}
|
||||
|
||||
void sort_heapify(uint32_t addr, unsigned int i, unsigned int heapsize)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
unsigned int l = 2*i+1;
|
||||
unsigned int r = 2*i+2;
|
||||
|
||||
unsigned int largest = (l < heapsize && sort_cmp_idx(addr, i, l) < 0) ? l : i;
|
||||
|
||||
if(r < heapsize && sort_cmp_idx(addr, largest, r) < 0)
|
||||
largest = r;
|
||||
|
||||
if(largest != i)
|
||||
{
|
||||
uint32_t tmp = sort_get_elem(addr, i);
|
||||
sort_put_elem(addr, i, sort_get_elem(addr, largest));
|
||||
sort_put_elem(addr, largest, tmp);
|
||||
i = largest;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
void sort_dir(uint32_t addr, unsigned int size)
|
||||
{
|
||||
stat_getstring=0;
|
||||
if(size > QSORT_MAXELEM) {
|
||||
printf("more than %d dir entries, doing slower in-place sort\n", QSORT_MAXELEM);
|
||||
ext_heapsort(addr, size);
|
||||
} else {
|
||||
/* retrieve, sort, and store dir table */
|
||||
sram_readblock(ptrcache, addr, size*4);
|
||||
qsort((void*)ptrcache, size, 4, sort_cmp_elem);
|
||||
sram_writeblock(ptrcache, addr, size*4);
|
||||
}
|
||||
}
|
||||
|
||||
void ext_heapsort(uint32_t addr, unsigned int size) {
|
||||
for(unsigned int i = size/2; i > 0;) sort_heapify(addr, --i, size);
|
||||
|
||||
for(unsigned int i = size-1; i>0; --i) {
|
||||
uint32_t tmp = sort_get_elem(addr, 0);
|
||||
sort_put_elem(addr, 0, sort_get_elem(addr, i));
|
||||
sort_put_elem(addr, i, tmp);
|
||||
sort_heapify(addr, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
15
src/sort.h
Normal file
15
src/sort.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _SORT_H
|
||||
#define _SORT_H
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
|
||||
uint32_t sort_get_elem(uint32_t base, unsigned int index);
|
||||
void sort_put_elem(uint32_t base, unsigned int index, uint32_t elem);
|
||||
int sort_cmp_idx(uint32_t base, unsigned int index1, unsigned int index2);
|
||||
int sort_cmp_elem(const void* elem1, const void* elem2);
|
||||
void sort_getstring_for_dirent(char *ptr, uint32_t addr);
|
||||
void sort_getlong_for_dirent(uint32_t* ptr, uint32_t addr);
|
||||
void sort_heapify(uint32_t addr, unsigned int i, unsigned int heapsize);
|
||||
void sort_dir(uint32_t addr, unsigned int size);
|
||||
void ext_heapsort(uint32_t addr, unsigned int size);
|
||||
#endif
|
||||
179
src/spi.c
179
src/spi.c
@ -28,6 +28,7 @@
|
||||
#include "bits.h"
|
||||
#include "config.h"
|
||||
#include "spi.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define SSP_TFE 0 // Transmit FIFO empty
|
||||
#define SSP_TNF 1 // Transmit FIFO not full
|
||||
@ -35,10 +36,6 @@
|
||||
#define SSP_RFF 3 // Receive FIFO full
|
||||
#define SSP_BSY 4 // Busy
|
||||
|
||||
// FIXME: Move to config.h!
|
||||
#define SSP_CLK_DIVISOR_FAST 4
|
||||
#define SSP_CLK_DIVISOR_SLOW 250
|
||||
|
||||
// #define SSP_REGS LPC_SSP1
|
||||
// #define SSP_PCLKREG PCLKSEL0
|
||||
/* SSP0: PCLKSEL1
|
||||
@ -54,118 +51,173 @@
|
||||
SSP1: 3 */
|
||||
|
||||
typedef struct {
|
||||
LPC_SSP_TypeDef *SSP_REGS;
|
||||
LPC_GPDMA_TypeDef *SSP_DMAC;
|
||||
__IO uint32_t SSP_PCLKREG;
|
||||
int SSP_PCLKBIT;
|
||||
int SSP_DMAID_TX;
|
||||
int SSP_DMAID_RX;
|
||||
LPC_SSP_TypeDef *SSP_REGS;
|
||||
LPC_GPDMACH_TypeDef *SSP_DMACH;
|
||||
uint32_t *SSP_PCLKREG;
|
||||
int SSP_PCLKBIT;
|
||||
int SSP_DMAID_TX;
|
||||
int SSP_DMAID_RX;
|
||||
} ssp_props;
|
||||
|
||||
|
||||
static ssp_props SSP_SEL[2] = {
|
||||
{ LPC_SSP0, LPC_GPDMA0, PCLKSEL1, 10, 0, 1 }, /* SSP0 */
|
||||
{ LPC_SSP1, LPC_GPDMA1, PCLKSEL0, 20, 2, 3 }
|
||||
{ LPC_SSP0, LPC_GPDMACH0, (uint32_t*)&(LPC_SC->PCLKSEL1), 10, 0, 1 }, /* SSP0 */
|
||||
{ LPC_SSP1, LPC_GPDMACH1, (uint32_t*)&(LPC_SC->PCLKSEL0), 20, 2, 3 } /* SSP1 */
|
||||
};
|
||||
|
||||
void spi_init(spi_speed_t speed) {
|
||||
void spi_preinit(int device) {
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Set clock prescaler to 1:1 */
|
||||
BITBAND(LPC_SC->SSP_PCLKREG, SSP_PCLKBIT) = 1;
|
||||
BITBAND(*(ssp->SSP_PCLKREG), ssp->SSP_PCLKBIT) = 1;
|
||||
}
|
||||
|
||||
void spi_init(spi_speed_t speed, int device) {
|
||||
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* configure data format - 8 bits, SPI, CPOL=0, CPHA=0, 1 clock per bit */
|
||||
SSP_REGS->CR0 = (8-1);
|
||||
ssp->SSP_REGS->CR0 = (8-1);
|
||||
|
||||
/* set clock prescaler */
|
||||
if (speed == SPI_SPEED_FAST) {
|
||||
SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
|
||||
} else if (speed == SPI_SPEED_SLOW) {
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
|
||||
} else if (speed == SPI_SPEED_FPGA_FAST) {
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FPGA_FAST;
|
||||
} else {
|
||||
SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FPGA_SLOW;
|
||||
}
|
||||
|
||||
/* Enable SSP */
|
||||
SSP_REGS->CR1 = BV(1);
|
||||
ssp->SSP_REGS->CR1 = BV(1);
|
||||
|
||||
/* Enable DMA controller, little-endian mode */
|
||||
BITBAND(LPC_SC->PCONP, 29) = 1;
|
||||
LPC_GPDMA->DMACConfig = 1;
|
||||
}
|
||||
|
||||
void spi_tx_byte(uint8_t data) {
|
||||
void spi_tx_sync(int device) {
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until TX fifo is flushed */
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_BSY)) ;
|
||||
}
|
||||
|
||||
void spi_tx_byte(uint8_t data, int device) {
|
||||
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until TX fifo can accept data */
|
||||
while (!BITBAND(SSP_REGS->SR, SSP_TNF)) ;
|
||||
while (!BITBAND(ssp->SSP_REGS->SR, SSP_TNF)) ;
|
||||
|
||||
/* Send byte */
|
||||
SSP_REGS->DR = data;
|
||||
ssp->SSP_REGS->DR = data;
|
||||
}
|
||||
|
||||
uint8_t spi_rx_byte(void) {
|
||||
uint8_t spi_txrx_byte(uint8_t data, int device) {
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until SSP is not busy */
|
||||
while (BITBAND(SSP_REGS->SR, SSP_BSY)) ;
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_BSY)) ;
|
||||
|
||||
/* Clear RX fifo */
|
||||
while (BITBAND(SSP_REGS->SR, SSP_RNE))
|
||||
(void) SSP_REGS->DR;
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_RNE))
|
||||
(void) ssp->SSP_REGS->DR;
|
||||
|
||||
/* Transmit a single dummy byte */
|
||||
SSP_REGS->DR = 0xff;
|
||||
ssp->SSP_REGS->DR = data;
|
||||
|
||||
/* Wait until answer has been received */
|
||||
while (!BITBAND(SSP_REGS->SR, SSP_RNE)) ;
|
||||
while (!BITBAND(ssp->SSP_REGS->SR, SSP_RNE)) ;
|
||||
|
||||
return SSP_REGS->DR;
|
||||
return ssp->SSP_REGS->DR;
|
||||
}
|
||||
|
||||
void spi_tx_block(const void *ptr, unsigned int length) {
|
||||
uint8_t spi_rx_byte(int device) {
|
||||
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until SSP is not busy */
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_BSY)) ;
|
||||
|
||||
/* Clear RX fifo */
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_RNE))
|
||||
(void) ssp->SSP_REGS->DR;
|
||||
|
||||
/* Transmit a single dummy byte */
|
||||
ssp->SSP_REGS->DR = 0xff;
|
||||
|
||||
/* Wait until answer has been received */
|
||||
while (!BITBAND(ssp->SSP_REGS->SR, SSP_RNE)) ;
|
||||
|
||||
return ssp->SSP_REGS->DR;
|
||||
}
|
||||
|
||||
void spi_tx_block(const void *ptr, unsigned int length, int device) {
|
||||
const uint8_t *data = (const uint8_t *)ptr;
|
||||
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
while (length--) {
|
||||
/* Wait until TX fifo can accept data */
|
||||
while (!BITBAND(SSP_REGS->SR, SSP_TNF)) ;
|
||||
while (!BITBAND(ssp->SSP_REGS->SR, SSP_TNF)) ;
|
||||
|
||||
SSP_REGS->DR = *data++;
|
||||
ssp->SSP_REGS->DR = *data++;
|
||||
}
|
||||
}
|
||||
|
||||
void spi_rx_block(void *ptr, unsigned int length) {
|
||||
void spi_rx_block(void *ptr, unsigned int length, int device) {
|
||||
uint8_t *data = (uint8_t *)ptr;
|
||||
unsigned int txlen = length;
|
||||
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until SSP is not busy */
|
||||
while (BITBAND(SSP_REGS->SR, SSP_BSY)) ;
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_BSY)) ;
|
||||
|
||||
/* Clear RX fifo */
|
||||
while (BITBAND(SSP_REGS->SR, SSP_RNE))
|
||||
(void) SSP_REGS->DR;
|
||||
while (BITBAND(ssp->SSP_REGS->SR, SSP_RNE))
|
||||
(void) ssp->SSP_REGS->DR;
|
||||
|
||||
if ((length & 3) != 0 || ((uint32_t)ptr & 3) != 0) {
|
||||
/* Odd length or unaligned buffer */
|
||||
while (length > 0) {
|
||||
/* Wait until TX or RX FIFO are ready */
|
||||
while (txlen > 0 && !BITBAND(SSP_REGS->SR, SSP_TNF) &&
|
||||
!BITBAND(SSP_REGS->SR, SSP_RNE)) ;
|
||||
while (txlen > 0 && !BITBAND(ssp->SSP_REGS->SR, SSP_TNF) &&
|
||||
!BITBAND(ssp->SSP_REGS->SR, SSP_RNE)) ;
|
||||
|
||||
/* Try to receive data */
|
||||
while (length > 0 && BITBAND(SSP_REGS->SR, SSP_RNE)) {
|
||||
*data++ = SSP_REGS->DR;
|
||||
while (length > 0 && BITBAND(ssp->SSP_REGS->SR, SSP_RNE)) {
|
||||
*data++ = ssp->SSP_REGS->DR;
|
||||
length--;
|
||||
}
|
||||
|
||||
/* Send dummy data until TX full or RX ready */
|
||||
while (txlen > 0 && BITBAND(SSP_REGS->SR, SSP_TNF) && !BITBAND(SSP_REGS->SR, SSP_RNE)) {
|
||||
while (txlen > 0 && BITBAND(ssp->SSP_REGS->SR, SSP_TNF) && !BITBAND(ssp->SSP_REGS->SR, SSP_RNE)) {
|
||||
txlen--;
|
||||
SSP_REGS->DR = 0xff;
|
||||
ssp->SSP_REGS->DR = 0xff;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Clear interrupt flags of DMA channels 0 */
|
||||
LPC_GPDMA->DMACIntTCClear = BV(0);
|
||||
LPC_GPDMA->DMACIntErrClr = BV(0);
|
||||
LPC_GPDMA->DMACIntTCClear = BV(device);
|
||||
LPC_GPDMA->DMACIntErrClr = BV(device);
|
||||
|
||||
/* Set up RX DMA channel */
|
||||
LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&SSP_REGS->DR;
|
||||
LPC_GPDMACH0->DMACCDestAddr = (uint32_t)ptr;
|
||||
LPC_GPDMACH0->DMACCLLI = 0; // no linked list
|
||||
LPC_GPDMACH0->DMACCControl = length
|
||||
ssp->SSP_DMACH->DMACCSrcAddr = (uint32_t)&ssp->SSP_REGS->DR;
|
||||
ssp->SSP_DMACH->DMACCDestAddr = (uint32_t)ptr;
|
||||
ssp->SSP_DMACH->DMACCLLI = 0; // no linked list
|
||||
ssp->SSP_DMACH->DMACCControl = length
|
||||
| (0 << 12) // source burst size 1 (FIXME: Check if larger possible/useful)
|
||||
| (0 << 15) // destination burst size 1
|
||||
| (0 << 18) // source transfer width 1 byte
|
||||
@ -173,45 +225,52 @@ void spi_rx_block(void *ptr, unsigned int length) {
|
||||
| (0 << 26) // source address not incremented
|
||||
| (1 << 27) // destination address incremented
|
||||
;
|
||||
LPC_GPDMACH0->DMACCConfig = 1 // enable channel
|
||||
| (SSP_DMAID_RX << 1) // data source SSP RX
|
||||
ssp->SSP_DMACH->DMACCConfig = 1 // enable channel
|
||||
| (ssp->SSP_DMAID_RX << 1) // data source SSP RX
|
||||
| (2 << 11) // transfer from peripheral to memory
|
||||
;
|
||||
|
||||
/* Enable RX FIFO DMA */
|
||||
SSP_REGS->DMACR = 1;
|
||||
ssp->SSP_REGS->DMACR = 1;
|
||||
|
||||
/* Write <length> bytes into TX FIFO */
|
||||
// FIXME: Any value in doing this using DMA too?
|
||||
while (txlen > 0) {
|
||||
while (txlen > 0 && BITBAND(SSP_REGS->SR, SSP_TNF)) {
|
||||
while (txlen > 0 && BITBAND(ssp->SSP_REGS->SR, SSP_TNF)) {
|
||||
txlen--;
|
||||
SSP_REGS->DR = 0xff;
|
||||
ssp->SSP_REGS->DR = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait until DMA channel disables itself */
|
||||
while (LPC_GPDMACH0->DMACCConfig & 1) ;
|
||||
while (ssp->SSP_DMACH->DMACCConfig & 1) ;
|
||||
|
||||
/* Disable RX FIFO DMA */
|
||||
SSP_REGS->DMACR = 0;
|
||||
ssp->SSP_REGS->DMACR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void spi_set_speed(spi_speed_t speed) {
|
||||
void spi_set_speed(spi_speed_t speed, int device) {
|
||||
/* select interface */
|
||||
ssp_props *ssp = &(SSP_SEL[device]);
|
||||
|
||||
/* Wait until TX fifo is empty */
|
||||
while (!BITBAND(SSP_REGS->SR, 0)) ;
|
||||
while (!BITBAND(ssp->SSP_REGS->SR, 0)) ;
|
||||
|
||||
/* Disable SSP (FIXME: Is this required?) */
|
||||
SSP_REGS->CR1 = 0;
|
||||
ssp->SSP_REGS->CR1 = 0;
|
||||
|
||||
/* Change clock divisor */
|
||||
if (speed == SPI_SPEED_FAST) {
|
||||
SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
|
||||
} else if (speed == SPI_SPEED_SLOW) {
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
|
||||
} else if (speed == SPI_SPEED_FPGA_FAST) {
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FPGA_FAST;
|
||||
} else {
|
||||
SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
|
||||
ssp->SSP_REGS->CPSR = SSP_CLK_DIVISOR_FPGA_SLOW;
|
||||
}
|
||||
|
||||
/* Enable SSP */
|
||||
SSP_REGS->CR1 = BV(1);
|
||||
ssp->SSP_REGS->CR1 = BV(1);
|
||||
}
|
||||
|
||||
23
src/spi.h
23
src/spi.h
@ -30,24 +30,33 @@
|
||||
#define SPI_H
|
||||
|
||||
/* Low speed 400kHz for init, fast speed <=20MHz (MMC limit) */
|
||||
typedef enum { SPI_SPEED_FAST, SPI_SPEED_SLOW } spi_speed_t;
|
||||
typedef enum { SPI_SPEED_FAST, SPI_SPEED_SLOW, SPI_SPEED_FPGA_FAST, SPI_SPEED_FPGA_SLOW } spi_speed_t;
|
||||
|
||||
/* Pre-Initialize SPI interface (PCLK divider before PLL setup) */
|
||||
void spi_preinit(int device);
|
||||
|
||||
/* Initialize SPI interface */
|
||||
void spi_init(spi_speed_t speed);
|
||||
void spi_init(spi_speed_t speed, int device);
|
||||
|
||||
/* Transmit a single byte */
|
||||
void spi_tx_byte(uint8_t data);
|
||||
void spi_tx_byte(uint8_t data, int device);
|
||||
|
||||
/* Transmit a single byte and return received data */
|
||||
uint8_t spi_txrx_byte(uint8_t data, int device);
|
||||
|
||||
/* Transmit a data block */
|
||||
void spi_tx_block(const void *data, unsigned int length);
|
||||
void spi_tx_block(const void *data, unsigned int length, int device);
|
||||
|
||||
/* Receive a single byte */
|
||||
uint8_t spi_rx_byte(void);
|
||||
uint8_t spi_rx_byte(int device);
|
||||
|
||||
/* Receive a data block */
|
||||
void spi_rx_block(void *data, unsigned int length);
|
||||
void spi_rx_block(void *data, unsigned int length, int device);
|
||||
|
||||
/* Switch speed of SPI interface */
|
||||
void spi_set_speed(spi_speed_t speed);
|
||||
void spi_set_speed(spi_speed_t speed, int device);
|
||||
|
||||
/* wait for SPI TX FIFO to become empty */
|
||||
void spi_tx_sync(int device);
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user