/*** BeginHeader ********************************************/ #ifndef __SERDOWNL #define __SERDOWNL /*** EndHeader ***********************************************/ /* START LIBRARY DESCRIPTION ********************************************* SERDOWNL.LIB Copyright (c) 2002-2006, SHDesigns, www.shdesigns.org Updated: 6-2-2003 now supports separate I&D. 6-24-2003 - fixes for bios problems in DC 7.3x Version 1.1 7-9-2003 Added delays to modem commands. Found modem missed data even though it responded with an OK. Added 100ms between commands. Added support for modems that default to numeric result codes. Update 8-7-2003: Changed source to be compatible when included with Ethernet loader. Update 7-1-2004 Removed need for serdlinc.h Added USE_SERIAL_X defines Update 4-6-2005: Added RCM3300/3360 support Update 11-9-2005: Rewrite memory mapper from ethernet version. Uses macros to make code easier. This should work better on newer boards, especially the odd boards like the RCM33600 and RCM3365. Update 1-4-2006: Added IO INIT functionality #define SERDL_IOINIT to use the fucntionality. The value is an initialization string for an array as Port,value. The last port # should be 0 i.e to set Port D bit 0 as an output high and PE6 as an outout low #define SERDL_IOINIT {PDDR,0x1,PDDDR,0x1,PEDR,0,PDDR,0x40,0} Update 7-13-2006 Added comments for RS485 handshaking Update 09-06-2006 Added ram_loader parameter to data passed to RAM loader Some versions of DC fill unused areas with trash, this caused parts of the RAM loader to exist in unused areas. The RAM loader would search the flash and find a bogus ID string and think it had found the RAM loader in flash. Also added the serial port passed as a parameter. That will allow future generic RAM loaders that support any port. Update 03-28-2008 Added support for the RCM4xxx boards with 8-bit RAM. Update 08-17-2008 Fix undefined R4000 define DESCRIPTION: FLASH Download via Serial port or modem. SUPPORT LIB'S: END DESCRIPTION **********************************************************/ /* START FUNCTION DESCRIPTION ******************************************** SerDL_Init() SYNTAX: int SerDL_Init(char * id); PARAMETER1: String to report to downloader Use NULL to use the default string KEYWORDS: download DESCRIPTION: Initialize the download manager. The string will appear in the list of boards ready to download in the PC download app. RETURN VALUE: int - non-0 if error END DESCRIPTION **********************************************************/ /*** BeginHeader SerDL_Init */ #ifdef USE_SERIAL_A //#define SERA_USEPORTD if needed #define DLM_SERIAL_PORT 0 #define AINBUFSIZE 1023 #define AOUTBUFSIZE 255 #define serXread serAread #define serXrxused serArdUsed #define serXtxused serAwrUsed #define serXopen serAopen #define serXwrite serAwrite #define serXclose serAclose #define serXflowon serAflowcontrolOn // if using I/O port D pins uncomment and change to //#define SERA_USEPORTD #endif #ifdef USE_SERIAL_B //#define SERB_USEPORTD if needed #define DLM_SERIAL_PORT 1 #define BINBUFSIZE 1023 #define BOUTBUFSIZE 255 #define serXread serBread #define serXrxused serBrdUsed #define serXtxused serBwrUsed #define serXopen serBopen #define serXwrite serBwrite #define serXclose serBclose #define serXflowon serBflowcontrolOn // if using I/O port D pins uncomment and change to //#define SERB_USEPORTD #endif #ifdef USE_SERIAL_C #define DLM_SERIAL_PORT 2 #define CINBUFSIZE 1023 #define COUTBUFSIZE 255 #define serXread serCread #define serXrxused serCrdUsed #define serXtxused serCwrUsed #define serXopen serCopen #define serXwrite serCwrite #define serXclose serCclose #define serXflowon serCflowcontrolOn #endif #ifdef USE_SERIAL_D #define DLM_SERIAL_PORT 3 // bl1800 has rs485 drivers #if ((_BOARD_TYPE_&0xff00) == 0x0100) #define JR485 #warnt "Compile for RS485" #endif #define DINBUFSIZE 1023 #define DOUTBUFSIZE 255 #define serXread serDread #define serXrxused serDrdUsed #define serXtxused serDwrUsed #define serXopen serDopen #define serXwrite serDwrite #define serXclose serDclose #define serXflowon serDflowcontrolOn #endif #ifdef USE_SERIAL_E #define DLM_SERIAL_PORT 4 #define EINBUFSIZE 1023 #define EOUTBUFSIZE 255 #define serXread serEread #define serXrxused serErdUsed #define serXtxused serEwrUsed #define serXopen serEopen #define serXwrite serEwrite #define serXclose serEclose #define serXflowon serEflowcontrolOn #endif #ifdef USE_SERIAL_F #define DLM_SERIAL_PORT 5 #define FINBUFSIZE 1023 #define FOUTBUFSIZE 255 #define serXread serFread #define serXrxused serFrdUsed #define serXtxused serFwrUsed #define serXopen serFopen #define serXwrite serFwrite #define serXclose serFclose #define serXflowon serFflowcontrolOn #endif #ifndef COMM_BLOCK_LEN #define COMM_BLOCK_LEN 1030 #endif typedef struct { unsigned char flag; unsigned char cmd,status; unsigned short int length; // data size unsigned long int address; // write address unsigned char data[COMM_BLOCK_LEN]; // can be up to 512 bytes. } SER_COMM_HEADER; #define SER_COMM_HEADER_SIZE (sizeof(SER_COMM_HEADER)-COMM_BLOCK_LEN) // command definitions #define UDPDNLD_QUERY 1 // query for all boards (broadcast) #define UDPDNLD_DOWNLOAD_RAM 2 // download RAM code #define UDPDNLD_XMEM_SIZE 3 // xmem size needed for RAM code #define UDPDNLD_DOWNLOAD_FLASH 4 // download FLASH code (data len=0 when done) #define UDPDNLD_RUN 5 // run download RAM code #define UDPDNLD_REBOOT 6 // restart with new code #define UDPDNLD_SET_IP 7 // set the board to diff IP #define UDPDNLD_GET_USERBLOCK 9 // query status #define UDPDNLD_STATUS_NULL 0 // not set #define UDPDNLD_STATUS_NEED_CODE 1 // board needs code downloaded to RAM #define UDPDNLD_STATUS_HAS_CODE 2 // board has co #define UDPDNLD_STATUS_RAM_CODE 3 // ram code already running #define UDPDNLD_STATUS_NOMEM 4 // no xmem available #define UDPDNLD_STATUS_REBOOT 5 // rebooting // download status #define UDPDNLD_STATUS_ACK 6 // download acknowledge #define UDPDNLD_STATUS_NACK 7 // download fail acknowledge #define UDPDNLD_STATUS_SEQUENCE 8 // dld sequence error #define UDPDNLD_STATUS_RAM_CODE_IN_XMEM 9 // RAM loader in flash #define UDPDNLD_STATUS_FRAG 10 // fragmented packet received #define __false 0 #define __true !0 typedef struct { char use_modem; // 0= direct connect, 1=modem answer, 2=dial out long int baud_rate; char phone_num[50]; char io_init[30]; char modem_init[80]; char id_string[76]; unsigned long ram_loader; char port; // 0=A,1=b... } COMM_PARAMS; int SerDL_Init(char * s); char * _id_string; unsigned int _dl_ram_size; char _dl_xmem_size; unsigned long _dl_ram_address; // if loader is included, use it //_ser_dl_loader // note: the following parameter cannot be changed unless the RAM loaders are compiled to support it. #define SERIAL_PARAMS 0x2f00 #ifdef SERIAL_LOADER #ximport SERIAL_LOADER _ser_dl_loader #endif /*** EndHeader *****/ #ifdef DIRECT_SERIAL int SerDL_Init(char * str) { _dl_ram_size=0; _dl_ram_address=0l; _id_string=str; if (str==NULL) _id_string="Serial Download Manager"; return (serXopen(BAUD_RATE)!=1); } #endif /* START FUNCTION DESCRIPTION ******************************************** SerDL_Tick(); SYNTAX: int SerDL_Tick(); PARAMETERS: KEYWORDS: download DESCRIPTION: Checks for download request and processes Queries. Only used for direct connection. RETURN VALUE: 0=if no download request 1=if Download requested Note: When this function returns 1 the user could should do the following: 1. Free up some xmem if not enough free (needs about 26k.) 2. Shut down user functions like interrupts and threads After this routine returns 1, at some later call, the ram loader will be executed and any user code may be lost. This return allows user code to exit gracefully. I.e. flush buffers, close connections. Turn off power to devices. For fastest download, it can be polled as follows: // part of main loop . if (SerDL_Tick()) { // Free mem and stop interrupts, i.e. //xrelease(my_xmem_buff); // only needed if less than 26k avail //TimerBUninit(); // stop timer ints while (1) SerDL_Tick(); // do nothing else! } END DESCRIPTION **********************************************************/ /*** BeginHeader CRC16 */ unsigned CRC16(unsigned char * pcdataptr,unsigned uslength,unsigned uscrc); /*** EndHeader ****/ #ifdef DIRECT_SERIAL unsigned CRC16(unsigned char * pcdataptr,unsigned uslength,unsigned uscrc) { unsigned usdata; if (uslength==0) return(0); while(uslength--) { usdata=(*(pcdataptr++))<<8; uscrc=((uscrc&0xff)<<8)+(uscrc>>8); uscrc=uscrc^usdata; usdata=uscrc& 0xff00; usdata<<=4; uscrc=uscrc^usdata; usdata = uscrc & 0xff00; usdata >>= 5; uscrc = uscrc ^ usdata; usdata >>= 7; } uscrc = ~(((uscrc & 0x00ff) <<8)+ (uscrc >> 8 )); return(uscrc); } #endif // /*** BeginHeader send_ack */ void send_ack(SER_COMM_HEADER * dbgp,int err); /*** EndHeader ****/ // send the ack, don't mess with command, status set to err. // no data bytes // #ifdef DIRECT_SERIAL void send_ack(SER_COMM_HEADER * dbgp,int err) { // if RS485 // enable transmitter /// unsigned * crc; crc=(unsigned *)(dbgp->data+dbgp->length); dbgp->status=err; *crc=CRC16((unsigned char *)dbgp,SER_COMM_HEADER_SIZE+dbgp->length,0xffff); serXwrite(dbgp,SER_COMM_HEADER_SIZE+dbgp->length+2); // // if RS485 // wait for TX to complete and then switch to RX } int check_packet(SER_COMM_HEADER * dbgp) { unsigned * crcpos; crcpos=(unsigned *)(dbgp->data+dbgp->length); if (CRC16((unsigned char *)dbgp,SER_COMM_HEADER_SIZE+dbgp->length,0xffff)!=*crcpos) { #if DEBUG_RST printf("Packet CRC error\n"); #endif return __false; } return __true; } #endif /*** BeginHeader read_block */ int read_block(char * dest,int len,unsigned long wait); /*** EndHeader ****/ int read_block(char * dest,int len,unsigned long wait) { unsigned long time; int tlen,bytes; tlen=0; time=MS_TIMER+wait; while (len>0&&MS_TIMERflag!=0x7e) return __false; if (dbgp->length>COMM_BLOCK_LEN+2) return __false; if (read_block((char *)&dbgp->data[2],dbgp->length,(dbgp->length)*delay)!=dbgp->length) return __false; return check_packet(dbgp); } return __false; } #endif /*** BeginHeader */ #ifndef RCM3200 // this gets rid of error on older compilers. #define RCM3200 0 #endif #ifndef BL2500C #define BL2500C 0 #endif #ifndef RCM3800A // this gets rid of error on older compilers. #define RCM3800A 0 #endif #ifndef RCM3220A // this gets rid of error on older compilers. #define RCM3220A 0 #endif #ifndef EM1500A // this gets rid of error on older compilers. #define EM1500A 0 #endif #ifndef RCM3300A // this gets rid of error on older compilers. #define RCM3300A 0 #endif #ifndef BL2600D // this gets rid of error on older compilers. #define BL2600D 0 #endif #ifndef BL2600A // this gets rid of error on older compilers. #define BL2600A 0 #endif //7-14-2004 fix for 7.2x compiler. #ifndef FAST_RAM_COMPILE #define FAST_RAM_COMPILE 0 #endif #define CS2_MAP 0x85 #if !FAST_RAM_COMPILE #if ((_BOARD_TYPE_ == RCM3200) || (_BOARD_TYPE_ == RCM3220A) \ || (_BOARD_TYPE_ == BL2500C) || (_BOARD_TYPE_ == EM1500A) \ || ((_BOARD_TYPE_ >= RCM3300A) && (_BOARD_TYPE_ <= (RCM3300A+0x00FF))) \ || (_BOARD_TYPE_ == RCM3800A) \ || (_BOARD_TYPE_ == BL2600A) || (_BOARD_TYPE_ == BL2600D)) #define USE_CS2 #endif #endif #ifdef USE_CS2 #define SET_NORM_CS2 $\ ld a,c $\ ioi ld (MB2CR),a #else #define SET_NORM_CS2 #endif #ifdef USE_CS2 #define SET_256K_CS2 $\ ld a,CS2_MAP $\ ioi ld (MB2CR),a #else #define SET_256K_CS2 #endif #ifndef R4000 #define R4000 0x0200 #endif /*** EndHeader ***/ /*** BeginHeader SerLoad */ #ifndef DL_DEBUG #define DL_DEBUG nodebug #endif void SerLoad(int use_modem,long int baud_rate,char * id_string,char * modem_init,char * phone_num); /*** EndHeader ***/ #ifdef SERDL_IOINIT const char io_init[]=SERDL_IOINIT; #endif DL_DEBUG root void SerLoad(int use_modem,long int baud_rate,char * id_string,char * modem_init,char * phone_num) { auto COMM_PARAMS params; #GLOBAL_INIT{ #ifdef SERIAL_LOADER xmem2root(&_dl_ram_size,_ser_dl_loader,2); // only get low bytes _dl_ram_address=_ser_dl_loader+4; #else _dl_ram_address=0l; #endif } if (_dl_ram_address==0l) { #if DEBUG_RST printf("RAM loader not loaded, make sure SERIAL_LOADER is defined."); #endif return; } memset(¶ms,0,sizeof(params)); params.use_modem=use_modem; params.baud_rate=baud_rate; #ifdef NO_DLM_CACHE params.ram_loader=_dl_ram_address|0x1000000l; #else params.ram_loader=_dl_ram_address; #endif params.port=DLM_SERIAL_PORT; if (phone_num==NULL) phone_num=""; // put in empty # #ifdef SERDL_IOINIT memcpy(params.io_init,io_init,30); #endif strcpy(params.phone_num,phone_num); if (id_string==NULL) id_string="Serial Downloader"; strcpy(params.id_string,id_string); if (modem_init!=NULL) strcpy(params.modem_init,modem_init); #if DEBUG_RST printf("Run RAM Downloader - %s\r\n%ld baud, Addr=0x%lx, %d bytes\n",id_string,params.baud_rate,_dl_ram_address,_dl_ram_size); #endif #define LOADER_COPY 0x80000l #define LOADER_SEG 0x8 #asm nodebug ipset 3 // disable wd ld a,0x51 ioi ld (WDTTR),a ld a,0x54 ioi ld (WDTTR),a ld a,(SACRShadow) and 0xfc ioi ld (SACR),a ld a,(SBCRShadow) and 0xfc ioi ld (SBCR),a ld a,(SCCRShadow) and 0xfc ioi ld (SCCR),a ld a,(SDCRShadow) and 0xfc ioi ld (SDCR),a ld a,(TACRShadow) and 0xfc ioi ld (TACR),a ld a,(TBCRShadow) and 0xfc ioi ld (TBCR),a ld a,(SPCRShadow) and 0xfc ioi ld (SPCR),a ld a,(I0CRShadow) and 0xfc ioi ld (I0CR),a ld a,(I1CRShadow) and 0xfc ioi ld (I1CR),a ld a,(GCSRShadow) and 0xfc ioi ld (GCSR),a // older version fo the compiler do not have _CPU_ID_ #if CC_VER>0x721 #if (CPU_ID_MASK(_CPU_ID_) == R3000) ld a,(SECRShadow) and 0xfc ioi ld (SECR),a ld a,(SFCRShadow) and 0xfc ioi ld (SFCR),a ld a,(QDCRShadow) and 0xfc ioi ld (QDCR),a ld a,(ICCRShadow) and 0xfc ioi ld (ICCR),a ld a,0x80 ioi ld (BDCR),a #endif #endif // // // make reg copy of variables as they mey get trashed. // ld hl,(_dl_ram_address) ld a,(_dl_ram_address+2) ld b,a ld de,(_dl_ram_size) ;// get count #ifdef USE_CS2 ld a,(MB2CRShadow) ld c,a #endif exx ; save for later #ifdef USE_CS2 ld c,a #endif // // if seprarate I&D then stack is most likely where we want to move the loader // so we need to copy params first. This will trash global vars, so they are cached in alt regs // ld hl,@SP+params add hl,sp ld ix,hl ld iy,SERIAL_PARAMS ; start of param area ld b,128 ; copy, 256 bytes shoud be enough ld de,2 movestack: SET_NORM_CS2 ld hl,(ix+0) SET_256K_CS2 ld a,LOADER_SEG ldp (iy),hl add ix,de add iy,de djnz movestack ; ;//now copy loader exx ; restore, hl=address, b=seg, de=size, c=MB2CR ld ix,hl ; hl has _dl_ram_address inc de dec d ; 256 bytes are skipped xor a // clear carry rr de // divide by 2 ld iy,0 copy_ldr: SET_NORM_CS2 ld a,b ; current loader seg ldp hl,(ix) inc ix inc ix SET_256K_CS2 ld a,LOADER_SEG ldp (iy),hl inc iy inc iy // see if source 64k rollover ld hl,ix bool hl jr nz,same_seg inc b ; next 64k same_seg: ld hl,iy ld a,l or a jr nz,no_skip ld a,h cp SERIAL_PARAMS>>8 jr nz,no_skip ex de,hl ;; save count ld de,0x100 add ix,de add iy,de ex de,hl no_skip: dec de ld a,d or e jr nz,copy_ldr ; ioi ld a,(MMIDR) and a,0x10 ioi ld (MMIDR),a // disable separate I&D SET_256K_CS2 ld hl, 0xdfff // stack in root ld sp, hl ld iy,0xe000 ld ix,_J2Ram_s ld b,20 // RCODE_SIZE does not work!, 30 is plenty ld de,2 ldirfix: xor a ldp hl,(ix) ld a,LOADER_SEG ldp (iy),hl add ix,de add iy,de djnz ldirfix db 0xc7,0x00,0xe0,0x80 // ljump to 8e000 #endasm #asm nodebug _J2Ram_s: // First quadrant is RAM ld a,CS2_MAP ioi ld (MB0CR),a ioi ld (MB1CR),a xor a ioi ld (GCDR),a // turn off clock doubler ld a,0x8 ioi ld (STACKSEG),a // stack seg in root space ioi ld (DATASEG),a ld a,0xd8 ioi ld (SEGSIZE),a #if (CPU_ID_MASK(_CPU_ID_) == R4000) ld a,0x00 ioi ld (EDMR),a nop nop #endif jp 0 #endasm // we will never return } /*** BeginHeader SerDL_Tick */ int SerDL_Tick(); /*** EndHeader ****/ #ifdef DIRECT_SERIAL int SerDL_Tick() { auto SER_COMM_HEADER * up; auto int len; struct userBlockInfo UB; auto char buff[sizeof(SER_COMM_HEADER)]; // allow room for max code block #GLOBAL_INIT { _dl_xmem_size=0;}; up=(SER_COMM_HEADER *)buff; if (_dl_xmem_size) { if (xavail(NULL)>_dl_ram_size) up->status=UDPDNLD_STATUS_ACK; else UDPDNLD_STATUS_NOMEM; up->length=0; send_ack(up,up->status); _dl_xmem_size=0; } len= get_packet(up); if (len>0) { if ((up->cmd==UDPDNLD_QUERY)&&(up->length==0)) // check valid, no data { len=strlen(_id_string); if (len>79) len=79; memcpy(up->data,_id_string,len); up->data[len]='\0'; #ifdef SERIAL_LOADER xmem2root(&_dl_ram_size,_ser_dl_loader,2); // only get low bytes _dl_ram_address=_ser_dl_loader+4; up->status= UDPDNLD_STATUS_RAM_CODE_IN_XMEM; // tell downloader we have loader in xmem #else up->status= UDPDNLD_STATUS_NEED_CODE; // tell downloader to send us loader #endif up->address=1200; // used by downloader (1024 blocks+extra) up->length=len+1; send_ack(up,up->status); return 0; } else if ((up->cmd==UDPDNLD_XMEM_SIZE)&&(up->length==0)) // prepare for download { _dl_ram_size=(unsigned int)up->address; // how much mem we will need later. _dl_ram_address=0l; _dl_xmem_size=1; #if DEBUG_RST printf("Set XMEM RAM size %d\n",_dl_ram_size); #endif return 1; // tell caller we will be downloading soon! } else if (up->cmd==UDPDNLD_DOWNLOAD_RAM) // here's boot loader ;) { if (_dl_ram_address==0l) { if (_dl_ram_size==0) _dl_ram_size=36*1024; // big buff if unknown _dl_ram_address=xalloc((long)_dl_ram_size+8l); #if DEBUG_RST printf("Allocated %d bytes at %lx\n",_dl_ram_size+8,_dl_ram_address); #endif } root2xmem(_dl_ram_address+up->address,&up->data,up->length); // copy 2 xmem up->status=_dl_ram_address!=0?UDPDNLD_STATUS_ACK:UDPDNLD_STATUS_NOMEM; #if DEBUG_RST printf("Download %d bytes at %lx\n",up->length,_dl_ram_address+up->address); #endif up->length=0; send_ack(up,up->status); return 0; } else if (up->cmd==UDPDNLD_RUN) // off we go! SerLoad(0,BAUD_RATE,_id_string,NULL,NULL); else if (up->cmd==UDPDNLD_GET_USERBLOCK) { GetUserBlockInfo(&UB); up->length=0; if (UB.blockSize) { up->address=UB.addrA; if (UB.addrB && UB.addrBaddress) up->address=UB.addrB; } else up->address=0x80000l; send_ack(up,up->status); return 0; } } return 0; } #endif // /*** BeginHeader ********************************************/ #endif /*** EndHeader ***********************************************/