/* GECKO3COM
|
/* GECKO3COM
|
*
|
*
|
* Copyright (C) 2008 by
|
* Copyright (C) 2008 by
|
* ___ ____ _ _
|
* ___ ____ _ _
|
* ( _`\ ( __)( ) ( )
|
* ( _`\ ( __)( ) ( )
|
* | (_) )| (_ | |_| | Bern University of Applied Sciences
|
* | (_) )| (_ | |_| | Bern University of Applied Sciences
|
* | _ <'| _) | _ | School of Engineering and
|
* | _ <'| _) | _ | School of Engineering and
|
* | (_) )| | | | | | Information Technology
|
* | (_) )| | | | | | Information Technology
|
* (____/'(_) (_) (_)
|
* (____/'(_) (_) (_)
|
*
|
*
|
*
|
*
|
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
* (at your option) any later version.
|
* (at your option) any later version.
|
*
|
*
|
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
*/
|
*/
|
|
|
/*********************************************************************/
|
/*********************************************************************/
|
/** \file fpga_load.c
|
/** \file fpga_load.c
|
*********************************************************************
|
*********************************************************************
|
* \brief functions to programm an FPGA
|
* \brief functions to programm an FPGA
|
*
|
*
|
* These functions handle the bit file for an Xilinx Spartan3
|
* These functions handle the bit file for an Xilinx Spartan3
|
* FPGA and programm it in parallel slave mode.
|
* FPGA and programm it in parallel slave mode.
|
*
|
*
|
* \note Currently only Xilinx FPGA's are supported, function stubs
|
* \note Currently only Xilinx FPGA's are supported, function stubs
|
* to handle Altera are provided as a guide for porting.
|
* to handle Altera are provided as a guide for porting.
|
*
|
*
|
* \author GNUradio team, Matthias Zurbrügg bfh.ch,
|
* \author GNUradio team, Matthias Zurbrügg bfh.ch,
|
* Christoph Zimmermann bfh.ch
|
* Christoph Zimmermann bfh.ch
|
* \date 2009-1-13
|
* \date 2009-1-13
|
*
|
*
|
*/
|
*/
|
|
|
#include "gecko3com_common.h"
|
#include "gecko3com_common.h"
|
#include "gecko3com_regs.h"
|
#include "gecko3com_regs.h"
|
#include "fpga_load.h"
|
#include "fpga_load.h"
|
#include "delay.h"
|
#include "delay.h"
|
#include "debugprint.h"
|
#include "debugprint.h"
|
|
|
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
/* Xilinx stuff. We use slave parallel mode (select map) to configure the FPGA
|
/* Xilinx stuff. We use slave parallel mode (select map) to configure the FPGA
|
*/
|
*/
|
#ifdef XILINX
|
#ifdef XILINX
|
|
|
/** makro to toggle the configuration clock line */
|
/** makro to toggle the configuration clock line */
|
#define toggle_cclk() { \
|
#define toggle_cclk() { \
|
XILINX_CCLK &= ~bmXILINX_CCLK; /* bring CCLK low */ \
|
XILINX_CCLK &= ~bmXILINX_CCLK; /* bring CCLK low */ \
|
XILINX_CCLK |= bmXILINX_CCLK; /* bring CCLK high */ \
|
XILINX_CCLK |= bmXILINX_CCLK; /* bring CCLK high */ \
|
}
|
}
|
|
|
|
|
void init_fpga_interface(void) {
|
void init_fpga_interface(void) {
|
|
|
/* IFCLK is generated internally and runs at 48 MHz; IO Pins configured as normal Ports */
|
/* IFCLK is generated internally and runs at 48 MHz; IO Pins configured as normal Ports */
|
//IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE;
|
//IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE;
|
IFCONFIG = bmIFCLKSRC | bmIFCLKOE;
|
IFCONFIG = bmIFCLKSRC | bmIFCLKOE;
|
SYNCDELAY;
|
SYNCDELAY;
|
}
|
}
|
|
|
|
|
int8_t fpga_scan_file(const xdata unsigned char *p, idata uint16_t *offset, \
|
int8_t fpga_scan_file(const xdata unsigned char *p, idata uint16_t *offset, \
|
idata uint16_t *length, xdata Fpga_Info* info)
|
idata uint16_t *length, xdata Fpga_Info* info)
|
{
|
{
|
idata uint8_t string_length = 0, chars_left_to_read = 0;
|
idata uint8_t string_length = 0, chars_left_to_read = 0;
|
xdata uint16_t local_position = *offset;
|
xdata uint16_t local_position = *offset;
|
|
|
for(local_position; local_position < *length; local_position++) {
|
for(local_position; local_position < *length; local_position++) {
|
//printf_tiny("fi: %d\n",local_position);
|
//printf_tiny("fi: %d\n",local_position);
|
/* information found, copy data to output array */
|
/* information found, copy data to output array */
|
if(chars_left_to_read < string_length) {
|
if(chars_left_to_read < string_length) {
|
info->info[chars_left_to_read++] = p[local_position];
|
info->info[chars_left_to_read++] = p[local_position];
|
|
|
/* end of information, return successfull */
|
/* end of information, return successfull */
|
if(chars_left_to_read == string_length) {
|
if(chars_left_to_read == string_length) {
|
info->position = local_position;
|
info->position = local_position;
|
*offset = local_position+1;
|
*offset = local_position+1;
|
return FPGA_INFO_COMPLETE;
|
return FPGA_INFO_COMPLETE;
|
}
|
}
|
else {
|
else {
|
continue; /* ignore rest of these loop, load next character */
|
continue; /* ignore rest of these loop, load next character */
|
}
|
}
|
}
|
}
|
|
|
/* search for the start of the desired type of information */
|
/* search for the start of the desired type of information */
|
if(chars_left_to_read == 0 && p[local_position] == info->type){
|
if(chars_left_to_read == 0 && p[local_position] == info->type){
|
chars_left_to_read = 1;
|
chars_left_to_read = 1;
|
continue; /* ignore rest of these loop, load next character */
|
continue; /* ignore rest of these loop, load next character */
|
}
|
}
|
|
|
/* start character found, check next character if it is \0 */
|
/* start character found, check next character if it is \0 */
|
if(chars_left_to_read == 1) {
|
if(chars_left_to_read == 1) {
|
if(p[local_position] == 0) {
|
if(p[local_position] == 0) {
|
chars_left_to_read = 2;
|
chars_left_to_read = 2;
|
|
|
}
|
}
|
else {
|
else {
|
/* false alert, continue searching */
|
/* false alert, continue searching */
|
chars_left_to_read = 0;
|
chars_left_to_read = 0;
|
}
|
}
|
continue; /* ignore rest of these loop, load next character */
|
continue; /* ignore rest of these loop, load next character */
|
}
|
}
|
|
|
/* start of information found, copy length of following string */
|
/* start of information found, copy length of following string */
|
if(chars_left_to_read == 2) {
|
if(chars_left_to_read == 2) {
|
chars_left_to_read = 0;
|
chars_left_to_read = 0;
|
|
|
if(p[local_position] > FPGA_INFO_LEN) {
|
if(p[local_position] > FPGA_INFO_LEN) {
|
string_length = FPGA_INFO_LEN;
|
string_length = FPGA_INFO_LEN;
|
}
|
}
|
else {
|
else {
|
string_length = p[local_position];
|
string_length = p[local_position];
|
}
|
}
|
|
|
/* exception: file length has a fixed length */
|
/* exception: file length has a fixed length */
|
if(info->type == FILE_LENGTH) {
|
if(info->type == FILE_LENGTH) {
|
string_length = 3;
|
string_length = 3;
|
chars_left_to_read = 1;
|
chars_left_to_read = 1;
|
info->info[0] = p[local_position];
|
info->info[0] = p[local_position];
|
}
|
}
|
}
|
}
|
|
|
/* end of for loop. nothing found yet, load next character */
|
/* end of for loop. nothing found yet, load next character */
|
}
|
}
|
|
|
|
|
/* end of packet reached, no info found or not finished copying string */
|
/* end of packet reached, no info found or not finished copying string */
|
info->position = local_position;
|
info->position = local_position;
|
*offset = local_position;
|
*offset = local_position;
|
return FPGA_INFO_NOT_COMPLETE;
|
return FPGA_INFO_NOT_COMPLETE;
|
}
|
}
|
|
|
|
|
uint8_t fpga_load_begin(void)
|
uint8_t fpga_load_begin(void)
|
{
|
{
|
idata uint8_t i;
|
idata uint8_t i;
|
|
|
/* enable autopointer 0 */
|
/* enable autopointer 0 */
|
AUTOPTRSETUP = bmAPTREN | bmAPTR1INC;
|
AUTOPTRSETUP = bmAPTREN | bmAPTR1INC;
|
|
|
/* CS_B, RDWR_B should be high after board initialization
|
/* CS_B, RDWR_B should be high after board initialization
|
* but when something went wrong during fpga config the state is unknown */
|
* but when something went wrong during fpga config the state is unknown */
|
if(!(XILINX_CS_B | bmXILINX_CS_B) || !(XILINX_RDWR_B | bmXILINX_RDWR_B)) {
|
if(!(XILINX_CS_B | bmXILINX_CS_B) || !(XILINX_RDWR_B | bmXILINX_RDWR_B)) {
|
/* bring first RDWR_B high to signal ABORT to the FPGA */
|
/* bring first RDWR_B high to signal ABORT to the FPGA */
|
XILINX_RDWR_B |= bmXILINX_RDWR_B;
|
XILINX_RDWR_B |= bmXILINX_RDWR_B;
|
|
|
/* toggle CCLK four times more to complete the abort sequenze */
|
/* toggle CCLK four times more to complete the abort sequenze */
|
for(i=0; i<4; i++) {
|
for(i=0; i<4; i++) {
|
toggle_cclk();
|
toggle_cclk();
|
}
|
}
|
XILINX_CS_B |= bmXILINX_CS_B;
|
XILINX_CS_B |= bmXILINX_CS_B;
|
}
|
}
|
|
|
/* bring Prog_B low brings the device in the initalisation mode */
|
/* bring Prog_B low brings the device in the initalisation mode */
|
XILINX_PROG_B &= ~bmXILINX_PROG_B;
|
XILINX_PROG_B &= ~bmXILINX_PROG_B;
|
udelay(100); // and hold it there
|
udelay(100); // and hold it there
|
|
|
/* bring Prog_B bit high */
|
/* bring Prog_B bit high */
|
XILINX_PROG_B |= bmXILINX_PROG_B;
|
XILINX_PROG_B |= bmXILINX_PROG_B;
|
|
|
/* if Init_B goes high the device is in the configuration load mode */
|
/* if Init_B goes high the device is in the configuration load mode */
|
for(i=0;i<50;i++) {
|
for(i=0;i<50;i++) {
|
if(XILINX_INIT_B & bmXILINX_INIT_B) {
|
if(XILINX_INIT_B & bmXILINX_INIT_B) {
|
//if(1) { /* this line is needed for LA tests, uncomment this and comment the line befor */
|
//if(1) { /* this line is needed for LA tests, uncomment this and comment the line befor */
|
|
|
/* bring CS_B, RDWR_B low */
|
/* bring CS_B, RDWR_B low */
|
XILINX_RDWR_B &= ~bmXILINX_RDWR_B;
|
XILINX_RDWR_B &= ~bmXILINX_RDWR_B;
|
XILINX_CS_B &= ~bmXILINX_CS_B;
|
XILINX_CS_B &= ~bmXILINX_CS_B;
|
|
|
return 1;
|
return 1;
|
}
|
}
|
mdelay(1);
|
mdelay(1);
|
}
|
}
|
|
|
/* FPGA not ready to configure */
|
/* FPGA not ready to configure */
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
uint8_t fpga_load_xfer(xdata unsigned char *p, idata uint16_t *offset, \
|
uint8_t fpga_load_xfer(xdata unsigned char *p, idata uint16_t *offset, \
|
idata uint16_t *bytecount)
|
idata uint16_t *bytecount)
|
{
|
{
|
idata uint16_t local_count;
|
idata uint16_t local_count;
|
uint8_t local_data;
|
uint8_t local_data;
|
|
|
//printf_tiny("off %d ",local_count);
|
//printf_tiny("off %d ",local_count);
|
//printf_tiny("c %d\n",*bytecount);
|
//printf_tiny("c %d\n",*bytecount);
|
|
|
local_count = *offset;
|
local_count = *offset;
|
|
|
/* setup autopointer source adress from parameter p and the offset */
|
/* setup autopointer source adress from parameter p and the offset */
|
AUTOPTRH1 = ((uintptr_t)p >> 8);
|
AUTOPTRH1 = ((uintptr_t)p >> 8);
|
AUTOPTRL1 = ((uintptr_t)p & 0xFF);
|
AUTOPTRL1 = ((uintptr_t)p & 0xFF);
|
AUTOPTRH1 += (local_count >> 8);
|
AUTOPTRH1 += (local_count >> 8);
|
AUTOPTRL1 += (local_count & 0xFF);
|
AUTOPTRL1 += (local_count & 0xFF);
|
|
|
/* setup a for loop to send the data to the fpga data port */
|
/* setup a for loop to send the data to the fpga data port */
|
for(local_count; local_count < *bytecount; local_count++ ) {
|
for(local_count; local_count < *bytecount; local_count++ ) {
|
//XILINX_DATA = AUTODAT1; // drive Data Port with data
|
//XILINX_DATA = AUTODAT1; // drive Data Port with data
|
local_data = AUTODAT1;
|
local_data = AUTODAT1;
|
XILINX_DATA = local_data;
|
XILINX_DATA = local_data;
|
|
|
toggle_cclk();
|
toggle_cclk();
|
|
|
//printf_tiny("0x%x ",local_data);
|
//printf_tiny("0x%x ",local_data);
|
|
|
/* no need for us because we are way to slow that a busy occours */
|
/* no need for us because we are way to slow that a busy occours */
|
/* loop while busy is true */
|
/* loop while busy is true */
|
/*while((XILINX_BUSY & bmXILINX_BUSY) == bmXILINX_BUSY) {
|
/*while((XILINX_BUSY & bmXILINX_BUSY) == bmXILINX_BUSY) {
|
// if FPGA busy, toggle CCLK
|
// if FPGA busy, toggle CCLK
|
toggle_cclk();
|
toggle_cclk();
|
}
|
}
|
*/
|
*/
|
}
|
}
|
|
|
*offset += *bytecount;
|
*offset += *bytecount;
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* check for successful load...
|
* check for successful load...
|
*/
|
*/
|
uint8_t
|
uint8_t
|
fpga_load_end(void)
|
fpga_load_end(void)
|
{
|
{
|
idata uint8_t i;
|
idata uint8_t i;
|
|
|
/* toggle CCLK four times more to complete the startup sequenze */
|
/* toggle CCLK four times more to complete the startup sequenze */
|
for(i=0; i<4; i++) {
|
for(i=0; i<4; i++) {
|
toggle_cclk();
|
toggle_cclk();
|
}
|
}
|
|
|
/* bring CS_B, RDWR_B high */
|
/* bring CS_B, RDWR_B high */
|
XILINX_CS_B |= bmXILINX_CS_B;
|
XILINX_CS_B |= bmXILINX_CS_B;
|
XILINX_RDWR_B |= bmXILINX_RDWR_B;
|
XILINX_RDWR_B |= bmXILINX_RDWR_B;
|
|
|
if(!fpga_done()) {
|
if(!fpga_done()) {
|
/* if not DONE, an error occoured during configuration */
|
/* if not DONE, an error occoured during configuration */
|
print_err("fin.\n");
|
//print_err("fin.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
return 1;
|
return 1;
|
}
|
}
|
#endif /* XILINX */
|
#endif /* XILINX */
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
/* Altera stuff. only copied from USRP source code. does not work. only a
|
/* Altera stuff. only copied from USRP source code. does not work. only a
|
* guide to give you a start to port GECKO3COM to other boards using Altera
|
* guide to give you a start to port GECKO3COM to other boards using Altera
|
* devices
|
* devices
|
*/
|
*/
|
|
|
#ifdef ALTERA
|
#ifdef ALTERA
|
/*
|
/*
|
* setup altera FPGA serial load (PS).
|
* setup altera FPGA serial load (PS).
|
*
|
*
|
* On entry:
|
* On entry:
|
* don't care
|
* don't care
|
*
|
*
|
* On exit:
|
* On exit:
|
* ALTERA_DCLK = 0
|
* ALTERA_DCLK = 0
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NSTATUS = 1 (input)
|
* ALTERA_NSTATUS = 1 (input)
|
*/
|
*/
|
uint8_t
|
uint8_t
|
fpga_load_begin(void)
|
fpga_load_begin(void)
|
{
|
{
|
ALTERA_CONFIG &= ~bmALTERA_BITS; // clear all bits (NCONFIG low)
|
ALTERA_CONFIG &= ~bmALTERA_BITS; // clear all bits (NCONFIG low)
|
udelay (40); // wait 40 us
|
udelay (40); // wait 40 us
|
ALTERA_CONFIG |= bmALTERA_NCONFIG; // set NCONFIG high
|
ALTERA_CONFIG |= bmALTERA_NCONFIG; // set NCONFIG high
|
|
|
if (UC_BOARD_HAS_FPGA){
|
if (UC_BOARD_HAS_FPGA){
|
// FIXME should really cap this loop with a counter so we
|
// FIXME should really cap this loop with a counter so we
|
// don't hang forever on a hardware failure.
|
// don't hang forever on a hardware failure.
|
while ((USRP_ALTERA_CONFIG & bmALTERA_NSTATUS) == 0) // wait for NSTATUS to go high
|
while ((USRP_ALTERA_CONFIG & bmALTERA_NSTATUS) == 0) // wait for NSTATUS to go high
|
;
|
;
|
}
|
}
|
|
|
// ready to xfer now
|
// ready to xfer now
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/*
|
/*
|
* clock out the low bit of bits.
|
* clock out the low bit of bits.
|
*
|
*
|
* On entry:
|
* On entry:
|
* ALTERA_DCLK = 0
|
* ALTERA_DCLK = 0
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NSTATUS = 1 (input)
|
* ALTERA_NSTATUS = 1 (input)
|
*
|
*
|
* On exit:
|
* On exit:
|
* ALTERA_DCLK = 0
|
* ALTERA_DCLK = 0
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NSTATUS = 1 (input)
|
* ALTERA_NSTATUS = 1 (input)
|
*/
|
*/
|
|
|
static void
|
static void
|
clock_out_config_byte(const uint8_t bits) _naked
|
clock_out_config_byte(const uint8_t bits) _naked
|
{
|
{
|
_asm
|
_asm
|
mov a, dpl
|
mov a, dpl
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
rrc a
|
rrc a
|
mov _bitALTERA_DATA0,c
|
mov _bitALTERA_DATA0,c
|
setb _bitALTERA_DCLK
|
setb _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
clr _bitALTERA_DCLK
|
|
|
ret
|
ret
|
|
|
_endasm;
|
_endasm;
|
}
|
}
|
|
|
static void
|
static void
|
clock_out_bytes(const uint8_t bytecount,
|
clock_out_bytes(const uint8_t bytecount,
|
uint8_t xdata *p)
|
uint8_t xdata *p)
|
{
|
{
|
while (bytecount-- > 0)
|
while (bytecount-- > 0)
|
clock_out_config_byte (*p++);
|
clock_out_config_byte (*p++);
|
}
|
}
|
|
|
/*
|
/*
|
* Transfer block of bytes from packet to FPGA serial configuration port
|
* Transfer block of bytes from packet to FPGA serial configuration port
|
*
|
*
|
* On entry:
|
* On entry:
|
* ALTERA_DCLK = 0
|
* ALTERA_DCLK = 0
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NSTATUS = 1 (input)
|
* ALTERA_NSTATUS = 1 (input)
|
*
|
*
|
* On exit:
|
* On exit:
|
* ALTERA_DCLK = 0
|
* ALTERA_DCLK = 0
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NCONFIG = 1
|
* ALTERA_NSTATUS = 1 (input)
|
* ALTERA_NSTATUS = 1 (input)
|
*/
|
*/
|
uint8_t
|
uint8_t
|
fpga_load_xfer(const xdata uint8_t *p, const uint8_t bytecount)
|
fpga_load_xfer(const xdata uint8_t *p, const uint8_t bytecount)
|
{
|
{
|
clock_out_bytes (bytecount, p);
|
clock_out_bytes (bytecount, p);
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/*
|
/*
|
* check for successful load...
|
* check for successful load...
|
*/
|
*/
|
uint8_t
|
uint8_t
|
fpga_load_end(void)
|
fpga_load_end(void)
|
{
|
{
|
uint8_t status = ALTERA_CONFIG;
|
uint8_t status = ALTERA_CONFIG;
|
|
|
if (!UC_BOARD_HAS_FPGA) // always true if we don't have FPGA
|
if (!UC_BOARD_HAS_FPGA) // always true if we don't have FPGA
|
return 1;
|
return 1;
|
|
|
if ((status & bmALTERA_NSTATUS) == 0) // failed to program
|
if ((status & bmALTERA_NSTATUS) == 0) // failed to program
|
return 0;
|
return 0;
|
|
|
if ((status & bmALTERA_CONF_DONE) == bmALTERA_CONF_DONE)
|
if ((status & bmALTERA_CONF_DONE) == bmALTERA_CONF_DONE)
|
return 1; // everything's cool
|
return 1; // everything's cool
|
|
|
// I don't think this should happen. It indicates that
|
// I don't think this should happen. It indicates that
|
// programming is still in progress.
|
// programming is still in progress.
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
#endif /* ALTERA */
|
#endif /* ALTERA */
|
|
|