/* Do not modify this file. Report bugs or desired changes to: Steve Pier University of California, Irvine pier@nucleus.ps.uci.edu 714-824-3162 */ /* dsp_init.c Host's DSP initialization code This file contains one function intended for direct use by the host software: int init_dsps( int dsp_min, int dsp_max, char* path ) -- initializes DSP's To initialize DSP's, the host should call init_dsps(), passing it the first DSP #, the last DSP #, and the path to the file containing the system code for these DSP's. init_dsps() attempts to complete the system download for each DSP, even if another DSP has caused an error. In this file, "port" refers to the port on the VME card that is writable by the VME host processor. This port is used to cause DSP reset or interrupt and to control the host's red LED on the VME card. See eboot.h for a description of the system file format. See eboot.h for a description of the DSP bootstrap process. */ #define I_AM_HOST /* this software runs in the host */ #include "hostspec.h" /* host-specific definitions */ /* include public first, then private */ #include "sys_pub.h" /* public communication system definitions */ #include "sys_priv.h" /* private communication system definitions */ #include "eboot.h" /* DSP boot definitions */ /* functions in this file */ int init_dsps( int dsp_min, int dsp_max, char* path ); /* reset and initialize DSP's, send system */ void send_system ( int dsp_min, int dsp_max, char *path ); /* download system to DSP's */ void depart(); /* close files, etc., before leaving send_system() */ void check_final( int dsp_no ); /* check if download completed ok */ void prep_dsp( int dsp_no ); /* prepare DSP for system download */ int timed_wait( int32* var1, int32 var2 ); /* wait until *var1 == var2 or timeout */ int prep_file( char *path ); /* return 0 if everything went ok, else -1 */ void send_page( int dsp_no, int32 *page_data ); /* send page of system from host RAM to DSP */ void log_timeout( int dsp_no, char *err_mess ); /* log timeout error */ int get_page( int32 *page ); /* get page of system file into host's RAM */ int check_word_0( int32 w ); /* check that word 0 of system file is 0x20 */ int check_addr( int32 w ); /* check that address in system file is valid */ int check_blck_size( int32 w ); /* check that block size in system file is valid */ int get_word( int32 *word ); /* return GW_ERR, GW_EOF, or GW_OK */ void log_err( int err_code, char *err_mess ); /* print out errors */ void log_boot( int dsp_no ); /* print out contents of boot structure */ void init_dpram( int dsp_no ); /* zero all of DPRAM except host_state */ void reset_dsp( int dsp_no ); /* reset DSP and perform minimal initializations */ /* FORM_bpt(dsp_no) forms a pointer to the specified DSP's boot structure */ #define FORM_bpt(dsp_no) \ struct boot_dpr *bpt; \ bpt = (struct boot_dpr*) dsp_base( dsp_no ); extern int dsp_status[]; /* download status of each DSP */ int down_errs; /* count of errors encountered during download */ int sysf_state; /* host's state w.r.t. reading the system file */ long sysf_words; /* number of words read from the system file */ long sysf_blk_size; /* size of current block in system file */ long sysf_blk_index; /* index in current block in system file */ FILE* fpt; /* pointer to system file */ #define SS_START (0) /* state of system file */ #define SS_WORD_0 (1) #define SS_WORD_1 (2) #define SS_BLK_SIZE (3) #define SS_BLK_DEST (4) #define SS_BLK_DATA (5) #define SS_DATA (6) #define SS_END (7) /* these values are used for error checking */ #define MAX_SYSTEM_SIZE (250000) /* max system size in INT32's */ #define MAX_SYSTEM_BLCK (250000) /* max size of block in system file */ #define MIN_SYSTEM_ADDR (0x809800) /* min address of block in system file */ #define MAX_SYSTEM_ADDR (0x93ffff) /* max address of block in system file */ #include "hos_init.c" /* include any host-specific functions (e.g., error loggers) */ /* reset and initialize the specified DSP's, then download system */ /* returns a count of errors encountered */ /* dsp_status contains status/errors for individual DSP's */ int init_dsps( int dsp_min, int dsp_max, char* path ) { int dsp_no; long t_zero; if ( dsp_min < 0 || /* check for valid parameters */ dsp_max >= NUM_CHAN || dsp_min > dsp_max ) { LOG_ERR( 10, "init_dsps(): invalid dsp_min or dsp_max" ); return( down_errs ); /* return with one error */ } for ( dsp_no = dsp_min; dsp_no <= dsp_max; ++ dsp_no ) /* init each DSP's status */ dsp_status[ dsp_no ] = DOWN_INCOMPLETE; /* download ok, but not done */ for ( dsp_no = dsp_min; dsp_no <= dsp_max; ++ dsp_no ) /* reset each DSP */ reset_dsp( dsp_no ); /* wait while DSP's reset */ for ( t_zero = (long) CLOCK(); (long)CLOCK() - t_zero <= DSP_RES_PERIOD; ); send_system( dsp_min, dsp_max, path ); return( down_errs ); } /* read system from file and send it to DSP's */ void send_system ( int dsp_min, int dsp_max, char *path ) { int i; int32 insure; int32 page_data[ PAGE_SIZE ]; /* or use malloc() (use free() in depart()) */ down_errs = 0; sysf_state = SS_START; /* state = at start of system file */ sysf_words = 0; /* number of words read = 0 */ fpt = NULL; /* open system file, remove header, etc. */ if ( prep_file( path ) ) depart(); /* get each DSP's attention, */ for ( i = dsp_min; i <= dsp_max; ++ i ) prep_dsp( i ); /* 'insure' should never cause the exit from this loop */ for ( insure = MAX_SYSTEM_SIZE; insure > 0; insure -= PAGE_SIZE ) { if ( sysf_state == SS_END ) break; /* if end of system file */ if ( get_page( page_data ) ) /* get page of file */ depart(); /* return if error */ /* try to send page to each DSP that is still ok */ for ( i = dsp_min; i <= dsp_max; ++ i ) { if ( dsp_status[ i ] == DOWN_INCOMPLETE ) send_page( i, page_data ); } /* continue while any DSP's download is incomplete */ for ( i = dsp_min; i <= dsp_max; ++ i ) { if ( dsp_status[ i ] == DOWN_INCOMPLETE ) break; } if ( i > dsp_max ) break; /* exit loop if no DSP is OK */ } if ( insure <= 0 ) { /* this should never happen */ LOG_ERR( 20, "send_system(): MAX_SYSTEM_SIZE exceeded" ); depart(); } for ( i = dsp_min; i <= dsp_max; ++ i ) { check_final( i ); /* do final check of dsp */ } depart(); } void depart() { if ( fpt != NULL ) fclose( fpt ); return; } void check_final( int dsp_no ) /* check if download completed ok */ { FORM_bpt( dsp_no ); /* form pointer to boot structure */ if ( dsp_status[ dsp_no ] != DOWN_INCOMPLETE ) /* if an error is already flagged */ return; /* then don't change it */ /* check for final DBS_DOWNLOAD_OK, watch for timeout */ if ( timed_wait( &bpt->dsp_bstate, (int32) DBS_DOWNLOAD_OK ) ) { log_timeout( dsp_no , "check_final(): DSP timed out after last page was downloaded" ); return; } if ( bpt->words_read != sysf_words ) { LOG_ERR( 30, "check_final(): DSP's word count does not agree with host's" ); dsp_status[ dsp_no ] = DOWN_ERROR; return; } bpt->host_bstate = HBS_IDLE; dsp_status[ dsp_no ] = DOWN_DONE; /* download was successful */ return; } /* make sure DSP is ready for download */ /* any errors are returned in dsp_status[ dsp_no ] */ void prep_dsp( int dsp_no ) { FORM_bpt( dsp_no ); /* form pointer to boot structure */ /* wait until dsp_state == DBS_READY */ /* abort if timeout */ if ( timed_wait( &bpt->dsp_bstate, (int32) DBS_READY ) ) { log_timeout( dsp_no, "prep_dsp(): DSP timed out during preparation for download" ); return; } /* *** check here for OK DSP memory test, etc. *** */ bpt->host_bstate = HBS_READY; /* wait until dsp_state == DBS_DOWNLOADING */ /* abort if timeout */ if ( timed_wait( &bpt->dsp_bstate, (int32) DBS_DOWNLOADING ) ) { log_timeout( dsp_no, "prep_dsp(): DSP timed out before entering DBS_DOWNLOADING state" ); return; } return; } /* wait until *var1 == var2, but do not wait beyond TIMEOUT_PERIOD */ /* return -1 if timeout, else 0 */ int timed_wait( int32* var1, int32 var2 ) { unsigned long t_zero; for ( t_zero = (long) CLOCK(); (long)CLOCK() - t_zero <= TIMEOUT_PERIOD; ) { if ( *var1 == var2 ) if ( *var1 == var2 ) /* make sure value is really there */ if ( *var1 == var2 ) return( 0 ); /* success */ } return( -1 ); /* signal timeout */ } /* See 'Format of System File' in eboot.h */ /* prep system code file for page reads */ int prep_file( char *path ) /* return 0 if everything went ok, else -1 */ { fpt = fopen ( path, "r" ); /* open file */ if ( fpt == NULL ) { LOG_ERR( 40, "prep_file(): could not open DSP system file" ); return( -1 ); } if ( getc( fpt ) != 0x02 ) { /* get rid of first character (ctrl-B) */ LOG_ERR( 50, "prep_file(): unexpected first character of DSP system file" ); return( -1 ); } sysf_state = SS_WORD_0; /* system file state: at word 0 */ return( 0 ); /* no errors */ } /* attempt to pass data to DSP specified by dsp_no */ /* return any error in dsp_status[ dsp_no ] */ void send_page( int dsp_no, int32 *page_data ) { int i; FORM_bpt( dsp_no ); /* form pointer to boot structure */ if ( bpt->dsp_bstate != DBS_DOWNLOADING ) { dsp_status[ dsp_no ] = DOWN_ERROR; LOG_ERR( 60, "send_page(): DSP aborted download" ); LOG_BOOT( dsp_no ); /* print out boot structure for DSP */ return; } /* wait until req == HAND_HI, abort if timeout */ if ( timed_wait( &bpt->req, (int32) HAND_HI ) ) { log_timeout( dsp_no, "send_page(): DSP timed out before activating req" ); return; } for (i = 0; i < PAGE_SIZE; ++ i ) /* move page to DPRAM */ bpt->page[ i ] = page_data[ i ]; for (i = 0; i < PAGE_SIZE; ++ i ) /* confirm that it made it */ if ( bpt->page[ i ] != page_data[ i ] ) break; if ( i < PAGE_SIZE ) { dsp_status[ dsp_no ] = DOWN_ERROR; LOG_ERR( 70, "send_page(): page data in DPRAM is corrupt" ); LOG_BOOT( dsp_no ); /* print out boot structure for DSP */ return; } bpt->ack = HAND_HI; /* complete handshake */ /* wait until req == HAND_LO, abort if timeout */ if ( timed_wait( &bpt->req, (int32) HAND_LO ) ) { log_timeout( dsp_no, "send_page(): DSP timed out before deactivating req" ); return; } bpt->ack = HAND_LO; return; } void log_timeout( int dsp_no, char *err_mess ) /* log timeout error */ { dsp_status[ dsp_no ] = DOWN_TIMEOUT; LOG_ERR( 80, err_mess ); /* log error, forward err_mess */ LOG_BOOT( dsp_no ); /* print out boot structure for DSP */ return; } #define GW_ERR 99 /* get_word() error */ #define GW_EOF -1 /* get_word() end of file */ #define GW_OK 0 /* get_word() word is ok */ /* get page from system file */ /* return -1 if initial EOF or other error, else 0 */ int get_page( int32 *page ) { int i, gw_code; int32 w; /* current word from system file */ for ( i = 0; i < PAGE_SIZE; ++ i ) { if ( sysf_state == SS_END ) break; /* get no more words */ gw_code = get_word( &w ); /* get_word() reports its own errors */ if ( gw_code != GW_OK ) return( -1 ); /* flag error */ page[ i ] = w; /* place word in page buffer */ ++ sysf_words; /* count words read from system file */ switch ( sysf_state ) { /* trace system file to help find errors */ case SS_WORD_0: if ( check_word_0( w ) ) return( -1 ); sysf_state = SS_WORD_1; break; /* next word: word 1 */ case SS_WORD_1: /* word 1 is ignored */ sysf_state = SS_BLK_SIZE; break; /* next word: block size */ case SS_BLK_SIZE: if ( check_blck_size( w ) ) return( -1 ); sysf_blk_size = w; /* set up for block */ sysf_blk_index = 0; if ( w == 0 ) sysf_state = SS_END; /* size of 0 == no more blocks */ else sysf_state = SS_BLK_DEST; /* next word: dest */ break; case SS_BLK_DEST: if ( check_addr( w ) ) return( -1 ); sysf_state = SS_BLK_DATA; break; /* next words: data */ case SS_BLK_DATA: ++ sysf_blk_index; /* count data words */ if ( sysf_blk_index == sysf_blk_size ) sysf_state = SS_BLK_SIZE; /* start another block */ break; case SS_END: /* should never happen */ LOG_ERR( 90, "get_page(): page read attempted after final block" ); break; } } if ( i == 0 ) { /* SS_END not allowed on first word */ LOG_ERR( 100, "get_page(): attempt to read beyond end of system file" ); return( -1 ); } return( 0 ); } int check_word_0( int32 w ) { if ( w != 0x20 ) { LOG_ERR( 110, "check_word_0(): first word of system file is not 0x20" ); return( -1 ); } return( 0 ); /* no error */ } int check_addr( int32 w ) { if ( w < MIN_SYSTEM_ADDR || w > MAX_SYSTEM_ADDR ) { LOG_ERR( 120, "check_addr(): illegal destination address in system file" ); return( -1 ); } return( 0 ); /* no error */ } int check_blck_size( int32 w ) { if ( w > MAX_SYSTEM_BLCK ) { LOG_ERR( 130, "check_blck_size(): illegal block size in system file" ); return( -1 ); } return( 0 ); /* no error */ } int get_word( int32 *word ) /* return GW_ERR, GW_EOF, or GW_OK */ { int i, f_err; unsigned u; int32 i32; *word = 0xdeadbeef; /* this value is returned in *word if error */ for ( i = 0, i32 = 0; i < 4; ++ i ) { /* read four bytes */ f_err = fscanf( fpt, "%2x", &u ); /* read hex byte, skip white space */ if ( f_err != 1 ) break; /* one value should be read, else problem */ if ( u > 255 ) { /* this should never happen */ LOG_ERR( 140, "get_word(): hex value in system file is too large" ); break; } i32 = (i32 << 8 ) + u; /* bytes are read from file MSB first */ } if ( i == 4 ) { *word = i32; return( GW_OK ); } /* all went well */ if ( f_err == EOF ) { /* EOF not expected */ LOG_ERR( 150, "get_word(): unexpected EOF in system file" ); return( GW_EOF ); } LOG_ERR( 160, "get_word(): error while reading system file" ); return( GW_ERR ); } void log_err( int err_code, char *err_mess ) /* print out errors */ { ++ down_errs; if ( down_errs > MAX_ERR_LOG ) return; /* ignore error if too many */ printf( "\n" ); printf( "\nDownload error #%d -->%s.", err_code, err_mess ); printf( "\nSystem file state: %d, words read so far: %ld.", sysf_state, sysf_words ); if ( down_errs == MAX_ERR_LOG ) printf( "\n%d download errors: no more will be logged.", down_errs ); return; } void log_boot( int dsp_no ) /* print out contents of boot structure */ { FORM_bpt( dsp_no ); /* form pointer to boot structure */ dsp_led( dsp_no, 1 ); /* turns red LED on DSP's VME card on */ printf( "\n" ); printf( "\nBoot structure for DSP #%d:", dsp_no ); printf( "\n host_bstate: %#10lx", (unsigned long) bpt->host_bstate ); printf( "\n boots: %10ld", (unsigned long) bpt->boots ); printf( "\n rom_rev: %10ld", (unsigned long) bpt->rom_rev ); printf( "\n dip_switches: %#10lx", (unsigned long) bpt->dip_switches); printf( "\n dsp_bstate: %#10lx", (unsigned long) bpt->dsp_bstate ); printf( "\n req: %#10lx", (unsigned long) bpt->req ); printf( "\n ack: %#10lx", (unsigned long) bpt->ack ); printf( "\n lo_mem %#10lx", (unsigned long) bpt->lo_mem ); printf( "\n hi_mem %#10lx", (unsigned long) bpt->hi_mem ); printf( "\n words_read %10ld", (unsigned long) bpt->words_read ); printf( "\n ram_loops %10ld", (unsigned long) bpt->ram_loops ); printf( "\n ram_errors %10ld", (unsigned long) bpt->ram_errors ); return; } void init_dpram( int dsp_no ) /* zero all of DPRAM except host_state */ { int i; int32 *bpt; bpt = (int32*) dsp_base( dsp_no ); /* pointer to base of DSP's dual-port RAM */ for ( i = 1; i < DPRAM_SIZE; ++ i ) /* do not clear host_bstate ( bpt[ 0 ] ) */ bpt[ i ] = 0; } void reset_dsp( int dsp_no ) /* reset DSP and perform minimal initializations */ { FORM_bpt( dsp_no ); /* form pointer to boot structure */ /*** --> start critical region (ideally: disable interrupts) ***/ bpt->host_bstate = HBS_RESETTING; /* tell DSP to wait after it is reset */ set_port( dsp_no, 0xff ); /* reset DSP by toggling HRESET\ line on VME card */ set_port( dsp_no, 0x7e ); /* ( this also clears the interrupt to the DSP */ set_port( dsp_no, 0xff ); /* and turns off the host's LED ) */ bpt->host_bstate = HBS_RESETTING; /* just in case DSP wrote host_bstate before being reset */ /*** <-- end critical region (ideally: re-enable interrupts) ***/ init_dpram( dsp_no ); /* clear DPRAM to 0 (except host_bstate) */ bpt->dsp_bstate = DBS_RESETTING; bpt->host_bstate = HBS_IDLE; /* allow DSP to proceed with RAM test */ return; } /******* functions below should be moved from init.c to one of Joe's files for communication functions *************/ #if 0 void dsp_led( int dsp_no, int on ) /* turns red LED on DSP's VME card on or off */ { int i; i = get_port( dsp_no ); /* get theoretical current value in port */ i &= ~0x80; /* clear bit 7 = turn LED on */ if ( ! on ) i |= 0x80; /* set bit 7 = turn LED off */ set_port( dsp_no, i ); /* write new value to port */ } void interrupt_dsp( int dsp_no ) /* interrupts DSP */ { int i; i = get_port( dsp_no ); /* get theoretical current value in port */ i |= 0x2; /* set bit 1 */ set_port( dsp_no, i ); i &= ~0x2; /* clear bit 1 */ set_port( dsp_no, i ); i |= 0x2; /* set bit 1 */ set_port( dsp_no, i ); } int port_image[ NUM_CHAN ]; /* image of VME cards' host ports */ int get_port( int dsp_no ) /* returns image of port */ { return( port_image[ dsp_no ] ); /* return image of port */ } void set_port( int dsp_no, int value ) /* writes value to port */ { * ( dsp_base( dsp_no ) + 2048 ) = value; /* write to hardware */ port_image[ dsp_no ] = value; /* write to image */ } #endif