Listing 7 Main programming routine

/**********************************************************************
Write data to the Flash Memory. Returns non-zero on success; on error
zero is returned and fm_err contains failure data. The pDst and length
parameters should be word aligned.

The pScrBuf parameter determines the fate of words erased in a sector but
not written with new data:
       if (pScrBuf == NULL), then writes to partial sectors leave the
              unwritten words of those sectors erased & unwritten.
       if (pScrBuf! = NULL), then *pScrBuf is assumed to point to at least
              FMINFO.SectorSize bytes, and unwritten (but erased) words
              in partially written sectors will be saved (in the scratch
              buffer) and re-written, maintaining their prior values.
**********************************************************************/

fm_write(pbase, pDst, pSrc, length, pScrBuf)
unsigned short *pbase;           /* ptr to the base of the Flash memory */
unsigned short *pDst;            /* where to write in Flash Memory space */
unsigned short *pSrc;            /* bytes from here are copied to Flash */
size_t length;                   /* copy this many bytes from pSrc to pDst */
unsigned short *pScrBuf;         /* scratch buffer for partial sector writes */
{
       size_t wri_len;          /* # partial sector bytes of user data */
       size_t keep_before;      /* # partial sector bytes prior to user data */
       size_t keep_after;       /* # partial sector bytes after user data */
       size_t offset;           /* word offsets for various uses */
       size_t SectorAddrMask;   /* converts ptr to offset within a sector */
       unsigned short *pSector; /* ptr to even sector boundary */
       char errcode;            /* non-zero indicates a parameter error */

       /* share this with other routines in this module: */
       pBase = pbase;

       /* clear out error structure: */
       memset(&fm_err, 0, sizeof(fm_err));

       /* reset the chip and load FMInfo with info about it: */
       if (!fm_status(pBase, (FMINFO *) 0))
              return 0;

       /* check input parameters for word alignment and overflow: */
       errcode = 0;
       if (((size_t) pDst & 1) || (length & 1))
              errcode = 6;

       else if (pDst + (length >> 1) pBase + (FMInfo.TotalSize>> 1))
              errcode = 7;

       /* these errors return length in pieces in the exp and act fields: */
       if (errcode)
       {       fm_error(pDst, (unsigned short) length >> 8,
                          (unsigned short) length & 0xFFFF, errcode);
              return 0;
       }

       /* this masks off address bits indicating offsets into a sector: */
       SectorAddrMask = FMInfo.SectorSize - 1;

       /* see if we are starting on an even sector boundary: */
       keep_before = ((size_t) pDst) & SectorAddrMask;

       /* if the first sector is a partial, do it separately: */
       if (keep_before)
       {
              /* get a pointer to the start of the sector: */
              pSector = pDst - (keep_before)) 1);

              /* compute # bytes in this sector being written by user: */

              wri_len = FMInfo.SectorSize - keep_before;
              if (length < wri_len)
                     wri_len = length;

              /* compute # bytes to keep after area being written: */
              keep_after = FMInfo.SectorSize - keep_before - wri_len;

              /* read existing Flash sector into scratch buffer: */
              if (pScrBuf)
                     memcpy(pScrBuf, pSector, FMInfo.SectorSize);

              /* erase the sector: */
              if (!fm_sector_erase(pDst, pDst))
                     return 0;

              /* copy the user's data to Flash: */
              if (!fm_cpy(pDst, pSrc, wri_len))
                     return 0;

              /* restore data in sector before user's data: */

              if (pScrBuf)
                     if (!fm_cpy(pSector, pScrBuf, keep_before))
                            return 0;

              /* restore data in sector after user's data: */
              if (pScrBuf && keep_after)
              {        offset = (wri_len + keep_before) >> 1;
                     if (!fm_cpy(pSector + offset,
                               pScrBuf + offset, keep_after))
                            return 0;
              }

              /* bump pointers: */
              pDst += (wri_len >> 1);
              pSrc += (wri_len >> 1);
              length -= wri_len;

              /* quit if done: */
              if (!length)
                     return 1;
       }

       /* see if we are ending on an even sector boundary: */
       wri_len = length & SectorAddrMask;

       /* handle partial final sector: */
       if (wri_len)
       {
              /* get a pointer to the start of the final sector: */
              pSector = pDst + ((length - wri_len) >> 1);

              /* compute # bytes to keep after area being written: */
              keep_after = FMInfo.SectorSize - wri_len;

              /* read partial existing Flash sector into scratch buffer: */
              if (pScrBuf)
                     memcpy(pScrBuf, pSector + (wri_len >> 1), keep_after);
       }
       /* erase the remaining sector(s): */

       if (!fm_sector_erase(pDst, pDst + (length >> 1) - 1))
              return 0;

       /* copy the user's data to Flash: */
       if (!fm_cpy(pDst, pSrc, length))
              return 0;

       /* restore data in sector after user's data: */
       if (wri_len && pScrBuf && keep_after)
       {       offset = wri_len >> 1;
              if (!fm_cpy(pSector + offset, pScrBuf, keep_after))
                     return 0;
       }

       /* return happy: */
       return 1;
}
/* End of File */