<body bgcolor="#FFFFFF">
/*****************************************************************************

BIN_LOADER Rev E


IMPORTANT: be sure "Include debug code RST/28 instructions" is NOT checked
on the
<Compile>
menu!

then
<Compile>
"Compile To Target"

  Run with a serial utility such as Kermit.
  Configure the serial utility for port connected to RS232, 19200 8N1.
     
  Run Hyperterminal.
  Run this program.


 10/20/01	Initial coding.
 10/24/01	Changed assy parameter for baud & result to HL
 10/25/01	Hard coded flash buffer for extension code
 01/26/02	Test MMU remap after xmem2xmem
 01/29/02	forth now runs with fully mapped ram at $0000
 				No BIOS customization needed.
 04/15/03	Serial port selection via define
 				Better dialog on flash exit

 
*****************************************************************************/

// turn of stdio print
#undef DEBUG 

// use xmem for main()!!
//
// it is critical that the in-line
// assembly that reconfigures the MMU and calls FORTH
// be located in xmem (0xE000-0xFFFF) so it is still mapped
// during the flash to ram and back change
//

#memmap xmem


/*****************************************************************************

 DEFINES to make it easier to change the serial port

 Change the definition of PORT in this file
 _AND_
 change the definition of PORT in the assembly source file

*****************************************************************************/

#define TRUE 1
#define FALSE 0

#define spA 1
#define spB 2
#define spC 3

#define PORT spC


// go ahead and define buffer sizes for all possible serial ports

#define AINBUFSIZE 15
#define BINBUFSIZE 15
#define CINBUFSIZE 15

#define OUTBUFSIZE 15

#define AOUTBUFSIZE 15
#define BOUTBUFSIZE 15
#define COUTBUFSIZE 15



#define BAUDRATE 19200


/*****************************************************************************/
// NO CODE BEFORE #ximports!


#ximport "forthr2000_rev20e.bin" forthbin


// places the length of
<filename>
( stored as a long)
// and its binary contents at the next available place in xmem flash.
// forth is about 8k bytes.

// the progam goes to xmem too, so saving room for forth
// additions requires allocating space or using a separate
// flash buffer. allocate space...
// can't use xalloc(long sz) because the xmem addresses won't be
// consecutive.


#ximport "empty4k.bin" extdbin
#ximport "empty4k.bin" extdbin2		// start with 8k extra.


// the entire forth image must be re-written to flash
// because of pointers that are defined (initialized)
// forthbin..lastUsedMem
/*****************************************************************************/


#define FORTHORG 0x0000

// forth is in assy. org to start at 0x0000 (in RAM).

/*****************************************************************************

SERIAL wrapper routines

*****************************************************************************/

int SerialOpen(long br)
{
#if PORT==spA
  return(serAopen(br));  
#elif PORT==spB
  return(serBopen(br));
#elif PORT==spC
  return(serCopen(br));
#endif

}

int SerialPutc(char ch)
{
#if PORT==spA 
  return(serAputc(ch));
#elif PORT==spB
  return(serBputc(ch));
#elif PORT==spC
  return(serCputc(ch));
#endif

}

int SerialGetc()
{
#if PORT==spA 
  return(serAgetc());
#elif PORT==spB
  return(serBgetc());
#elif PORT==spC
  return(serCgetc());
#endif

}

int SerialPuts(char *str)
{
#if PORT==spA 
  return(serAputs(str));
#elif PORT==spB
  return(serBputs(str));
#elif PORT==spC
  return(serCputs(str));
#endif

}

int SerialwrFree()
{
#if PORT==spA 
  return(serAwrFree());
#elif PORT==spB
  return(serBwrFree());
#elif PORT==spC
  return(serCwrFree());
#endif
}

void SerialClose()
{
#if PORT==spA 
  serAclose();
#elif PORT==spB
  serBclose();
#elif PORT==spC
  serCclose();
#endif
}


/*****************************************************************************

	Routines for segment read

*****************************************************************************/

int get_dataseg( )
{
#asm nodebug
	ioi ld a,(DATASEG)
	ld l,a
	ld h,0
#endasm
}

int get_stackseg( )
{
#asm nodebug
	ioi ld a,(STACKSEG)
	ld l,a
	ld h,0
#endasm
}
   		
int get_segsize( )
{
#asm nodebug
	ioi ld a,(SEGSIZE)
	ld l,a
	ld h,0
#endasm
}

// (root) data builds down from (watch_code_base - 1)

// keep out of:	
// extended memory logical address region E000H to FFFFH
// stack logical address D000H to DFFFH

// CHECK .map FILE (7.xx compiler) !!
// what? no .map (6.57 compiler)...you'll have to walk through your
// code with Inspect-Disassemble at Cursor to see addresses.

// check Information Window !!


/*****************************************************************************


							MAIN


*****************************************************************************/

// the stdio printf output code is executed during the
// 1st run of the program while in program mode
// (attached to PC running Dyn-C).


