// // DCC2Tool.cc - interactive debugger for new HCAL DCC // perform minimal initialization of DCC, let usr read/write // to any DCC address // // 05 Jan 2009, pdl - Project started // #define REVISION "05 Jan 2009" #include #include "hcal/dcc/motherboard.hh" #include "log4cplus/logger.h" #include "log4cplus/loglevel.h" #include "log4cplus/configurator.h" #include "hcal/dcc/DCC2.hh" #include #include // default path to find HAL address table files #define XDAQ_ROOT "/home/daqowner/dist" // default parameters if none given and no config file #define DCC_SLOT 14 #define BUS_NAME "caen:0" //Flash registers #define VME_csr_addr 0x10 #define F_wbuf_addr 0x800 #define F_rbuf_addr 0xa00 #define F_cmd_addr 0x100 #define ERROR -1 #define OK 0 using namespace std; /* Globals */ static char *xdaq_root = XDAQ_ROOT; static int slot_number = DCC_SLOT; static char *vme_bus = BUS_NAME; static char *default_log_level = "error"; static char *hal_path; static vector prefix_list; static hcalDCC::DCC2* dcc2; static uint32_t f_sector[4] = {0,4,8,24}; /* Prototypes */ void set_log_level( Logger& mylog, string input); char *rl_gets( string prompt); int tokenize( char *buff, vector& tokens, int maxt); bool split_command( string str, string& group, string& command); bool match( string group, string command, string comp); void checkFlash(); void FlashErase(uint32_t file_num); int FLASHburn(char *Filename, int backup, int check); int main( int argc, char *argv[] ) { // Declarations for tool execution char *script_name = NULL; char *stmp = NULL; FILE *sf = NULL; cout << "DCC2Tool.exe revision " << REVISION << endl; // Check to make sure XDAQ_ROOT is set if( (xdaq_root = getenv("XDAQ_ROOT")) == NULL) { printf("\007\007*** XDAQ_ROOT not set. This is highly recommended, and will be\n"); printf("*** required in future versions (used to find HAL files, etc)\n"); printf("*** Setting to default /home/daqowner/dist which may or may not work for you!\n"); xdaq_root = XDAQ_ROOT; } if (argc > 1) { // process command line args here for(int i = 1; i < argc; i++) { if(argv[i][0] != '-') { if( isdigit( argv[i][0])) { slot_number = strtol( argv[i], NULL, 0); cout << "Slot number " << slot_number << " specified" << endl; } else { vme_bus = argv[i]; cout << "Bus:device " << vme_bus << " specified" << endl; } } else { // process '-' options here switch( toupper( argv[i][1])) { case 'X': // execute script, like htr.exe if( i+1 >= argc) { cout << "Need script name after -X" << endl; exit(1); } script_name = argv[i+1]; ++i; break; case 'L': // set log level if( i+1 >= argc) { cout << "Need log level after -L" << endl; exit( 1); } default_log_level = argv[i+1]; ++i; break; } } } } // set default HAL path using XDAQ_ROOT hal_path = (char *)malloc(256); snprintf( hal_path, 255, "%s/hal/hcal/", xdaq_root); printf("HAL search path set to %s\n", hal_path); // PROGRAMMER_HAL_PATH has priority over XDAQ_ROOT if( (stmp = getenv("PROGRAMMER_HAL_PATH")) != NULL) { hal_path = stmp; printf("Overriding default HAL path with %s from PROGRAMMER_HAL_PATH\n", hal_path); } cout << "Looking for HAL addresstable files in directory " << hal_path << endl; cout << "(change by setting PROGRAMMER_HAL_PATH environment variable)" << endl; Logger* mylog; try { // setup a logger log4cplus::BasicConfigurator config; config.configure(); Logger temp_log = log4cplus::Logger::getInstance("mylog"); mylog = &temp_log; // set default log level set_log_level( *mylog, default_log_level); } catch (exception &e) { cout << "Setting up logger: " << e.what() << endl; abort(); } cout << "INFO: Logger set up" << endl; // construct the DCC2 // hcalDCC::DCC2* dcc2; dcc2 = new hcalDCC::DCC2; cout << "INFO: DCC2 constructed" << endl; // attempt to set up logger for DCC2 cout << "DCC2::setLogger()" << endl; try { dcc2->setLogger(*mylog,slot_number); } catch (exception &e) { cout << e.what() << endl; abort(); } // setup paths to mapfiles const string HalPath(hal_path); const string vme_mapfile(HalPath + "DCC2_VME_A24_r1.dat"); const string xilinx_mapfile(HalPath + "DCC2_XILINX_A32_r1.dat"); // initialize DCC2 try { cout << "DCC2::initialize()..." << endl; if( !dcc2->initialize(vme_bus,slot_number, vme_mapfile, xilinx_mapfile)) { cout << "DCC2::initialize() returned false!" << endl; } } catch (exception &e) { cout << "DCC2::initialize() failed" << endl << e.what() << endl; abort(); } // Start command execution if( script_name) { if( (sf = fopen( script_name, "r")) == NULL) { cout << "Can't open script file: " << script_name << endl; exit(1); } printf("[Script %s start]\n", script_name); } // Start command prompt loop bool quit = false; char buff[256]; char *input, *input_copy; string prefix = ""; string group = ""; int j = 0; vector tokens; vector nc_tokens; string command; #define MAX_TOKENS 30 while( !quit) { if( sf != NULL) { if( fgets( buff, sizeof(buff)-1, sf) == NULL) { fclose( sf); sf = NULL; printf("[Script %s EOF]\n", script_name); } else { buff[strlen(buff)-1] = '\0'; printf("%s\n", buff); } } if( sf == NULL) { input = rl_gets( prefix + ">" ); input_copy = strdup( input); } else { input = buff; input_copy = strdup( buff); } if(input != NULL && strlen(input)>0 && *input != '#') { // lowercase the input for( size_t k=0; k " << endl; } else { uint32_t file_num; file_num = strtoul(nc_tokens[1].c_str(), NULL, 0); if(file_num < 0 || file_num > 3) printf("legal file numbers are 0 thru 3, entered as %d\n",file_num); else FlashErase(file_num); } } else if( match( group, command, "flash/prog")) { if( j < 2) { cout << "Usage: flash/prog [backup] [check]" << endl; } else { uint32_t backup; uint32_t check; char filename[30]; strcpy(filename, nc_tokens[1].c_str()); check = 0; backup = 0; if(j > 2){ if(!strncasecmp(nc_tokens[2].c_str(),"b",1)) backup = 1; if(!strncasecmp(nc_tokens[2].c_str(),"c",1)) check = 1; } if(j > 3){ if(!strncasecmp(nc_tokens[3].c_str(),"b",1)) backup = 1; if(!strncasecmp(nc_tokens[3].c_str(),"c",1)) check = 1; } if(check == 0) FLASHburn(filename,backup,0); FLASHburn(filename,backup,1); } } else if( match( group, command, "*/exit")) { if( sf == NULL) { cout << "Not running a script (use \"quit\"?)" << endl; } else { fclose( sf); sf = NULL; } } else if( match( group, command, "xilinx/read")) { if( j < 2) { cout << "Usage: xilinx/read [count]" << endl; } else { uint32_t dat; const char *item; uint32_t count = 1; item = nc_tokens[1].c_str(); if(j > 2) { count = strtoul(nc_tokens[2].c_str(), NULL, 0); printf("Reading %d registers\n", count); } // see if this is a string or a number if( isalpha( *item)) { // reading from HAL id if (j > 2) { printf("Reading multiple registers only supported when specifying register offset!\n"); continue; } dat = dcc2->readItem(item); printf("Read 0x%08x from %s\n", dat, tokens[1].c_str()); } else { // readinf from offset for (unsigned int i=0; iread(offset); printf("addr: 0x%05x data: 0x%08x\n", offset, dat); } } } } else if( match( group, command, "event/read")) { if( j < 2) { cout << "Usage: event/read [offset] [count] [cycle]" << endl; } else { uint32_t dat; uint32_t sa = 0x8000; uint32_t count = 0x100; uint32_t cycle = 0x100; if(j > 1) { sa = strtoul(nc_tokens[1].c_str(), NULL, 0); printf("starting addr: 0x%08x\n", sa); } if(j > 2) { count = strtoul(nc_tokens[2].c_str(), NULL, 0); printf("Reading %d words per event\n", count); } if(j > 3) { cycle = strtoul(nc_tokens[3].c_str(), NULL, 0); printf("Reading %d cycles\n", cycle); } // readinf from offset for (unsigned int k=0; kread(offset); // printf("addr: 0x%05x data: 0x%08x\n", offset, dat); } printf("\rcycle: 0x%08x",k); fflush(stdout); } printf(" \n"); } } else if( match( group, command, "xilinx/write")) { if( j < 3) { cout << "Usage: xilinx/write " << endl; } else { uint32_t dat; const char *item; item = nc_tokens[1].c_str(); // convert data to be written from hex/decimal dat = strtoul( tokens[2].c_str(), NULL, 0); // see if address is a string (HAL item) or number (offset) if( isalpha( *item)) { dcc2->writeItem(item, dat); } else { uint32_t offset = strtoul( item, NULL, 0); dcc2->write(offset, dat); } } } else if( match( group, command, "vme/read")) { if( j < 2) { cout << "Usage: vme/read [count]" << endl; } else { uint32_t dat; const char *item; uint32_t count = 1; item = nc_tokens[1].c_str(); if(j > 2) { count = strtoul(nc_tokens[2].c_str(), NULL, 0); printf("Reading %d registers\n", count); } // see if this is a string or a number if( isalpha( *item)) { // reading from HAL id if (j > 2) { printf("Reading multiple registers only supported when specifying register offset!\n"); continue; } dat = dcc2->readVMEItem(item); printf("Read 0x%x (%d) from %s\n", dat, dat, tokens[1].c_str()); } else { uint32_t offset = strtoul( item, NULL, 0); // readinf from offset for (unsigned int i=0; ireadVME(offset); printf("Read 0x%08x from offset 0x%06x\n", dat, offset); offset += 4; } } } } else if( match( group, command, "vme/write")) { if( j < 3) { cout << "Usage: vme/write " << endl; } else { uint32_t dat; const char *item; item = nc_tokens[1].c_str(); // convert data to be written from hex/decimal dat = strtoul( tokens[2].c_str(), NULL, 0); // see if address is a string (HAL item) or number (offset) if( isalpha( *item)) { dcc2->writeVMEItem(item, dat); } else { uint32_t offset = strtoul( item, NULL, 0); dcc2->writeVME(offset, dat); } } } else if( match( group, command, "*/quit")) { quit = true; continue; } else cout << "Unknown command: " << group << "/" << command << endl; } catch(exception& e) { cout << "Command failed (" << e.what() << ")" << endl; } free(input_copy); } } delete dcc2; return 0; } /* Helper functions */ void set_log_level( Logger& mylog, string input) { for( size_t k=0; k& tokens, int maxt) { int i = 0; char *p; // first free leftovers tokens.clear(); i = 1; p = strtok(buff, " \t"); tokens.push_back( p); #ifdef DEBUG printf("Save token %s as number %d\n", p, i); #endif while ( (p = strtok(NULL, " \t")) != NULL ) { tokens.push_back( p); ++i; #ifdef DEBUG printf("Save token %s as number %d\n", p, i); #endif if (i == maxt) return i; } #ifdef DEBUG printf("returning i=%d\n", i); #endif return i; } // split a command of format ggg/ccc into group, command // if there is no slash, check if the bool split_command( string str, string& group, string& command) { string::size_type s; // check for silly mistakes if( str.length() == 0) return true; if( str == "/") return true; // see if string contains a / if( (s = str.find( "/")) != string::npos) { // leading slash is not meaningful if( s == 0) { group = ""; command = str.substr(1); } else { group = str.substr( 0, s); command = str.substr( s+1); } } else { // check for bare prefix // cout << "Check for bare prefix" << endl; vector::iterator i = find( prefix_list.begin(), prefix_list.end(), str); if( i != prefix_list.end()) { cout << "Found prefix = " << *i << endl; group = *i; command = ""; return false; } group = ""; command = str; } return false; } // compare user command with string to match // bool match( string group, string command, string comp) { string g, c; split_command( comp, g, c); // cout << "Input Compare [" << group << "],[" << command << "] with " << comp << endl; // require command for a match if( command.length() == 0) { // cout << "Null command: no match" << endl; return false; } // empty group can match '*' (only) if( group.length() == 0) { // cout << "Null group matches only *" << endl; group = "*"; } if( g != "*") { if( g.length() < group.length() || group != g.substr( 0, group.length())) { return false; } } if( c.length() < command.length() || command != c.substr( 0, command.length())) { return false; } return true; } void checkFlash() { uint32_t rdata; //check for FLASH busy rdata = 1; while(rdata & 1) rdata = dcc2->readVME(VME_csr_addr); //waiting for write process to end rdata = 1 << 24; dcc2->writeVME(F_wbuf_addr, 5 << 24); while(rdata & (1 << 24)){ dcc2->writeVME(F_cmd_addr, 1); rdata = dcc2->readVME(F_rbuf_addr); } return; } void FlashErase(uint32_t file_num) { uint32_t l_sector[4] = {4,8,24,28}; for(uint32_t i = f_sector[file_num]; i < l_sector[file_num]; i++){ //enable write dcc2->writeVME(F_wbuf_addr, 0x6 << 24); dcc2->writeVME(F_cmd_addr, 0); //wait for FLASH ready checkFlash(); dcc2->writeVME(F_wbuf_addr, (0xd8 << 24)+(i << 16)); dcc2->writeVME(F_cmd_addr, 3); printf("\rerase secotr%d command sent!",i); fflush(stdout); //wait for FLASH ready checkFlash(); } printf("Erase done!\n"); return; } int FLASHburn(char *Filename, int backup, int check) { FILE *f; int ln = 0,last_dataline_found = 0; char line[100]; int file_num,i,j,k,addr,crc = 0xffffff; uint32_t rdata,buf,vme_file_size = 0x247eb; // open mcs file f = fopen(Filename,"r"); if (!f) { printf("FLASHburn: Cannot open file %s\n",Filename); return ERROR; } i = dcc2->readVME(VME_csr_addr); //if vme_chip is xc3s400a if(i & 0x800000){ vme_file_size = 0x3990b; printf("VME_chip is XC3S400A\n"); } // check device ID //wait for FLASH ready checkFlash(); dcc2->writeVME(F_wbuf_addr, 0x9f << 24); dcc2->writeVME(F_cmd_addr, 3); rdata = dcc2->readVME(F_rbuf_addr); if((rdata & 0xffffff00) != 0x20201600){ printf("Wrong FLASH ID : 0x%06x found\n",(rdata & 0xffffff00) >> 8); return ERROR; } strcpy(line,Filename); //convert to lower case for(i = 0; i < strlen(line); i++) if(line[i] > 64 && line[i] < 91) line[i] += 32; //find out address to start writing if(strstr(line,"vme") != NULL) file_num = backup; else if(strstr(line,"lrb") != NULL) file_num = 3; else file_num = 2; if(!check) //sector erase FlashErase(file_num); addr = f_sector[file_num] << 16; printf(" base address = 0x%08x\n",addr); last_dataline_found = 0; // loop over record in the file and read them in the array "line" while ( fgets(line, 100, f) != NULL) { char c1[3],c2[5]; unsigned char data[200]; int byte_count,address,rec_type,total; ln++; if(ln%0x1000 == 0){ // printf("\rcurrent line: 0x%x",ln); // fflush(stdout); printf("current line: 0x%x\n",ln); } // check that the record has more than 9 characters if ( strlen(line) < 9 ) { printf("FLASHburn: Error while reading " "line %d: it has less than 9 characters\n",ln); return ERROR; } // number of bytes in the record (first two hex numbers) strncpy(c1,line+1,2); c1[2] = '\0'; sscanf(c1,"%x",&byte_count); // address (hex numbers 3-6) strncpy(c2,line+3,4); c2[4] = '\0'; sscanf(c2,"%x",&address); // record type (hex numbers 7-8) strncpy(c1,line+7,2); c1[2] = '\0'; sscanf(c1,"%x",&rec_type); // calculate checksum total = byte_count+address/256+address%256+rec_type; // loop over the rest of the characters in the record and // convert them to int for (i=0; i<(byte_count+1);i++) { strncpy(c1,line+2*i+9,2); c1[2] = '\0'; data[i] = strtol(c1,NULL,16); total = total + data[i]; } // check the checksum for the record if (total%256 != 0) { printf("programChip: Error while reading line " "%d - a checksum error is found\n",ln); return ERROR; } //byte count must be multiples of 4, except last data line if(rec_type == 0 && byte_count%4 != 0){ if(last_dataline_found == 1){ printf("byte number not multiple of 4 at address 0x%06x exit\n",addr); return ERROR; }else{ last_dataline_found = 1; for(i=byte_count;(i%4) != 0;i++) data[i] = 0xff; byte_count++; } } // only data records are written if (rec_type == 0 && byte_count != 0) { //calculate CRC for (i=0; i> 23)^(tmp%2)); tmp = tmp >> 1; } if(file_num < 2 && ((addr+i) & 0x3ffff) == vme_file_size) printf("CRC-24 (MIL STD 188-184) of this file is 0x%06x\n",crc); } for (i=0; iwriteVME(F_wbuf_addr, (0xb << 24)+(addr & 0xffff00)); dcc2->writeVME(F_cmd_addr, 0x104); } else{ //enable write checkFlash(); dcc2->writeVME(F_wbuf_addr, (0x6 << 24)); dcc2->writeVME(F_cmd_addr, 0); //page program command and address dcc2->writeVME(F_wbuf_addr, (0x2 << 24)+(addr & 0xffff00)); } } buf = data[i+3] + (data[i+2] << 8) + (data[i+1] << 16) + (data[i] << 24); if(check){ rdata = dcc2->readVME(F_rbuf_addr + (addr & 0xfc)); if(rdata != buf){ printf("FLASH error addr = 0x%06x expected data : 0x%08x real data : 0x%08x\n",addr,buf,rdata); return ERROR; } } else dcc2->writeVME(F_wbuf_addr+(addr & 0xfc)+4,buf); addr += 4; //256 bytes of data in buffer, start page write if (addr%256 == 0 && check == 0) { //execute page write dcc2->writeVME( F_cmd_addr, 0x103); //waiting for page write end checkFlash(); } } // loop over bytes in the line } // rec_type equal to 0 } // loop over lines if(file_num > 1) printf("CRC-24 (MIL STD 188-184) of this file is 0x%06x\n",crc); // close mcs file printf("Last address is 0x%08x\n",addr); //if there are unwritten data in the buffer if (addr%256 != 0 && check == 0) { //fill buffer with 0xffff for(i = (addr & 0xfc); i < 256; i += 4) dcc2->writeVME(F_wbuf_addr+i+4, 0xffffffff); //execute page write dcc2->writeVME(F_cmd_addr, 0x103); //waiting for page write end checkFlash(); } fclose(f); if(check) printf("FLASH content is the same as the file %s\n",Filename); return OK; }