sd2snes/src/fpga_spi.c
2012-07-09 01:19:44 +02:00

423 lines
10 KiB
C

/* 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
=============================================
0t bbhhll set address to 0xbbhhll
t = target
target: 0 = RAM
1 = MSU Audio buffer
2 = MSU Data buffer
targets 1 & 2 only require 2 address bytes to
be written.
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, 6=SF96, 7=Menu
4s - trigger SD DMA (512b from SD to memory)
s: Bit 2 = partial, Bit 1:0 = target
target: see above
60 xsssyeee set SD DMA partial transfer parameters
x: 0 = read from sector start (skip until
start offset reached)
8 = assume mid-sector position and read
immediately
sss = start offset (msb first)
y: 0 = skip rest of SD sector
8 = stop mid-sector if end offset reached
eee = end offset (msb first)
8p - read (RAM only)
p: 0 = no increment after read
8 = increment after read
9p {xx}* write xx
p: i-tt
tt = target (see above)
i = increment (see above)
E0 ssrr set MSU-1 status register (=FPGA status [7:0])
ss = bits to set in status register (1=set)
rr = bits to reset in status register (1=reset)
E1 - pause DAC
E2 - resume/play DAC
E3 - reset DAC playback pointer (0)
E4 hhll set MSU read pointer
E5 tt{7} set RTC (SPC7110 format + 1000s of year,
nibbles packed)
eg 0x20111210094816 is 2011-12-10, 9:48:16
E6 ssrr set/reset BS-X status register [7:0]
E7 - reset SRTC state
E8 - reset DSP program and data ROM write pointers
E9 hhmmllxxxx write+incr. DSP program ROM (xxxx=dummy writes)
EA hhllxxxx write+incr. DSP data ROM (xxxx=dummy writes)
EB - put DSP into reset
EC - release DSP from reset
ED - set feature enable bits (see below)
EE - set $213f override value (0=NTSC, 1=PAL)
F0 - receive test token (to see if FPGA is alive)
F1 - receive status (16bit, MSB first), see below
F2 - get MSU data address (32bit, MSB first)
F3 - get MSU audio track no. (16bit, MSB first)
F4 - get MSU volume (8bit)
FE - get SNES master clock frequency (32bit, MSB first)
measured 1x/sec
FF {xx}* echo (returns the sent data in the next byte)
FPGA status word:
bit function
==========================================================================
15 SD DMA busy (0=idle, 1=busy)
14 DAC read pointer MSB
13 MSU read pointer MSB
12 reserved (0)
11 reserved (0)
10 reserved (0)
9 reserved (0)
8 reserved (0)
7 reserved (0)
6 reserved (0)
5 MSU1 Audio request from SNES
4 MSU1 Data request from SNES
3 reserved (0)
2 MSU1 Audio control status: 0=no repeat, 1=repeat
1 MSU1 Audio control status: 0=pause, 1=play
0 MSU1 Audio control request
FPGA feature enable bits:
bit function
==========================================================================
7 -
6 -
5 -
4 enable $213F override
3 enable MSU1 registers
2 enable SRTC registers
1 enable ST0010 mapping
0 enable DSPx mapping
*/
#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"
#include "sdnative.h"
void fpga_spi_init(void) {
spi_init();
BITBAND(FPGA_MCU_RDY_REG->FIODIR, FPGA_MCU_RDY_BIT) = 0;
}
void set_msu_addr(uint16_t address) {
FPGA_SELECT();
FPGA_TX_BYTE(0x02);
FPGA_TX_BYTE((address>>8)&0xff);
FPGA_TX_BYTE((address)&0xff);
FPGA_DESELECT();
}
void set_dac_addr(uint16_t address) {
FPGA_SELECT();
FPGA_TX_BYTE(0x01);
FPGA_TX_BYTE((address>>8)&0xff);
FPGA_TX_BYTE((address)&0xff);
FPGA_DESELECT();
}
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 */
uint8_t result = FPGA_RX_BYTE();
FPGA_DESELECT();
return result;
}
uint16_t fpga_status() {
FPGA_SELECT();
FPGA_TX_BYTE(0xF1); /* STATUS */
uint16_t result = (FPGA_RX_BYTE()) << 8;
result |= FPGA_RX_BYTE();
FPGA_DESELECT();
return result;
}
void fpga_set_sddma_range(uint16_t start, uint16_t end) {
FPGA_SELECT();
FPGA_TX_BYTE(0x60); /* DMA_RANGE */
FPGA_TX_BYTE(start>>8);
FPGA_TX_BYTE(start&0xff);
FPGA_TX_BYTE(end>>8);
FPGA_TX_BYTE(end&0xff);
//if(tgt==1 && (test=FPGA_RX_BYTE()) != 0x41) printf("!!!!!!!!!!!!!!! -%02x- \n", test);
FPGA_DESELECT();
}
void fpga_sddma(uint8_t tgt, uint8_t partial) {
uint32_t test = 0;
uint8_t status = 0;
BITBAND(SD_CLKREG->FIODIR, SD_CLKPIN) = 0;
FPGA_SELECT();
FPGA_TX_BYTE(0x40 | (tgt & 0x3) | ((partial & 1) << 2) ); /* DO DMA */
FPGA_TX_BYTE(0x00); /* dummy for falling DMA_EN edge */
//if(tgt==1 && (test=FPGA_RX_BYTE()) != 0x41) printf("!!!!!!!!!!!!!!! -%02x- \n", test);
FPGA_DESELECT();
FPGA_SELECT();
FPGA_TX_BYTE(0xF1); /* STATUS */
DBG_SD printf("FPGA DMA request sent, wait for completion...");
while((status=FPGA_RX_BYTE()) & 0x80) {
FPGA_RX_BYTE(); /* eat the 2nd status byte */
test++;
}
DBG_SD printf("...complete\n");
FPGA_DESELECT();
// if(test<5)printf("loopy: %ld %02x\n", test, status);
BITBAND(SD_CLKREG->FIODIR, SD_CLKPIN) = 1;
}
void set_dac_vol(uint8_t volume) {
FPGA_SELECT();
FPGA_TX_BYTE(0x50);
FPGA_TX_BYTE(volume);
FPGA_TX_BYTE(0x00); /* latch rise */
FPGA_TX_BYTE(0x00); /* latch fall */
FPGA_DESELECT();
}
void dac_play() {
FPGA_SELECT();
FPGA_TX_BYTE(0xe2);
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
void dac_pause() {
FPGA_SELECT();
FPGA_TX_BYTE(0xe1);
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
void dac_reset() {
FPGA_SELECT();
FPGA_TX_BYTE(0xe3);
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
void msu_reset(uint16_t address) {
FPGA_SELECT();
FPGA_TX_BYTE(0xe4);
FPGA_TX_BYTE((address>>8) & 0xff); /* address hi */
FPGA_TX_BYTE(address & 0xff); /* address lo */
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
void set_msu_status(uint8_t set, uint8_t reset) {
FPGA_SELECT();
FPGA_TX_BYTE(0xe0);
FPGA_TX_BYTE(set);
FPGA_TX_BYTE(reset);
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
uint8_t get_msu_volume() {
FPGA_SELECT();
FPGA_TX_BYTE(0xF4); /* MSU_VOLUME */
uint8_t result = FPGA_RX_BYTE();
FPGA_DESELECT();
return result;
}
uint16_t get_msu_track() {
FPGA_SELECT();
FPGA_TX_BYTE(0xF3); /* MSU_TRACK */
uint16_t result = (FPGA_RX_BYTE()) << 8;
result |= FPGA_RX_BYTE();
FPGA_DESELECT();
return result;
}
uint32_t get_msu_offset() {
FPGA_SELECT();
FPGA_TX_BYTE(0xF2); /* MSU_OFFSET */
uint32_t result = (FPGA_RX_BYTE()) << 24;
result |= (FPGA_RX_BYTE()) << 16;
result |= (FPGA_RX_BYTE()) << 8;
result |= (FPGA_RX_BYTE());
FPGA_DESELECT();
return result;
}
uint32_t get_snes_sysclk() {
FPGA_SELECT();
FPGA_TX_BYTE(0xFE); /* GET_SYSCLK */
FPGA_TX_BYTE(0x00); /* dummy (copy current sysclk count to register) */
uint32_t result = (FPGA_RX_BYTE()) << 24;
result |= (FPGA_RX_BYTE()) << 16;
result |= (FPGA_RX_BYTE()) << 8;
result |= (FPGA_RX_BYTE());
FPGA_DESELECT();
return result;
}
void set_bsx_regs(uint8_t set, uint8_t reset) {
FPGA_SELECT();
FPGA_TX_BYTE(0xe6);
FPGA_TX_BYTE(set);
FPGA_TX_BYTE(reset);
FPGA_TX_BYTE(0x00); /* latch reset */
FPGA_DESELECT();
}
void set_fpga_time(uint64_t time) {
FPGA_SELECT();
FPGA_TX_BYTE(0xe5);
FPGA_TX_BYTE((time >> 48) & 0xff);
FPGA_TX_BYTE((time >> 40) & 0xff);
FPGA_TX_BYTE((time >> 32) & 0xff);
FPGA_TX_BYTE((time >> 24) & 0xff);
FPGA_TX_BYTE((time >> 16) & 0xff);
FPGA_TX_BYTE((time >> 8) & 0xff);
FPGA_TX_BYTE(time & 0xff);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_reset_srtc_state() {
FPGA_SELECT();
FPGA_TX_BYTE(0xe7);
FPGA_TX_BYTE(0x00);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_reset_dspx_addr() {
FPGA_SELECT();
FPGA_TX_BYTE(0xe8);
FPGA_TX_BYTE(0x00);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_write_dspx_pgm(uint32_t data) {
FPGA_SELECT();
FPGA_TX_BYTE(0xe9);
FPGA_TX_BYTE((data>>16)&0xff);
FPGA_TX_BYTE((data>>8)&0xff);
FPGA_TX_BYTE((data)&0xff);
FPGA_TX_BYTE(0x00);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_write_dspx_dat(uint16_t data) {
FPGA_SELECT();
FPGA_TX_BYTE(0xea);
FPGA_TX_BYTE((data>>8)&0xff);
FPGA_TX_BYTE((data)&0xff);
FPGA_TX_BYTE(0x00);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_dspx_reset(uint8_t reset) {
FPGA_SELECT();
FPGA_TX_BYTE(reset ? 0xeb : 0xec);
FPGA_TX_BYTE(0x00);
FPGA_DESELECT();
}
void fpga_set_features(uint8_t feat) {
printf("set features: %02x\n", feat);
FPGA_SELECT();
FPGA_TX_BYTE(0xed);
FPGA_TX_BYTE(feat);
FPGA_DESELECT();
}
void fpga_set_213f(uint8_t data) {
printf("set 213f: %d\n", data);
FPGA_SELECT();
FPGA_TX_BYTE(0xee);
FPGA_TX_BYTE(data);
FPGA_DESELECT();
}