xmem main()
{
	char msg[32];

	int i;
	int c;
	int addr;	// return value from FORTH

   long baud;
   static long divisor;

   unsigned long addr1;
   unsigned long addr2;
   unsigned length;

   int br_div;

   unsigned int segsize_val;
   unsigned int dataseg_val;

   unsigned char nss;
   unsigned char nds;
   unsigned char oss;
   unsigned char ods;

	int ValidReply;
      
   static char buffer[0x2000];	// 8K BYTES for flash write on exit



   	
   ods=get_dataseg();
   #ifdef DEBUG
	printf("DATASEG: %02x\n",ods);
   #endif

   i=get_stackseg();
   #ifdef DEBUG
   printf("STACKSEG: %02x\n",i);
   #endif

   oss=get_segsize();
   #ifdef DEBUG
  	printf("SEGSIZE: %02x\n",oss);

		
	printf("physical address: %06lx\n",(long)forthbin);
   printf("physical address (extd): %06lx\n",(long)extdbin);
  	#endif
  	
	xmem2root(&length,forthbin,sizeof(long));		// set length (var in root)

	#ifdef DEBG
	printf("length: %x\n",length);
	#endif

   baud = BAUDRATE;
	// (divisor+1) for 19200 baud is stored in BIOS variable "freq_divider"
	divisor = (long)(freq_divider * 19200.0/(float)baud + 0.5) - 1L;
   // The counter divides by (n+1)

   br_div = (int)divisor;
   #ifdef DEBUG
	printf("baud divisor: %d\n",br_div);
	printf("BIOS freq_divider: %d\n",freq_divider);
	#endif
				
	// change segsize...keeps
	// vars where they are & makes more ram available...
	// forth can now grow up from 0 to bottom of vars

	addr1=xalloc(0xC000);		// allocate 48K of ram
   #ifdef DEBUG
	printf("physical address allocated: %06lx\n",(long)addr1);
	#endif
	if (addr1 == -1)
	  {
	  #ifdef DEBUG
	  printf("failed to allocate RAM!\n");
	  #endif
	  exit(-1);
	  }

	// put forth at next 4K boundary...
	
	addr2=(((addr1 >> 12) + 1) * 0x1000)+FORTHORG;
	#ifdef DEBUG
	printf("run code at pa: %06lx\n",(long)addr2);
	#endif

	nds=(unsigned char)(addr2 >> 12);		// calculate new DATASEG

	xmem2xmem(addr2,forthbin+4,length);		// move forth from flash to ram

	#ifdef DEBUG	
	printf("starting forth...\n");
	printf("dummy line\n"); 
	printf("dummy line2\n"); // so we can see the 2nd previous line before d-c times out
	#endif

	// structure old and new values for SEGSIZE & DATASEG
	// for in-line assy use...
	
	segsize_val=((oss & 0xF0) << 8)+ oss;		// (new * 0x100 + original)
	dataseg_val=(nds << 8)+ ods;

	
#asm nodebug

   // stop ints & wdt before changing mem map!
	ld a,0x53
	ioi ld (WDTTR),a
	ld a,0x54
	ioi ld (WDTTR),a			; NO WATCHDOG!

	ioi ld a,(GCSR)
	and	0xFC					; no periodic ints!!!
	ioi	ld (GCSR),a
	

	ld	hl,(br_div)				; set up parameters

	ld bc,(segsize_val)
	ld de,(dataseg_val)

   // new MMU mapping
	ld A,b
	ioi	ld (SEGSIZE),A
	ld A,d
	ioi	ld (DATASEG),A

   // START FORTH!
	
	call	FORTHORG				;with baudrate parameter in HL

   // restore MMU mapping
	ld A,e
	ioi	ld (DATASEG),A
	ld A,c
	ioi	ld (SEGSIZE),A

	ld (addr),hl				; get return value
	
#endasm

   SerialOpen(baud);
   
   // return value is next address in forth image
   //   if flash or forget used to quit
   //   or ZERO if BYE used to quit
   
   if (addr != 0)
     {
	  do	// prompt & response
	    {
	    strcpy(msg,"\r\nWrite to flash (Y/N)?");
   	 SerialPuts(msg);
	    while (SerialwrFree() != OUTBUFSIZE) ;

       do
         {
         c=SerialGetc();
         } while (c == -1);
       SerialPutc(c); // echo
		 if ((c == 'Y') || (c == 'N'))
		   {
		   ValidReply=TRUE;
		   }
		 else
		   {
		   ValidReply=FALSE;
		   SerialPuts("\r\nUPPERCASE ONLY\r\n");
		   }
       } while (!ValidReply);
   
     if (c == 'Y')
       {
       strcpy(msg,"\r\nWriting Flash...\r\n");
       SerialPuts(msg);
       while (SerialwrFree() != OUTBUFSIZE) ;

       length=addr-FORTHORG;	/* base image + extension */

		// xmem2xmem(forthbin+4,addr2,length);
		// CAN'T xmem2xmem into flash! so do it by hand...
		// see \SAMPLES\XMEM\FLASHDEM.C

		// write flash from buffer in 8K pieces

		xmem2root(buffer, addr2, 0x2000);       
      WriteFlash(forthbin+4, buffer, 0x2000);

      xmem2root(buffer, addr2+(unsigned long)0x2000, 0x2000);
      WriteFlash(forthbin+(unsigned long)0x2004, buffer, 0x2000);

      WriteFlash(forthbin,&length,sizeof(long));  /* update length var*/

      strcpy(msg,"\r\nFlash write done!\r\n");
      SerialPuts(msg);
      while (SerialwrFree() != OUTBUFSIZE) ;
      } // if (c == 'Y')
   } // if (addr != 0)

   strcpy(msg,"\r\nDone...\r\n");
   SerialPuts(msg);
   while (SerialwrFree() != OUTBUFSIZE) ;
   
   
   SerialClose();
   
} // end main


