changeset 311:9cecc930d78f

fluid-mnf: original source from TI, defenestrated line endings and rearranged directory structure, but no *.[ch] source file content changes yet
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 29 Feb 2020 05:36:07 +0000
parents ae39d76d5b7a
children 6cba849e3332
files fluid-mnf/README fluid-mnf/calplus/ram_load.h fluid-mnf/calplus/secure_types.h fluid-mnf/calplus/standard.h fluid-mnf/efluid.c fluid-mnf/fileio.c fluid-mnf/fileio.h fluid-mnf/flash.c fluid-mnf/flash.h fluid-mnf/fluid.c fluid-mnf/fluid.h fluid-mnf/getopt.c fluid-mnf/getopt.h fluid-mnf/lz.h fluid-mnf/lzdecode.c fluid-mnf/lzencode.c fluid-mnf/machine.c fluid-mnf/misc.c fluid-mnf/misc.h fluid-mnf/protocol.h fluid-mnf/serial.c fluid-mnf/serial.h fluid-mnf/target.c fluid-mnf/target.h fluid-mnf/trace.c fluid-mnf/trace.h
diffstat 26 files changed, 8618 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/README	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,11 @@
+In the summer of 2019 we (FreeCalypso) had recovered a copy of TI's original
+FLUID package including source, but this TI original FLUID source targets only
+Windows, no Unix or Linux support included.  Back in 2007 or earlier Openmoko
+had made their own port of FLUID to Linux and we have their Linux/ARM binary,
+but the source for that Linux port appears to have been lost.
+
+This directory contains what is going to be my (Mother Mychaela's) attempt to
+do my own port of FLUID to Unix/Linux; I am starting by checking in TI's
+original source with defenestrated line endings.  I am also changing the
+directory structure a little bit, and I have checked the files in according to
+what will be my new directory structure.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/calplus/ram_load.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,299 @@
+/*                %Z% nom : %M% SID: %I% date : %G%                           */
+/* Filename:      %M%                                                         */
+/* Version:       %I%                                                         */
+/******************************************************************************
+ *                   WIRELESS COMMUNICATION SYSTEM DEVELOPMENT
+ *
+ *             (C) 2002 Texas Instruments France. All rights reserved
+ *
+ *                          Author : Francois AMAND
+ *
+ *
+ *  Important Note
+ *  --------------
+ *
+ *  This S/W is a preliminary version. It contains information on a product 
+ *  under development and is issued for evaluation purposes only. Features 
+ *  characteristics, data and other information are subject to change.
+ *
+ *  The S/W is furnished under Non Disclosure Agreement and may be used or
+ *  copied only in accordance with the terms of the agreement. It is an offence
+ *  to copy the software in any way except as specifically set out in the 
+ *  agreement. No part of this document may be reproduced or transmitted in any
+ *  form or by any means, electronic or mechanical, including photocopying and
+ *  recording, for any purpose without the express written permission of Texas
+ *  Instruments Inc.
+ *
+ ******************************************************************************
+ *
+ *  FILE NAME: ram_load.c
+ *
+ *
+ *  PURPOSE:  Describe the RAM loader state machine used during boot procedure
+ *            in order to download a FLASH programmer into the Internal RAM if
+ *            CALYPSOPLUS chip.
+ *
+ *
+ *
+ *  FILE REFERENCES:
+ *
+ *  Name                  IO      Description
+ *  -------------         --      ---------------------------------------------
+ *  
+ *
+ *
+ *  EXTERNAL VARIABLES:
+ *
+ *  Source:
+ *
+ *  Name                    Type              IO   Description
+ *  -------------------     ---------------   --   ----------------------------
+ *
+ *
+ *  EXTERNAL REFERENCES:
+ *
+ *  Name                Description
+ *  ------------------  -------------------------------------------------------
+ *
+ *
+ *
+ *  ABNORMAL TERMINATION CONDITIONS, ERROR AND WARNING MESSAGES:
+ *  
+ *
+ *
+ *  ASSUMPTION, CONSTRAINTS, RESTRICTIONS:
+ *  
+ *
+ *
+ *  NOTES:
+ *  
+ *
+ *
+ *  REQUIREMENTS/FUNCTIONAL SPECIFICATION REFERENCES:
+ *
+ *
+ *
+ *
+ *  DEVELOPMENT HISTORY:
+ *
+ *  Date        Name(s)         Version  Description
+ *  ----------  --------------  -------  --------------------------------------
+ *  31-May-02   Francois AMAND  V1.0.0   Import from CALYPSO
+ *
+ *  ALGORITHM: Use the RAM loader state machine defined in CALPLUS208 specifica-
+ *             tion.
+ *
+ *
+ *****************************************************************************/
+
+
+#ifndef _RAM_LOADER_H_
+  #define _RAM_LOADER_H_
+  
+  /*
+   *  Include files
+   */
+  #include "standard.h"
+  #include "secure_types.h"
+
+  #define C_MAX_PLATFORM_DATA 64192
+
+  /*
+   *  Main buffer size
+   */
+  // Include manufacture certificate + platform data + manufacturer certificate signature
+  #define C_MAX_BUFFER_SIZE (sizeof(T_MANUFACTURER_CERTIFICATE) + C_MAX_PLATFORM_DATA + C_MANUF_SIG_SIZE * C_WORD32LGB)
+
+  /*
+   *  Serial interface choice
+   */
+  enum {
+    #ifdef _SERIAL_IRDA_
+      C_SERIAL_ID_MODEM = 0,
+      C_SERIAL_ID_IRDA  = 1
+    #else
+      C_SERIAL_ID_MODEM = 0
+    #endif
+  };
+  
+  
+  /*
+   *  RAM loader state
+   */
+  typedef enum {
+    C_RESET_STATE               = 0,
+    C_SIGNALLING_STATE          = 1,
+    C_AWAIT_PARAMETER_STATE     = 2,
+    C_COMMAND_PHASE_STATE       = 3
+  } T_RAM_LOADER_PC_STATE;
+
+
+  /*
+   *  RAM loader event
+   */
+  typedef enum {
+    C_NO_EVENT                  = 0,
+
+    C_USER_DOWNLOAD_REQUEST     = 1,
+    C_USER_ABORT_REQUEST        = 2,
+
+    C_SIGNALLING_TIMEOUT        = 3,
+    C_WATCHDOG_TIMEOUT          = 4,
+
+    C_SIGNALLING_RESPONSE       = 5,
+    C_PARAMETER_ACK_RESPONSE    = 6,
+    C_PARAMETER_NACK_RESPONSE   = 7,
+    C_WRITE_ACK_RESPONSE        = 8,
+    C_WRITE_NACK_RESPONSE       = 9,
+    C_CERTIFICATE_ACK_RESPONSE  = 10
+  } T_RAM_LOADER_PC_EVENT;
+
+
+  /*
+   *  RAM loader command
+   */
+  typedef enum {
+    C_SIGNALLING_REQUEST_CMD  = 0,
+    C_PARAMETER_REQUEST_CMD   = 1,
+    C_WRITE_REQUEST_CMD       = 2,
+    C_ABORT_REQUEST_CMD       = 3,
+    C_CERTIFICATE_REQUEST_CMD = 4
+  } T_RAM_LOADER_PC_COMMAND;
+
+
+  /*
+   *  RAM loader timer
+   */
+  typedef enum {
+    C_SIGNALLING_TIMER = 0,
+    C_WATCHDOG_TIMER   = 1
+  } T_RAM_LOADER_PC_TIMER;
+  
+  #define C_RAM_LOADER_PC_NB_TIMER 2
+
+
+  /*
+   *  Timeout definition in ms
+   */
+  #define C_SIGNALLING_TIMEOUT_VALUE 4L       /* 2 ms */
+  #define C_WATCHDOG_TIMEOUT_VALUE   120000L  /* 2 mn  */
+
+
+  /*
+   *  RAM loader status
+   */
+  typedef enum {
+    C_NO_STATUS              = 0,
+    C_BAD_INPUT_FILE         = 1,
+    C_SUCCESS                = 2,
+    C_BAD_PARAMETERS         = 3,
+    C_ERROR_DURING_WRITE     = 4,
+    C_BAD_ADDRESS_OF_BRANCH  = 5,
+    C_WATCHDOG_TIMER_REACHED = 6,
+    C_USER_ABORT             = 7
+  } T_RAM_LOADER_PC_STATUS;
+
+
+  enum {
+    C_COMMAND_NOT_RECEIVED = 0,
+    C_COMMAND_RECEIVED     = 1,
+    C_SERIAL_TIMEOUT       = 2
+  };
+  
+  typedef struct {
+    UWORD8  d_nb_data;
+    UWORD32 d_address;
+    UWORD8  *p_block;
+  } T_WRITE_REQUEST;
+
+
+  typedef struct {
+  	UWORD16	d_max_byte;
+  	UWORD8	a_data[sizeof(T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER)];
+  } T_FRAME;
+
+
+  typedef struct {
+    UWORD8  d_device_id;
+    UWORD8  d_baud_rate;
+    char    *p_file_name;
+
+    /*
+     *  Signalling response variable
+     */
+    UWORD16 d_romcode_version;
+    UWORD8  a_hash_man_pub_key[C_MD5HASHLG * C_WORD32LGB];
+    UWORD8  a_die_id[C_WORD32LGB * C_DIE_ID_SIZE];
+    UWORD8  a_Certsig[C_WORD32LGB * C_MANUF_SIG_SIZE];
+
+    /*
+     *  Parameter NACK response variable
+     */
+    UWORD8  d_param_req_sts;
+
+    /*
+     *  Certificate request variable
+     */
+    BOOLEAN b_certificate_request;
+
+    /*
+     *  Certificate response variable
+     */
+    union {
+      UWORD8                      a_firm_cert[C_MAX_BUFFER_SIZE]; /* Take into account max data_platform size */
+      T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA d_firm_cert;
+    } u_firm_cert;
+
+    /*
+     *  Command request variable
+     */
+    UWORD32                       d_uart_timeout;
+    union {
+      UWORD8                      a_code_certificate[sizeof(T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER)];
+      T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER d_code_certificate;
+    } u_code_certificate;
+
+    /*
+     *  Write request variable
+     */
+    UWORD32 d_nb_byte_in_block;
+    UWORD32 d_nb_byte_sent;
+    UWORD8  *p_block_buffer;
+    UWORD32 d_block_address;
+    UWORD32 d_block_size;
+
+    /*
+     *  Mobile received variable
+     */
+    //UWORD16 d_max_block_size;
+    //UWORD16 d_mobile_buffer_size;
+    UWORD8 d_write_status;
+
+    //T_WRITE_REQUEST d_parameter_request;
+  } T_RAM_LOADER;
+
+
+  /*
+   *  RAM loader baud rate definition
+   */
+  typedef enum {
+    C_BAUD_RATE_812500  = 0,
+    C_BAUD_RATE_406250  = 1,
+    C_BAUD_RATE_203125  = 2,
+    C_BAUD_RATE_115200  = 3,
+    C_BAUD_RATE_57600   = 4,
+    C_BAUD_RATE_38400   = 5,
+    C_BAUD_RATE_28800   = 6,
+    C_BAUD_RATE_19200   = 7,
+    C_BAUD_RATE_DEFAULT = 7,
+    C_BAUD_RATE_9600    = 8
+  } T_BAUD_RATE;
+
+
+  #define C_BLOCK_INDEX_OFFSET   0
+  #define C_NB_BLOCK_OFFSET      1
+  #define C_BLOCK_SIZE_OFFSET    2
+  #define C_BLOCK_ADDRESS_OFFSET 4
+  #define C_BLOCK_DATA_OFFSET    8
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/calplus/secure_types.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,508 @@
+/*                %Z% nom : %M% SID: %I% date : %G%                           */
+/* Filename:      %M%                                                         */
+/* Version:       %I%                                                         */
+/******************************************************************************
+ *                   WIRELESS COMMUNICATION SYSTEM DEVELOPMENT
+ *
+ *             (C) 2002 Texas Instruments France. All rights reserved
+ *
+ *                          Author : Constantin HAIDAMOUS
+ *
+ *
+ *  Important Note
+ *  --------------
+ *
+ *  This S/W is a preliminary version. It contains information on a product
+ *  under development and is issued for evaluation purposes only. Features
+ *  characteristics, data and other information are subject to change.
+ *
+ *  The S/W is furnished under Non Disclosure Agreement and may be used or
+ *  copied only in accordance with the terms of the agreement. It is an offence
+ *  to copy the software in any way except as specifically set out in the
+ *  agreement. No part of this document may be reproduced or transmitted in any
+ *  form or by any means, electronic or mechanical, including photocopying and
+ *  recording, for any purpose without the express written permission of Texas
+ *  Instruments Inc.
+ *
+ ******************************************************************************
+ *
+ *  FILE NAME: secure_types.h
+ *
+ *
+ *  PURPOSE:
+ *
+ *
+ *  FILE REFERENCES:
+ *
+ *  Name                  IO      Description
+ *  -------------         --      ---------------------------------------------
+ *
+ *
+ *
+ *  EXTERNAL VARIABLES:
+ *
+ *  Source: none
+ *
+ *  Name                    Type              IO   Description
+ *  -------------------     ---------------   --   ----------------------------
+ *
+ *
+ *
+ *  ABNORMAL TERMINATION CONDITIONS, ERROR AND WARNING MESSAGES:
+ *
+ *
+ *
+ *  ASSUMPTION, CONSTRAINTS, RESTRICTIONS:
+ *
+ *
+ *
+ *  NOTES:
+ *
+ *
+ *
+ *  REQUIREMENTS/FUNCTIONAL SPECIFICATION REFERENCES:
+ *
+ *
+ *
+ *
+ *  DEVELOPMENT HISTORY:
+ *
+ *  Date        Name(s)               Version  Description
+ *  ----------  --------------------  -------  ---------------------------------
+ *  04/12/2002  Constantin HAIDAMOUS  V1.0.0   First release
+ *  22-Apr-02   Francois AMAND        V1.0.1   Update of secure status to
+ *                                             facilitate integration in final
+ *                                             ROM code.
+ *                                             Data alignment in struture to
+ *                                             optimize memory requirement.
+ *                                             Management of global secure data.
+ *  28-Apr-02   Francois AMAND        V1.0.2   Update some constants to be
+ *                                             compliant with certificate
+ *                                             definition.
+ *                                             Add CALYPSO PLUS specific
+ *                                             parameters structure.
+ *                                             Differentiate Manufacturer and
+ *                                             Platform certificate.
+ *                                             Add debug request field in Manu-
+ *                                             facturer certificate.
+ *                                             Optimize certificate field size.
+ *                                             Change commentary wrapper to be
+ *                                             ANSI compliant.
+ *  29-Apr-02   Francois AMAND        V1.0.3   Remove unused constant.
+ *                                             Set under compilation flag the
+ *                                             secure services.
+ *  14-May-02   Francois AMAND        V1.0.4   Add CONF_CSI field in T_CONF_PARAM
+ *                                             structure definition.
+ *                                             Change name of CS_MODE to EX_CTRL
+ *                                             Change size of DCCTRL_CSx to 8
+ *                                             bits to optimize size and alignment.
+ *  17-May-02   Francois AMAND        V1.0.5   Modification of hashing size for
+ *                                             binding/unbinding.
+ *  17-May-02   Constantin HAIDAMOUS  V1.0.6   Integration of data structure for
+ *                                             binding/unbinding services API .
+ *  17-May-02   Francois AMAND        V1.0.7   Integration of RSA S/W and Check
+ *                                             ROM in Secure Services.
+ *                                             Update of Secure Services manage-
+ *                                             ment.
+ *  22-May-02   Constantin HAIDAMOUS  V1.0.8   Changing RSA modulus length , Max
+ *                                             RSA length =2048 bits. Adding initial
+ *                                             vectore for Binding structure.
+ *  27-May-02   Francois AMAND        V1.0.9   Changing SAMSON to CALYPSO.
+ *                                             Addition of Secure Services for
+ *                                             RUN Time checker.
+ *  28-May-02   Constantin HAIDAMOUS  V1.0.10  Changing C_PLAT_SIG_SIZE to 4.
+ *
+ *  06-June-02  Constantin HAIDAMOUS  V1.0.11  Changing Secure service API.
+ *
+ *  12-Jun-02   Francois AMAND        V1.0.12  Update of T_CONF_PARAM according
+ *                                             to last memory interface spec.
+ *  13-Jun-02   Constantin HAIDAMOUS  V1.0.13  Update of T_UNBINDCTX for segmented
+ *                                             unbind operation optimization.
+ *  14-Jun-02   Constantin HAIDAMOUS  V1.0.14  Update of T_BINDCTX for segmented
+ *                                             bind operation .
+ *  14-Jun-02   Francois AMAND        V1.0.15  Force d_temp in Secure RAM.
+ *                                             Remove other definitions.
+ *  25-Jun-02   Francois AMAND        V1.0.16  Addition of Platform unbinding
+ *                                             during boot concept under compi-
+ *                                             lation flag C_PLATFORM_UNBIND_BOOT.
+ *  27-Jun-02   Constantin HAIDAMOUS  V1.0.17  Adding C_SECURE_RNG_ALARM to E_SECURE_STATUS
+ *                                             C_SECURE_RNG_ALARM = C_RNG_ALARM from Safenet
+ *  09-Jul-02   Constantin HAIDAMOUS  V1.0.18  Adding Application ID and Timeout for Bind function
+ *  16-Jul-02   Francois AMAND        V1.0.19  Add S/W pseudo-random generator.
+ *  19-Jul-02   Francois AMAND        V1.0.20  Remove S/W pseudo-random.
+ *  01-Aug-02   Constantin HAIDAMOUS  V1.0.21  Removing boolean b_HashDone in Bind and Unbind Context
+ *  27-Jan-03   Francois AMAND        V2.0.0   Remove of C_PLATFORM_UNBIND_BOOT flag
+ *  27-Jan-03   Francois AMAND        V2.0.1   Add compliance with SW@P 2.0 (REQ03047)
+ *  20-Mar-03   Francois AMAND        V2.0.2   Code cleaning
+ *
+ *  ALGORITHM:
+ *
+ *
+ *******************************************************************************/
+
+
+#include "standard.h"
+
+#ifndef _SECURE_TYPES_H
+  #define _SECURE_TYPES_H
+
+  #ifndef C_SECURE_SERVICES
+    #define C_SECURE_SERVICES 1
+  #endif
+
+  #ifndef C_CHIPSET
+    #define C_CHIPSET_CALYPSO        4
+    #define C_CHIPSET_CALYPSOPLUS   11
+    #define C_CHIPSET               C_CHIPSET_CALYPSOPLUS
+  #endif
+
+
+
+  /****************************************************************************
+   * Constants
+   ****************************************************************************/
+
+  #define C_WORD32LGB     4
+
+//  #ifndef NULL  /* To avoid conflict with other compilers */
+//    #define NULL (UWORD32 *) 0x00000000L
+//  #endif
+
+  /* Certificate block */
+
+  /* Length in long word (32 bits) */
+
+  #define C_SHA1HASHLG          5
+  #define C_MD5HASHLG           4
+
+  #define C_RSAKEYLG            64 /* Max Modulus size : 2048 bits */
+  #define C_RSASIGLG            C_RSAKEYLG
+
+  #define C_DIE_ID_SIZE         2  /* DIE ID defined on 64-bits */
+
+  #define C_PLATFORM_DATA_SIZE  16048 /* Maximum value to have CertSize coded on 16-bits */
+
+  #if C_SECURE_SERVICES == 1
+    #define C_IVLG              2
+    #define C_TDESKEYLG         4
+    #define C_TDESKEYLGB        C_TDESKEYLG * C_WORD32LGB
+    #define C_PLAT_SIG_SIZE     4 /* Must be a multiple of 64 bits */
+  #endif
+
+  #define C_MANUF_SIG_SIZE      C_RSASIGLG
+
+
+  /* Certificate Type */
+
+  #define C_CERTTYPE_MAN     0x00
+  #define C_CERTTYPE_PLAT    0x01
+
+  #if C_SECURE_SERVICES == 1
+    /* Confidentiality request */
+
+    #define C_CRYPTVOID      0x00
+    #define C_CRYPTNOREQUEST 0x00
+    #define C_CRYPTREQUEST   0x01
+  #endif
+
+
+  /* Debug request */
+
+  #define C_DEBUGNOREQUEST   0x00
+  #define C_DEBUGREQUEST     0x01
+
+
+  /* CS image check request */
+
+  #define C_CSIMGNOREQUEST   0x00
+  #define C_CSIMGREQUEST     0x01
+
+
+  /* Temporary block */
+
+  #define C_TEMPDATALG        32
+  #define C_TEMPDATALGB       C_TEMPDATALG * C_WORD32LGB
+
+  #define C_CERT_TEMP_SWKEY   0
+  #define C_CERT_TEMP_DATA    C_CERT_TEMP_SWKEY + C_TDESKEYLG
+
+
+  /****************************************************************************
+   * Structures
+   ****************************************************************************/
+
+  /* CALYPSO PLUS Parameters */
+  typedef struct {
+    /* External Memory Interface configuration */
+    UWORD16 d_conf_cs5;
+    UWORD16 d_exws_cs5;
+    UWORD16 d_ex_ctrl;
+
+    /* Authentication configuration */
+    UWORD16 d_cs_img_req;
+    UWORD32 d_flash_size;
+    UWORD32 d_granularity;
+  } T_CONF_PARAM;
+
+
+  /* RSA Public key */
+
+  typedef struct
+  {
+    UWORD32  a_Modulus[C_RSAKEYLG];  /* Public Modulus */
+    UWORD32  d_ModulusLength;        /* Public Modulus length in bytes */
+    UWORD32  d_Exponent;             /* Public Exponent */
+  } T_RSAPUBKEY;
+
+
+  /*Certificate Structure*/
+
+  typedef struct
+  {
+    UWORD16       d_Certsize;                         /* Size of Certificate */
+    UWORD8        d_Certtype;                         /* Type of Certificate */
+    UWORD8        d_Debugrequest;                     /* Debug Request */
+    UWORD32       d_Addcode;                          /* Start Address of Code */
+    UWORD32       d_Codesize;                         /* Size of Code */
+    UWORD32       d_CodeStartAdd;                     /* Entry Point Address */
+    T_RSAPUBKEY   d_Manpubkey;                        /* Manufacturer Public Key */
+    T_RSAPUBKEY   d_Origpubkey;                       /* Originator Public Key */
+    UWORD32       a_Origpubkeysig[C_MANUF_SIG_SIZE];  /* Originator Public Key Signature */
+    UWORD32       a_Swsig[C_MANUF_SIG_SIZE];          /* Software Signature */
+    T_CONF_PARAM  d_Confparam;                        /* Configuration Parameters */
+    UWORD32       a_die_id[C_DIE_ID_SIZE];            /* Die Id */
+  } T_MANUFACTURER_CERTIFICATE;
+
+
+  /*
+   * Manufacturer Certificate structure containing dynamic Platform Data
+   */
+  typedef struct
+  {
+    T_MANUFACTURER_CERTIFICATE  d_manufacturer_certificate;
+    UWORD32                     a_platform_data[C_PLATFORM_DATA_SIZE];   /* Platform Data */
+    UWORD32                     a_Certsig[C_MANUF_SIG_SIZE];             /* Certificate Signature */
+  } T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA;
+
+
+  /*
+   * Manufacturer Certificate structure for the flash programmer without the dynamic Platform Data
+   */
+  typedef struct
+  {
+    UWORD16       d_Certsize;                         /* Size of Certificate */
+    UWORD8        d_Certtype;                         /* Type of Certificate */
+    UWORD8        d_Debugrequest;                     /* Debug Request */
+    UWORD32       d_Addcode;                          /* Start Address of Code */
+    UWORD32       d_Codesize;                         /* Size of Code */
+    UWORD32       d_CodeStartAdd;                     /* Entry Point Address */
+    T_RSAPUBKEY   d_Manpubkey;                        /* Manufacturer Public Key */
+    T_RSAPUBKEY   d_Origpubkey;                       /* Originator Public Key */
+    UWORD32       a_Origpubkeysig[C_MANUF_SIG_SIZE];  /* Originator Public Key Signature */
+    UWORD32       a_Swsig[C_MANUF_SIG_SIZE];          /* Software Signature */
+    T_CONF_PARAM  d_Confparam;                        /* Configuration Parameters */
+    UWORD32       a_die_id[C_DIE_ID_SIZE];            /* Die Id */
+    UWORD32       a_Certsig[C_MANUF_SIG_SIZE];        /* Certificate Signature */
+  } T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER;
+
+
+  #if C_SECURE_SERVICES == 1
+    /*
+     *  Define ROM secure service entry point address
+     */
+    #define C_ROM_SSERVICE_ENTRY_POINT_ADDR   0x00000024L
+
+    /*
+     *  Definition of function pointer to use ROM Secure Services
+     */
+    typedef UWORD16 (*T_ROM_SSERVICE) (UWORD16, void *, void *);
+
+
+    typedef struct
+    {
+      UWORD16       d_Certsize;                   /* Size of Certificate */
+      UWORD8        d_Certtype;                   /* Type of Certificate */
+      UWORD8        d_Confrequest;                /* Confidentiality Request */
+      UWORD32       d_Addcode;                    /* Start Address of Code */
+      UWORD32       d_Codesize;                   /* Size of Code */
+      UWORD32       d_AppID;                      /* Application Id */
+      UWORD32       a_iv[C_IVLG];                 /* Initial Vector for TDES CBC */
+      UWORD32       a_Encswkey[C_TDESKEYLG];      /* Encrypted S/W Key */
+      UWORD32       a_Swsig[C_PLAT_SIG_SIZE];     /* Software Signature */
+      UWORD32       a_Certsig[C_PLAT_SIG_SIZE];   /* Certificate Signature */
+    } T_PLATFORM_CERTIFICATE;
+
+
+    /* Unbind Context Structure used for segmented Unbind operation */
+
+    typedef struct
+    {
+      UWORD32  d_Startpos;                    /* Start Position of Data to Process */
+      UWORD32  d_Currentpos;                  /* Current Position of Data to Process */
+      UWORD32  a_Currentdigest[C_MD5HASHLG];  /* Current Digest */
+      UWORD32  d_Digcount;                    /* Digest Count */
+      UWORD32  a_Currentiv[C_IVLG];           /* Current Initial Vector */
+      UWORD32  a_Encswkey[C_TDESKEYLG];       /* Encrypted TDES Software Key */
+      UWORD32  a_iv[C_IVLG];                  /* Initial Vector */
+      UWORD32  d_Codesize;                    /* Code Size */
+      UWORD32  d_AppID;                       /* Application Id */
+      UWORD32  a_Swsig[C_PLAT_SIG_SIZE];      /* Software Signature */
+      UWORD8   d_Confrequest;                 /* Confidentiality Request */
+      BOOLEAN  b_UnbindDone;                  /* Set to 1 if Data Unbinding is Done */
+    } T_UNBINDCTX;
+
+
+   /* Bind Context Structure used for segmented Bind operation */
+
+    typedef struct
+    {
+      UWORD32  d_Startpos;                    /* Start Position of Data to Process */
+      UWORD32  d_Currentpos;                  /* Current Position of Data to Process */
+      UWORD32  a_Currentdigest[C_MD5HASHLG];  /* Current Digest */
+      UWORD32  d_Digcount;                    /* Digest Count */
+      UWORD32  a_Currentiv[C_IVLG];           /* Current Initial Vector */
+      UWORD32  a_Encswkey[C_TDESKEYLG];       /* Encrypted TDES Software Key */
+      UWORD32  a_iv[C_IVLG];                  /* Initial Vector */
+      UWORD32  d_Addcode;                     /* Store Address of Code */
+      UWORD32  d_Codesize;                    /* Code Size */
+      UWORD32  d_AppID;                       /* Application Id */
+      UWORD8   d_Confrequest;                 /* Confidentiality Request */
+      BOOLEAN  b_KeyCreateDone;               /* Set to 1 if TDES Software Key Creation is Done */
+      BOOLEAN  b_BindDone;                    /* Set to 1 if Data Binding is Done */
+    } T_BINDCTX;
+
+
+    typedef struct
+    {
+      T_PLATFORM_CERTIFICATE*  p_Cert;
+      UWORD32*                 p_Code;
+      T_PLATFORM_CERTIFICATE*  p_CertCtx;
+      T_UNBINDCTX*             p_UnbindCtx;
+      UWORD32                  d_Steplength;
+      BOOLEAN                  b_start;
+    } T_SSERVICE_UNBIND;
+
+
+
+    typedef struct
+    {
+      T_PLATFORM_CERTIFICATE*   p_Cert;
+      UWORD32*                  p_Code;
+      T_PLATFORM_CERTIFICATE*   p_CertCtx;
+      T_BINDCTX*                p_BindCtx;
+      UWORD32                   d_Steplength;
+      UWORD32                   d_timeout;
+      BOOLEAN                   b_start;
+    } T_SSERVICE_BIND;
+
+
+    /*
+     *  Structure definition for RSA S/W secure services
+     */
+    typedef struct
+    {
+      UWORD32 *     p_datain;
+      UWORD32 *     p_dataout;
+      UWORD32       output_length;
+      T_RSAPUBKEY * p_rsapubkey;
+      UWORD32 *     p_rsaheap;
+    } T_SSERVICE_RSA;
+
+
+    /*
+     *  Structure definition for Checker ROM secure services
+     */
+    typedef struct
+    {
+      UWORD16   d_checksum;
+      UWORD16   d_rom_id;
+    } T_SSERVICE_CHECKROM;
+
+
+    /*
+     *  Structure definition for Run Time Checker secure services
+     */
+    typedef struct
+    {
+      UWORD32 *                       p_rsaheap;
+      T_MANUFACTURER_CERTIFICATE *    p_certificate;
+    } T_SSERVICE_RUNTIMECHECKER;
+
+
+    /*
+     *  Structure definition for Run Time Platform Data Checker secure services
+     */
+    typedef struct
+    {
+      T_PLATFORM_CERTIFICATE*  p_Cert;
+    } T_SSERVICE_RUNTIME_PLAT_CHECKER;
+
+
+  #endif /*  C_SECURE_SERVICES == 1 */
+
+  /****************************************************************************
+   * Global variables
+   ****************************************************************************/
+  #ifndef SECURE_GLOBAL
+    #define SECURE_GLOBAL extern
+  #endif
+
+  #ifdef _TMS470
+    #pragma DATA_SECTION(d_temp,".secdata")
+    #pragma DATA_SECTION(a_hash_certificate,".secdata")
+  #endif
+
+  SECURE_GLOBAL UWORD32 d_temp[C_TEMPDATALG];               /* Temporary data in Secure RAM */
+  SECURE_GLOBAL UWORD32 a_hash_certificate[C_SHA1HASHLG];   /* SHA-1 hashing of Manufacturer Certificate */
+
+  /****************************************************************************
+   * Status
+   ****************************************************************************/
+
+  typedef enum
+  {
+    C_SECURE_ERROR          = 0,
+    C_SECURE_SUCCESS        = 1,
+    C_SECURE_INVALID_ID     = 2,
+    C_SECURE_RNG_ALARM      = 3,
+    C_SECURE_INVALID_DIE_ID = 4,
+    C_SECURE_BLANK_DIE_ID   = 5
+  } E_SECURE_STATUS;
+
+
+  /****************************************************************************
+   * Function prototype for secure services
+   ****************************************************************************/
+
+  #if C_SECURE_SERVICES == 1
+    #define C_MAX_DEFINED_ID                                6
+    #define C_SEC_SERVICE_BINDING_ID                        0x0000
+    #define C_SEC_SERVICE_UNBINDING_ID                      0x0001
+    #define C_SEC_SERVICE_RSA_ID                            0x0002
+    #define C_SEC_SERVICE_CHECKROM_ID                       0x0003
+    #define C_SEC_SERVICE_RUN_TIME_CHECKER_ID               0x0004
+    #define C_SEC_SERVICE_RUN_TIME_PLATFORM_DATA_CHECKER    0x0005
+
+    E_SECURE_STATUS ROM_Sservice_Unbind(UWORD16            reserved,
+                                        T_SSERVICE_UNBIND* p_StructUnbind);
+
+    E_SECURE_STATUS ROM_Sservice_Bind(UWORD16          reserved,
+                                      T_SSERVICE_BIND* p_StructBind);
+
+    E_SECURE_STATUS ROM_Sservice_Rsa(UWORD16           reserved,
+                                     T_SSERVICE_RSA*   p_StructRsa);
+
+    E_SECURE_STATUS ROM_Sservice_CheckRom(UWORD16              reserved,
+                                          T_SSERVICE_CHECKROM* p_StructCheckRom);
+
+    E_SECURE_STATUS ROM_Sservice_RunTimeChecker(
+                                  UWORD16                      reserved,
+                                  T_SSERVICE_RUNTIMECHECKER*   p_StructRunTimeChecker);
+
+    E_SECURE_STATUS ROM_Sservice_RunTimePlatformDataChecker(
+                                  UWORD16                          reserved,
+                                  T_SSERVICE_RUNTIME_PLAT_CHECKER* p_StructRunTimePlatChecker);
+
+  #endif
+
+#endif /* _SECURE_TYPES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/calplus/standard.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,17 @@
+#ifndef _STANDARD_H_
+  #define _STANDARD_H_
+
+  #define _PC_RAM_LOADER_
+
+  typedef unsigned char      UWORD8;
+  typedef unsigned short int UWORD16;
+  typedef unsigned long int  UWORD32;
+
+  typedef unsigned char BOOLEAN;
+
+  enum {
+    C_FALSE = 0,
+    C_TRUE  = 1
+  };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/efluid.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,62 @@
+/* This file is autogenerated --- do not edit. */
+
+#include "fluid.h"
+
+char *main_strerror(int error)
+{
+    switch (error) {
+    case E_OK: return "Ok"; /* 0 */
+    case E_DRIVER_INIT: return "Driver failed to initialize"; /* -3 */
+    case E_DRIVER_WAIT: return "Driver recv_wait() failed"; /* -4 */
+    case E_UART_INIT: return "UART failed to initialize"; /* -5 */
+    case E_UART_PARAM: return "UART parameter bad or unsupported"; /* -6 */
+    case E_UART_DRV_SEND: return "UART driver transmit error"; /* -7 */
+    case E_UART_DRV_RECV: return "UART driver receive error"; /* -8 */
+    case E_RECV_TIMEOUT: return "Receive timeout (no target reply)"; /* -10 */
+    case E_RECV_ANTITIMEOUT: return "Receive anti-timeout (target replied!?)"; /* -11 */
+    case E_SEND_CHECKSUM: return "Transmit checksum error"; /* -12 */
+    case E_RECV_CHECKSUM: return "Receive checksum error"; /* -13 */
+    case E_PROTO_ERROR: return "Protocol error (bad char from target)"; /* -14 */
+    case E_INVALID: return "Invalid command parameter"; /* -15 */
+    case E_FIFO_OVERFLOW: return "RX FIFO overflow in target"; /* -16 */
+    case E_FLASH_UNKNOWN: return "Flash device unknown"; /* -20 */
+    case E_FLASH_TIMEOUT: return "Flash operation timeout"; /* -21 */
+    case E_FLASH_VERIFY: return "Flash verify error"; /* -22 */
+    case E_FLASH_COMMAND: return "Flash command sequence error"; /* -23 */
+    case E_FLASH_VPPRANGE: return "Flash Vpp range error"; /* -24 */
+    case E_FLASH_LOCKED: return "Flash block locked error"; /* -25 */
+    case E_FLASH_ERROR: return "Flash error (unknown!?)"; /* -26 */
+    case E_TARGET_TYPE: return "Target type not detected, unspecified or unknown"; /* -27 */
+    case E_TARGET_MEMORY: return "Target out of memory"; /* -28 */
+    case E_PARSER_EOF: return "Unexpected end of file"; /* -30 */
+    case E_PARSER_KEYWORD: return "Syntax error: keyword expected"; /* -31 */
+    case E_PARSER_STRING: return "Syntax error: string expected"; /* -32 */
+    case E_PARSER_NUMBER: return "Syntax error: number expected"; /* -33 */
+    case E_PARSER_END_BRACE: return "Syntax error: missing end brace"; /* -34 */
+    case E_PARSER_SYNTAX: return "Syntax error"; /* -35 */
+    case E_PARSER_MEMMAP: return "Undefined flash memmap"; /* -36 */
+    case E_PARSER_ALGORITHM: return "Undefined flash algorithm"; /* -37 */
+    case E_BOOTLOADER: return "Unsupported bootloader"; /* -40 */
+    case E_FILE_OPEN: return "File open error"; /* -50 */
+    case E_FILE_CLOSE: return "File close error"; /* -52 */
+    case E_FILE_READ: return "File read error"; /* -53 */
+    case E_FILE_WRITE: return "File write error"; /* -54 */
+    case E_FILE_FORMAT: return "File format/syntax error"; /* -55 */
+    case E_FILE_EMPTY: return "File empty or unreadable?"; /* -56 */
+    case E_FILE_BUF_SMALL: return "File buffer too small"; /* -57 */
+    case E_FILE_INPUT: return "No input file name supplied"; /* -58 */
+    case E_FILE_OUTPUT: return "No output file name supplied"; /* -59 */
+    case E_ADDR_RANGE: return "Bad address range"; /* -70 */
+    case E_ERASE_SPEC: return "Bad erase override specifier"; /* -71 */
+    case E_READ_SPEC: return "Bad memory read specifier"; /* -72 */
+    case E_WRITE_SPEC: return "Bad memory write specifier"; /* -73 */
+    case E_BADARG: return "Bad argument or out of range"; /* -80 */
+    case E_ARG_MULTI: return "Multiple ambiguous arguments supplied"; /* -81 */
+    case E_ARG_TOOMANY: return "Too many arguments supplied"; /* -82 */
+    case E_MEMORY: return "Out of memory"; /* -85 */
+    case E_BUFFER: return "Internal (static) buffer too small"; /* -86 */
+    case E_ROM_SSERVICE: return "Secure ROM service error"; /* -90 */
+    case E_INTERNAL: return "Internal program state error"; /* -99 */
+    default: return "unknown error code!";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/fileio.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,592 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * File reading/loading
+ *
+ * $Id: fileio.c 1.24 Mon, 28 Apr 2003 08:49:16 +0200 tsj $
+ *
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "flash.h"
+#include "fileio.h"
+#include "misc.h"
+#include "trace.h"
+#include "../target/target.h"
+#include "../inc/secure_types.h"   // Secure Calypso Plus
+
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+// Secure Calypso Plus
+extern int bootloader_is_secure_rom;
+extern int a_certified_cmd_file_name;
+
+#define HEX_MOTOROLA_LINE_SIZE 32 // number of bytes in each line
+#define HEX_MOTOROLA_ADDR_SIZE 32 // number of bits in addresses (16, 24 or 32)
+
+
+struct {
+    char   type;
+    char   size;
+    uint32 addr;
+    uint8  data[128];
+    uint8  dummy; // required - don't remove!
+} mhex;
+
+
+int hexfile_read(char *name, char *buf, int buf_size,
+                 char *usage_map, int usage_map_chunk_size);
+int hexline_motorola_read(char* line);
+int hextoint(char *src, int digits);
+void hextobytes(uint8 *dst, char *src, int bytes);
+
+int hexblock_write(char *buf, int size, unsigned long addr, int addr_size,
+                   char hexfile_type);
+int hexline_motorola_write(char *buf, int size,
+                           unsigned long addr, int addr_size);
+int hexfile_write_open(char *name, char hexfile_type, char *buf, int size);
+int hexfile_write_close(char hexfile_type, int addr_size);
+
+/******************************************************************************
+ * File Reading
+ ******************************************************************************/
+
+// Convert image from one endian type to another. The memory width is
+// specified with <width>.
+void buffer_endian_convert(unsigned char *buf, int buf_size, int width)
+{
+    unsigned char tmp1, tmp2;
+    int i;
+
+    tr(TrHexWrite, "buffer_endian_convert(*, %d, %d)\n", buf_size, width);
+
+    for (i = 0; i < buf_size; i += width) {
+        if (width == 16 || width == 2) {
+            tmp1     = buf[i+0];
+            buf[i+0] = buf[i+1];
+            buf[i+1] = tmp1;
+        }
+        else if (width == 32 || width == 4) {
+            tmp1     = buf[i+0];
+            tmp2     = buf[i+1];
+            buf[i+0] = buf[i+3];
+            buf[i+1] = buf[i+2];
+            buf[i+2] = tmp2;
+            buf[i+3] = tmp1;
+        }
+    }
+}
+
+int file_read_rc(char *filename)
+{
+    // TODO: Read the .fluidrc file. It can contain the following
+    // directives:
+    //
+    // path = <path>  /* semi-colon? separated list of directories in which
+    //                   to look for m0 files etc. */
+    // target = [h]|[c]
+    // baudrate = <baudrate>
+    // port = <port>
+    // more?
+
+    return 0;
+}
+
+extern void tr_image_usage_map(void);
+
+int file_read_image(char *image, int image_size,
+                    char *usage_map, int usage_map_chunk_size)
+{
+    int size, size_total = 0, i = 0;
+    int time_load;
+
+    flowf(NORMAL, "Reading image file:");
+
+    memset(image,     0xFF, image_size);
+    memset(usage_map, 0,    image_size / usage_map_chunk_size);
+
+    if (arg_file_list[0] == NULL)
+        main_warning(E_FILE_INPUT);
+
+    time_load = stopwatch_start();
+
+    while (arg_file_list[i] != NULL)
+    {
+        flowf(NORMAL, " '%s'", arg_file_list[i]);
+        if ((size = hexfile_read(arg_file_list[i], image, image_size,
+                                 usage_map, usage_map_chunk_size)) < 0) {
+            flowf(ALWAYS, " MESSAGE: File '%s' not found\n", arg_file_list[i]);
+            main_error(size);
+        }
+
+        size_total += size;
+        flowf(NORMAL, " (%dkB)", (size + 512) / 1024);
+
+        i++;
+        if (arg_file_list[i] != NULL)
+            flowf(NORMAL, ",");
+    }
+    time_load = (stopwatch_stop(time_load) + 50) /100;
+    flowf(BLABBER, " (%d.%ds)", time_load / 10, time_load % 10);
+    flowf(NORMAL, " ok\n");
+
+    // Now convert image from big endian to little endian format
+    buffer_endian_convert(image, image_size, arg_hexfile_memwidth);
+
+    return size_total;
+}
+
+int file_read_cmd(char *image, int image_size, char *filename)
+{
+    //char filename[20] = "cmd.m0";
+
+    memset(image, 0, image_size);
+
+    flowf(BLABBER, "Reading cmd file '%s': ", filename);
+    if ((image_size = hexfile_read(filename, image, image_size, 0, 0)) < 0) {
+        flowf(ALWAYS, "MESSAGE: File '%s' not found\n", filename);
+        main_error(image_size);
+    }
+    flowf(BLABBER, "(%dB) ok\n", image_size);
+
+    return image_size;
+}
+
+int file_read_method(char *image, int image_size, struct device_s *device)
+{
+    char filename[20];
+
+    strncpy(filename,
+            algorithm_name_lookup_by_id(device->algorithm_id),
+            20 - sizeof(".m0"));
+    strcat(filename, ".m0");
+
+    memset(image, 0, image_size);
+
+    flowf(BLABBER, "Reading method file '%s': ", filename);
+    if ((image_size = hexfile_read(filename, image, image_size, 0, 0)) < 0) {
+        flowf(ALWAYS, "MESSAGE: File '%s' not found\n", filename);
+        main_error(image_size);
+    }
+    flowf(BLABBER, "(%dB) ok\n", image_size);
+
+    return image_size;
+}
+
+
+/******************************************************************************
+ * Hex File Read Functions
+ ******************************************************************************/
+
+// Read an input file in Motorola (or Intel) hex format. On success, return
+// the number of raw data bytes read.
+int hexfile_read(char *filename, char *buf, int buf_size,
+                 char *usage_map, int usage_map_chunk_size)
+{
+    FILE* stream;
+    char line[100];
+    uint32 addr;
+    int type, mysize = 0;
+
+    // First look for file in current directory. Then look for it in the
+    // directory where the fluid executable was found.
+    flowf(DEBUG, "(looking for '%s') ", filename);
+
+    if ((stream = fopen(filename, "rt")) == NULL)
+    {
+        char buf[256];
+
+        flowf(DEBUG, "(oops) ");
+
+        if (pathname_make(buf, sizeof(buf), argv_0, filename) < 0)
+            return E_BUFFER;
+
+        flowf(DEBUG, "(looking for '%s') ", buf);
+
+        if ((stream = fopen(buf, "rt")) == NULL)
+            return E_FILE_OPEN;
+    }
+    flowf(DEBUG, "(ok) ");
+
+    // TODO?: Read the first character of the file and determine the file
+    // type this way (Motorola format, Intel format or .out format)
+    type = 'S';
+
+    while (fgets(line, 100, stream) != NULL) {
+        switch (type) {
+        case 'S':
+            if (hexline_motorola_read(line)) {
+                mysize += (int) mhex.size;
+
+                // Secure Calypso Plus
+                if (bootloader_is_secure_rom &&
+                   strcmp(filename, (char *)&a_certified_cmd_file_name) == 0 &&
+                    mhex.addr >= CMD_SECURE_CALP_OFFSET) {
+                    // The flash programmer is linked to 0x08020000 in internal
+                    // SRAM.
+                    addr = mhex.addr - CMD_SECURE_CALP_OFFSET;
+                }
+                else if (mhex.addr >= CALP_OFFSET)
+                    // Assume linked to Calypso Plus (0x04000000 Flash Base)
+                    addr = mhex.addr - CALP_OFFSET;
+                else
+                    addr = mhex.addr;
+
+                if (addr > (uint32) buf_size) {
+                    fprintf(stderr, "Address too big: 0x%08X\n", (int) addr);
+                    return E_FILE_BUF_SMALL;
+                }
+                memcpy(&buf[addr], &mhex.data[0], mhex.size);
+                // Update the image usage map
+                if (usage_map != NULL) {
+                    usage_map[(addr) / usage_map_chunk_size] = 'x';
+                    usage_map[(addr + mhex.size - 1) / usage_map_chunk_size] = 'x';
+                }
+            }
+            break;
+        case '?':
+            // Intel format
+            break;
+        case 'O':
+            // .out format
+            break;
+        default:
+            return E_FILE_FORMAT;
+        }
+    }
+    fclose(stream);
+
+    return mysize;
+}
+
+// Read and decode one line of a Motorola hex file.
+// Original design and code by Delta Technologies, 2001.
+int hexline_motorola_read(char* line)
+{
+    mhex.type = (uint8) line[1] - '0';
+    mhex.size = hextoint(&line[2], 2);
+
+    tr(TrHexRead, "S%d%02X", mhex.type, mhex.size);
+
+    switch (mhex.type) {
+    case 0:
+        // First record in file - no action required
+        mhex.size = 0;
+        break;
+    case 1:
+        // Data record 16-bit address: S1nnAAAAxxxxxxxxxxxxxxxCC
+        mhex.size -= 3;
+        mhex.addr = hextoint(&line[4], 4);
+        tr(TrCont|TrHexRead, "%04X", mhex.addr);
+        hextobytes(&mhex.data[0], &line[8], mhex.size);
+        break;
+    case 2:
+        // Data record 24-bit address: S2nnAAAAAAxxxxxxxxxxxxxxxCC
+        mhex.size -= 4;
+        mhex.addr = hextoint(&line[4], 6);
+        tr(TrCont|TrHexRead, "%06X", mhex.addr);
+        hextobytes(&mhex.data[0], &line[10], mhex.size);
+        break;
+    case 3:
+        // Data record 32-bit address: S3nnAAAAAAAAxxxxxxxxxxxxxxxCC
+        mhex.size -= 5;
+        mhex.addr = hextoint(&line[4], 8);
+        tr(TrCont|TrHexRead, "%08X", mhex.addr);
+        hextobytes(&mhex.data[0], &line[12], mhex.size);
+        break;
+    case 7:
+        // End of file record 32-bit address
+        mhex.size = 0;
+        break;
+    case 8:
+        // End of file record 24-bit address
+        mhex.size = 0;
+        break;
+    case 9:
+        // End of file record 16-bit address
+        mhex.size = 0;
+        break;
+    default:
+        fprintf(stderr, "WARNING: Illegal hex line: %s\n", line);
+        main_error(E_FILE_FORMAT);
+    }
+    tr(TrCont|TrHexRead, "\n");
+
+    return mhex.size;
+}
+
+int hextoint(char *src, int digits)
+{
+    int number = 0;
+    char ch;
+
+    while (digits-- && *src) {
+        ch = *src++;
+        if (ch >= '0' && ch <= '9')
+            ch = ch - '0';
+        else if (ch >= 'A' && ch <= 'F')
+            ch = ch - 'A' + 10;
+        else if (ch >= 'a' && ch <= 'f')
+            ch = ch - 'a' + 10;
+        else
+            break;
+        number = (number << 4) + ch;
+    }
+    return number;
+}
+
+void hextobytes(uint8 *dst, char *src, int bytes)
+{
+    while (bytes-- && *src) {
+        *dst++ =
+            (src[0] - (src[0] <= '9' ? '0' : 'A' - 10)) * 16 +
+            (src[1] - (src[1] <= '9' ? '0' : 'A' - 10));
+        src += 2;
+        tr(TrCont|TrHexRead, "%02X", dst[-1]);
+    }
+}
+
+
+/******************************************************************************
+ * File Writing
+ ******************************************************************************/
+
+static FILE* ostream;
+
+int file_write_image(char *image, int image_size,
+                     struct image_part_s *image_list)
+{
+    int size, size_total = 0;
+    struct image_part_s *image_list_start = image_list;
+
+    if (arg_show_hexdump == 0 && arg_file_list[0] == NULL)
+        main_fatal(E_FILE_OUTPUT);
+
+    if (arg_file_list[1] != NULL)
+        main_fatal(E_ARG_MULTI);
+
+    if (arg_file_list[0] != NULL)
+    {
+        flowf(NORMAL, "Writing flash image file: '%s' ", arg_file_list[0]);
+
+        if ((size = hexfile_write_open(arg_file_list[0], arg_hexfile_type,
+                                       image, image_size)) < 0)
+            main_error(size);
+
+        while (image_list->size != 0)
+        {
+            // Note that we wrap/mirror memory each 'image_size' bytes
+            if ((size =
+                 hexblock_write(&image[image_list->addr & (image_size - 1)],
+                                image_list->size,
+                                image_list->addr, 32,
+                                arg_hexfile_type)) < 0)
+                main_error(E_FILE_BUF_SMALL);
+
+            size_total += size;
+            flowf(NORMAL, "(%dkB) ", (size + 512) / 1024);
+            image_list++;
+        }
+        if (hexfile_write_close(arg_hexfile_type, 32) < 0)
+            main_error(E_FILE_CLOSE);
+
+        flowf(NORMAL, " ok\n");
+    }
+
+    if (arg_show_hexdump) {
+        image_list = image_list_start;
+        while (image_list->size != 0)
+        {
+            hexdump(&image[image_list->addr & (image_size - 1)],
+                    image_list->size,
+                    image_list->addr, 1);
+            putchar('\n');
+            image_list++;
+        }
+    }
+
+    return size_total;
+}
+
+int file_write_die_id(unsigned char *die_id, char *filename) {
+    int i;
+
+    if (arg_hexfile_type == 'b') {
+        // Binary write
+        if ((ostream = fopen(filename, "wb")) == NULL)
+            return E_FILE_OPEN;
+
+        if (fwrite(die_id, C_WORD32LGB * C_DIE_ID_SIZE, 1, ostream) < 0)
+            return E_FILE_WRITE;
+    }
+    else {
+        // Text write
+        if ((ostream = fopen(filename, "wt")) == NULL)
+            return E_FILE_OPEN;
+
+        for (i = 0 ; i < (C_WORD32LGB * C_DIE_ID_SIZE) ; i++)
+            fprintf(ostream, "0x%2.2x ", die_id[i]);
+    }
+
+    fclose(ostream);
+
+    return 0;
+}
+
+/******************************************************************************
+ * Hex File Write Functions
+ ******************************************************************************/
+
+int hexblock_write(char *buf, int size, unsigned long addr, int addr_size,
+                   char hexfile_type)
+{
+    int size_start = size;
+    int line_size;
+
+    tr(TrHexWrite, "hexblock_write(*, %d, 0x%x, %d, '%c')\n",
+       size, addr, addr_size, hexfile_type);
+
+    while (size > 0) {
+        switch (hexfile_type) {
+        case 'b':
+            line_size = fwrite(buf, 1, size, ostream);
+            if (line_size < size_start)
+                return E_FILE_WRITE;
+            break;
+        case 'm':
+        case 'S':
+            line_size = (size > HEX_MOTOROLA_LINE_SIZE ?
+                         HEX_MOTOROLA_LINE_SIZE : size);
+            hexline_motorola_write(buf, line_size, addr, addr_size);
+            break;
+        case '?':
+            // Intel format
+            break;
+        default:
+            main_fatal(E_FILE_FORMAT);
+        }
+        buf  += line_size;
+        size -= line_size;
+        addr += line_size;
+    }
+
+    return size_start;
+}
+
+int hexfile_write_open(char *name, char hexfile_type, char *buf, int size)
+{
+    if ((ostream = fopen(name, "wt")) == NULL)
+        return E_FILE_OPEN;
+
+    // Write file header
+    switch (hexfile_type) {
+    case 'b':
+        // Binary format --- close file, then reopen it for binary writing
+        if (fclose(ostream) == EOF)
+            return E_FILE_OPEN;
+        if ((ostream = fopen(name, "wb")) == NULL)
+            return E_FILE_OPEN;
+        flowf(VERBOSE, "(binary) ");
+        break;
+    case 'm':
+    case 'S':
+        // Motorola hex files are always in big endian format.
+        flowf(VERBOSE, "(motorola) ");
+        buffer_endian_convert(buf, size, arg_hexfile_memwidth);
+        fprintf(ostream,"S0030000FC\n");
+        break;
+    case '?':
+        flowf(VERBOSE, "(intel) ");
+        // Intel format
+        break;
+    default:
+        return E_FILE_FORMAT;
+    }
+
+    return 0;
+}
+
+int hexfile_write_close(char hexfile_type, int addr_size)
+{
+    switch (hexfile_type) {
+    case 'b':
+        // Binary format --- do nothing
+        break;
+    case 'm':
+    case 'S':
+        switch (addr_size) {
+        case 16: fprintf(ostream, "S9030000FC\n"); break;
+        case 24: fprintf(ostream, "S804000000FB\n"); break;
+        case 32: fprintf(ostream, "S70500000000FA\n"); break;
+        }
+        break;
+    case '?':
+        // Intel format
+        break;
+    default:
+        return E_FILE_FORMAT;
+    }
+
+    fclose(ostream);
+
+    return 0;
+}
+
+int hexline_motorola_write(char *buf, int size,
+                           unsigned long addr, int addr_size)
+{
+    uint8 cksum;
+    int	i;
+
+    tr(TrHexWrite, "hexline_motorola_write(*, %d, 0x%x, %d)\n",
+       size, addr, addr_size);
+
+    if (addr_size == 0) {
+        if ((addr + (unsigned long)(size - 1)) < 0x10000L)
+            addr_size = 16;
+        else if ((addr + (unsigned long)(size - 1)) < 0x1000000L)
+            addr_size = 24;
+        else
+            addr_size = 32;
+    }
+    switch (addr_size) {
+    case 16:
+        fprintf(ostream, "S1%02X%04lX", size + 3, addr);
+        cksum = size + 3;
+        break;
+    case 24:
+        fprintf(ostream, "S2%02X%06lX", size + 4, addr);
+        cksum = size + 4;
+        break;
+    case 32:
+        fprintf(ostream, "S3%02X%08lX", size + 5, addr);
+        cksum = size + 5;
+        break;
+    }
+    cksum +=
+        (uint8) ((addr >> 24) & 0xFF) +
+        (uint8) ((addr >> 16) & 0xFF) +
+        (uint8) ((addr >>  8) & 0xFF) +
+        (uint8) ((addr >>  0) & 0xFF);
+    
+    for (i = 0; i < size; i++) {
+        fprintf(ostream,"%02X", buf[i] & 0xFF);
+        cksum += buf[i];
+    }
+    cksum = ~cksum;
+    fprintf(ostream,"%02X\n", cksum);
+
+    return 0;
+}
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/fileio.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * File reading/loading
+ *
+ * $Id: fileio.h 1.5 Wed, 09 Jan 2002 13:01:15 +0100 mmj $
+ *
+ ******************************************************************************/
+
+
+struct image_part_s {
+    uint32 addr;
+    uint32 size;
+};
+
+void buffer_endian_convert(unsigned char *buf, int size, int width);
+
+int file_read_rc(char *filename);
+int file_read_image(char *image, int image_size,
+                    char *usage_map, int usage_map_chunk_size);
+int file_read_cmd(char *image, int image_size, char *filename);   // Secure Calypso Plus
+int file_read_method(char *image, int image_size, struct device_s *device);
+
+int file_write_image(char *image, int image_size,
+                     struct image_part_s *image_list);
+int file_write_die_id(unsigned char *die_id, char *filename);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/flash.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,614 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Flash device database and lookup
+ *
+ * $Id: flash.c 1.26 Wed, 30 Oct 2002 12:09:08 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "misc.h"
+#include "flash.h"
+#include "trace.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+
+/******************************************************************************
+ * Global, Static definitions
+ ******************************************************************************/
+
+const struct algorithm_s algorithms[] = {
+    { ALGORITHM_AMD,        "amd" },
+    { ALGORITHM_INTEL,      "intel" },
+    { ALGORITHM_INTEL_BW,   "intel_bw" },
+    { ALGORITHM_MITSUBISHI, "mitsubishi" },
+    { ALGORITHM_SST,        "sst" },
+    { 0,                    "unknown" }
+};
+
+struct manufact_s manufacturers[] = {
+    { MANUFACT_AMD,        "AMD" },
+    { MANUFACT_ATMEL,      "Atmel" },
+    { MANUFACT_FUJITSU,    "Fujitsu" },
+    { MANUFACT_INTEL,      "Intel" },
+    { MANUFACT_MXIC,       "MXIC" },
+    { MANUFACT_MITSUBISHI, "Mitsubishi" },
+    { MANUFACT_SAMSUNG,    "Samsung" },
+    { MANUFACT_SHARP,      "Sharp" },
+    { MANUFACT_STM,        "STM" },
+    { MANUFACT_SST,        "SST" },
+    { MANUFACT_TOSHIBA,    "Toshiba" },
+    { 0x00,                "Unknown" }
+};
+
+
+/******************************************************************************
+ * Default Device Database
+ ******************************************************************************/
+
+struct memmap_s map_63x64_8x8 = {
+    0,
+    "63x64_8x8kB",
+    63 + 8,
+    {
+        { 0x000000, 0x10000 }, { 0x010000, 0x10000 },
+        { 0x020000, 0x10000 }, { 0x030000, 0x10000 },
+        { 0x040000, 0x10000 }, { 0x050000, 0x10000 },
+        { 0x060000, 0x10000 }, { 0x070000, 0x10000 },
+        { 0x080000, 0x10000 }, { 0x090000, 0x10000 },
+        { 0x0A0000, 0x10000 }, { 0x0B0000, 0x10000 },
+        { 0x0C0000, 0x10000 }, { 0x0D0000, 0x10000 },
+        { 0x0E0000, 0x10000 }, { 0x0F0000, 0x10000 },
+
+        { 0x100000, 0x10000 }, { 0x110000, 0x10000 },
+        { 0x120000, 0x10000 }, { 0x130000, 0x10000 },
+        { 0x140000, 0x10000 }, { 0x150000, 0x10000 },
+        { 0x160000, 0x10000 }, { 0x170000, 0x10000 },
+        { 0x180000, 0x10000 }, { 0x190000, 0x10000 },
+        { 0x1A0000, 0x10000 }, { 0x1B0000, 0x10000 },
+        { 0x1C0000, 0x10000 }, { 0x1D0000, 0x10000 },
+        { 0x1E0000, 0x10000 }, { 0x1F0000, 0x10000 },
+
+        { 0x200000, 0x10000 }, { 0x210000, 0x10000 },
+        { 0x220000, 0x10000 }, { 0x230000, 0x10000 },
+        { 0x240000, 0x10000 }, { 0x250000, 0x10000 },
+        { 0x260000, 0x10000 }, { 0x270000, 0x10000 },
+        { 0x280000, 0x10000 }, { 0x290000, 0x10000 },
+        { 0x2A0000, 0x10000 }, { 0x2B0000, 0x10000 },
+        { 0x2C0000, 0x10000 }, { 0x2D0000, 0x10000 },
+        { 0x2E0000, 0x10000 }, { 0x2F0000, 0x10000 },
+
+        { 0x300000, 0x10000 }, { 0x310000, 0x10000 },
+        { 0x320000, 0x10000 }, { 0x330000, 0x10000 },
+        { 0x340000, 0x10000 }, { 0x350000, 0x10000 },
+        { 0x360000, 0x10000 }, { 0x370000, 0x10000 },
+        { 0x380000, 0x10000 }, { 0x390000, 0x10000 },
+        { 0x3A0000, 0x10000 }, { 0x3B0000, 0x10000 },
+        { 0x3C0000, 0x10000 }, { 0x3D0000, 0x10000 },
+        { 0x3E0000, 0x10000 },
+
+        { 0x3F0000, 0x02000 }, { 0x3F2000, 0x02000 },
+        { 0x3F4000, 0x02000 }, { 0x3F6000, 0x02000 },
+        { 0x3F8000, 0x02000 }, { 0x3FA000, 0x02000 },
+        { 0x3FC000, 0x02000 }, { 0x3FE000, 0x02000 },
+    }
+};
+
+struct memmap_s *memmaps = &map_63x64_8x8;
+
+// Default B-Sample device
+struct device_s device_fujitsu_dl323t = {
+    0,
+    ALGORITHM_AMD,
+    MANUFACT_FUJITSU,
+    0x2250,
+    "MBM29DL323DT",
+    0,
+    0,
+    &map_63x64_8x8
+};
+
+// Default C-Sample device
+struct device_s device_amd_dl322t = {
+    &device_fujitsu_dl323t, // link to next (previous) device defintion
+    ALGORITHM_AMD,
+    MANUFACT_AMD,
+    0x2255,
+    "Am29DL322DT",
+    0,
+    0,
+    &map_63x64_8x8
+};
+
+struct device_s *devices = &device_amd_dl322t;
+
+
+/******************************************************************************
+ * Device file reading and parsing
+ ******************************************************************************/
+
+#define INBUF_SIZE 1024
+
+static char inbuf[INBUF_SIZE];
+static char *pin;
+static FILE *fp;
+static int  linenum;
+
+static char string[1024];
+static int  length;
+static int  number;
+
+enum ParserTokens {
+    TOKEN_EOF,
+    TOKEN_STRING,
+    TOKEN_NUMBER,
+    TOKEN_KEYWORD
+};
+
+enum ParserKeywords {
+    KEYWORD_NONE,
+    KEYWORD_DEVICE,
+    KEYWORD_MEMMAP
+};
+
+void parser_error(int error)
+{
+    fprintf(stderr, "At line %d, ", linenum);
+    main_fatal(error);
+}
+
+void file_read_devices(char *filename)
+{
+    int token, i, n = 0;
+    struct device_s *device;
+    struct memmap_s *memmap;
+
+    flowf(BLABBER, "Reading '%s': ", filename);
+
+    // First look for file in current directory. Then look for it in the
+    // directory where the fluid executable was found.
+    if ((fp = fopen(filename, "rt")) == NULL)
+    {
+        char buf[256];
+
+        if (pathname_make(buf, sizeof(buf), argv_0, filename) < 0)
+            main_fatal(E_BUFFER);
+
+        flowf(DEBUG, "(looking for '%s') ", buf);
+
+        if ((fp = fopen(buf, "rt")) == NULL) {
+            fprintf(stderr, "WARNING: file '%s' not found. Using default device database.\n", filename);
+            return;
+        }
+    }
+
+    devices = (struct device_s *) 0;
+    memmaps = (struct memmap_s *) 0;
+
+    pin = inbuf;
+    inbuf[0] = '\n';
+    linenum = 0;
+
+    // Each loop represents one block/statement of the file
+    while ((token = get_keyword()) != E_PARSER_EOF) {
+        switch (token) {
+        case KEYWORD_MEMMAP:
+            tr(TrBegin|TrParser, "keyword: memmap {\n");
+            if ((token = get_string()) < 0)
+                parser_error(token);
+
+            if ((memmap = malloc(sizeof(struct memmap_s) + length + 1)) == NULL)
+                parser_error(E_MEMORY);
+            memmap->name = (char *) memmap + sizeof(struct memmap_s);
+            strcpy(memmap->name, string);
+
+            if ((token = get_token()) != '{')
+                parser_error(E_PARSER_SYNTAX);
+
+            i = 0;
+            while ((token = get_token()) == TOKEN_NUMBER)
+            {
+                memmap->sectors[i].addr = number;
+
+                if ((token = get_number()) < 0)
+                    parser_error(token);
+                memmap->sectors[i].size = number;
+
+                i++;
+            }
+            if (token != '}')
+                parser_error(E_PARSER_END_BRACE);
+
+            memmap->size = i;
+
+            // Append to linked list
+            memmap->next = memmaps;
+            memmaps = memmap;
+
+            tr(TrEnd|TrParser, "}\n");
+            break;
+
+        case KEYWORD_DEVICE:
+            tr(TrBegin|TrParser, "keyword: device {\n");
+            if ((token = get_string()) < 0)
+                parser_error(token);
+            if ((device = malloc(sizeof(struct device_s) + length + 1)) == NULL)
+                parser_error(E_MEMORY);
+            device->name = (char *) device + sizeof(struct device_s);
+            strcpy(device->name, string);
+
+            if ((token = get_number()) < 0)
+                parser_error(token);
+            device->manufacturer_id = number;
+
+            if ((token = get_number()) < 0)
+                parser_error(token);
+            device->device_id = number;
+
+            if ((token = get_string()) < 0)
+                parser_error(token);
+            device->algorithm_id = algorithm_id_lookup_by_name(string);
+            if (device->algorithm_id == 0)
+                parser_error(E_PARSER_ALGORITHM);
+
+            if ((token = get_string()) < 0)
+                parser_error(token);
+            device->memmap = memmap_lookup_by_name(string);
+            if (device->memmap == 0)
+                parser_error(E_PARSER_MEMMAP);
+
+            // Append to linked list
+            device->next = devices;
+            devices = device;
+
+            tr(TrEnd|TrParser, "}\n");
+            break;
+        default:
+            parser_error(E_PARSER_KEYWORD);
+        }
+        n++;
+    }
+
+    flowf(BLABBER, "(%d blocks read) ok.\n", n);
+}
+
+int get_next_line(void)
+{
+    int result;
+
+    result = (fgets(inbuf, INBUF_SIZE, fp) != NULL);
+
+    pin = inbuf;
+    linenum++;
+
+    tr(TrParser, "get_next_line() (%d) %d ", result);
+
+    return result;
+}
+
+int get_token(void)
+{
+    char *pin_start, *pin_end;
+    int whitespace;
+
+    {
+        char tmp[8];
+        for (whitespace = 0; whitespace < 7; whitespace++)
+            tmp[whitespace] = (pin[whitespace] < ' ' ? '.' : pin[whitespace]);
+        tmp[7] = 0;
+        tr(TrParser, "get_token() ('%s...')", tmp);
+    }
+
+    whitespace = 1;
+
+    while (whitespace)
+    {
+        if (*pin == ' ' || *pin == '\t' || *pin == '\n') {
+            // Skip white-space
+            tr(TrParser, " skip white-space {");
+            while (*pin == ' ' || *pin == '\t' || *pin == '\n')
+            {
+                while (*pin == ' ' || *pin == '\t')
+                    pin++;
+
+                // If end of line, read the next line
+                if (*pin == '\n') {
+                    if (get_next_line() == 0)
+                        return TOKEN_EOF;
+                }
+            }
+            tr(TrCont|TrParser, "}");
+        }
+        else if (pin[0] == '/' && pin[1] == '*') {
+            // Skip comment
+            tr(TrParser, " skip comment {");
+            while (pin[0] != '*' || pin[1] != '/')
+            {
+                while ((pin[0] != '*' || pin[1] != '/') && *pin != '\n')
+                    pin++;
+
+                // If end of line, read the next line
+                if (*pin == '\n') {
+                    if (get_next_line() == 0)
+                        return TOKEN_EOF;
+                }
+                else {
+                    pin += 2;
+                    break;
+                }
+            }
+            tr(TrCont|TrParser, "}");
+        }
+        else {
+            whitespace = 0;
+        }
+    }
+
+    {
+        char tmp[8];
+        for (whitespace = 0; whitespace < 7; whitespace++)
+            tmp[whitespace] = (pin[whitespace] < ' ' ? '.' : pin[whitespace]);
+        tmp[7] = 0;
+        tr(TrCont|TrParser, " ('%s...')\n", tmp);
+    }
+
+    // See if token is a string
+    if (isalpha(*pin) || *pin == '_') {
+        pin_start = pin;
+        while (isalnum(*pin) || *pin == '_')
+            pin++;
+        length = pin - pin_start;
+        strncpy(string, pin_start, length);
+        string[length] = 0;
+        return TOKEN_STRING;
+    }
+
+    // See if token is a number
+    if (isdigit(*pin)) {
+        number = (int) strtol(pin, &pin_end, 0);
+        pin = pin_end;
+        if (*pin_end == 'k') {
+            number *= 1024;
+            pin++;
+        }
+        return TOKEN_NUMBER;
+    }
+
+    // Token is a character
+    return *pin++;
+}
+
+int get_keyword(void)
+{
+    int token;
+
+    token = get_token();
+    tr(TrParser, "get_keyword() (%d) ", token);
+
+    if (token == TOKEN_EOF)
+        return E_PARSER_EOF;
+
+    if (token != TOKEN_STRING)
+        return E_PARSER_KEYWORD;
+
+    if (strcmp("memmap", string) == 0)
+        token = KEYWORD_MEMMAP;
+    else if (strcmp("device", string) == 0)
+        token = KEYWORD_DEVICE;
+    else
+        token = E_PARSER_KEYWORD;
+
+    tr(TrCont|TrParser, "%d\n", token);
+    return token;
+}
+
+int get_string(void)
+{
+    int token;
+
+    token = get_token();
+    tr(TrParser, "get_string() (%d) ", token);
+
+    if (token == TOKEN_EOF)
+        return E_PARSER_EOF;
+
+    if (token != TOKEN_STRING)
+        return E_PARSER_STRING;
+
+    tr(TrCont|TrParser, "'%s'\n", string);
+    return 0;
+}
+
+int get_number(void)
+{
+    int token;
+
+    token = get_token();
+    tr(TrParser, "get_number() (%d) ", token);
+
+    if (token == TOKEN_EOF)
+        return E_PARSER_EOF;
+
+    if (token != TOKEN_NUMBER)
+        return E_PARSER_NUMBER;
+
+    tr(TrCont|TrParser, "0x%X\n", number);
+    return 0;
+}
+
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+// Estimate the time taken for erasure and programming of the flash
+// device. <bytes> is the number of bytes to program.
+int time_compute(struct device_s *device,
+                 int sectors, int bytes, int chunks,
+                 int *time_erase, int *time_program, int *time_transfer)
+{
+    int te =  0; // sector erase time in milli seconds
+    int tp = 16; // 16-bit word program time in micro seconds
+    int tdt, tco, trp;
+
+    switch (device->algorithm_id) {
+    case ALGORITHM_AMD:        te =  700; break;
+    case ALGORITHM_INTEL:      te =  800; break;
+    case ALGORITHM_INTEL_BW:   te = 1300; break;
+    case ALGORITHM_MITSUBISHI: te =   40; break;
+    case ALGORITHM_SST:        te =   20; break;
+    }
+    *time_erase   = te * sectors;
+
+    // Data transmission time: with 12 bytes per chunk
+    tdt = (bytes + 12 * chunks) / (arg_uart_baudrate / 10) * 1000;
+
+    // Communication overhead time: 2 waits of 10ms per chunk.
+    tco = chunks * 2 * 10;
+
+    *time_transfer = tdt + tco;
+
+    // Raw programming time:
+    *time_program = trp = (bytes / 2) * tp / 1000;
+
+    tr(TrUtility, "tdt = %d\n", tdt);
+    tr(TrUtility, "tco = %d\n", tco);
+    tr(TrUtility, "trp = %d\n", trp);
+
+    return *time_erase + *time_transfer;
+}
+
+void device_print(struct device_s *device, char format)
+{
+    int device_size =
+        (device->memmap->sectors[device->memmap->size - 1].addr +
+         device->memmap->sectors[device->memmap->size - 1].size) /
+        (1024 * 1024 / 8);
+
+    if (format == 'l') {
+        printf("%s %s (0x%02X, 0x%04X). %dMb in %d sectors, %s algorithm",
+               manufacturer_name_lookup_by_id(device->manufacturer_id),
+               device->name,
+               device->manufacturer_id,
+               device->device_id,
+               device_size,
+               device->memmap->size,
+               algorithm_name_lookup_by_id(device->algorithm_id));
+    }
+    else if (format == 's') {
+        printf("(0x%02X, 0x%04X) %s %s",
+               device->manufacturer_id,
+               device->device_id,
+               manufacturer_name_lookup_by_id(device->manufacturer_id),
+               device->name);
+    }
+}
+
+void devices_list(void)
+{
+    struct device_s *device = devices;
+
+    while (device != NULL) {
+        device_print(device, 'l');
+        putchar('\n');
+        device = device->next;
+    }
+}
+
+struct device_s *device_lookup_by_id(int m, int d)
+{
+    struct device_s *device = devices;
+
+    while (device != NULL) {
+        if ((m & 0xFF) == device->manufacturer_id && d == device->device_id)
+            return device;
+        device = device->next;
+    }
+    return (struct device_s *) 0;
+}
+
+struct device_s *device_lookup_by_name(char *name)
+{
+    struct device_s *device = devices;
+
+    while (device != NULL) {
+        if (strcmp(name, device->name) == 0)
+            return device;
+        device = device->next;
+    }
+    return (struct device_s *) 0;
+
+}
+
+struct memmap_s *memmap_lookup_by_name(char *name)
+{
+    struct memmap_s *memmap = memmaps;
+
+    while (memmap != NULL) {
+        if (strcmp(name, memmap->name) == 0)
+            return memmap;
+        memmap = memmap->next;
+    }
+    return (struct memmap_s *) 0;
+}
+
+char *manufacturer_name_lookup_by_id(int id)
+{
+    int i = 0;
+
+    while (manufacturers[i].id != 0) {
+        if (manufacturers[i].id == id)
+            return manufacturers[i].name;
+        i++;
+    }
+
+    return manufacturers[i].name;
+}
+
+int manufacturer_id_lookup_by_name(char *name)
+{
+    int i = 0;
+
+    while (manufacturers[i].id != 0) {
+        if (strcmp(manufacturers[i].name, name) == 0)
+            return manufacturers[i].id;
+        i++;
+    }
+
+    return 0;
+}
+
+char *algorithm_name_lookup_by_id(int id)
+{
+    int i = 0;
+
+    while (algorithms[i].id != 0) {
+        if (algorithms[i].id == id)
+            return algorithms[i].name;
+        i++;
+    }
+
+    return algorithms[i].name;
+}
+
+int algorithm_id_lookup_by_name(char *name)
+{
+    int i = 0;
+
+    while (algorithms[i].id != 0) {
+        if (strcmp(algorithms[i].name, name) == 0)
+            return algorithms[i].id;
+        i++;
+    }
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/flash.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,102 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Flash device database and lookup
+ *
+ * $Id: flash.h 1.11 Wed, 30 Oct 2002 12:09:08 +0100 tsj $
+ *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+struct sector_s {
+    int addr;
+    int size;
+};
+
+// We make room for a device of 2047 * 64kB + plus 8 * 8kB sectors (eg. 1Gb)
+struct memmap_s {
+    struct memmap_s *next;
+    char *name;
+    int size;
+    struct sector_s sectors[2047+7];
+};
+
+struct device_s {
+    struct device_s *next;
+    int algorithm_id;
+    int manufacturer_id;
+    int device_id;
+    char *name;
+    int t_erase;   // typical time (milli-seconds) for erasing one sector
+    int t_program; // typical time (micro-seconds) for programming one word
+    struct memmap_s *memmap;
+};
+
+struct manufact_s {
+    // struct manufact_s *next;
+    int id;
+    char *name;
+};
+
+struct algorithm_s {
+    int id;
+    char *name;
+};
+
+enum FlashAlgorithms {
+    ALGORITHM_AMD      = 1,
+    ALGORITHM_AMDFAST,
+    ALGORITHM_INTEL,
+    ALGORITHM_INTEL_BW,
+    ALGORITHM_MITSUBISHI,
+    ALGORITHM_SST
+};
+
+enum FlashManufacturers {
+    MANUFACT_AMD        = 0x01,
+    MANUFACT_ATMEL      = 0x1F,
+    MANUFACT_FUJITSU    = 0x04,
+    MANUFACT_INTEL      = 0x89,
+    MANUFACT_MXIC       = 0xC2,
+    MANUFACT_MITSUBISHI = 0x1C,
+    MANUFACT_SAMSUNG    = 0xEC,
+    MANUFACT_SHARP      = 0xB0,
+    MANUFACT_STM        = 0x20,
+    MANUFACT_SST        = 0xBF,
+    MANUFACT_TOSHIBA    = 0x98,
+    MANUFACT_TEST       = 0xFF
+};
+
+
+/******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+void device_print(struct device_s *device, char format);
+void devices_list(void);
+void file_read_devices(char *filename);
+
+int get_next_line(void);
+int get_token(void);
+int get_keyword(void);
+int get_string(void);
+int get_number(void);
+
+int time_compute(struct device_s *device,
+                 int sectors, int bytes, int chunks,
+                 int *time_erase, int *time_program, int *time_trransfer);
+    
+struct device_s *device_lookup_by_id(int manid, int devid);
+struct memmap_s *memmap_lookup_by_name(char *name);
+char *manufacturer_name_lookup_by_id(int id);
+int   manufacturer_id_lookup_by_name(char *name);
+char *algorithm_name_lookup_by_id(int id);
+int   algorithm_id_lookup_by_name(char *name);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/fluid.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,818 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Main, command-line argument parsing, error handling.
+ *
+ * $Id: fluid.c 1.50 Thu, 14 Nov 2002 13:10:05 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "flash.h"
+#include "fileio.h"
+#include "trace.h"
+// Secure Calypso Plus
+#include "../inc/ram_load.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if defined(MSC) || defined(BCC)
+  #include "getopt.h"
+  #include "windows.h"
+#else
+  #include <getopt.h>
+#endif
+
+#include <errno.h> // for ERANGE
+
+
+/******************************************************************************
+ * Prototypes and Globals
+ ******************************************************************************/
+
+extern T_RAM_LOADER d_ram_loader;   // Secure Calypso Plus
+
+char *arg_file_list[ARG_FILE_LIST_SIZE_MAX] = { (char *) 0 };
+int  arg_file_list_size = 0;
+
+char *arg_erase_override = "";
+char *arg_read = "";
+char *arg_write = "";
+int  arg_checksum = 1;
+int  arg_compress = 1;
+int  arg_dry_run = 0;
+int  arg_list_devices = 0;
+char arg_target_type = 0;
+int  arg_image_map_show = 0;
+int  arg_sector_map_show = 0;
+int  arg_sector_list_show = 0;
+int  arg_timers_show = 0;
+int  arg_timers_extended_show = 0;
+int  arg_checksum_show = 0;
+int  arg_show_hexdump = 0;
+int  arg_target_trace_enable = 0;
+int  arg_progress = 'a';
+char arg_hexfile_type = 'm';
+char arg_hexfile_memwidth = 2;
+
+int  arg_target_reset = 1;
+int  arg_rom_bootloader = 0;
+int  arg_boot_delay_rom = 15;
+int  arg_boot_delay_fluid = 15;
+int  arg_device_id0 = -1;
+int  arg_device_id1 = -1;
+
+int  arg_uart_port = 1;
+int  arg_uart_baudrate = 115200;
+char arg_uart_flowcontrol[] = "pn";
+char arg_uart_level_convert = 0;
+
+char arg_verbose = 0;
+int  arg_debug_resume = 0;
+int  arg_debug_trace_pe = 0;
+int  arg_keep_going = 0;
+int  arg_show_main_args = 0;
+int  arg_skip_erase = 0;
+
+// Secure Calypso Plus
+char *arg_die_id_file_name = "";
+char *arg_imeisv = "";
+char *arg_platform_certificate_addr = "";
+int  arg_request_certificate = 0;
+int  arg_delay_for_changing_cs5 = 0;
+int  arg_uart_baudrate_during_cmd_download = 115200;
+int  arg_uart_timeout_configuration = 0;
+int  arg_block_size = 8 * 1024;   // Must be a modulus of 64 bytes, except for the last command.
+
+int arg_usage = 0;
+
+char *argv_0;
+
+int  arg_tr_mask = 0;
+int  arg_tr_spaces = 2;
+char *arg_tr_file = NULL;
+
+int arg_errorfd = 2;
+
+static void main_usage(void);
+static void main_args(int argc, char *argv[]);
+static long arg_long_get(void);
+
+extern int fluid_machine(void);
+extern int fluid_compress(void);
+extern int fluid_decompress(void);
+
+extern int serial_is_baudrate(int bps);
+
+
+/******************************************************************************
+ * Error handling
+ ******************************************************************************/
+
+extern char *main_strerror(int error);
+
+char *win32_strerror(void)
+{
+    static char buf[220];
+    int error;
+    char *p = buf;
+
+    error = GetLastError();
+    p += sprintf(buf, "%d: ", error);
+
+    if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
+                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                      p, sizeof(buf) - 20, NULL) == 0)
+        sprintf(p, "(Unknown Win32 error)");
+
+    return buf;
+}
+
+void main_msg(char *format, ...)
+{
+    va_list args;
+    char buf[1024];
+
+    va_start(args, format);
+    vsprintf(buf, format, args);
+    va_end(args);
+
+    if (arg_errorfd == 2) {
+        fprintf(stderr, "%s", buf);
+        fflush(stderr);
+    }
+    else {
+        fprintf(stdout, "%s", buf);
+        fflush(stdout);
+    }
+}
+
+void main_error_str(char type, int error, char *string)
+{
+    // If it was an OS error...
+    if (error < E_OS) {
+        error -= E_OS;
+        main_msg("OS-ERROR: %s", win32_strerror());
+    }
+
+    main_msg(" %s(%d): %s%s\n", (type == 'w' ? "WARNING" : "ERROR"),
+             -error, main_strerror(error), string);
+}
+
+void main_warning(int error)
+{
+    main_error_str('w', error, "");
+}
+
+void main_error(int error)
+{
+    main_error_str('e', error, "");
+
+    if (arg_keep_going == 0)
+        exit(-error);
+}
+
+void main_fatal(int error)
+{
+    main_error(error);
+    exit(-error);
+}
+
+
+/******************************************************************************
+ * Command line parsing
+ ******************************************************************************/
+
+static void main_help(void)
+{
+    printf(
+        "\n"
+        "You have started fluid with no command line arguments\n"
+        "\n"
+        "To see all the available command line arguments, start fluid\n"
+        "from a command line prompt (cmd.exe or similar) with:\n"
+        "\n"
+        "    fluid -h\n"
+        "\n"
+        "To see some basic and common examples of usage, start fluid with:\n"
+        "\n"
+        "    fluid -ic\n"
+        "\n"
+        "You can get an overview of all the available examples with:\n"
+        "\n"
+        "    fluid -ii\n"
+        "\n"
+//        "Please read the README file for notes and other info and read the\n"
+//        "HISTORY file to see what has happened with fluid since last release.\n"
+//        "\n"
+        "Press RETURN to exit...\n"
+        );
+    getchar();
+}
+
+static void main_example(int type)
+{
+    switch (type) {
+    case 'c':
+        printf(
+            "Download into board:\n"
+            "  fluid -f gsm.m0\n"
+            "\n"
+            "Simulate a download into board (dry-run):\n"
+            "  fluid -n -f gsm.m0\n"
+            "\n"
+            "Check if file has already been downloaded into board:\n"
+            "  fluid -n -f gsm.m0\n"
+            "\n"
+            "Download into board without erasing boot sector:\n"
+            "  fluid -e-0 -f gsm.m0\n"
+            "\n"
+            "Download into board with another progress indication:\n"
+            "  fluid -gc -f gsm.m0\n"
+            "\n"
+            );
+        break;
+    case 'a':
+        printf(
+            "Download into board with more output verbosity:\n"
+            "  fluid -v -v -f gsm.m0\n"
+            "\n"
+            "Show the image map (which parts of the flash are used, which are not):\n"
+            "  fluid -si -n -f gsm.m0\n"
+            "\n"
+            "Show both the image and the erase maps:\n"
+            "  fluid -sis -n -f gsm.m0\n"
+            "\n"
+            "Download into board without delta download:\n"
+            "  fluid -C -f gsm.m0\n"
+            "\n"
+            );
+        break;
+    case 'e':
+        printf(
+            "Erase all flash (including boot sector!):\n"
+            "  fluid -e+*\n"
+            "\n"
+            "Erase all flash except the boot sector:\n"
+            "  fluid -e+*,-0\n"
+            "\n"
+            "Erase the last megabyte of a 4MB flash device:\n"
+            "  fluid -e+3M..4M\n"
+            "\n"
+            "Erase all flash except sectors 1..7 and addresses 1984k..2048k:\n"
+            "  fluid -e+*,-1..8,-1984k..2048k\n"
+            "\n"
+            );
+        break;
+    case 'r':
+        printf(
+            "Read whole FFS system from a B-Sample:\n"
+            "  fluid -r3M..4M -f bsffs.m0\n"
+            "\n"
+            "Then copy/download it (e.g., to another B-Sample):\n"
+            "  fluid -f bsffs.m0\n"
+            "\n"
+            "Read serial switch config from a B- or C-Sample:\n"
+            "(serial switch config is in sector 2 on TI releases earlier than SSA-5.3.1)\n"
+            "  fluid -r0x11ffe..0x12000 -f usxx.m0 -sx\n"
+            "\n"
+            "Copy it to a(nother) B- or C-sample:\n"
+            "  fluid -f usxx.m0\n"
+            "\n");
+        break;
+    case 'w':
+        printf(
+            "Over-write image with a byte string at a specific address:\n"
+            "  fluid -f gsm.m0 -w7800=0x11,0x22,0x33,0x44,0x55,0x66\n"
+            "\n"
+            "Write zeroes into top-most 2MB of C-Sample flash memory:\n"
+            "  fluid -w2M..4M=0\n"
+            "\n"
+            "Write a string to a specific address:\n"
+            "  fluid -w0x1800=\"\"\"Mads\"\"\",0\n"
+            "\n");
+            break;
+    case 's':
+        printf(
+            "Reset target, doing nothing else (requires special cable):\n"
+            "  fluid -n -or\n"
+            "\n"
+            );
+        break;
+    default:
+        printf(
+            "Avaliable examples:\n"
+            "  a = Advanced, common usage\n"
+            "  c = Common usage\n"
+            "  e = Erase override\n"
+            "  r = Read target memory\n"
+            "  w = Write target memory\n"
+            "  s = Special usage\n"
+            );
+        break;
+    }
+    exit(0);
+}
+
+static void main_debug_usage(void)
+{
+    printf("Debug usage: fluid [OPTIONS...]\n"
+           "\n"
+           "  -d r       Display target (remote) tracing.\n"
+           "  -d c       Resume fluid state machine in command interpreter.\n"
+           "  -d o       Display final command line option values.\n"
+           "  -d t<char> Trace mask in human format:\n"
+           "               a = All, except ?\n"
+           "               * = All\n"
+           "               g = getchar()\n"
+           "               p = putchar()\n"
+           "               G = target driver receive\n"
+           "               P = target driver transmit\n"
+           "               w = target wait\n"
+           "               t = target/transport layer driver\n"
+           "               h = hexfile read/decode\n"
+           "               H = hexfile write/encode\n"
+           "               r = device file parser\n"
+           "               c = Command line argument parser\n"
+           "               u = utility functions\n"
+           "               m = state machine functions\n"
+           "               \n"
+           "  -d v       Display info on compiler used.\n"
+           "  -d f<file> Trace to file.\n"
+           "  -d i<n>    Trace indentation multiplier. Default is 2.\n"
+           "  -d m<n>    Trace mask. Default is 0.\n"
+           "  -t <char>  Trace mask in human format. Same as '-d t<char>'.\n"
+           "\n"
+           "B-/C-/D-Sample LEDs layout:\n"
+           "\n"
+           "+---0---+---1---+---2---+---3---+---4---+---5---+---6---+---7---+\n"
+           "| Recv  | Erase | Prog  | Overhd| Idle  |       |       | Busy  |\n"
+           "+-------+-------+-------+-------+-------+-------+-------+-------+\n"
+        );
+    exit(0);
+}
+
+static void main_args_debug_trace(void)
+{
+    while (*optarg) {
+        switch(*optarg++) {
+        case 'a': arg_tr_mask |= TrAll & ~(0); break;
+        case '*': arg_tr_mask |= TrAll; break;
+        case 'm': arg_tr_mask |= TrMachines; break;
+        case 'g': arg_tr_mask |= TrGetChar; break;
+        case 'p': arg_tr_mask |= TrPutChar; break;
+        case 'G': arg_tr_mask |= TrDriverGet; break;
+        case 'P': arg_tr_mask |= TrDriverPut; break;
+        case 'w': arg_tr_mask |= TrTargetWait; break;
+        case 't': arg_tr_mask |= TrTargetDrv; break;
+        case 'h': arg_tr_mask |= TrHexRead; break;
+        case 'H': arg_tr_mask |= TrHexWrite; break;
+        case 'r': arg_tr_mask |= TrParser; break;
+        case 'c': arg_tr_mask |= TrArgParser; break;
+        case 'C': arg_tr_mask |= TrCmdLineParser; break;
+        case 'u': arg_tr_mask |= TrUtility; break;
+        }
+    }
+}
+
+static void fluid_welcome(void)
+{
+    flowf(NORMAL,
+        "FLUID Revision 2.27, (23 Aug 2004). Copyright Texas Instruments, 2001-2004.\n");
+}
+
+static void fluid_compile_info(void)
+{
+    flowf(
+        NORMAL,
+        "Compiled " __DATE__ " " __TIME__ " with "
+#if defined(MSC)
+        "Microsoft cl.exe"
+#elif defined(BCC)
+        "Borland bcc"
+#else
+        "GNU gcc"
+#endif
+        "\n");
+}
+
+static void main_usage(void)
+{
+    printf(
+        "Usage: fluid [OPTIONS...]\n"
+        "\n");
+    if (!arg_usage)
+        fluid_welcome();
+    printf(
+        "FLUID is a Flash Loader Utility Independent of Device\n"
+        "This version supports:\n"
+        "  TI GSM Boot Loader V6.x.x (with fluid patch)\n"
+        "  TI ROM Boot Loader (Calypso devices only)\n"
+        "\n"
+        "  -f <file>  Flash image file (input or output file).\n"
+        "  -p <num>   Serial port number. Default is 1.\n"
+        "  -b <num>   Serial baudrate. Default is 115200.\n"
+        "  -t <char>  Target type (Default is auto-detect):\n"
+        "               h = Hercules\n"
+        "               u = Ulysses\n"
+        "               c = Calypso\n"
+        "               l = Calypso Lite\n"
+        "               p = Calypso Plus\n"
+        "  -l         List all known flash devices.\n"
+        "  -c, -C     Do or do not checksum target memory thus enabling delta\n"
+        "             download (only program changed sectors). Default is on.\n"
+        "  -z, -Z     Do or do not compress data on download. Default is on.\n"
+        "  -g <char>  Progress indication type:\n"
+        "               a = asterisks (default), c = chars, d = dots,\n"
+        "               x = address+size, n = none\n"
+        "  -e [+|-]<addr0>..<addr1>,... or [+|-]<n>,...<\n"
+        "             Erase/program override. Erase or don't erase flash\n"
+        "             memory in the range [addr0..addr1[. Use '-ie' to see\n"
+        "             examples of usage\n"
+        "             -<...> = do *not* erase and program\n"
+        "             +<...> = force erase\n"
+        "             Giving <n> as an asterisk, '*', means all sectors\n"
+        "  -r <addr0>..<addr1>,...\n"
+        "             Read target memory range [addr0..addr1[ and write the\n"
+        "             bytes to output file specified.\n"
+        "  -w <addr0>..<addr1>=<b0,b1,...,bN>:...\n"
+        "             Write bytes to image. The bytes b0..bN are replicated\n"
+        "             through the whole memory range [addr0..addr1[\n"
+        "  -o <char>  Extra options:\n"
+        "               o = Only bootstrap using ROM boot loader (Calypso devices only)\n"
+        "               O = Do NOT use ROM boot loader\n"
+        "               e = Skip erase (Require empty flash)\n"
+        "               r = Reset target after download (default)\n"
+        "               R = Do NOT reset target after download\n"
+        "               l = Activate (old-fashioned) UART level conversion\n"
+        "               m = Select Motorola hexfile output format (default)\n"
+        "               b = Select binary/raw file output format\n"
+        "               i<n1>,<n2> = Disable device auto-detection and set manufacturer\n"
+        "                   id and device id\n"
+        "               d<n1>,<n2> = Set detection delay (in ms) for ROM and fluid boot\n"
+        "                   loader, respectively\n"
+        "               1, 2, 4 = Select hexfile memory width 1, 2 or 4. Default is 2\n"
+        "  -s <char>  Show additional info:\n"
+        "               i = image map\n"
+        "               s = sector erase map\n"
+        "               l = sector erase list\n"
+        "               t = target timers, T = extended target timer info\n"
+        "               x = hexdump of target memory (together with '-r')\n"
+        "               c = checksums\n"
+        "  -n         Dry run. Do not program the flash device.\n"
+        "  -v         Be verbose. Multiple '-v's means more verbosity.\n"
+        "  -q         Be quiet.\n"
+//        "  -y         Use stdout for error messages.\n"
+        "  -dh        Display help on debug and trace options.\n"
+        "  -h         Display this help.\n"
+        "  -i <char>  Display examples (i = index/overview of examples).\n"
+        // Secure Calypso Plus
+        "\n  Secure Calypso Plus options:\n"
+        "  -I <char>  IMEI protection options:\n"
+        "               d <file> = Retrieve die id from target and write to <file>.\n"
+        "               n <num>  = 16 digits representing the IMEI-SV, [8 TAC]+[6 SNR]+\n"
+        "                          [2 SVN], which is used for non-secure E-samples or\n"
+        "                          secure E-samples when the die id is not added to the\n"
+        "                          DIE_ID field of the manufacturer certificate.\n"
+        "               a <addr> = Address of the platform certificate stored in flash.\n"
+        "  -R         Request firmware certificate.\n"
+        "  -D <num>   Insert a delay before detection of flash type. This delay is used\n"
+        "             for changing the memory mapping on CS5 due to a bug in ROM code\n"
+        "             0x0410 (see SECURITY.txt) or for connecting to target via JTAG.\n"
+        "  -U <num>   UART baudrate during flash programmer download. Default is 115200.\n"
+        "  -u <num>   UART timeout configuration. Default is 0.\n"
+        "  -B <num>   Block size. Must be a modulus of 64 bytes. Default is %d bytes.\n", arg_block_size
+        // End Secure Calypso Plus
+        );
+}
+
+static void main_args(int argc, char *argv[])
+{
+    char ch;
+    int i;
+    // IMEI Protection
+    char d_i, d_digit;
+    char a_imeisv_format[] = "The IMEI-SV must consist of 16 digits in compliance with the following format:\n[8 TAC]+[6 SNR]+[2 SVN]\n";
+
+    if (argc == 1) {
+        fluid_welcome();
+        main_help();
+        exit(0);
+    }
+
+    for (i = argc - 1; i >= 0; i--) {
+        // TODO?: scan for filenames.
+    }
+
+    while ((ch = getopt(argc, argv,
+                        "f:p:b:cCzZjJt:e:s:r:w:nlqg:o:vkd:i:hVyI:RD:U:u:B:")) != -1)
+    {
+        switch (ch)
+        {
+        case 'f':
+            if (arg_file_list_size < ARG_FILE_LIST_SIZE_MAX - 1)
+                arg_file_list[arg_file_list_size++] = optarg;
+            arg_file_list[arg_file_list_size] = NULL;
+            break;
+        case 'p':
+            arg_uart_port = arg_long_get();
+            if (arg_uart_port < 1 || 24 < arg_uart_port)
+                main_error(E_BADARG);
+            break;
+        case 'b':
+            arg_uart_baudrate = arg_long_get();
+            arg_uart_baudrate = serial_is_baudrate(arg_uart_baudrate);
+            if (arg_uart_baudrate == 0)
+                main_error(E_BADARG);
+            break;
+        case 't':
+            arg_target_type = *optarg;
+            break;
+        case 'c': arg_checksum = 1; break;
+        case 'C': arg_checksum = 0; break;
+        case 'z': arg_compress = 1; break;
+        case 'Z': arg_compress = 0; break;
+        case 'e':
+            if (*arg_erase_override != 0)
+                main_error(E_ARG_MULTI);
+            arg_erase_override = optarg;
+            break;
+        case 's':
+            while (*optarg) {
+                switch(*optarg++) {
+                case 'i': arg_image_map_show++; break;
+                case 's': arg_sector_map_show++; break;
+                case 'l': arg_sector_list_show++; break;
+                case 't': arg_timers_show++; break;
+                case 'T': arg_timers_extended_show++; break;
+                case 'c': arg_checksum_show++; break;
+                case 'x': arg_show_hexdump++; break;
+                }
+            }
+            break;
+        case 'r':
+            if (*arg_read != 0)
+                main_error(E_ARG_MULTI);
+            arg_read = optarg;
+            break;
+        case 'w':
+            if (*arg_write != 0)
+                main_error(E_ARG_MULTI);
+            arg_write = optarg;
+            break;
+        case 'l': arg_list_devices = 1; break;
+        case 'n': arg_dry_run++; break;
+        case 'k': arg_keep_going = 1; break;
+        case 'v': arg_verbose++; break;
+        case 'q': arg_verbose--; break;
+        case 'g':
+            if (*optarg != 'a' &&
+                *optarg != 'c' &&
+                *optarg != 'd' &&
+                *optarg != 'x' &&
+                *optarg != 'n')
+                main_error(E_BADARG);
+            arg_progress = *optarg;
+            break;
+        case 'o':
+            while (*optarg) {
+                tr(TrCmdLineParser, "main_args(): -o%s", optarg);
+                switch (*optarg) {
+                case 'e': arg_skip_erase = 1; break;
+                case 'R': arg_target_reset = 0; break;
+                case 'r': arg_target_reset = 2; break;
+                case 'o': arg_rom_bootloader = 1; break;
+                case 'O': arg_rom_bootloader = -1; break;
+                case 'l': arg_uart_level_convert = 1; break;
+                case 'b':
+                case 'm': arg_hexfile_type = *optarg; break;
+                case 'i':
+                    optarg++;
+                    arg_device_id0 = arg_long_get();
+                    if (*optarg == ',') {
+                        optarg++;
+                        arg_device_id1 = arg_long_get();
+                    }
+                    else {
+                        fprintf(stderr, "arg: '%s'", optarg);
+                        main_error(E_BADARG);
+                    }
+                    optarg--;
+                    break;
+                case 'd':
+                    optarg++;
+                    arg_boot_delay_rom = arg_long_get();
+                    if (*optarg == ',') {
+                        optarg++;
+                        arg_boot_delay_fluid = arg_long_get();
+                    }
+                    else if (*optarg == 0)
+                        arg_boot_delay_fluid = arg_boot_delay_rom;
+                    else {
+                        fprintf(stderr, "arg: '%s'", optarg);
+                        main_error(E_BADARG);
+                    }
+                    optarg--;
+                    break;
+                case '1':
+                case '2':
+                case '4':
+                    arg_hexfile_memwidth = *optarg - '0';
+                    break;
+                default:
+                    main_error(E_BADARG);
+                }
+                tr(TrCmdLineParser, "\n");
+                optarg++;
+            }
+            break;
+        case 'd':
+            while (*optarg) {
+                switch (*optarg++) {
+                case 'h': main_debug_usage(); break;
+                case 'c': arg_debug_resume = 1; break;
+                case 'p': arg_debug_trace_pe = 1; break;
+                case 'r': arg_target_trace_enable = 1; break;
+                case 'o': arg_show_main_args = 1; break;
+                case 't': main_args_debug_trace(); break;
+                case 'v': fluid_compile_info(); exit(0); break;
+                case 'f': arg_tr_file = optarg; optarg += strlen(optarg); break;
+                case 'm': arg_tr_mask = arg_long_get(); break;
+                case 'i': arg_tr_spaces = arg_long_get(); break;
+                default:
+                    main_error(E_BADARG);
+                }
+            }
+            optarg++;
+            break;
+        case 'i': main_example(*optarg); break;
+        case 'h': arg_usage = 1; break;
+        case 'V': fluid_welcome(); exit(0);
+        case 'y': arg_errorfd = 1; break;
+        // IMEI Protection
+        case 'I':
+            switch (*optarg++) {
+            case 'd':
+                if (*arg_die_id_file_name != 0)
+                    main_error(E_ARG_MULTI);
+                if (*optarg == 0)
+                    optarg++;
+                arg_die_id_file_name = optarg;
+                break;
+            case 'n':
+                if (*arg_imeisv != 0)
+                    main_error(E_ARG_MULTI);
+                if (*optarg == 0)
+                    optarg++;
+                arg_imeisv = optarg;
+                if (strlen(arg_imeisv) != C_IMEISV_DIGITS) {
+                    fprintf(stderr, a_imeisv_format);
+                    main_error(E_BADARG);
+                }
+                for (d_i = 0; d_i < C_IMEISV_DIGITS; d_i++) {
+                    sscanf(arg_imeisv++, "%1c", &d_digit);
+                    if (d_digit < '0' ||d_digit > '9') {
+                        fprintf(stderr, a_imeisv_format);
+                        main_error(E_BADARG);
+                    }
+                }
+                arg_imeisv = optarg;   // Re-assign arg_imeisv after error check
+                break;
+            case 'a':
+                if (*arg_platform_certificate_addr != 0)
+                    main_error(E_ARG_MULTI);
+                if (*optarg == 0)
+                    optarg++;
+                arg_platform_certificate_addr = optarg;
+                if ((strlen(arg_platform_certificate_addr) == C_PLATFORM_CERT_ADDR_DIGITS + 2) &&
+                   (arg_platform_certificate_addr[0] == '0') &&
+                   (arg_platform_certificate_addr[1] == 'x'))
+                    arg_platform_certificate_addr += 2;
+                else if (strlen(arg_platform_certificate_addr) != C_PLATFORM_CERT_ADDR_DIGITS) {
+                    fprintf(stderr, "The platform certificate address must comply with the following format, e.g.,\n0x04650000\n");
+                    main_error(E_BADARG);
+                }
+                break;
+            default:
+                main_error(E_BADARG);
+            }
+            break;
+        // Secure Calypso Plus
+        case 'R':
+            arg_request_certificate = 1;
+            d_ram_loader.b_certificate_request = C_TRUE;
+            break;
+        case 'D':
+            arg_delay_for_changing_cs5 = arg_long_get();
+            if (arg_delay_for_changing_cs5 < 0)
+                main_error(E_BADARG);
+            break;
+        case 'U':
+            arg_uart_baudrate_during_cmd_download = arg_long_get();
+            if (arg_uart_baudrate_during_cmd_download < 0)
+                main_error(E_BADARG);
+            break;
+        case 'u':
+            arg_uart_timeout_configuration = arg_long_get();
+            d_ram_loader.d_uart_timeout = (UWORD32) arg_uart_timeout_configuration;
+            if (d_ram_loader.d_uart_timeout < 0)
+                main_error(E_BADARG);
+            break;
+        case 'B':
+            arg_block_size = arg_long_get();
+            d_ram_loader.d_nb_byte_in_block = (UWORD32) arg_block_size;
+            if (d_ram_loader.d_nb_byte_in_block < 1)
+                main_error(E_BADARG);
+            break;
+        // End Secure Calypso Plus
+        default:
+            main_usage();
+            exit(-E_BADARG);
+        }
+    }
+
+    if (arg_usage) {
+        main_usage();
+        exit(0);
+    }
+
+    if (arg_show_main_args) {
+        printf("Command line option values:\n");
+        printf("argv[0] = '%s'\n", argv[0]);
+        printf("\n");
+        printf("port = %d\n", arg_uart_port);
+        printf("baudrate = %d\n", arg_uart_baudrate);
+
+        printf("target_trace_enable = %d\n", arg_target_trace_enable);
+        printf("\n");
+    }
+
+}
+
+static long arg_long_get(void)
+{
+    long value;
+    char *endp;
+
+    errno = 0;
+    value = strtol(optarg, &endp, 0);
+
+    if (errno == ERANGE || endp == optarg) {
+        fprintf(stderr, "Invalid command line number argument: '%s'", optarg);
+        exit(1);
+    }
+    optarg = endp;
+    return value;
+}
+
+
+/******************************************************************************
+ * Globals and Main
+ ******************************************************************************/
+
+int flowf(int level, char *format, ...)
+{
+    int n = 0;
+    va_list args;
+    char buf[1024];
+
+    if (level <= arg_verbose) {
+        va_start(args, format);
+        vsprintf(buf, format, args);
+
+        n = fprintf(stdout, "%s", buf);
+    }
+    fflush(stdout);
+
+    return n;
+}
+
+int main(int argc, char *argv[])
+{
+    int error;
+
+    file_read_rc(".fluidrc");
+
+    main_args(argc, argv);
+    argv_0 = argv[0];
+
+    if (arg_verbose >= NORMAL)
+        fluid_welcome();
+
+    // Init tracing library
+    tr_init(arg_tr_spaces, arg_tr_file);
+    tr_mask(TrMAIN | arg_tr_mask);
+
+    error = fluid_machine();
+
+    if (error < 0)
+        main_error(error);
+
+    exit(-error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/fluid.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,213 @@
+/******************************************************************************
+ * FLUID (Flash Loader and Utility Independent of Device)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * Main
+ *
+ * $Id: fluid.h 1.43 Fri, 25 Oct 2002 14:46:33 +0200 tsj $
+ *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ * Exception definitions
+ ******************************************************************************/
+
+enum Exceptions {
+    E_OK               =   0, /* Ok */
+
+    E_DRIVER_INIT      =  -3, /* Driver failed to initialize */
+    E_DRIVER_WAIT      =  -4, /* Driver recv_wait() failed */
+
+    E_UART_INIT        =  -5, /* UART failed to initialize */
+    E_UART_PARAM       =  -6, /* UART parameter bad or unsupported */
+    E_UART_DRV_SEND    =  -7, /* UART driver transmit error */
+    E_UART_DRV_RECV    =  -8, /* UART driver receive error */
+
+    E_RECV_TIMEOUT     = -10, /* Receive timeout (no target reply) */
+    E_RECV_ANTITIMEOUT = -11, /* Receive anti-timeout (target replied!?) */
+    E_SEND_CHECKSUM    = -12, /* Transmit checksum error */
+    E_RECV_CHECKSUM    = -13, /* Receive checksum error */
+    E_PROTO_ERROR      = -14, /* Protocol error (bad char from target) */
+    E_INVALID          = -15, /* Invalid command parameter */
+    E_FIFO_OVERFLOW    = -16, /* RX FIFO overflow in target */
+
+    E_FLASH_UNKNOWN    = -20, /* Flash device unknown */
+    E_FLASH_TIMEOUT    = -21, /* Flash operation timeout */
+    E_FLASH_VERIFY     = -22, /* Flash verify error */
+    E_FLASH_COMMAND    = -23, /* Flash command sequence error */
+    E_FLASH_VPPRANGE   = -24, /* Flash Vpp range error */
+    E_FLASH_LOCKED     = -25, /* Flash block locked error */
+    E_FLASH_ERROR      = -26, /* Flash error (unknown!?) */
+    E_TARGET_TYPE      = -27, /* Target type not detected, unspecified or unknown */
+    E_TARGET_MEMORY    = -28, /* Target out of memory */
+
+    E_PARSER_EOF       = -30, /* Unexpected end of file */
+    E_PARSER_KEYWORD   = -31, /* Syntax error: keyword expected */
+    E_PARSER_STRING    = -32, /* Syntax error: string expected */
+    E_PARSER_NUMBER    = -33, /* Syntax error: number expected */
+    E_PARSER_END_BRACE = -34, /* Syntax error: missing end brace */
+    E_PARSER_SYNTAX    = -35, /* Syntax error */
+    E_PARSER_MEMMAP    = -36, /* Undefined flash memmap */
+    E_PARSER_ALGORITHM = -37, /* Undefined flash algorithm */
+
+    E_BOOTLOADER       = -40, /* Unsupported bootloader */
+
+    E_FILE_OPEN        = -50, /* File open error */
+    E_FILE_CLOSE       = -52, /* File close error */
+    E_FILE_READ        = -53, /* File read error */
+    E_FILE_WRITE       = -54, /* File write error */
+    E_FILE_FORMAT      = -55, /* File format/syntax error */
+    E_FILE_EMPTY       = -56, /* File empty or unreadable? */
+    E_FILE_BUF_SMALL   = -57, /* File buffer too small */
+    E_FILE_INPUT       = -58, /* No input file name supplied */
+    E_FILE_OUTPUT      = -59, /* No output file name supplied */
+
+    E_ADDR_RANGE       = -70, /* Bad address range */
+    E_ERASE_SPEC       = -71, /* Bad erase override specifier */
+    E_READ_SPEC        = -72, /* Bad memory read specifier */
+    E_WRITE_SPEC       = -73, /* Bad memory write specifier */
+
+    E_BADARG           = -80, /* Bad argument or out of range */
+    E_ARG_MULTI        = -81, /* Multiple ambiguous arguments supplied */
+    E_ARG_TOOMANY      = -82, /* Too many arguments supplied */
+
+    E_MEMORY           = -85, /* Out of memory */
+    E_BUFFER           = -86, /* Internal (static) buffer too small */
+
+    E_ROM_SSERVICE     = -90, /* Secure ROM service error */
+
+    E_INTERNAL         = -99, /* Internal program state error */
+
+    E_OS               = -100
+};
+
+
+/******************************************************************************
+ * Typedefs and Prototypes
+ ******************************************************************************/
+
+typedef unsigned char  uint8;
+typedef unsigned short uint16;
+typedef unsigned long  uint32;
+typedef signed char    int8;
+typedef signed short   int16;
+typedef signed long    int32;
+
+void main_warning(int error);
+void main_error(int error);
+void main_fatal(int error);
+void main_msg(char *format, ...);
+
+int flowf(int level, char *format, ...);
+
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+#define ARG_FILE_LIST_SIZE_MAX 8
+
+extern char *arg_file_list[ARG_FILE_LIST_SIZE_MAX];
+extern int  arg_file_list_size;
+
+extern char *arg_erase_override;
+extern char *arg_read;
+extern char *arg_write;
+extern int  arg_checksum;
+extern int  arg_compress;
+extern int  arg_flash_read;
+extern int  arg_dry_run;
+extern int  arg_list_devices;
+extern char arg_target_type;
+extern int  arg_image_map_show;
+extern int  arg_sector_map_show;
+extern int  arg_sector_list_show;
+extern int  arg_timers_show;
+extern int  arg_timers_extended_show;
+extern int  arg_checksum_show;
+extern int  arg_show_hexdump;
+extern int  arg_target_trace_enable;
+extern int  arg_progress;
+extern char arg_hexfile_type;
+extern char arg_hexfile_memwidth;
+
+extern int  arg_target_reset;
+extern int  arg_rom_bootloader;
+extern int  arg_boot_delay_rom;
+extern int  arg_boot_delay_fluid;
+extern int  arg_device_id0;
+extern int  arg_device_id1;
+
+extern int  arg_uart_port;
+extern int  arg_uart_baudrate;
+extern char arg_uart_flowcontrol[2];
+extern char arg_uart_level_convert;
+
+extern char arg_verbose;
+extern int  arg_debug_resume;
+extern int  arg_debug_trace_pe;
+extern int  arg_keep_going;
+
+extern char *argv_0;
+
+extern int  arg_trlevel;
+extern int  arg_trmask;
+extern int  arg_trspaces;
+extern int  arg_skip_erase;
+
+extern int arg_errorfd;
+
+// Secure Calypso Plus
+extern char *arg_die_id_file_name;
+extern char *arg_imeisv;
+extern char *arg_platform_certificate_addr;
+extern int  arg_request_certificate;
+extern int  arg_delay_for_changing_cs5;
+extern int  arg_uart_baudrate_during_cmd_download;
+extern int  arg_uart_timeout_configuration;
+extern int  arg_block_size;
+
+// IMEI protection
+#define C_IMEISV_DIGITS 16
+#define C_IMEISV_BYTES 8
+#define C_PLATFORM_CERT_ADDR_DIGITS 8
+#define C_PLATFORM_CERT_ADDR_BYTES 4
+// End Secure Calypso Plus
+
+enum VERBOSITY_LEVELS {
+    TESTOUTPUT = -2, // Only test output.
+    ALWAYS     = -2,
+    QUIET      = -1, // No messsages at all.
+    NORMAL     =  0, // Overview message level.
+    VERBOSE    =  1, // Detailed messages. Useful for diagnosing problems.
+    BLABBER    =  2, // Very verbose messages. Useful for debugging.
+    DEBUG      =  3  // Very very verbose messages. Useful for debugging.
+};
+
+
+/******************************************************************************
+ * Trace mask bits definition
+ ******************************************************************************/
+
+enum TraceMaskBits {
+    TrMAIN           = 1 << 24,
+
+    TrUtility        = TrMAIN | 0x000002,
+    TrMachines       = TrMAIN | 0x000004,
+
+    TrTargetDrv      = TrMAIN | 0x000010,
+    TrTargetWait     = TrMAIN | 0x000020,
+
+    TrGetChar        = TrMAIN | 0x000100,
+    TrPutChar        = TrMAIN | 0x000200,
+    TrDriverGet      = TrMAIN | 0x000400,
+    TrDriverPut      = TrMAIN | 0x000800,
+
+    TrHexRead        = TrMAIN | 0x001000,
+    TrHexWrite       = TrMAIN | 0x002000,
+    TrArgParser      = TrMAIN | 0x004000,
+    TrCmdLineParser  = TrMAIN | 0x008000,
+
+    TrParser         = TrMAIN | 0x010000
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/getopt.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,674 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+   	Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif	/* GNU C library.  */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#ifndef __STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+static const char *
+_getopt_initialize (optstring)
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0)
+    optstring = _getopt_initialize (optstring);
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+#ifndef NOPRCS
+	  return EOF;
+#endif
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if (nameend - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			     "%s: option `%c%s' doesn't allow an argument\n",
+			     argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+	    else
+	      fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/getopt.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,119 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if	__STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+/* Josh's comment: many GNU developers are ignorant of C++ */
+
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int , char *const *, const char *);
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/lz.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Simple LZ77 compressor (c) Texas Instruments, Jesper Pedersem TI-DK    
+ *
+ * $Id: lz.h 1.4 Thu, 31 Oct 2002 13:12:27 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#ifndef _LZ_H_
+#define _LZ_H_ 1
+
+// Algorithmn efficiency constants
+
+// Don't compress unless we have a > THRESHOLD match
+#define THRESHOLD 2
+
+// Number of bits to use for position, when storing a match
+#define POS_BITS 12
+#define POS_MASK 0x0FFF
+
+// Number of bits to use for length, when storing a match
+#define LEN_BITS 4  
+#define LEN_MASK 0xF000
+
+// Size and size-mask of sliding window
+#define WINDOW_SIZE (1 << POS_BITS)
+#define WINDOW_MASK (WINDOW_SIZE - 1)
+
+// Maximum match length
+#define MAX_MATCH ((1 << LEN_BITS) + THRESHOLD)
+
+// This structure is only being used by lzdecode/decompress().
+struct lz_s {
+    uint8 window[WINDOW_SIZE]; // Sliding window buffer
+    int16 window_pos;          // Current window position
+
+    // Static variables for get_bits()
+    uint32 bitbuf;      // buffer for remaining bits
+    uint8  bitbuf_size; // number of bits in buffer
+
+    // Global input/output buffer pointers and sizes
+    uint8  *buffer_in;
+    uint32 buffer_in_size;
+    uint32 total_in_size;
+    uint8  *buffer_out;
+    uint32 buffer_out_size;
+    uint32 total_out_size;
+};
+
+
+void compress_init(void);
+int compress(char *outbuf, char *inbuf, int size);
+
+void decompress_init(struct lz_s *plz);
+int  decompress(struct lz_s *plz,
+                unsigned char *outbuf, unsigned char *inbuf, int size);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/lzdecode.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ *
+ * Simple LZ77 compressor (c) Texas Instruments, Jesper Pedersem TI-DK    
+ *                                                                        
+ * File format:                                                          
+ * ---------------------------------------------------                   
+ * | Tag |   Data   | Tag |   Data   | Tag |   Data    etc...            
+ * ---------------------------------------------------                   
+ *                                                                        
+ * Where TAG is 1 bit indicating how to interpret the following data
+ * (0 = uncompressed, 1 = compressed)
+ *                                                                        
+ * Depending on TAG the Data is:                                         
+ *   0 : One uncompressed char of raw data                                
+ *   1 : A length of and a pointer to a match in the previous data
+ *
+ *                    ----------------------------------------        
+ * Length + pointer = | Length (3 bits) | Position (12 bits) |        
+ *                    ----------------------------------------        
+ *                     MSB           LSB MSB              LSB         
+ *                                                                        
+ * Compression threshold is 1 i.e. add 1 to Length to get the actual Length.
+ *                                                                        
+ * It has been found that 5+14 bits is the most optimum for our kind of
+ * data, but we use only 3+12 bits for improoved speed.  Compression is
+ * almost as good because we can set the threshold at 1 instead of 2 (2 char
+ * matches can be compressed to 12+3 bits)
+ *                                                                        
+ * With a 12 bit position we can use 4K for the sliding window.  Position
+ * indicates where the match exists as an absolute address into the
+ * window. This way we have a very simple "pseudo sliding window" which
+ * automatically enables RLE (Run Length Encoding).
+ *                                                                        
+ * The code performs a "lazy" string search i.e. a match will be dropped if
+ * it prevents an even greater match for the very next string. This yeild
+ * slightly better compression (approx. 1%) at minor cost of compression
+ * speed - decompression time is the same!  A second order lazy match could
+ * be implemented, but it gives an insignificant improovement of about 0.1%
+ * when compressing executeables
+ *                                                                        
+ ******************************************************************************/
+
+#if (TARGET == 0)
+#include "fluid.h"
+#include <stdlib.h>
+#endif
+
+#include "lz.h"
+
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+
+/******************************************************************************
+ * getchar/putchar
+ ******************************************************************************/
+
+#define EOF -1
+
+#define LZ_PUTCHAR(data) \
+    *plz->buffer_out++ = data; \
+    plz->buffer_out_size++;
+
+
+
+/******************************************************************************
+ * Code
+ ******************************************************************************/
+uint8 get_byte(struct lz_s *plz)
+{
+  plz->buffer_in_size--;
+  return(*plz->buffer_in++);
+}
+
+uint16 get_word(struct lz_s *plz)
+{
+  uint16 tmp;
+
+  tmp =  (*plz->buffer_in++) << 8;
+  tmp |= (*plz->buffer_in++);
+  plz->buffer_in_size -= 2;
+  return(tmp);
+}
+
+
+void decompress_init(struct lz_s *plz)
+{
+    plz->window_pos  = 0;
+    plz->bitbuf      = 0;
+    plz->bitbuf_size = 0;
+}
+
+int decompress(struct lz_s *plz,
+               unsigned char *outbuf, unsigned char *inbuf, int size)
+{
+    int16 match_pos;
+    int16 match_len, i;
+    int8  ch;
+    uint8 tag_byte;
+    uint8 tag_pos;
+    uint16 tmp;
+
+
+    plz->buffer_out      = outbuf;
+    plz->buffer_out_size = 0;
+    plz->buffer_in       = inbuf;
+    plz->buffer_in_size  = size;
+
+    while(plz->buffer_in_size > 0)
+    {
+        tag_byte = get_byte(plz);
+
+        for(tag_pos = 0x80; (plz->buffer_in_size > 0) && (tag_pos > 0x00); tag_pos >>= 0x01)
+        {
+          if(tag_byte & tag_pos) // Compressed?
+          {
+            tmp    = get_word(plz);
+            match_len = (tmp >> POS_BITS) + THRESHOLD + 1;
+            match_pos = (tmp & POS_MASK);
+            for (i = 0; i < match_len; i++) 
+            {
+              plz->window[plz->window_pos] = plz->window[WINDOW_MASK & (match_pos + i)];
+              LZ_PUTCHAR(plz->window[plz->window_pos]);
+              plz->window_pos++;
+              plz->window_pos &= WINDOW_MASK;
+            }
+          }
+          else
+          {
+            ch = get_byte(plz);
+            plz->window[plz->window_pos] = ch;
+            LZ_PUTCHAR(ch);
+            plz->window_pos++;
+            plz->window_pos &= WINDOW_MASK;
+          }
+        }
+    }
+    return plz->buffer_out_size;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/lzencode.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ *
+ * Simple LZ77 compressor (c) Texas Instruments, Jesper Pedersem TI-DK    
+ *                                                                        
+ * File format:                                                          
+ * ---------------------------------------------------                   
+ * | Tag |   Data   | Tag |   Data   | Tag |   Data    etc...            
+ * ---------------------------------------------------                   
+ *                                                                        
+ * Where TAG is 1 bit indicating how to interpret the following data     
+ * (0 = uncompressed, 1 = compressed)
+ *                                                                        
+ * Depending on TAG the Data is:                                         
+ *   0 : One uncompressed char of raw data                                
+ *   1 : A length of and a pointer to a match in the previous data        
+ *
+ *                    ----------------------------------------        
+ * Length + pointer = | Length (3 bits) | Position (12 bits) |        
+ *                    ----------------------------------------        
+ *                     MSB           LSB MSB              LSB         
+ *                                                                        
+ * Compression threshold is 1 i.e. add 1 to Length to get the actual Length.
+ *                                                                        
+ * It has been found that 5+14 bits is the most optimum for our kind of
+ * data, but we use only 3+12 bits for improoved speed.  Compression is
+ * almost as good because we can set the threshold at 1 instead of 2 (2 char
+ * matches can be compressed to 12+3 bits)
+ *
+ * With a 12 bit position we can use 4K for the sliding window.  Position
+ * indicates where the match exists as an absolute address into the
+ * window. This way we have a very simple "pseudo sliding window" which
+ * automatically enables RLE (Run Length Encoding).
+ *                                                                        
+ * The code performs a "lazy" string search i.e. a match will be dropped if
+ * it prevents an even greater match for the very next string. This yeild
+ * slightly better compression (approx. 1%) at minor cost of compression
+ * speed - decompression time is the same!  A second order lazy match could
+ * be implemented, but it gives an insignificant improovement of about 0.1%
+ * when compressing executeables
+ *                                                                        
+ * Searching in the window is done with help from an index and we maintain
+ * the window as a single linked list to further speed up the compression.
+ *                                                                        
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "lz.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/******************************************************************************
+ *
+ ******************************************************************************/
+
+#define NIL -1 // Used for indexing purposes
+
+// When we find a match put it into a struct like this.
+typedef struct {
+    int16 pos;
+    int8  len;
+} match_def_t;
+
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+static uint8 window[WINDOW_SIZE]; // Our sliding window buffer
+static int16 window_pos;          // And the current position in it
+static uint8 lookahead;          // number of bytes in the lookahead area
+
+// Global input/output buffer pointers
+static uint8  *buffer_out;
+static uint8  *buffer_in;
+static uint32 buffer_out_size;
+static uint32 buffer_in_size;
+
+static uint32 total_in_size = 0;
+static uint32 total_out_size = 0;
+
+static uint8  *p_tag_byte = 0;
+static uint8  tag_pos = 0;
+
+static int16 lookup[256]; // Table for looking up a link to any given character
+static int16 lookup_end[256]; // The last link in the window.
+static int16 next[WINDOW_SIZE]; // Contain links to next similar chars
+
+
+
+/******************************************************************************
+ * getchar/putchar
+ ******************************************************************************/
+
+static int lze_getchar(void)
+{
+    total_in_size++;
+
+    if (buffer_in_size-- > 0)
+        return *buffer_in++;
+
+    buffer_in_size++;
+
+    return EOF;
+}
+
+static int lze_putchar(unsigned char data)
+{
+    total_out_size++;
+
+    *buffer_out++ = data;
+    buffer_out_size++;
+
+    return 0;
+}
+
+static int lze_putword(uint16 data)
+{
+    total_out_size += 2;
+
+    *buffer_out++ = (uint8)((data >> 8) & 0x00FF);
+    *buffer_out++ = (uint8)(data  & 0x00FF);
+    buffer_out_size += 2;
+
+    return 0;
+}
+
+/******************************************************************************
+ * Code
+ ******************************************************************************/
+
+
+// Searches for the best possible match to the string at 'source_pos' within
+// the window. Lazy searches is made faster by specifying a match to beat
+// 'match_len' so we don't vaste time by testing too small matches. Will
+// stop at any match 'max_len' in size.
+match_def_t find_best_match(int16 source_pos, int16 match_len, int16 max_len)
+{
+    match_def_t current, best;
+    int16 start_pos;
+
+    best.len = match_len;
+
+    if ((start_pos = lookup[window[source_pos]]) != NIL) // Get the first entry
+    {
+        current.pos = start_pos;
+        do
+        {
+            if (window[WINDOW_MASK & (current.pos + best.len)] ==
+                window[WINDOW_MASK & (source_pos + best.len)]) // Possible match?
+            {
+                current.len = 1;
+
+                while((window[WINDOW_MASK & (current.pos + current.len)] ==
+                       window[WINDOW_MASK & (source_pos + current.len)]) &&
+                      current.len < max_len)
+                    current.len++;
+                if (current.len > best.len)
+                    best = current;
+            }
+            if (best.len >= max_len)
+                break; // no need to search for better matches when we have the best
+
+            current.pos = next[current.pos]; // jump to next matching char
+        } while(current.pos != NIL); // All. possibilities tested?
+    }
+    if (best.len <= match_len)
+        best.len = 0;
+    return best;
+}
+
+// Will remove 'count' links from 'begin' to make room for new data. Will be
+// called when we need to overwrite some of the window by new lookahead
+// chars.
+void clear_index_positions(uint16 begin, uint16 count)
+{
+    uint16 i, pos;
+
+    for (i = 0; i < count; i++)
+    {
+        pos = WINDOW_MASK & (begin +i );
+
+        if (lookup[window[pos]] == pos) {
+            if (lookup_end[window[pos]] == pos)
+                lookup[window[pos]] = lookup_end[window[pos]] = NIL;
+            else
+                lookup[window[pos]] = next[pos];
+        }
+    }
+}
+
+
+// Generate indexes for a string, so the match routines can find the
+// characters in it very fast! We need to clean up obsolete indexes after
+// this routine has been called
+void index_string(int16 source_pos, int16 source_len)
+{
+    int16 i, j;
+    uint8 c;
+
+    for (i=0; i<source_len; i++)
+    {
+        j = WINDOW_MASK & (source_pos + i);
+        c = window[j];
+
+        next[j] = NIL;
+        if (lookup[c] == NIL) // first time we encounter this char?
+            lookup[c] = j; // generate index for this new char
+        else
+            next[lookup_end[c]] = j;
+        lookup_end[c] = j;
+    }
+}
+
+
+void update_tag_byte(uint8 compressed)
+{
+  if(tag_pos == 0x00)
+  {
+    p_tag_byte = buffer_out++; // Grap a byte in the output stream
+    buffer_out_size++;
+    
+    compressed ? (*p_tag_byte = 0x80) : (*p_tag_byte = 0x00); 
+    tag_pos = 0x40;
+  }
+  else
+  {
+    if(compressed)
+      *p_tag_byte |= tag_pos;
+
+    tag_pos >>= 0x01;
+  }
+}
+
+
+
+// Puts an uncompressed char into the file and update the window
+// position. We cannot just putc(data) because the offset might be any
+// number of bits off.
+void save_raw(uint8 data)
+{
+    update_tag_byte(0);
+    lze_putchar(data);
+
+    index_string(window_pos, 1);
+    window_pos = WINDOW_MASK & (window_pos + 1);
+    lookahead--;
+}
+
+// Puts a compressed match (length and position) into the file and update
+// the window position.
+void save_compressed(uint8 len, uint16 pos)
+{
+    uint16 tmp = 0x0000;
+
+    update_tag_byte(1);
+    
+    tmp =  ((uint8)(len - (THRESHOLD + 1))) << POS_BITS;
+    tmp |= ((uint16)(pos & POS_MASK));
+
+    lze_putword(tmp);
+
+    index_string(window_pos, len);
+    window_pos = WINDOW_MASK & (window_pos + len);
+    lookahead -= len;
+}
+
+void compress_init(void)
+{
+    int i;
+
+    // Initialize - whole window is unindexed at beginning
+    for (i = 0; i < 256; i++)
+        lookup[i] = lookup_end[i] = NIL;
+    for (i = 0; i < WINDOW_SIZE; i++)
+        next[i] = window[i] =  NIL;
+    
+    buffer_out_size = 0;
+    window_pos = 0;
+}
+
+int compress(char *outbuf, char *inbuf, int size)
+{
+    int ch, eof;
+    match_def_t match, lazy_match;
+
+    buffer_out      = outbuf;
+    buffer_out_size = 0;
+    buffer_in       = inbuf;
+    buffer_in_size  = size;
+    if (size <= 0)
+        return 0;
+
+    p_tag_byte = NULL;
+    tag_pos    = 0x00;  
+
+    do
+    {
+        clear_index_positions(WINDOW_MASK & (window_pos + lookahead), MAX_MATCH);
+
+        // (re-)fill the lookahead buffer from the bit-stream
+        while (lookahead < MAX_MATCH) {
+            eof = ((ch = lze_getchar()) == EOF);
+            window[WINDOW_MASK & (window_pos + lookahead++)] = (uint8) ch;
+            if (eof) {
+                window[WINDOW_MASK & (window_pos + --lookahead)] = 0;
+                break;
+            }
+        }
+        // End of compression?
+        if (lookahead == 0)
+            break;
+
+        // Search for a match so we can compress the data
+        match = find_best_match(window_pos, THRESHOLD, lookahead);
+
+        if (match.len > THRESHOLD) {
+
+            lazy_match.len = 0;
+
+            // check if the lazy match is better
+            if (match.len < lookahead - 1) {
+                lazy_match = find_best_match(WINDOW_MASK & (window_pos + 1),
+                                             match.len, lookahead-1);
+            }
+            if (lazy_match.len > match.len) {
+                // skip the current and use the lazy
+                save_raw(window[window_pos]);
+                save_compressed(lazy_match.len, lazy_match.pos);
+            }
+            else {
+                save_compressed(match.len, match.pos);
+            }
+        }
+        else {
+            // Compression failed - just stuff the raw data
+            save_raw(window[window_pos]);
+        }
+
+    } while (!eof || lookahead > 0);
+
+//    put_bits(-1, 0); // No more data, so flush the buffer and exit
+
+    return buffer_out_size;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/machine.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,2635 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ * Original state-machine logic by Delta Technologies, Copyright, 2001.
+ *
+ * Core functionality. State machines and support functions.
+ *
+ * $Id: machine.c 1.35.1.37 Mon, 28 Apr 2003 08:49:16 +0200 tsj $
+ *
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "flash.h"
+#include "target.h"
+#include "fileio.h"
+#include "../target/protocol.h"
+#include "misc.h"
+#include "lz.h"
+#include "trace.h"
+// Secure Calypso Plus
+#include "../inc/ram_load.h"
+#include "../inc/secure_types.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+/******************************************************************************
+ * Constants and typedefs
+ ******************************************************************************/
+
+// Due to memory wrap/mirror used in flash_read_machine(), IMAGE_SIZE_MAX
+// *must* be a power of two.
+#define IMAGE_SIZE_MAX (8 * 1024 * 1024)
+
+#define IMAGE_CHUNK_SIZE 8192
+
+#define ERASE_LIST_SIZE_MAX 256
+#define SECTOR_MAP_SIZE_MAX 256
+
+#define TARGET_PROGRAM_SIZE_MAX (8 * 1024)
+
+#define READ_LIST_SIZE_MAX 40
+
+#define RETRIES_MAX 30
+
+// Default target receive delay in milli-seconds.
+#define TARGET_RECV_DELAY 250
+#define TARGET_RECV_LONG_DELAY 1000
+
+// Default target reset delay in milli-seconds.
+#define TARGET_RESET_DELAY 200
+
+// CS_MODE 0: Flash at 0x04000000 @ CS5 on E-Sample
+#define CALP_OFFSET 0x04000000
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+// Secure Calypso Plus
+T_RAM_LOADER d_ram_loader;
+T_FRAME      d_frame;
+UWORD16      d_certificate_length = 0;
+char         a_certified_cmd_file_name[] = "cmdp_cert.m0";
+
+struct target_s {
+    uint32 cmd_load_addr;
+    uint32 method_load_addr;
+    const char type;
+    const char *name;
+    const char *prefix;
+};
+// Note that the ROM bootloader of Calypso rev. A devices are unable to
+// write the bottom 128kB of internal RAM. Therefore the address have been
+// changed from 0x804000 to 0x0820000
+const struct target_s target[] =
+{
+    { 0x0000000, 0x0000000, 'u', "Unknown",  "oops"  },
+    { 0x0000000, 0x0000000, 'u', "Unknown1", "oops1" },
+    { 0x0000000, 0x0000000, 'G', "Gemini?",  "gem?"  },
+    { 0x3004000, 0x3000000, 'U', "Ulysses",  "uly"   },
+    { 0x0820000, 0x0800000, 'C', "Calypso",      "cal"   },
+    { 0x0804000, 0x0800000, 'c', "Calypso Lite", "cal_l" },
+    { 0x8020000, 0x8000100, 'P', "Calypso Plus", "cal_p" }
+};
+int target_type;
+int target_clk; // 13000000 or 14745600
+
+struct device_s *device;
+
+uint8 target_program[TARGET_PROGRAM_SIZE_MAX];
+int   target_program_size;
+int   target_fifo_size;
+
+uint8 image[IMAGE_SIZE_MAX];
+int   image_size;           // size of image buffer
+int   image_chunk_size;     // number of bytes in each chunk
+int   image_size_in_chunks; // size of image buffer in chunks
+
+// Each byte in the image_map represents one chunk of the image. Each byte
+// can have one of the following values:
+// '\0' = no data in this chunk
+//  's' = skip this chunk when programming
+//  'c' = chunk checksum ok, skip this chunk when programming
+//  'x' = used
+uint8 image_map[IMAGE_SIZE_MAX / IMAGE_CHUNK_SIZE];
+int   image_map_size;       // number of entries in image_map
+
+// Each byte in the sector_map represents one sector. Each byte can have one
+// of the following values:
+// '\0' = sector unused (don't erase)
+//  'c' = sector already empty/erased (don't erase) (not used)
+//  's' = skip this sector when erasing (due to erase override)
+//  'X' = force erase this sector (due to erase override)
+//  'x' = erase this sector (normal case --- sector is covered by image)
+int sector_map[SECTOR_MAP_SIZE_MAX];
+int sector_map_size;
+
+int erase_list[ERASE_LIST_SIZE_MAX];
+int erase_list_size;
+
+struct image_part_s read_list[READ_LIST_SIZE_MAX];
+int read_list_size;
+int read_total_size;
+
+int image_map_count_used_chunks(void);
+int image_map_update(void);
+int sector_map_init(void);
+
+void image_map_show(void);
+void sector_map_show(void);
+void target_timers_show(void);
+
+void parse_arg_erase_override(char *p);
+void parse_arg_read(char *p);
+void parse_arg_write(char *p);
+
+void error_proto(char ch, char ch_expected);
+
+int target_type_set(uint16 code);
+
+// Secure Calypso Plus
+void f_print_signalling_response(int level);
+void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate);
+void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate);
+void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts);
+void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts);
+UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate);
+void target_imei_protection(void);
+
+/******************************************************************************
+ * Main
+ ******************************************************************************/
+
+void bootloader_machine(void);
+void cmd_machine(void);
+void flash_checksum_machine(void);
+void flash_detect_machine(void);
+void method_download_machine(void);
+void flash_program_machine(void);
+void flash_read_machine(void);
+void target_reset_machine(void);
+
+void fluid_machine(void)
+{
+    int error;
+
+    // If user has specifically asked fluid just to reset the target, we do
+    // that and only that! This way, we can use fluid just to reset the
+    // target without doing anything else!
+    if (arg_target_reset == 2 && arg_dry_run) {
+        flowf(VERBOSE, "Resetting target: ");
+        target_reset(0);
+        target_wait(0, TARGET_RESET_DELAY);
+        target_reset(1);
+        flowf(VERBOSE, "ok\n");
+    }
+
+    file_read_devices("devices.txt");
+
+    if (arg_list_devices) {
+        devices_list();
+        exit(0);
+    }
+
+    image_size = IMAGE_SIZE_MAX;
+    image_chunk_size = IMAGE_CHUNK_SIZE;
+    image_map_size = IMAGE_SIZE_MAX / image_chunk_size;
+    image_size_in_chunks =
+        (image_size + image_chunk_size - 1) / image_chunk_size;
+
+    // Read the flash image file(s) unless user wants to read from the flash
+    if (*arg_read == 0) {
+        file_read_image(image, IMAGE_SIZE_MAX, image_map, image_chunk_size);
+
+        // Optionally overwrite image with values given on the command-line
+        parse_arg_write(arg_write);
+
+        if (arg_image_map_show)
+            image_map_show();
+    }
+
+    if ((error = target_driver_init(arg_uart_port, 115200,
+                                    arg_uart_flowcontrol)) < 0)
+        main_fatal(error);
+
+    if (target_type_set(arg_target_type) != 0)
+        flowf(VERBOSE, "Target type '%s' selected.\n", target[target_type].name);
+
+    // Conditionally disable tracing
+    if (arg_debug_trace_pe)
+        tr_enable(0);
+
+    if (arg_debug_resume) {
+        // If resuming in command interpreter, we should set the baudrate
+        // because we do not pass through the code that normally sets it.
+        if ((error = target_driver_baudrate(arg_uart_baudrate)) < 0)
+            main_fatal(error);
+    }
+    else {
+        bootloader_machine();
+        cmd_machine();
+    }
+    if (*arg_read != 0) {
+        parse_arg_read(arg_read);
+        flash_read_machine();
+        file_write_image(image, image_size, read_list);
+    }
+    else {
+        if (arg_checksum)
+            flash_checksum_machine();
+        flash_detect_machine();
+        if (!arg_debug_resume) {
+            method_download_machine();
+        }
+        tr_enable(1); // Ensure full tracing is on
+        flash_program_machine();
+        if (*arg_imeisv && *arg_platform_certificate_addr)
+            target_imei_protection();
+        if (arg_timers_show)
+            target_timers_show();
+        if (arg_target_reset == 1)
+            target_reset_machine();
+    }
+}
+
+
+/******************************************************************************
+ * Bootloader (TI Target Monitor) Access
+ ******************************************************************************/
+
+// Invoke the Fluid bootloader embedded in the TI bootloader/target-monitor
+// code. The command to enter the loader is 0xAA 0x01 0xDD, which must be
+// received by the phone within 50ms from reset.
+
+int bootloader_is_rom;
+int bootloader_is_secure_rom;   // Secure Calypso Plus
+int bootloader_blocksize_max;
+
+void bootloader_fluid_init(void);
+void bootloader_rom_init(void);
+void bootloader_secure_rom_init(void);   // Secure Calypso Plus
+
+void bootloader_machine(void)
+{
+    // FIXME: why do we have to send an additional char (0) ?
+    uint8 sendbuf_rom[3] = { '<', 'i', 0x0 };
+    uint8 sendbuf_fluid[3] = { 0xAA, 0x01, 0xDD };
+    int i, error;
+    char ch1, ch2;
+    // Secure Calypso Plus
+    UWORD16 d_j;
+
+    target_trace_enable(0);
+
+    flowf(NORMAL, "Bootloader: ");
+
+    // Wait a short while with power removed, then flush receive buffer.
+    target_power(1);
+    target_reset(0);
+    target_wait(0, TARGET_RESET_DELAY);
+    target_reset(1);
+    target_recv_reset();
+
+    // Continuously send Fluid Bootloader escape sequence until we get an
+    // acknowledgement. Note that we have to establish contact within 50ms
+    // from reset, otherwise we lose our chance! Note that we actually wait
+    // up to 500ms because the target may take some time to reset.
+    i = 0;
+    flowf(DEBUG, "(ROM/fluid-delay = %d/%d, ",
+          arg_boot_delay_rom, arg_boot_delay_fluid);
+
+    switch (arg_rom_bootloader) {
+    case -1:
+        if ((error = target_driver_baudrate(115200)) < 0)
+            main_fatal(error);
+        break;
+    case +1:
+        if ((error = target_driver_baudrate(19200)) < 0)
+            main_fatal(error);
+        break;
+    }
+    while (1)
+    {
+        target_recv_reset();
+
+        // If we are allowed to try fluid bootloader...
+        if (arg_rom_bootloader != +1) {
+            // If we should ONLY try fluid bootloader...
+            flowf(DEBUG, "F");
+            if (arg_rom_bootloader == 0)
+                if ((error = target_driver_baudrate(115200)) < 0)
+                    main_fatal(error);
+            target_send(sendbuf_fluid, 3);
+            if (target_wait(1, arg_boot_delay_fluid) > 0 &&
+                target_getchar() == PROTO_HELLO) {
+                bootloader_is_rom = 0;
+                bootloader_is_secure_rom = 0;   // Secure Calypso Plus
+                break;
+            }
+        }
+        // If we are allowed to try ROM bootloader...
+        if (arg_rom_bootloader != -1) {
+            flowf(DEBUG, "R");
+            if (arg_rom_bootloader == 0)
+                if ((error = target_driver_baudrate(19200)) < 0)
+                    main_fatal(error);
+            target_send(sendbuf_rom, 3);
+
+            if (target_wait(1, arg_boot_delay_rom) >= 1) {
+                ch1 = target_getchar();
+                if (ch1 == '>') {
+                    if (target_wait(1, arg_boot_delay_rom) >= 1) {
+                        ch2 = target_getchar();
+                        if (ch2 == 'i') {
+                            bootloader_is_rom = 1;
+
+                            // Secure Calypso Plus
+                            if (target_wait(2, arg_boot_delay_rom) < 2)
+                                flowf(DEBUG, ", Non-secure boot ROM code");
+                            else {
+                                flowf(DEBUG, ", Secure Calypso Plus ROM)");
+                                ch1 = target_getchar();
+                                ch2 = target_getchar();
+                                d_ram_loader.d_romcode_version = (UWORD16)(ch1) & 0xFF;
+                                d_ram_loader.d_romcode_version |= ((UWORD16)(ch2 & 0xFF)) << 8;
+                                //d_ram_loader.d_romcode_version |= (((UWORD16)ch2) << 8) & 0xFF00;
+
+                                if (d_ram_loader.d_romcode_version == 0x0410 || d_ram_loader.d_romcode_version == 0x0411) {
+                                    bootloader_is_secure_rom = 1;
+
+                                    if (target_wait((C_WORD32LGB * C_MD5HASHLG), TARGET_RECV_DELAY) < (C_WORD32LGB * C_MD5HASHLG))
+                                        main_fatal(E_RECV_TIMEOUT);
+
+                                    for (d_j = 0 ; d_j < (C_WORD32LGB * C_MD5HASHLG) ; d_j++)
+                                        d_ram_loader.a_hash_man_pub_key[d_j] = target_getchar();
+
+                                    if (target_wait((C_WORD32LGB * C_DIE_ID_SIZE), TARGET_RECV_DELAY) < (C_WORD32LGB * C_DIE_ID_SIZE))
+                                        main_fatal(E_RECV_TIMEOUT);
+
+                                    for (d_j = 0 ; d_j < (C_WORD32LGB * C_DIE_ID_SIZE) ; d_j++)
+                                        d_ram_loader.a_die_id[d_j] = target_getchar();
+
+                                    // SIGNALLING RESPONSE
+                                    f_print_signalling_response(VERBOSE);
+
+                                    if (*arg_die_id_file_name != 0) {
+                                        if ((error = file_write_die_id(&d_ram_loader.a_die_id[0], arg_die_id_file_name)) < 0) {
+                                            flowf(NORMAL, "\n");
+                                            main_fatal(error);
+                                        }
+
+                                        flowf(NORMAL, "\nDie id retrieved and written to %s.\n", arg_die_id_file_name);
+                                        exit(0);
+                                    }
+                                }
+                                else {
+                                    flowf(NORMAL, "\nSecure Calypso Plus ROM Code Version 0x%4.4x is not supported by FLUID.\n", d_ram_loader.d_romcode_version);
+                                    main_fatal(E_BOOTLOADER);
+                                }
+                            }
+                            // End Secure Calypso Plus
+
+                            break;
+                        }
+                        else
+                            flowf(DEBUG, "?");
+                    }
+                }
+            }
+        }
+        // If target is still not responding, we could not control the reset
+        // line, so we ask the user to reset the target
+        if (i++ == RETRIES_MAX)
+            flowf (NORMAL, "(reset target) ");
+    }
+    if (!bootloader_is_secure_rom)
+        flowf(DEBUG, ") ");
+
+    // Read the command interpreter image file.
+    if (bootloader_is_secure_rom)
+        target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, a_certified_cmd_file_name);
+    else
+        target_program_size = file_read_cmd(target_program, TARGET_PROGRAM_SIZE_MAX, "cmd.m0");
+
+    if (target_program_size == 0)
+        main_error(E_FILE_EMPTY);
+
+    if (bootloader_is_secure_rom)
+        bootloader_secure_rom_init();
+    else if (bootloader_is_rom)
+        bootloader_rom_init();
+    else
+        bootloader_fluid_init();
+
+    flowf(NORMAL, ") ok\n");
+}
+
+void bootloader_fluid_init(void)
+{
+    int divider;
+    char version;
+    uint8 data[4];
+    uint16 chip_id_code;
+
+    flowf(NORMAL, "(fluid");
+
+    target_clk = 13000000;
+
+    // Now send baudrate to make the target stop sending 'H'ello.
+    divider = target_uart_baudrate_divider_get(target_clk, 115200);
+    flowf(DEBUG, ", baudrate = ");
+    target_putchar(0);
+    target_putchar((char) divider);
+    flowf(DEBUG, "%d, ", 115200);
+
+    // Wait a short while before flushing receive buffer. Then make sure
+    // that the target is indeed silent
+    target_wait(0, 10);
+    target_recv_reset();
+    if (target_wait(1, 50) > 0)
+        main_fatal(E_RECV_ANTITIMEOUT);
+
+    // NOTEME: The sequence below to query the Bootloader VERSION *has* to
+    // have 100ms + 100ms delays. It seems as unnecessarily large delays but
+    // practice shows that they cannot be shorter. To be investigated...
+
+    // Get version of bootloader
+    target_putchar(PROTO_VERSION);
+    if (target_wait(1, TARGET_RECV_DELAY) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+    version = target_getchar();
+    flowf(NORMAL, ", version %c", version);
+
+    // Bootloader revision 3 and upwards supports generic query
+    if (version < '3') {
+        main_fatal(E_BOOTLOADER);
+    }
+
+    target_trace_enable(1);
+    target_putchar(PROTO_QUERY);
+    target_putchar(PROTO_QUERY_CHIP);
+    if (target_wait(4, TARGET_RECV_DELAY) < 4)
+        main_fatal(E_RECV_TIMEOUT);
+    target_recv(data, 4);
+    chip_id_code = data[0] + (data[1] << 8);
+    if (target_type_set(chip_id_code) == 0 || arg_verbose >= VERBOSE) {
+        flowf(VERBOSE, ", chipid = 0x%04X", chip_id_code);
+        if (target_type_set(chip_id_code) == 0)
+            main_fatal(E_TARGET_TYPE);
+    }
+    flowf(VERBOSE, ", %s", target[target_type].name);
+}
+
+void bootloader_rom_init(void)
+{
+    int error;
+    char ch, version = '?';
+
+    // Initialization: 115200 bps, 39 MHz DPLL, no timeout
+    uint8 sendbuf[11] = { '<',  'p',  0x00, 0x0D, 0x14, 0x25,
+                           0x22, 0x00, 0x00, 0x00, 0x00};
+    // Initialization: 115200 bps, 13 MHz DPLL, no timeout.
+    //uint8 sendbuf[11] = { '<',  'p',  0x00, 0x00, 0x1C, 0xE7,
+    //                    0x22, 0x00, 0x00, 0x00, 0x00 };
+
+    flowf(NORMAL, "(ROM");
+
+    // Configure/init the ROM bootloader
+    flowf(VERBOSE, ", baudrate = %d", 115200);
+    target_send(sendbuf, 11);
+
+    // Wait until DPLL is settled and target responds
+    if (target_wait(4, 300) < 4)
+        main_fatal(E_RECV_TIMEOUT);
+    if ((ch = target_getchar ()) != '>')
+        error_proto(ch, '>');
+    if ((ch = target_getchar ()) != 'p')
+        error_proto(ch, 'p');
+
+    // Receive maximum blocksize
+    bootloader_blocksize_max  = target_getchar();
+    bootloader_blocksize_max += target_getchar() << 8;
+    bootloader_blocksize_max -= 10; // Subtract the block header
+    flowf(DEBUG, ", blocksize = %iB", bootloader_blocksize_max);
+
+    if ((error = target_driver_baudrate (115200)) < 0)
+        main_fatal(error);
+
+    flowf(NORMAL, ", version %c", version);
+
+    // NOTEME: Can we be sure that it is always a Calypso type?
+    target_type_set('c');
+}
+
+// Secure Calypso Plus
+void bootloader_secure_rom_init(void)
+{
+    int error;
+    UWORD8 d_char;
+    UWORD16 d_j;
+
+    // cmdp_cert.m0 has been 16 bit aligned using hex470, so the memory width
+    // parameter is set to 2 bytes.
+    buffer_endian_convert(target_program, target_program_size, 2);
+
+    // Check if firmware manufacturer certificate stored in flash is requested
+    if (arg_request_certificate) {
+        // Clear the request
+        arg_request_certificate = 0;
+        d_ram_loader.b_certificate_request = C_FALSE;
+
+        // Certificate Request
+        d_frame.a_data[0] = '<';
+        d_frame.a_data[1] = 'c';
+        d_frame.d_max_byte = 2;
+
+        target_send(&d_frame.a_data[0], d_frame.d_max_byte);
+
+        // Certificate Response
+        target_expect_char('>', arg_boot_delay_rom);
+        target_expect_char('c', arg_boot_delay_rom);
+
+        if (target_wait(2, TARGET_RECV_DELAY) < 2)
+            main_fatal(E_RECV_TIMEOUT);
+
+        d_ram_loader.u_firm_cert.a_firm_cert[0] = target_getchar ();
+        d_ram_loader.u_firm_cert.a_firm_cert[1] = target_getchar ();
+
+        d_certificate_length = (UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[0]) & 0xFF;
+        d_certificate_length |= ((UWORD16)(d_ram_loader.u_firm_cert.a_firm_cert[1]) << 8) & 0xFF00;
+
+        // We have already read two bytes of the certificate for the CERT_SIZE
+        // and the certificate signature is handled later.
+        for (d_j = 2 ; d_j < d_certificate_length - (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) {
+            if (target_wait(1, arg_boot_delay_rom * 4) > 0)
+                d_ram_loader.u_firm_cert.a_firm_cert[d_j] = target_getchar ();
+            else
+                main_fatal(E_RECV_TIMEOUT);
+        }
+
+        for (d_j = 0; d_j < (C_WORD32LGB * C_MANUF_SIG_SIZE); d_j++) {
+            if (target_wait(1, arg_boot_delay_rom * 4) > 0)
+                d_ram_loader.a_Certsig[d_j] = target_getchar ();
+            else
+                main_fatal(E_RECV_TIMEOUT);
+
+            d_ram_loader.u_firm_cert.a_firm_cert[d_j + sizeof(T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA) - (C_WORD32LGB * C_MANUF_SIG_SIZE)] = d_ram_loader.a_Certsig[d_j];
+        }
+
+        f_print_certificate_platform_data(NORMAL, &d_ram_loader.u_firm_cert.d_firm_cert);
+    }
+
+    // Parameter Request
+    d_ram_loader.d_baud_rate = f_convert_uart_baud_rate(arg_uart_baudrate_during_cmd_download);
+    d_ram_loader.d_uart_timeout = arg_uart_timeout_configuration;   // TODO: Verify that MSB byte is sent in first position.
+
+    d_frame.a_data[0] = '<';
+    d_frame.a_data[1] = 'p';
+    d_frame.a_data[2] = d_ram_loader.d_baud_rate;
+    memcpy(&d_frame.a_data[3], &d_ram_loader.d_uart_timeout, sizeof(UWORD32));
+
+    d_frame.d_max_byte = 3 + sizeof(UWORD32);
+
+    d_certificate_length = (UWORD16)(target_program[0]) & 0xFF;
+    d_certificate_length |= ((UWORD16)(target_program[1]) & 0xFF) << 8;
+
+    for (d_j = 0 ; d_j < d_certificate_length; d_j++)
+        d_ram_loader.u_code_certificate.a_code_certificate[d_j] = target_program[d_j];
+
+    f_print_certificate(DEBUG, &d_ram_loader.u_code_certificate.d_code_certificate);
+
+    // Send the data
+    target_send(&d_frame.a_data[0], d_frame.d_max_byte);
+    target_send(&target_program[0], d_certificate_length);
+
+    // Parameter Response
+    if (target_wait(2, TARGET_RECV_DELAY) < 2)
+        main_fatal(E_RECV_TIMEOUT);
+
+    if ((d_char = target_getchar ()) != '>')
+        error_proto(d_char, '>');
+
+    if ((d_char = target_getchar ()) != 'p') {
+        if (d_char == 'P') {
+            // PARAMETER_NACK_RESPONSE
+            if (target_wait(1, arg_boot_delay_rom) >= 1) {
+                d_ram_loader.d_param_req_sts = target_getchar();
+                f_print_parameter_nack_status(NORMAL, d_ram_loader.d_param_req_sts);
+            }
+        }
+        error_proto(d_char, 'p');
+    }
+
+    // PARAMETER_ACK_RESPONSE
+
+    flowf(NORMAL, "\n(Secure ROM");
+
+    if ((error = target_driver_baudrate (arg_uart_baudrate_during_cmd_download)) < 0)
+        main_fatal(error);
+
+    // Configure/init the ROM bootloader
+    flowf(VERBOSE, ", UART baud rate during download of flash programmer, %s = %d Kbps", a_certified_cmd_file_name, arg_uart_baudrate_during_cmd_download);
+}
+// End Secure Calypso Plus
+
+/******************************************************************************
+ * Command Interpreter Download
+ ******************************************************************************/
+
+int cmd_baudrate(int baudrate);
+void cmd_machine_fluid(void);
+void cmd_machine_rom(void);
+void cmd_machine_secure_rom(void);   // Secure Calypso Plus
+
+void cmd_machine(void)
+{
+    char ramcs0, ch;
+    uint8 count = 0;
+    uint16 chip_id;
+
+    flowf(VERBOSE, "Command Interpreter: (");
+
+    target_trace_enable(0);
+
+    // Secure Calypso Plus
+    if (bootloader_is_secure_rom)
+        cmd_machine_secure_rom();
+    else if (bootloader_is_rom)
+        cmd_machine_rom();
+    else
+        cmd_machine_fluid();
+
+    // Now send 'H'ello command to target and get the response, such as
+    // hardware type etc.
+    while (count < RETRIES_MAX) {
+        target_putchar(PROTO_HELLO);
+        if (target_wait(1, TARGET_RECV_DELAY) >= 1) {
+            ch = target_getchar();
+            flowf(DEBUG, ", received %c (0x%2.2x)", ch, ch);
+            if (ch == PROTO_READY)
+                break;
+        }
+        count++;
+    }
+
+    if (count == RETRIES_MAX)
+        main_fatal(E_RECV_TIMEOUT);
+
+    if (target_wait(5, TARGET_RECV_DELAY) < 4)
+        main_fatal(E_RECV_TIMEOUT);
+
+    chip_id  = (target_getchar() & 0xFF);
+    chip_id |= (target_getchar() & 0xFF) << 8;
+    ramcs0   = (target_getchar() == 'R');
+    ch       = target_getchar();
+    flowf(BLABBER, ", SRAM = %dk", (1 << ch) / 1024);
+    target_fifo_size = target_getchar();
+    flowf(DEBUG, ", fifo = %d", target_fifo_size);
+
+    if (target_type_set(chip_id) == 0 || arg_verbose >= VERBOSE) {
+        flowf(BLABBER, ", ");
+        flowf(VERBOSE, "chipid = 0x%04X", chip_id);
+        if (target_type_set(chip_id) == 0)
+            main_fatal(E_TARGET_TYPE);
+    }
+    flowf(VERBOSE, ", %s", target[target_type].name);
+
+    if (ramcs0)
+        flowf(VERBOSE, ", RAM");
+
+    // Configure target
+    target_putchar(PROTO_INIT);
+    target_putchar(target[target_type].type);
+    target_expect_char(PROTO_READY, TARGET_RECV_DELAY);
+
+    // Change baudrate. First try to change to new baudrate. If this fails,
+    // try 115.2 Kbps. If this also fails, panic and bail out.
+    if (arg_uart_baudrate != 115200) {
+        flowf(VERBOSE, ", baudrate = ");
+        flowf(VERBOSE, "%d", arg_uart_baudrate);
+        if (!cmd_baudrate(arg_uart_baudrate)) {
+            arg_uart_baudrate = 115200;
+            flowf(VERBOSE, " %d", arg_uart_baudrate);
+            if (!cmd_baudrate(arg_uart_baudrate))
+                main_fatal(E_RECV_TIMEOUT);
+        }
+    }
+    flowf(VERBOSE, ") ");
+    flowf(VERBOSE, "ok\n");
+
+    // Secure Calypso Plus
+
+    // There is a bug in ROM code 0x0410 which means that the secure boot
+    // loader cannot boot if the firmware certificate size is greater than the
+    // max size of 0xFFF8. A workaround is to change the memory mapping on CS5
+    // by initially setting DIP switches 9 and 10 to ON and thereby exchanging
+    // the mapping of RAM and flash. While waiting, set the DIP switches back
+    // to OFF. See SECURITY.txt and BUG03314 in CALPLUS228.
+    if (arg_delay_for_changing_cs5 != 0) {
+        flowf(NORMAL, "\nWaiting %d seconds for changing memory mapping on CS5 or connecting via JTAG...\n", arg_delay_for_changing_cs5);
+        target_wait(0, arg_delay_for_changing_cs5 * 1000);
+    }
+}
+
+int cmd_baudrate(int baudrate)
+{
+    int error;
+    int divider;
+    char xxo;
+
+    target_putchar(PROTO_BAUDRATE);
+    if (baudrate == 230400 || baudrate == 460800 || baudrate == 921600) {
+        // Changing the target clock frequency to 14 MHz
+        target_clk = 14745600;
+        // If we are using a 14 MHz compatible baud rate, we should enable the
+        // eXternal Xtal Oscillator of the target
+        xxo = PROTO_BAUDRATE_XXO;
+    }
+    else {
+        target_clk = 13000000;
+        xxo = 0;
+    }
+
+    divider = target_uart_baudrate_divider_get(target_clk, baudrate);
+    target_putchar(xxo);
+    target_putchar((char) divider);
+
+    if ((error = target_driver_baudrate(baudrate)) < 0)
+        main_fatal(error);
+
+    // Wait for acknowledgement
+    if (target_wait(1, 2 * TARGET_RECV_DELAY) >= 1 &&
+        target_getchar() == PROTO_READY) {
+        return 1;
+    }
+    else {
+        if ((error = target_driver_baudrate(115200)) < 0)
+            main_fatal(error);
+        return 0;
+    }
+}
+
+void cmd_machine_fluid(void)
+{
+    uint8 sendbuf[1+4+2];
+    int error;
+
+    // Send 'Download' command header. Then wait for acknowledgement.
+    buf_put1(&sendbuf[0],   PROTO_DOWNLOAD);
+    buf_put4(&sendbuf[1],   target[target_type].cmd_load_addr);
+    buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2);
+    target_send(sendbuf, 1+4+2);
+    flowf(BLABBER, "0x%X", target[target_type].cmd_load_addr);
+    if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0)
+        main_fatal(error);
+
+    // Send data. Then wait for acknowledgement.
+    target_trace_enable(1);
+    target_send(target_program, target_program_size);
+    flowf(BLABBER, ", %d", target_program_size);
+}
+
+void cmd_machine_rom(void)
+{
+    uint8 sendbuf[10], *buf;
+    int error, i;
+    int block_addr;
+    int block_offset = 0;
+    int block_size;
+    uint8 ch, blksum, cksum = 0;
+
+    // NOTEME: Can we be sure that it is always a Calypso type?
+    target_type_set('c');
+
+    block_addr = target[target_type].cmd_load_addr;
+
+    buffer_endian_convert(target_program, target_program_size, 2);
+
+    flowf(BLABBER, "0x%X, ", target[target_type].cmd_load_addr);
+
+    // Transfer the target program as blocks
+    while (block_offset < target_program_size)
+    {
+        block_size = target_program_size - block_offset;
+        if (block_size > bootloader_blocksize_max)
+            block_size = bootloader_blocksize_max;
+
+        // Initialize block transfer
+        buf  = sendbuf;
+        buf += buf_put1(buf, '<');
+        buf += buf_put1(buf, 'w');
+        buf += buf_put1(buf, 0x01); // block index - just use #1 - not important
+        buf += buf_put1(buf, 0x01); // block number - just use #1 - not important
+        buf += buf_put2no(buf, (uint16) block_size);
+        buf += buf_put4no(buf, block_addr + block_offset);
+        target_send(sendbuf, 10);
+
+        // Send the data
+        target_send(&target_program[block_offset], block_size);
+
+        // Calculate block check-sum
+        blksum  = 5;
+        blksum += block_size & 0x00ff;
+        blksum += (((block_addr + block_offset) & 0xff000000) >> 24);
+        blksum += (((block_addr + block_offset) & 0x00ff0000) >> 16);
+        blksum += (((block_addr + block_offset) & 0x0000ff00) >> 8);
+        blksum += ( (block_addr + block_offset) & 0x000000ff);
+        for (i = block_offset; i < (block_offset + block_size); i++)
+            blksum += target_program[i];
+        cksum += ~blksum;
+
+        block_offset = block_offset + block_size;
+
+        if ((error = target_expect_char ('>', TARGET_RECV_DELAY)) < 0)
+            main_fatal (error);
+        if ((error = target_expect_char ('w', TARGET_RECV_DELAY)) < 0)
+            main_fatal (error);
+
+        flowf(BLABBER, ".");
+    }
+    flowf(BLABBER, ", %d", target_program_size);
+    target_wait(0, 100);
+
+    // Request compare of checksum
+    target_putchar('<');
+    target_putchar('c');
+    target_putchar((char) ~cksum);
+
+    if ((error = target_expect_char('>', TARGET_RECV_DELAY)) < 0)
+        main_fatal(error);
+    if ((error = target_expect_char('c', TARGET_RECV_DELAY)) < 0)
+        main_fatal(error);
+    if ((error = target_wait(1, TARGET_RECV_DELAY)) < 1)
+        main_fatal(error);
+    ch = target_getchar();
+    flowf(DEBUG, ", cksum = 0x%x (0x%x)", ch, cksum);
+    if (ch != cksum)
+        main_fatal(E_SEND_CHECKSUM);
+
+    // Branch to code
+    buf  = sendbuf;
+    buf += buf_put1(buf, '<');
+    buf += buf_put1(buf, 'b');
+    buf += buf_put4no(buf, target[target_type].cmd_load_addr);
+    target_send(sendbuf, 6);
+
+    if (target_wait(2, TARGET_RECV_DELAY) < 2)
+        main_fatal(E_RECV_TIMEOUT);
+    if ((ch = target_getchar()) != '>')
+        error_proto(ch, '>');
+    if ((ch = target_getchar()) != 'b')
+        error_proto(ch, 'b');
+
+    target_wait(0, 100);
+}
+
+// Secure Calypso Plus
+void cmd_machine_secure_rom(void)
+{
+    UWORD8 d_char;
+    UWORD16 d_i;
+
+    target_type_set('p');
+    flowf(BLABBER, "0x%X", d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode);
+    flowf(DEBUG, ")");
+
+    // Prepare the write command
+    d_ram_loader.d_nb_byte_in_block = (UWORD32) arg_block_size;
+    d_ram_loader.d_nb_byte_sent = 0;
+    d_ram_loader.d_block_address = d_ram_loader.u_code_certificate.d_code_certificate.d_Addcode;
+
+    while (d_ram_loader.d_nb_byte_sent < d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize) {
+        flowf(DEBUG, "\nCurrent write parameters:\n");
+        flowf(DEBUG, "        Max Number of Bytes in Block: %ld\n", d_ram_loader.d_nb_byte_in_block);
+        flowf(DEBUG, "        Block Address               : 0x%8.8lx\n", d_ram_loader.d_block_address);
+        flowf(DEBUG, "        Code Size                   : %ld\n", d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize);
+        flowf(DEBUG, "        Bytes sent                  : %ld\n", d_ram_loader.d_nb_byte_sent);
+
+        // Set block size
+        d_ram_loader.d_block_size = d_ram_loader.u_code_certificate.d_code_certificate.d_Codesize - d_ram_loader.d_nb_byte_sent;
+        if (d_ram_loader.d_block_size > d_ram_loader.d_nb_byte_in_block)
+            d_ram_loader.d_block_size = d_ram_loader.d_nb_byte_in_block;
+
+        flowf(DEBUG, "        Block Size                  : %ld\n", d_ram_loader.d_block_size);
+
+        // Write Request
+        d_frame.a_data[0] = '<';
+        d_frame.a_data[1] = 'w';
+
+        // Send block size
+        for (d_i = 0; d_i < 32; d_i += 8)
+            d_frame.a_data[2 + d_i / 8] = (UWORD8)(d_ram_loader.d_block_size >> (24 - d_i));
+
+        // Send block address
+        for (d_i = 0; d_i < 32; d_i += 8)
+            d_frame.a_data[2 + sizeof(UWORD32) + d_i / 8] = (UWORD8)(d_ram_loader.d_block_address >> (24 - d_i));
+
+        d_frame.d_max_byte = 2 + sizeof(UWORD32) + sizeof(UWORD32);
+
+        // Send the data
+        target_send(&d_frame.a_data[0], d_frame.d_max_byte);
+        target_send(&target_program[d_certificate_length + d_ram_loader.d_nb_byte_sent], d_ram_loader.d_block_size);
+
+        // Update next block address
+        d_ram_loader.d_block_address += d_ram_loader.d_block_size;
+        d_ram_loader.d_nb_byte_sent  += d_ram_loader.d_block_size;
+
+        // Write Response
+        if (target_wait(2, TARGET_RECV_DELAY) < 2)
+            main_fatal(E_RECV_TIMEOUT);
+
+        if ((d_char = target_getchar ()) != '>')
+            error_proto(d_char, '>');
+
+        if ((d_char = target_getchar ()) != 'w') {
+            if (d_char == 'W') {
+                // WRITE_NACK_RESPONSE
+                if (target_wait(1, arg_boot_delay_rom) >= 1) {
+                    d_ram_loader.d_write_status = target_getchar();
+                    f_print_write_nack_status(NORMAL, d_ram_loader.d_write_status);
+                }
+            }
+            error_proto(d_char, 'w');
+        }
+
+        // WRITE_ACK_RESPONSE
+    }  // End while
+    if (arg_verbose == BLABBER)
+        flowf(BLABBER, ", ");
+    else
+        flowf(DEBUG, "(");
+
+    flowf(BLABBER, "%d", d_ram_loader.d_nb_byte_sent);
+    target_wait(0, 100);
+
+    // Abort Request
+    d_frame.a_data[0] = '<';
+    d_frame.a_data[1] = 'a';
+    d_frame.d_max_byte = 2;
+
+    target_send(&d_frame.a_data[0], d_frame.d_max_byte);
+    target_wait(0, 100);
+}
+
+void f_print_signalling_response(int level) {
+    UWORD16 d_i;
+
+    flowf(level, "\nSignalling Response:\n");
+
+    flowf(level, "        ROM Code Version: 0x%4.4x\n", d_ram_loader.d_romcode_version);
+
+    flowf(level, "        Hash (ManPubKey): ");
+    for (d_i = 0; d_i < (C_WORD32LGB * C_MD5HASHLG); d_i++) {
+        if (d_i == (C_WORD32LGB * C_MD5HASHLG) / 2)
+            flowf(level, "\n                          ");
+        flowf(level, "0x%2.2x ", d_ram_loader.a_hash_man_pub_key[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Die Id          : ");
+    for (d_i = 0; d_i < (C_WORD32LGB * C_DIE_ID_SIZE); d_i++)
+        flowf(level, "0x%2.2x ", d_ram_loader.a_die_id[d_i]);
+    flowf(level, "\n");
+} /* f_print_signalling_response() */
+
+void f_print_certificate_platform_data(int level, T_MANUFACTURER_CERTIFICATE_PLATFORM_DATA *p_certificate) {
+    UWORD16 d_i, d_j, d_max = 4;
+
+    flowf(level, "\nFirmware Manufacturer Certificate:\n");
+    flowf(level, "----------------------------------\n");
+
+    flowf(level, "        Size of Certificate: %d bytes\n", p_certificate->d_manufacturer_certificate.d_Certsize);
+    flowf(level, "        Type of Certificate: 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Certtype);
+    flowf(level, "        Emulation Request  : 0x%2.2x\n", p_certificate->d_manufacturer_certificate.d_Debugrequest);
+    flowf(level, "        Address of Code    : 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Addcode);
+    flowf(level, "        Size of Code       : %ld bytes\n", p_certificate->d_manufacturer_certificate.d_Codesize);
+    flowf(level, "        Entry Point Address: 0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_CodeStartAdd);
+
+    flowf(level, "        Manufacturer Public Key:\n");
+    flowf(level, "                Public Modulus:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                        ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Manpubkey.a_Modulus[d_i]);
+    }
+    flowf(level, "\n");
+    flowf(level, "                Public Modulus Length:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_ModulusLength);
+    flowf(level, "                Public Exponent:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Manpubkey.d_Exponent);
+
+    flowf(level, "        Originator Public Key:\n");
+    flowf(level, "                Public Modulus:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                        ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.d_Origpubkey.a_Modulus[d_i]);
+    }
+    flowf(level, "\n");
+    flowf(level, "                Public Modulus Length:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_ModulusLength);
+    flowf(level, "                Public Exponent:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_manufacturer_certificate.d_Origpubkey.d_Exponent);
+
+    flowf(level, "        Originator Public Key Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSASIGLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Origpubkeysig[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Software Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSASIGLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_Swsig[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Configuration Parameters:\n");
+    flowf(level, "                CONF_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_conf_cs5);
+    flowf(level, "                EXWS_CS5 register: %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_exws_cs5);
+    flowf(level, "                EX_CTRL register : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_ex_ctrl);
+    flowf(level, "                CS image request : %4.4x\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_cs_img_req);
+    flowf(level, "                Flash size       : %ld bytes\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_flash_size);
+    flowf(level, "                Granularity      : %ld words\n",p_certificate->d_manufacturer_certificate.d_Confparam.d_granularity);
+
+    flowf(level, "        Die Id: ");
+    for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) {
+        flowf(level, "0x%8.8lx ", p_certificate->d_manufacturer_certificate.a_die_id[d_i]);
+    }
+    flowf(level, "\n");
+
+    if (p_certificate->d_manufacturer_certificate.d_Certsize > (sizeof(T_MANUFACTURER_CERTIFICATE) + (C_WORD32LGB * C_MANUF_SIG_SIZE))) {
+        flowf(level, "        Platform Data:");
+        d_j = d_max;
+        for(d_i = 0; d_i < (p_certificate->d_manufacturer_certificate.d_Certsize - sizeof(T_MANUFACTURER_CERTIFICATE) - (C_WORD32LGB * C_MANUF_SIG_SIZE)) / sizeof(UWORD32); d_i++) {
+            if (d_j++ == d_max) {
+                flowf(level, "\n                ");
+                d_j = 1;
+            }
+            flowf(level, "0x%8.8lx ", p_certificate->a_platform_data[d_i]);
+        }
+        flowf(level, "\n");
+    }
+
+    flowf(level, "        Certificate Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]);
+    }
+    flowf(level, "\n");
+} /* f_print_certificate_platform_data() */
+
+void f_print_certificate(int level, T_MANUFACTURER_CERTIFICATE_FLASH_PROGRAMMER *p_certificate) {
+    UWORD16 d_i, d_j, d_max = 4;
+
+    flowf(level, "\nFlash Programmer Manufacturer Certificate:\n");
+    flowf(level, "------------------------------------------\n");
+
+    flowf(level, "        Size of Certificate: %d bytes\n", p_certificate->d_Certsize);
+    flowf(level, "        Type of Certificate: 0x%2.2x\n", p_certificate->d_Certtype);
+    flowf(level, "        Emulation Request  : 0x%2.2x\n", p_certificate->d_Debugrequest);
+    flowf(level, "        Address of Code    : 0x%8.8lx\n", p_certificate->d_Addcode);
+    flowf(level, "        Size of Code       : %ld bytes\n", p_certificate->d_Codesize);
+    flowf(level, "        Entry Point Address: 0x%8.8lx\n", p_certificate->d_CodeStartAdd);
+
+    flowf(level, "        Manufacturer Public key:\n");
+    flowf(level, "                Public Modulus:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                        ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_Manpubkey.a_Modulus[d_i]);
+    }
+    flowf(level, "\n");
+    flowf(level, "                Public Modulus Length:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_Manpubkey.d_ModulusLength);
+    flowf(level, "                Public Exponent:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_Manpubkey.d_Exponent);
+
+    flowf(level, "        Originator Public key:\n");
+    flowf(level, "                Public Modulus:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSAKEYLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                        ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->d_Origpubkey.a_Modulus[d_i]);
+    }
+    flowf(level, "\n");
+    flowf(level, "                Public Modulus Length:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_Origpubkey.d_ModulusLength);
+    flowf(level, "                Public Exponent:\n");
+    flowf(level, "                        0x%8.8lx\n", p_certificate->d_Origpubkey.d_Exponent);
+
+    flowf(level, "        Originator Public Key Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSASIGLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->a_Origpubkeysig[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Software Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_RSASIGLG); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->a_Swsig[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Configuration Parameters:\n");
+    flowf(level, "                CONF_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_conf_cs5);
+    flowf(level, "                EXWS_CS5 register: %4.4x\n",p_certificate->d_Confparam.d_exws_cs5);
+    flowf(level, "                EX_CTRL register : %4.4x\n",p_certificate->d_Confparam.d_ex_ctrl);
+    flowf(level, "                CS image request : %4.4x\n",p_certificate->d_Confparam.d_cs_img_req);
+    flowf(level, "                Flash size       : %ld bytes\n",p_certificate->d_Confparam.d_flash_size);
+    flowf(level, "                Granularity      : %ld words\n",p_certificate->d_Confparam.d_granularity);
+
+    flowf(level, "        Die Id: ");
+    for(d_i = 0; d_i < (C_DIE_ID_SIZE); d_i++) {
+        flowf(level, "0x%8.8lx ", p_certificate->a_die_id[d_i]);
+    }
+    flowf(level, "\n");
+
+    flowf(level, "        Certificate Signature:");
+    d_j = d_max;
+    for (d_i = 0; d_i < (C_MANUF_SIG_SIZE); d_i++) {
+        if (d_j++ == d_max) {
+            flowf(level, "\n                ");
+            d_j = 1;
+        }
+        flowf(level, "0x%8.8lx ", p_certificate->a_Certsig[d_i]);
+    }
+    flowf(level, "\n");
+} /* f_print_certificate() */
+
+void f_print_parameter_nack_status(int level, UWORD8 d_parameter_nack_sts) {
+    flowf(level, "\nParameter NAck Response Status:\n");
+    flowf(level, "        0x%2.2x", d_parameter_nack_sts);
+
+    switch(d_parameter_nack_sts) {
+        case 0x01 : { flowf(level, "    Incorrect baud rate\n"); break; }
+        case 0x02 : { flowf(level, "    Incorrect certificate\n"); break; }
+        case 0x03 : { flowf(level, "    Incorrect code address\n"); break; }
+    }
+
+    flowf(level, "\n");
+} /* f_print_parameter_nack_status() */
+
+void f_print_write_nack_status(int level, UWORD8 d_write_nack_sts) {
+    flowf(level, "\nWrite NAck Response Status:\n");
+    flowf(level, "        0x%2.2x", d_write_nack_sts);
+
+    switch(d_write_nack_sts) {
+        case 0x01 : { flowf(level, "    Incorrect block address\n"); break; }
+        case 0x02 : { flowf(level, "    Non-64 bytes block size\n"); break; }
+        case 0x03 : { flowf(level, "    First block is not code address\n"); break; }
+        case 0x04 : { flowf(level, "    Error in firmware signature check\n"); break; }
+        case 0x05 : { flowf(level, "    Received code size does not match the code size in certificate\n"); break; }
+        case 0x06 : { flowf(level, "    Error during block hashing\n"); break; }
+    }
+
+    flowf(level, "\n");
+} /* f_print_write_nack_status() */
+
+UWORD8 f_convert_uart_baud_rate(UWORD32 d_baud_rate) {
+    UWORD8 d_converted_baud_rate;
+
+    switch (d_baud_rate) {
+        case 0:
+        case 812:
+        case 812500: {
+            d_converted_baud_rate = 0x00;
+            arg_uart_baudrate_during_cmd_download = 812500;
+            break;
+        }
+        case 1:
+        case 406:
+        case 406250: {
+            d_converted_baud_rate = 0x01;
+            arg_uart_baudrate_during_cmd_download = 406250;
+            break;
+        }
+        case 2:
+        case 203:
+        case 203125: {
+            d_converted_baud_rate = 0x02;
+            arg_uart_baudrate_during_cmd_download = 203125;
+            break;
+        }
+        case 3:
+        case 115:
+        case 115200: {
+            d_converted_baud_rate = 0x03;
+            arg_uart_baudrate_during_cmd_download = 115200;
+            break;
+        }
+        case 4:
+        case 57:
+        case 57600: {
+            d_converted_baud_rate = 0x04;
+            arg_uart_baudrate_during_cmd_download = 57600;
+            break;
+        }
+        case 5:
+        case 38:
+        case 38400: {
+            d_converted_baud_rate = 0x05;
+            arg_uart_baudrate_during_cmd_download = 38400;
+            break;
+        }
+        case 6:
+        case 28:
+        case 28800: {
+            d_converted_baud_rate = 0x06;
+            arg_uart_baudrate_during_cmd_download = 28800;
+            break;
+        }
+        case 7:
+        case 19:
+        case 19200: {
+            d_converted_baud_rate = 0x07;
+            arg_uart_baudrate_during_cmd_download = 19200;
+            break;
+        }
+        default: {
+            d_converted_baud_rate = 0x03;
+            arg_uart_baudrate_during_cmd_download = 115200;
+            break;
+        }
+    }
+
+    return d_converted_baud_rate;
+} /* f_convert_uart_baud_rate() */
+
+void target_imei_protection(void)
+{
+    uint8 a_imeisv[C_IMEISV_BYTES];
+    uint8 a_platform_cert_addr[C_PLATFORM_CERT_ADDR_BYTES];
+    uint8 d_i, d_digit, d_temp;
+    uint8 d_error;
+
+    flowf(NORMAL, "\nIMEI protection: ");
+
+    if (arg_dry_run) {
+        flowf(NORMAL, "(dry-run) ok\n");
+        return;
+    }
+
+    target_putchar(PROTO_IMEI_PROTECT);
+
+    // Send IMEI-SV
+    for (d_i = 0; d_i < C_IMEISV_DIGITS; d_i++) {
+        sscanf(arg_imeisv++, "%1d", &d_digit);
+        if (!(d_i & 1))
+            d_temp = d_digit << 4;
+        else {
+            d_temp |= d_digit;
+            a_imeisv[d_i / 2] = d_temp;
+        }
+    }
+
+    target_send(a_imeisv, C_IMEISV_BYTES);
+    target_expect_char(PROTO_READY, TARGET_RECV_DELAY);
+
+    // Send platform certificate address
+    for (d_i = 0; d_i < C_PLATFORM_CERT_ADDR_DIGITS; d_i++) {
+        sscanf(arg_platform_certificate_addr++, "%1x", &d_digit);
+        if (!(d_i & 1))
+            d_temp = d_digit << 4;
+        else {
+            d_temp |= d_digit;
+            a_platform_cert_addr[d_i / 2] = d_temp;
+        }
+    }
+
+    target_send(a_platform_cert_addr, C_PLATFORM_CERT_ADDR_BYTES);
+    target_expect_char(PROTO_READY, TARGET_RECV_DELAY);
+
+    // Check if address range is erased
+    if (target_wait(1, TARGET_RECV_DELAY) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+
+    d_error = target_getchar();
+    if (d_error == PROTO_ERROR_VERIFY) {
+        flowf(NORMAL, "\n The address range for platform certificate and IMEI-SV is not erased.\n");
+        main_fatal(E_FLASH_VERIFY);
+    }
+
+    if (d_error != PROTO_READY)
+        error_proto(d_error, PROTO_READY);
+
+    // Verify that the binding service call in target has succeeded
+    if (target_wait(1, TARGET_RECV_DELAY) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+
+    d_error = target_getchar();
+    if (d_error == PROTO_ERROR_ROM_SSERVICE) {
+        flowf(NORMAL, "\n The Run-Time Loader (Binding) Service failed.\n");
+        main_fatal(E_ROM_SSERVICE);
+    }
+
+    if (d_error != PROTO_FLASH_START)
+        error_proto(d_error, PROTO_FLASH_START);
+
+    // Receive acknowledgement for programming the platform certificate
+    if (target_wait(1, TARGET_RECV_DELAY) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+
+    d_error = target_getchar();
+    if (d_error != PROTO_PROGRAM) {
+        flowf(NORMAL, "\n Platform certificate was not stored correctly in flash.\n");
+        error_proto(d_error, PROTO_PROGRAM);
+    }
+
+    // Receive acknowledgement for programming the IMEI-SV
+    if (target_wait(1, TARGET_RECV_DELAY) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+
+    d_error = target_getchar();
+    if (d_error != PROTO_PROGRAM) {
+        flowf(NORMAL, "\n IMEI-SV was not stored correctly in flash.\n");
+        error_proto(d_error, PROTO_PROGRAM);
+    }
+
+    flowf(NORMAL, "Platform certificate and IMEI-SV stored in flash.\n");
+}
+
+// End Secure Calypso Plus
+
+/******************************************************************************
+ * Flash Detect
+ ******************************************************************************/
+
+void flash_detect_machine(void)
+{
+    uint8  data[12];
+    uint16 m0, d0, m1, d1, d1ex1, d1ex2;
+
+    flowf(NORMAL, "Flash Detect: ");
+    target_trace_enable(0);
+
+    if (arg_device_id0 != -1 || arg_device_id1 != -1) {
+        // Device auto-detection is disabled
+        m0 = m1 = arg_device_id0;
+        d0 = d1 = arg_device_id1;
+        flowf(VERBOSE, "(ID override) ");
+    }
+    else {
+        target_putchar(PROTO_DETECT);
+        if (target_wait(12, TARGET_RECV_DELAY) < 12)
+            main_fatal(E_RECV_TIMEOUT);
+
+        target_recv(data, 12);
+        m0 = data[0] + (data[1] << 8); // Intel manufacturer id
+        d0 = data[2] + (data[3] << 8); // Intel device id
+        m1 = data[4] + (data[5] << 8); // AMD manufacturer id
+        d1 = data[6] + (data[7] << 8); // AMD device di
+        d1ex1 = data[8] + (data[9] << 8);   // AMD extended device id
+        d1ex2 = data[10] + (data[11] << 8); // AMD extended device id
+    }
+
+    // Lookup multi-id device
+    if ((m1 == MANUFACT_AMD || m1 == MANUFACT_FUJITSU) && d1 == 0x227E) {
+        flowf(NORMAL, "Multi-id device detected: (0x%04X, 0x%04X, 0x%04X)\n"
+              , d1, d1ex1, d1ex2);
+        d1 = (d1ex1 << 8) | (d1ex2 & 0xFF);
+        flowf(DEBUG, "Multi-id converted to: 0x%04X\n", d1);
+        
+        if ((device = device_lookup_by_id(m1, d1)) == NULL) {
+            flowf(NORMAL, "Id not found, lookup default multi-id conf.\n");
+            // Backward compatible/keep default multi-id configuration
+            device = device_lookup_by_id(m1, 0x227E);
+        }
+    }
+    
+    // Lookup device with AMD and Intel ids
+    else if ((device = device_lookup_by_id(m1, d1)) == NULL)
+        device = device_lookup_by_id(m0, d0);
+
+    if (device == NULL || arg_verbose >= DEBUG) {
+        flowf(NORMAL, "(0x%02X, 0x%04X, 0x%02X, 0x%04X) ", m0, d0, m1, d1);
+        if (device == NULL)
+            main_fatal(E_FLASH_UNKNOWN);
+    }
+
+    if (arg_verbose >= NORMAL) {
+        device_print(device, 's');
+        flowf(NORMAL, " ok\n");
+    }
+
+    // Note that device_id is only 0x227E if the Multi-id configuration not
+    // is found in device.txt (else device_id will be the 'converted' id)
+    if (arg_device_id0 == -1 && arg_device_id1 == -1 &&
+        (device->manufacturer_id == MANUFACT_FUJITSU || 
+         device->manufacturer_id == MANUFACT_AMD ) 
+        && device->device_id == 0x227E) {
+        flowf(NORMAL, "Warning: Extended device codes are supported when detecting flash devices,\n");
+        flowf(NORMAL, "         but the detected multi-id configuration is not found in device.txt. \n");
+        flowf(NORMAL, "         Update the device.txt manually if the default flash device is invalid.\n");
+        flowf(NORMAL, "         Currently, %s %s is used as default.\n\n",
+            manufacturer_name_lookup_by_id(device->manufacturer_id), device->name);
+    }
+}
+
+
+/******************************************************************************
+ * Method Load
+ ******************************************************************************/
+
+void method_download_machine(void)
+{
+    char sendbuf[1+2+4];
+    int error;
+
+    target_program_size = file_read_method(target_program,
+                                           TARGET_PROGRAM_SIZE_MAX,
+                                           device);
+
+    flowf(BLABBER, "Method Download: ");
+    target_trace_enable(0);
+
+    // Send 'Download' command header. Then wait for acknowledgement.
+    buf_put1(&sendbuf[0],   PROTO_DOWNLOAD);
+    buf_put4(&sendbuf[1],   target[target_type].method_load_addr);
+    buf_put2(&sendbuf[1+4], (uint16) target_program_size / 2);
+    target_send(sendbuf, 1+4+2);
+    flowf(BLABBER, "(0x%X", target[target_type].method_load_addr);
+    if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0)
+        main_fatal(error);
+
+    // Send data. Then wait for acknowledgement.
+    target_trace_enable(1);
+    target_send(target_program, target_program_size);
+    flowf(BLABBER, ", %d) ", target_program_size);
+    if ((error = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0)
+        main_fatal(error);
+
+    flowf(BLABBER, "ok\n");
+}
+
+
+/******************************************************************************
+ * Flash Checksum
+ ******************************************************************************/
+
+int time_checksum;
+
+#define CHECKSUMS 8
+
+void flash_checksum_machine(void)
+{
+    unsigned char sendbuf[1+1+4+4*CHECKSUMS], *buf;
+    uint32 addr, cksum, mycksum;
+    uint16 word;
+    uint8  data[4];
+    int index = 0, chunks, n, i, j;
+    int line = -1;
+    struct {
+        uint32 index;
+        uint32 addr;
+        uint32 mycksum;
+    } block[CHECKSUMS];
+
+    chunks = image_map_count_used_chunks();
+    flowf(NORMAL, "Checksumming (%d * %dkB = %dkB): ",
+          chunks, image_chunk_size / 1024,
+          chunks * image_chunk_size / 1024);
+    target_trace_enable(0);
+
+    time_checksum = stopwatch_start();
+    while (chunks > 0)
+    {
+        n = (chunks > CHECKSUMS ? CHECKSUMS : chunks);
+
+        buf = sendbuf;
+        buf += buf_put1(buf, PROTO_CHECKSUM);
+        buf += buf_put1(buf, (unsigned char) n);
+        buf += buf_put4(buf, image_chunk_size);
+
+        for (i = 0; i < n; i++) {
+            // Find next used entry in image_map
+            while (image_map[index] != 'x' && index < image_map_size)
+                index++;
+
+            if (index == image_map_size)
+                break;
+
+            addr = index * image_chunk_size;
+            block[i].index   = index;
+            block[i].addr    = addr;
+
+            buf += buf_put4(buf, addr);
+
+            index++;
+        }
+        target_send(sendbuf, buf - sendbuf);
+
+        // Compute checksums while we wait for reply
+        for (i = 0; i < n; i++) {
+            index = block[i].index;
+            addr  = block[i].addr;
+            for (j = 0, mycksum = 0; j < image_chunk_size; j += 2) {
+                word = (image[addr + j + 1] << 8) | image[addr + j + 0];
+                mycksum += word * ((addr + j) & 0xFFFF);
+            }
+            block[i].mycksum = mycksum;
+        }
+
+        if (target_wait(4 * n, TARGET_RECV_LONG_DELAY) <= 0)
+            main_fatal(E_RECV_TIMEOUT);
+
+        for (i = 0; i < n; i++) {
+            target_recv(data, 4);
+            cksum   = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
+            mycksum = block[i].mycksum;
+            index   = block[i].index;
+
+            if (cksum == mycksum)
+                image_map[index] = 'c';
+
+            if (arg_checksum_show) {
+                // This is a far from perfect dump of checksums... We don't know
+                // the exact block number of each checksum in a line.
+                if (line != (int) index / 4) {
+                    flowf(NORMAL, "\n%4d:", index);
+                    line = index / 4;
+                }
+                if (cksum == mycksum)
+                    flowf(NORMAL, "%08X          ", cksum);
+                else
+                    flowf(NORMAL, "%08X/%08X ", cksum, mycksum);
+
+            }
+            else if (arg_verbose >= VERBOSE) {
+                flowf(VERBOSE, "%c", (image_map[index] == 'c' ? 'c' : '.'));
+            }
+        }
+        index++;
+        chunks -= n;
+    }
+    time_checksum = (stopwatch_stop(time_checksum) + 50) / 100;
+    flowf(BLABBER, " (%d.%ds)", time_checksum / 10, time_checksum % 10);
+    flowf(NORMAL, " ok\n");
+}
+
+
+/******************************************************************************
+ * Flash Program
+ ******************************************************************************/
+
+int time_program;
+int programs_recv, programs_send, erasures;
+int index, src_size;
+uint32 dst;
+char *src;
+
+void flash_erase_machine(void);
+int  flash_operation_wait(int delay);
+int  flash_program_next(void);
+
+void flash_program_machine(void)
+{
+    uint8 cksum, sendbuf[1+4+4];
+    int i, te, tp, tt;
+    int expected, chunks, total_size, sectors;
+    int image_chunk_size_old = image_chunk_size;
+    char ch;
+
+    programs_recv = programs_send = erasures = 0;
+    index = 0;
+
+    // Prepare erase
+    erase_list_size = sectors = sector_map_init();
+    i = image_map_count_used_chunks();
+
+    if (arg_skip_erase)
+        erase_list_size = 0;
+
+    time_compute(device, erase_list_size,
+                 i * image_chunk_size, i, &te, &tp, &tt);
+
+    flowf(BLABBER, "Estimated time (uncompressed) ");
+    if (te + tp > tt)
+        flowf(BLABBER, "(erase + program = total): %ds + %ds = %ds\n",
+              te/1000, tp/1000, te/1000 + tp/1000);
+    else
+        flowf(BLABBER, "transfer: %ds\n", tt/1000);
+
+    chunks = image_map_count_used_chunks();
+    flowf(NORMAL, "Program: (%d sectors, %d*%dk=%dk) ",
+          sectors,
+          chunks, image_chunk_size / 1024,
+          chunks * image_chunk_size / 1024);
+    target_trace_enable(1);
+
+    // Expected total number of acknowledgements
+    expected = erase_list_size + chunks;
+
+    if (arg_dry_run) {
+        flowf(NORMAL, "(dry-run) ");
+        if (arg_dry_run == 2)
+            image_chunk_size = 0;
+    }
+
+    if (arg_skip_erase)
+        flowf(NORMAL, "(skip erase) ");
+
+    // Start erase
+    flash_erase_machine();
+
+    if (arg_dry_run == 0 || arg_dry_run == 2)
+        progress_begin(expected);
+
+    // Start the flash state machine in the target
+    target_putchar(PROTO_FLASH_START);
+    target_putchar(arg_compress ? PROTO_COMPRESS : 0);
+    ch = flash_operation_wait(TARGET_RECV_DELAY);
+    if (ch != PROTO_READY)
+        error_proto(ch, PROTO_READY);
+    if (arg_compress) {
+        compress_init();
+        total_size = 0;
+        // Worst case "compressed" buffer is 9/8 of original data size.
+        if ((src = malloc(9 * image_chunk_size / 8)) == NULL)
+            main_fatal(E_MEMORY);
+    }
+
+    time_program = stopwatch_start();
+
+    if (flash_program_next() && *arg_erase_override == 0) {
+        //Nothing to program
+        target_putchar(PROTO_FLASH_END);
+        if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0)
+            main_fatal(ch);
+    }
+    else {
+        while (programs_recv + erasures < expected) {
+            total_size += src_size;
+
+            if (arg_progress == 'x')
+                flowf(NORMAL, "(0x%06X, %d) ", dst, src_size);
+
+            if (src_size > 0 &&
+                (arg_dry_run == 0 || arg_dry_run == 2))
+            {
+                buf_put1(&sendbuf[0],   PROTO_PROGRAM);
+                buf_put4(&sendbuf[1],   src_size);
+                buf_put4(&sendbuf[1+4], dst);
+                target_send(sendbuf, 1+4+4);
+
+                for (i = 0, cksum = 0; i < src_size; i++)
+                    cksum += src[i];
+                cksum = (0x100 - cksum) & 0xFF;
+
+                // Wait for acknowledgement of command start
+                //while ((ch = flash_operation_wait(4000)) != PROTO_READY)
+                //    ;
+
+                // Make sure that the target FIFO not is full
+                while (programs_send - programs_recv >= target_fifo_size)
+                    flash_operation_wait(4000);
+
+                // Send data bytes and checksum.
+                target_send(src, src_size);
+                target_putchar(cksum);
+                programs_send++;
+
+                if (arg_verbose >= DEBUG)
+                    progress_update_simple('T');
+            }
+
+            // We compress and send next block while sending
+            // current block to target
+            if (arg_dry_run == 0 || arg_dry_run == 2) {
+                if (flash_program_next()) {
+                    // Wait for remaining acknowledgements
+                    flowf(DEBUG, "W%d", expected - (programs_recv + erasures));
+                    while (programs_recv + erasures < expected)
+                        flash_operation_wait(4000);
+                    target_putchar(PROTO_FLASH_END);
+                    if ((ch = target_expect_char(PROTO_FLASH_END, TARGET_RECV_DELAY)) < 0)
+                        main_fatal(ch);
+                    break;
+                }
+                else {
+                    // Wait for acknowledgement of data transfer
+                    while ((ch = flash_operation_wait(4000)) != PROTO_READY)
+                        ;
+                }
+            }
+            else {
+                if (flash_program_next())
+                    break;
+            }
+        }
+    }
+
+    if (arg_dry_run == 0 || arg_dry_run == 2)
+        progress_end(programs_recv + erasures);
+    flowf(NORMAL, "ok\n");
+
+    time_program = stopwatch_stop(time_program);
+    flowf(VERBOSE, "Used time: ");
+    if (arg_compress && chunks) {
+        image_chunk_size = image_chunk_size_old;
+        flowf(VERBOSE, "(compressed to %d%%) ",
+              100 * total_size / (chunks * image_chunk_size));
+    }
+    flowf(VERBOSE, "%.1fs ok\n", (double) time_program / 1000);
+}
+
+
+/******************************************************************************
+ * Flash Program sub functions
+ ******************************************************************************/
+
+void flash_erase_machine(void)
+{
+    uint8 sendbuf[1+2+4*256]; // NOTEME: static limit!
+    int i;
+    char ch;
+
+    if (arg_dry_run)
+        erase_list_size = 0;
+
+    if (erase_list_size > 0) {
+        buf_put1(&sendbuf[0], PROTO_ERASE);
+        buf_put2(&sendbuf[1], (uint16) erase_list_size);
+        for (i = 0; i < erase_list_size; i++)
+            buf_put4(&sendbuf[1+2+4*i], erase_list[i]);
+        target_send(sendbuf, 1+2+4*erase_list_size);
+
+        if ((ch = target_expect_char(PROTO_READY, TARGET_RECV_DELAY)) < 0)
+            main_fatal(ch);
+    }
+}
+
+// Setup address and size of next block to transfer. Also compress the
+// block. Return non-zero if this was the last block. Otherwise return zero.
+int flash_program_next(void)
+{
+    int oldindex;
+
+    // Find next used entry in image_map
+    while (index < image_map_size && image_map[index] != 'x')
+        index++;
+
+    oldindex = index;
+
+    if (index < image_map_size) {
+        dst = index * image_chunk_size;
+        if (arg_compress) {
+            src_size = compress(src, &image[dst], image_chunk_size);
+        }
+        else {
+            src = &image[dst];
+            src_size = image_chunk_size;
+        }
+        index++;
+    }
+    else {
+        dst = 0xFFFFFFFF;
+        src_size = 0;
+    }
+
+    return (oldindex >= image_map_size);
+}
+
+int flash_operation_wait(int delay)
+{
+    int n;
+    char ch;
+
+    tr(TrMachines, "fow() ");
+
+    if ((n = target_wait(1, delay)) < 1)
+        main_fatal(E_RECV_TIMEOUT);
+
+    // Minor optimization to avoid waiting for every char...
+    while (n--) {
+        ch = target_getchar();
+
+        if (ch == PROTO_READY) {
+            if (arg_verbose >= DEBUG)
+                progress_update_simple('R');
+            if (programs_send - programs_recv >= target_fifo_size)
+                progress_update_simple('W');  // Wait target FIFO is full
+            break;
+        }
+
+        switch (ch) {
+        case PROTO_READY:
+            break; // just return the char
+        case PROTO_PROGRAM:
+            programs_recv++;
+            progress_update_simple('P');
+            progress_update(programs_recv + erasures);
+            break; // just return the char
+        case PROTO_ERASE:
+            erasures++;
+            progress_update_simple('E');
+            progress_update(programs_recv + erasures);
+            if (arg_progress == 'x')
+                flowf(NORMAL, "E ");
+            break; // just return the char
+        case PROTO_FLASH_END:
+            progress_update_simple('Z');
+            break;
+        case PROTO_ERROR_CKSUM:
+            main_fatal(E_SEND_CHECKSUM);
+        case PROTO_ERROR_MEMORY:
+            main_fatal(E_MEMORY);
+        case PROTO_ERROR_VERIFY:
+            main_fatal(E_FLASH_VERIFY);
+        case PROTO_ERROR_FLASH_TIMEOUT:
+            main_fatal(E_FLASH_TIMEOUT);
+        case PROTO_ERROR_FLASH_COMMAND:
+            main_fatal(E_FLASH_COMMAND);
+        case PROTO_ERROR_FLASH_VPP:
+            main_fatal(E_FLASH_VPPRANGE);
+        case PROTO_ERROR_FLASH_LOCKED:
+            main_fatal(E_FLASH_LOCKED);
+        case PROTO_ERROR_FLASH_UNKNOWN:
+            main_fatal(E_FLASH_ERROR);
+        case PROTO_ERROR_INVALID:
+            main_fatal(E_INVALID);
+        case PROTO_ERROR_FIFO_OVERFLOW:
+            main_fatal(E_FIFO_OVERFLOW);
+        case PROTO_ERROR:
+        default:
+            flowf(NORMAL, "flash_operation_wait() got unexpected char '%c' 0x%02X (%d chars waiting)\n", (' ' <= ch  && ch  < 127 ? ch  : '.'), ch, n);
+//            main_fatal(E_PROTO_ERROR);
+        }
+    }
+
+    return ch;
+}
+
+void target_timers_show(void)
+{
+    int data[8], i;
+    struct {
+        double erase;
+        double program;
+        double recvonly;
+        double recv;
+        double comm;
+        double setup;
+        double overhead;
+        double dezip;
+        double erase_sector;
+        double program_word;
+    } timer;
+    double tmp, total, resolution = (double) (16 * 32 * 1000 / 13e6);
+
+    // Use only 14 MHz for D-/E-Sample specific rates (not for e.g. 812.5K).
+    if ((arg_uart_baudrate == 230400) || (arg_uart_baudrate == 460800) || (arg_uart_baudrate == 921600))
+        resolution = resolution * 13 / 14.746;
+
+    flowf(NORMAL,
+          "Target Timers:\n"
+          "  (erase + program + recvonly +   recv +  comm + setup + overhead + dezip)\n");
+
+    if (arg_dry_run)
+        for (i = 0; i < 8; i++) data[i] = 0;
+    else {
+        target_putchar(PROTO_TIMERS);
+        if (target_wait(sizeof(data), TARGET_RECV_DELAY) <= 0)
+            main_fatal(E_RECV_TIMEOUT);
+        target_recv(&data, sizeof(data));
+    }
+
+    // Convert all timers to milliseconds
+    timer.erase    = resolution * data[0];
+    timer.program  = resolution * data[1];
+    timer.recvonly = resolution * data[2];
+    timer.recv     = resolution * data[3];
+    timer.comm     = resolution * data[4];
+    timer.setup    = resolution * data[5];
+    timer.overhead = resolution * data[6];
+    timer.dezip    = resolution * data[7];
+
+    // Because we do erase-while-transfer in the target the reported erase
+    // time has some inherent tolerance, especially at low baudrates. It
+    // might make sense to adjust the sector erase time by half the chunk
+    // transfer time, although this is just another approximation!?
+
+//    total = timer.erase + timer.program + timer.recvonly + timer.recv + timer.comm + timer.setup;
+    flowf(NORMAL, "%8.0f + %7.0f + %8.0f + %6.0f + %5.0f + %5.0f + %8.0f + %5.0f\n",
+          timer.erase, timer.program, timer.recvonly, timer.recv,
+          timer.comm, timer.setup, timer.overhead, timer.dezip);
+
+    flowf(DEBUG, "resolution = %f, %d, %d, %d, %d, %d, %d, %d, %d\n",
+          resolution, data[0], data[1], data[2], data[3], data[4],
+          data[5], data[6], data[7]);
+
+    if (arg_timers_extended_show) {
+        int chunks, size_total, not_zero = 1;
+        flowf(NORMAL, "Target Timers Extended:\n");
+
+        if (erase_list_size == 0 || arg_dry_run)
+            flowf(NORMAL, "  Erase time         = 0.0ms/sector\n");
+        else {
+            timer.erase_sector = timer.erase / erase_list_size / 1000;
+            flowf(NORMAL, "  Erase time         = %.1fs / %d sectors = %.0fms/sector\n",
+                  timer.erase / 1000, erase_list_size, timer.erase_sector * 1000);
+        }
+
+        chunks = image_map_count_used_chunks();
+        size_total = chunks * image_chunk_size;
+        if (size_total == 0 || arg_dry_run) {
+            size_total = 1;
+            not_zero = 0;
+            flowf(NORMAL, "  Program time       = 0.0us/word = 0ms/MB\n");
+        }
+        else {
+            timer.program_word = timer.program / 1000 / (size_total / 2);
+            flowf(NORMAL, "  Program time       = %.1fs / %dkwords = %.2fus/word = %.0fms/MB\n",
+                  timer.program / 1000, size_total / 1024 / 2,
+                  timer.program_word * 1000000,
+                  timer.program_word * 1000 * 512 * 1024);
+        }
+
+        flowf(NORMAL, "  Receive-only time  = %.1fs = %.0fms/MB\n",
+              timer.recvonly / 1000,
+              not_zero * timer.recvonly * 1024 * 1024 / size_total);
+
+        flowf(NORMAL, "  Overhead time      = %.1fs = %.0fms/MB\n",
+              timer.overhead / 1000,
+              not_zero * timer.overhead * 1024 * 1024 / size_total);
+
+        flowf(NORMAL, "  Setup time         = %.1fs = %.0fms/MB\n",
+              timer.setup / 1000,
+              not_zero * timer.setup * 1024 * 1024 / size_total);
+
+        total = timer.erase + timer.program + timer.recvonly + timer.overhead +
+            timer.setup;
+        flowf(NORMAL,
+              "Total time: (erase + prog + recvonly + overhead + setup) = %.1fs\n",
+              total / 1000);
+
+        flowf(NORMAL, "  Receive time       = %.1fs = %.0fms/MB\n",
+              timer.recv / 1000, timer.recv * 1024 * 1024 / size_total);
+
+        flowf(NORMAL, "  Communication time = %.1fs = %.0fms/MB\n",
+              timer.comm / 1000, timer.comm * 1024 * 1024 / size_total);
+
+        flowf(NORMAL, "  Dezip time         = %.1fs = %.0fms/MB\n",
+              timer.dezip / 1000, timer.dezip * 1024 * 1024 / size_total);
+
+        // Now compute the overall performance. Note that the theoretical
+        // limit compuation is somewhat flawed in that it assumes 64kB
+        // sector sizes.
+
+        tmp = (double) not_zero * total / 1000 * 1024 * 1024 / size_total;
+        flowf(NORMAL, "  Performance = %.0fs/MB\n", tmp);
+#if 0
+        flowf(BLABBER, " (%.1f * min possible, %.1f * theoretical limit)",
+              time_program / (timer.program + timer.erase),
+              tmp / (16 * timer.erase_sector + 512 * 1024 * timer.program_word));
+        flowf(NORMAL, "\n");
+#endif
+    }
+}
+
+
+/******************************************************************************
+ * Flash Read
+ ******************************************************************************/
+
+int time_read;
+
+void flash_read_machine(void)
+{
+    int i;
+    unsigned char sendbuf[1+4+4];
+    int size, read_size, done_size = 0;
+    int read_size_max = image_chunk_size;
+    uint32 addr, index = 0;
+    uint8 cksum, mycksum;
+
+    flowf(NORMAL, "Reading Flash: (%dkB) ", read_total_size / 1024);
+    target_trace_enable(0);
+
+    //read_size_max = 256;
+    time_read = stopwatch_start();
+    progress_begin(read_total_size / read_size_max);
+
+    while (read_list[index].size > 0)
+    {
+        // Find next range to read
+        size = read_list[index].size;
+        addr = read_list[index].addr;
+        index++;
+
+        while (size > 0)
+        {
+            read_size = (size > read_size_max ? read_size_max : size);
+
+            // Read address interval is [MIN..MAX[
+            // If odd MAX address was specified round up to next even
+            if ((read_size % 2 == 1) && (read_size < read_size_max)) read_size++;
+
+            if (arg_progress == 'x')
+                flowf(DEBUG, "(0x%06X, %d) ", addr, read_size);
+
+            if (!arg_dry_run)
+            {
+                buf_put1(&sendbuf[0],   PROTO_READ);
+                buf_put4(&sendbuf[1]  , read_size);
+                buf_put4(&sendbuf[1+4], addr);
+                target_send(sendbuf, 1+4+4);
+
+                if (target_wait(read_size, TARGET_RECV_LONG_DELAY) <= 0)
+                    main_fatal(E_RECV_TIMEOUT);
+                // Note that we wrap/mirror memory each 'image_size' bytes
+                target_recv(&image[addr & (image_size - 1)], read_size);
+                for (i = 0, mycksum = 0; i < read_size; i++)
+                    mycksum ^= image[(addr + i) & (image_size - 1)];
+
+                if (target_wait(1, TARGET_RECV_DELAY) <= 0)
+                    main_fatal(E_RECV_TIMEOUT);
+                cksum = target_getchar();
+
+                if (cksum != mycksum)
+                    main_fatal(E_RECV_CHECKSUM);
+            }
+            done_size += read_size;
+            size -= read_size;
+            addr += read_size;
+
+            progress_update(done_size / read_size_max);
+            progress_update_simple('0' + read_size / 1024);
+        }
+    }
+    progress_end(done_size / read_size_max);
+    flowf(NORMAL, " ok\n");
+
+    time_read = stopwatch_stop(time_read);
+    flowf(VERBOSE, "Used time: %ds ok\n", time_read);
+}
+
+
+/******************************************************************************
+ * Flash Reset
+ ******************************************************************************/
+
+void target_reset_machine(void)
+{
+    int error;
+
+    flowf(VERBOSE, "Resetting target: ");
+
+    if (arg_dry_run) {
+        flowf(VERBOSE, "(dry-run) ");
+    }
+    else {
+        target_putchar(PROTO_RESET);
+        target_expect_char(PROTO_READY, TARGET_RECV_DELAY);
+    }
+    flowf(VERBOSE, "ok\n");
+}
+
+
+/******************************************************************************
+ * Show Functions (dump internal data structures)
+ ******************************************************************************/
+
+void image_map_show(void)
+{
+    uint32 addr;
+    int i;
+
+    flowf(ALWAYS, "image map of %d * %dkB chunks (x = used, s = skip, c = checksum ok):",
+           image_size_in_chunks, image_chunk_size / 1024);
+
+    // For each chunk of the image usage map...
+    for (i = 0, addr = 0; i < image_size_in_chunks; i++)
+    {
+        if ((i % 64) == 0) {
+            flowf(ALWAYS, "\n%4dkB: ", (int) addr >> 10);
+        }
+        putchar(image_map[i] != 0 ? image_map[i] : '.');
+        addr += image_chunk_size;
+    }
+    putchar('\n');
+}
+
+void sector_map_show(void)
+{
+    struct sector_s *sectors = device->memmap->sectors;
+    int i;
+
+    char n;
+    uint32 addr = 0;
+
+    flowf(ALWAYS, "sector map (x = used, s = skip, X = force erase):");
+
+        // For each sector of the device definition...
+    for (i = 0; i < device->memmap->size; i++)
+    {
+        if ((addr & 0xFFFFF) == 0) {
+            flowf(ALWAYS, "\n%2dMB: ", (int) addr >> 20);
+        }
+        n = (sector_map[i] ? sector_map[i] : '.');
+        putchar(n);
+
+        addr += sectors[i].size;
+    }
+    putchar('\n');
+}
+
+
+/******************************************************************************
+ * Utility Functions
+ ******************************************************************************/
+
+int image_is_within(int start, int end)
+{
+    return !(start < 0 || image_size <= start ||
+             end < 0   || image_size < end ||
+             end < start);
+}
+
+// Set the image usage map in the range [start..end[ as used
+int image_map_set(int start, int end)
+{
+    if (!image_is_within(start, end))
+        return -1;
+
+    do {
+        image_map[start / image_chunk_size] = 'x';
+        start += image_chunk_size;
+    } while (start < end);
+
+    return 0;
+}
+
+int target_type_set(uint16 code)
+{
+    // If there is an override from the command-line, use that
+    if (arg_target_type != 0)
+        code = arg_target_type;
+
+    switch (code)
+    {
+    case 'h': // Hercules
+    case 'u': // Ulysses
+    case '3': // Chipset 3
+    case CHIP_ID_ULYSSES_0:
+    case CHIP_ID_ULYSSES_A:
+    case CHIP_ID_HERCULES_A:
+    case CHIP_ID_HERCULES_B:
+        target_type = 3;
+        break;
+
+    case 'c': // Calypso
+    case '4': // Chipset 4
+    // case 's': // Samson
+    case CHIP_ID_CALYPSO_A:
+    case CHIP_ID_CALYPSO_B:
+    case CHIP_ID_CALYPSO_C:
+        target_type = 4;
+        break;
+
+    case 'l':  // Calypso Lite
+    case CHIP_ID_CALYPSO_L:
+        target_type = 5;
+        break;
+
+    case 'p':  // Calypso Plus
+    case CHIP_ID_CALYPSO_PLUS:
+    case CHIP_ID_CALYPSO_PLUS_A:
+        target_type = 6;
+        break;
+
+    default:
+        target_type = 0;
+    }
+
+    return target_type;
+}
+
+int image_map_count_used_chunks(void)
+{
+    int used, i;
+
+    // For each image chunk
+    for (i = 0, used = 0; i < image_size_in_chunks; i++) {
+        if (image_map[i] == 'x')
+            used++;
+    }
+    return used;
+}
+
+// When the sector_map have been changed, we have to update the image_map
+// such that we don't attempt to program within sectors that are not going
+// to be programmed anyway (due to the erase override). We also have to
+// program chunks contained in sectors that *are* going to be erased, even
+// though the chunks have been check-summed ok.
+int image_map_update(void)
+{
+    struct sector_s *sectors = device->memmap->sectors;
+    int changed, chunks, i, j;
+    int map_index;
+
+    map_index = 0;
+    changed = 0;
+
+    // For each sector of the device definition...
+    for (i = 0; i < device->memmap->size; i++) {
+        chunks = sectors[i].size / image_chunk_size;
+        // For each image--map-chunk contained in current sector...
+        for (j = 0; j < chunks; j++) {
+            if (!(sector_map[i] == 'x' || sector_map[i] == 'X')  &&
+                 image_map[map_index + j] == 'x') {
+                image_map[map_index + j] = 's'; // skip
+                changed++;
+            }
+            else if ((sector_map[i] == 'x' || sector_map[i] == 'X')
+                     && image_map[map_index + j] == 'c') {
+                image_map[map_index + j] = 'x'; // include!
+                changed++;
+            }
+        }
+        map_index += chunks;
+    }
+    return changed;
+}
+
+int sector_map_init(void)
+{
+    struct sector_s *sectors = device->memmap->sectors;
+    int map_index;
+    int used_list_index;
+    int used, chunks, i, j;
+
+    sector_map_size = SECTOR_MAP_SIZE_MAX;
+
+    memset(sector_map, 0, sector_map_size);
+
+    // Generate the sector_map from the image_map
+    map_index = 0;
+
+    // For each sector of the device definition...
+    for (i = 0; i < device->memmap->size; i++) {
+
+        chunks = sectors[i].size / image_chunk_size;
+
+        // For each image-usage-map-chunk contained in current sector...
+        for (j = 0, used = 0; j < chunks; j++)
+            if (image_map[map_index + j] == 'x')
+                used++;
+
+        sector_map[i] = (used ? 'x' : 0);
+        map_index += chunks;
+    }
+
+    parse_arg_erase_override(arg_erase_override);
+
+    // Generate the erase_list
+    // For each sector of the device definition...
+    used_list_index = 0;
+    for (i = 0; i < device->memmap->size; i++) {
+        if (sector_map[i] == 'x' || sector_map[i] == 'X')
+            erase_list[used_list_index++] = sectors[i].addr;
+    }
+
+    if (arg_sector_map_show)
+        sector_map_show();
+
+    if (arg_sector_list_show) {
+        flowf(ALWAYS, "sector used list: ");
+        for (i = 0; i < used_list_index; i++)
+            flowf(ALWAYS, "0x%06X ", erase_list[i]);
+        putchar('\n');
+    }
+
+    return used_list_index;
+}
+
+int parse_range(char *p, char **p_end, int *n1, int *n2)
+{
+    char *my_end;
+    int read_offset_calp = (*arg_read != 0 && target[target_type].type == 'P');
+
+    *n2 = 0;
+
+    *n1 = strtol(p, &my_end, 0);
+    if (p == my_end)
+        return 0; // error: no chars converted
+
+    if (*my_end == 'k' || *my_end == 'K') {
+        *n1 <<= 10;
+        if (read_offset_calp) *n1 += CALP_OFFSET;
+        my_end++;
+    }
+    else if (*my_end == 'M') {
+        *n1 <<= 20;
+        if (read_offset_calp) *n1 += CALP_OFFSET;
+        my_end++;
+    }
+
+    *p_end = my_end;
+    if (my_end[0] != '.' || my_end[1] != '.')
+        return 1;
+    p = my_end + 2;
+
+    *n2 = strtol(p, &my_end, 0);
+    if (p == my_end)
+        return 0; // error: no chars converted
+
+    if (*my_end == 'k' || *my_end == 'K') {
+        *n2 <<= 10;
+        if (read_offset_calp) *n2 += CALP_OFFSET;
+        my_end++;
+    }
+    else if (*my_end == 'M') {
+        *n2 <<= 20;
+        if (read_offset_calp) *n2 += CALP_OFFSET;
+        my_end++;
+    }
+
+    *p_end = my_end;
+    return 2;
+}
+
+// Parse and decode the erase override command line option string. The
+// sector_map is updated accordingly.
+void parse_arg_erase_override(char *p)
+{
+    struct sector_s *sectors = device->memmap->sectors;
+    int sector_bottom, sector_top;
+    int changed, i;
+
+    tr(TrBegin| TrArgParser, "erase_override:\n");
+    while (*p)
+    {
+        char *p_end;
+        int num, sign, n1 = 0, n2 = 0;
+
+        if (*p != '-' && *p != '+')
+            main_error(E_ERASE_SPEC);
+
+        sign = (*p == '-' ? -1 : +1);
+        p++;
+
+        if (*p == '*') {
+            sign = sign * 2;
+            p++;
+        }
+        else {
+            num = parse_range(p, &p_end, &n1, &n2);
+            if (num == 0)
+                main_error(E_ERASE_SPEC);
+            p = p_end;
+        }
+
+        switch (sign) {
+        case -1:
+        case +1:
+            if (num == 1) {
+                // Support for absolute addresses on Calypso Plus
+                if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET;
+
+                if (n1 > sector_map_size) {
+                    // For all sectors...
+                    for (i = 0; i < device->memmap->size; i++) {
+                        sector_bottom = sectors[i].addr;
+                        sector_top    = sector_bottom + sectors[i].size - 1;
+
+                        if (n1 >= sector_bottom && n1 < sector_top) {
+                            sector_map[i] = (sign > 0 ? 'X' : 's');
+                            break;
+                        }
+                    }
+                }
+                else
+                    sector_map[n1] = (sign > 0 ? 'X' : 's');
+                tr(TrArgParser, "%c%d\n", sign > 0 ? '+' : '-', n1);
+            }
+            else {
+                // Support for absolute addresses on Calypso Plus
+                if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) {
+                    n1 -= CALP_OFFSET;
+                    n2 -= CALP_OFFSET;
+                }
+
+                if (n1 > sector_map_size || n2 > sector_map_size) {
+                    // n1 and n2 must respresent an address range
+                    if (n1 >= n2)
+                        main_error(E_ERASE_SPEC);
+
+                    // For all sectors...
+                    for (i = 0; i < device->memmap->size; i++)
+                    {
+                        sector_bottom = sectors[i].addr;
+                        sector_top    = sector_bottom + sectors[i].size - 1;
+
+                        // If either sector bottom or top is contained in
+                        // [n1..n2[
+                        if ((n1 <= sector_bottom && sector_bottom < n2) ||
+                            (n1 <= sector_top    && sector_top    < n2)) {
+                            sector_map[i] = (sign > 0 ? 'X' : 's');
+                        }
+                    }
+                }
+                else {
+                    // n1 and n2 must respresent a sector range
+                    for (i = n1; i < n2; i++)
+                        sector_map[i] = (sign > 0 ? 'X' : 's');
+                }
+                tr(TrArgParser,
+                   "%c%d..%d\n", sign > 0 ? '+' : '-', n1, n2);
+            }
+            break;
+        case -2:
+        case +2:
+            // Fill whole sector_map...
+            for (i = 0; i < device->memmap->size; i++)
+                sector_map[i] = (sign > 0 ? 'X' : 's');
+            tr(TrArgParser, "%c*\n", sign > 0 ? '+' : '-');
+            break;
+        }
+        // skip optional comma
+        if (*p == ',')
+            p++;
+    }
+    tr(TrEnd| TrArgParser, "");
+
+    changed = image_map_update();
+
+    // If image map was changed, we trace it again.
+    if (changed && arg_image_map_show)
+        image_map_show();
+}
+
+void parse_arg_read(char *p)
+{
+    read_total_size = 0;
+    read_list_size  = 0;
+
+    tr(TrArgParser, "parse_arg_read() {\n");
+    while (*p)
+    {
+        char *p_end;
+        int num, n1, n2;
+
+        if (*p == '*') {
+            n1 = 0;
+            n2 = 0x1000000; // sufficiently large (16MB)
+            p++;
+        }
+        else {
+            num = parse_range(p, &p_end, &n1, &n2);
+            tr(TrArgParser, "parse_range('%s', ...)\n"
+               "    { #%d, p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n",
+               p, read_list_size, p_end, n1, n2, num);
+            if (num != 2 || n1 > n2)
+                main_error(E_ADDR_RANGE);
+            p = p_end;
+        }
+        read_list[read_list_size].addr = n1;
+        read_list[read_list_size].size = n2 - n1;
+        read_total_size += n2 - n1;
+        read_list_size++;
+        if (read_list_size >= READ_LIST_SIZE_MAX)
+            main_error(E_ARG_TOOMANY);
+
+        if (*p == 0)
+            break;
+
+        if (*p == ',')
+            p++;
+        else
+            main_error(E_READ_SPEC);
+    }
+    // Terminate the read_list with zeroes.
+    read_list[read_list_size].addr = 0;
+    read_list[read_list_size].size = 0;
+
+    tr(TrArgParser, "}\n");
+}
+
+void parse_arg_write(char *p)
+{
+    tr(TrArgParser, "parse_arg_write() {\n");
+
+    while (*p)
+    {
+        char bytes[1024];
+        char *p_end;
+        int num, n1, n2;
+        int index, value, size, i;
+
+        num = parse_range(p, &p_end, &n1, &n2);
+        tr(TrArgParser, "parse_range('%s', ...)\n"
+           "    { p_end = '%s', n1 = 0x%x, n2 = 0x%x } %d\n",
+           p, p_end, n1, n2, num);
+
+        if (num < 1 || num > 2)
+            main_error(E_ADDR_RANGE);
+
+        p = p_end;
+
+        if (*p++ != '=')
+            main_error(E_WRITE_SPEC);
+
+        tr(TrArgParser, "    { ");
+        if (*p == 0)
+            main_error(E_WRITE_SPEC);
+
+        index = 0;
+        while (*p) {
+            if (*p == '\"') {
+                // Collect text string
+                p++;
+                tr(TrCont|TrArgParser, "'");
+                while (*p) {
+                    if (*p == '\"')
+                        break;
+                    if (p[0] == '\\' && p[1] == '\"')
+                        p++; // skip leading backslash
+                    if (p[0] == '\\' && p[1] == '\\')
+                        p++; // skip leading backslash
+                    tr(TrCont|TrArgParser, "%c", *p);
+                    bytes[index] = *p++;
+                    if (index++ >= sizeof(bytes))
+                        main_error(E_WRITE_SPEC);
+                }
+                if (*p++ != '\"')
+                    main_error(E_WRITE_SPEC);
+                tr(TrCont|TrArgParser, "' ");
+            }
+            else {
+                // Collect byte string
+                value = strtol(p, &p_end, 0);
+                if (p == p_end)
+                    main_error(E_WRITE_SPEC);
+                if (value < 0 || 255 < value)
+                    main_error(E_WRITE_SPEC);
+                bytes[index] = value;
+                if (index++ >= sizeof(bytes))
+                    main_error(E_WRITE_SPEC);
+                p = p_end;
+
+                tr(TrCont|TrArgParser, "0x%x ", value);
+            }
+            if (*p == ':' || *p == 0)
+                break;
+            if (*p == ',')
+                p++;
+        }
+        size = index;
+        tr(TrArgParser, "} %d\n", size);
+
+        if (num == 1) {
+            // Support for absolute addresses on Calypso Plus
+            if (n1 >= CALP_OFFSET) n1 -= CALP_OFFSET;
+
+            n2 = n1 + size;
+        }
+        else if (n1 >= CALP_OFFSET && n2 >= CALP_OFFSET) {
+            n1 -= CALP_OFFSET;
+            n2 -= CALP_OFFSET;
+        }
+
+        if (image_map_set(n1, n2) < 0)
+            main_error(E_ADDR_RANGE);
+
+        index = 0;
+        for (i = n1; i < n2; i++) {
+            image[i] = bytes[index++];
+            if (index >= size)
+                index = 0;
+        }
+        if (*p == ':')
+            p++;
+    }
+    tr(TrArgParser, "}\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/misc.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,253 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Miscellaneous Utility Functions
+ *
+ * $Id: misc.c 1.14 Fri, 11 Oct 2002 08:40:21 +0200 mmj $
+ *
+ ******************************************************************************/
+
+#include "misc.h"
+#include "fluid.h"
+#include "trace.h"
+
+#include <stdio.h>
+#include <time.h>
+
+#if defined(MSC) || defined(BCC)
+#include "windows.h"
+#endif
+
+
+/******************************************************************************
+ * File And Path Name Functions
+ ******************************************************************************/
+
+// Return the length of the directory name preceding the leafname. The
+// terminating slash is included in the length. Length can be zero, if there
+// is no dirname.
+int dirname_len(const char *pathname)
+{
+    char *p;
+    int len;
+
+    tr(TrUtility, "dirname_len('%s')\n", pathname);
+
+    if ((len = strlen(pathname)) == 0)
+        return 0;
+    
+    p = (char *) (pathname + len - 1);
+
+    tr(TrUtility, "{ %d }\n", len);
+
+    while (*p != '/' && *p != '\\' && len-- > 1)
+        p--;
+
+    return len;
+}
+
+// Construct a full pathname from <dirname> and <leafname>. The full
+// pathname is copied in the buffer <buf> of size <size>. On success, the
+// full length of the pathname is returned. Otherwise, if the buffer is too
+// small, -1 is returned. NOTE: The <dirname> is supposed to end with a
+// slash. If not, the leafname part (if present) of the <dirname> will be
+// removed.
+int pathname_make(char *buf, int size, const char *dirname, const char *leafname)
+{
+    int dir_len, leaf_len, result;
+
+    tr(TrBegin|TrUtility, "pathname_make(*, %d, '%s', '%s') {\n",
+       size, dirname, leafname);
+
+    dir_len = dirname_len(dirname);
+    leaf_len = strlen(leafname);
+
+    if (dir_len > size - leaf_len - 1)
+        result = E_BUFFER;
+    else {
+        memcpy(buf, dirname, dir_len);
+        strcpy(buf + dir_len, leafname);
+        result = dir_len + leaf_len;
+    }
+
+    tr(TrEnd|TrUtility, "} %d\n", result);
+
+    return result;
+}
+
+
+/******************************************************************************
+ * Utility Funcions
+ ******************************************************************************/
+
+// Return the base 2 logarithm of <number>. Return -1 if <number> is zero.
+unsigned int log2(unsigned int number)
+{
+    int result = -1;
+
+    while (number > 0) {
+        number >>= 1;
+        result++;
+    }
+    return result;
+}
+
+
+/******************************************************************************
+ * Progress and Timer Functions
+ ******************************************************************************/
+
+static int  progress_mul;
+static int  progress_index;
+static char progress_string[35] = "(---------------------------------)";
+static char progress_backup[33] =
+"\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b\b\b";
+
+void progress_begin(int n)
+{
+    tr(TrUtility, "progress_begin(%d)\n", n); 
+
+    progress_index = 0;
+
+    switch (arg_progress) {
+    case 'a':
+        // We select a progress multiplier that is a power of two. Then we
+        // generate a progress indicator that is in the range [16..32[ chars
+        // in length.
+        progress_mul = n / 32;
+        progress_mul = 1 << (log2(progress_mul) + 1);
+        n = (n + progress_mul - 1) / progress_mul;
+
+        progress_string[1 + n]     = ')';
+        progress_string[1 + n + 1] = 0;
+        
+        flowf(NORMAL, "%s\b%s",
+                     progress_string, &progress_backup[32 - n]);
+        break;
+    case 'c':
+        break;
+    case 'd':
+        break;
+    }
+}
+
+void progress_update_simple(int n)
+{
+    tr(TrUtility, "progress_update_simple(%d)\n", n);
+
+    switch (arg_progress) {
+    case 'c':
+        flowf(NORMAL, "%c", n);
+        break;
+    }
+}
+
+void progress_update(int n)
+{
+    char ch;
+
+    tr(TrUtility, "progress_update(%d)\n", n);
+
+    switch (arg_progress) {
+    case 'a':
+        if (n / progress_mul > progress_index) {
+            progress_index++;
+            flowf(NORMAL, "*");
+        }
+
+        n = n % progress_mul;
+        ch = n + (n <= 9 ? '0' : 'A' - 10);
+        flowf(NORMAL, "%c\b", ch);
+        break;
+    case 'c':
+        break;
+    case 'd':
+        flowf(NORMAL, ".");
+        break;
+    }
+}
+
+void progress_end(int n)
+{
+    switch (arg_progress) {
+    case 'a':
+        if (n % progress_mul)
+            flowf(NORMAL, "*) ");
+        else
+            flowf(NORMAL, ") ");
+        break;
+    case 'c':
+    case 'd':
+        flowf(NORMAL, " ");
+        break;
+    }
+}
+
+int stopwatch_start(void)
+{
+#if defined(MSC) || defined(BCC)
+    return GetTickCount();
+#else
+    return 1000 * time(NULL);
+#endif
+}
+
+int stopwatch_stop(int time_start)
+{
+#if defined(MSC) || defined(BCC)
+    return GetTickCount() - time_start;
+#else
+    return 1000 * (time(NULL) - time_start);
+#endif
+}
+
+
+/******************************************************************************
+ * Hexdumping
+ ******************************************************************************/
+
+void hexdump(unsigned char *buf, int size, unsigned int addr, int unitsize)
+{
+    int n, i;
+    char string[(8+1+1) + (1+16+1+1) + (3*16) + 1];
+    char *s;
+
+    while (size > 0)
+    {
+        s = string;
+        s += sprintf(s, "%8x ", addr); // print offset
+
+        n = (size > 16 ? 16 : size);
+
+        // print the textual representation
+        for (i = 0; i < n; i++) {
+            if (buf[i] >= ' ' && buf[i] < 127)
+                *s++ = buf[i];
+            else
+                *s++ = '.';
+        }
+        // pad textual representation with spaces
+        for (i = 0; i < 16 - n; i++) {
+            *s++ = ' ';
+        }
+        *s++ = ' ';
+
+        // print hexedecimal representation
+        for (i = 0; i < n; i += unitsize) {
+            switch (unitsize) {
+            case 1: s += sprintf(s, "%02x ", *(uint8  *) (buf+i)); break;
+            case 2: s += sprintf(s, "%04x ", *(uint16 *) (buf+i)); break;
+            case 4:
+                s += sprintf(s, "%08x ", (int) (*(uint32 *) (buf+i)));
+                break;
+            }
+        }
+        buf += 16;
+        addr += 16;
+        size -= 16;
+        puts(string);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/misc.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,24 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Miscellaneous Utility Functions
+ *
+ * $Id: misc.h 1.4 Tue, 15 Jan 2002 15:19:31 +0100 mmj $
+ *
+ ******************************************************************************/
+
+int dirname_len(const char *pathname);
+int pathname_make(char *buf, int size, const char *dirname, const char *leafname);
+
+void progress_begin(int n);
+void progress_update_simple(int n);
+void progress_update(int n);
+void progress_end(int n);
+
+int stopwatch_start(void);
+int stopwatch_stop(int time_start);
+
+void hexdump(unsigned char *buf, int size, unsigned int address, int unitsize);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/protocol.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * (C) Delta Technologies 2001.
+ * Cleanup, modifications and extensions by Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Target/PC protocol definition
+ *
+ * $Id: protocol.h 1.21 Mon, 28 Apr 2003 08:49:16 +0200 tsj $
+ *
+ ******************************************************************************/
+
+
+enum ProtocolChars {
+    PROTO_HELLO         = 'H',
+    PROTO_BAUDRATE      = 'B',
+    PROTO_BAUDRATE_XXO  = 'X',
+    PROTO_INIT          = 'N',
+    PROTO_QUERY         = 'Q',
+    PROTO_QUERY_CHIP    = 'C',
+    PROTO_READY         = 'R',
+    PROTO_ISEMPTY       = 'I',
+    PROTO_DOWNLOAD      = 'L',
+    PROTO_DETECT        = 'D',
+    PROTO_ERASE         = 'E',
+    PROTO_COMPRESS      = 'Z',
+    PROTO_PROGRAM       = 'P',
+    PROTO_CKSUM         = 'C',
+    PROTO_READ          = 'R',
+    PROTO_RESET         = '0',
+    PROTO_CHECKSUM      = 'C',
+    PROTO_VERSION       = 'V',
+    PROTO_TIMERS        = 'T',
+    PROTO_FLASH_START   = '[',
+    PROTO_FLASH_END     = ']',
+    PROTO_IMEI_PROTECT  = 'I',
+
+    PROTO_ERROR               = '?',
+    PROTO_ERROR_INVALID       = '!', // Invalid command parameter
+    PROTO_ERROR_CKSUM         = 'X',
+    PROTO_ERROR_MEMORY        = 'M',
+    PROTO_ERROR_VERIFY        = 'D',
+    PROTO_ERROR_FLASH_TIMEOUT = 'T',
+    PROTO_ERROR_FLASH_COMMAND = 'C',
+    PROTO_ERROR_FLASH_VPP     = 'V',
+    PROTO_ERROR_FLASH_LOCKED  = 'L',
+    PROTO_ERROR_FLASH_UNKNOWN = 'F',
+    PROTO_ERROR_HARDWARE      = 'H',
+    PROTO_ERROR_FIFO_OVERFLOW = 'O',
+    PROTO_ERROR_ROM_SSERVICE  = 'S',
+
+    PROTO_IS_ERASING    = 'I', // Not a real protocol char - for internal use
+
+    PROTO_TRACE         = '$'
+};
+
+
+
+// Not really part of the protocol but as this header file is included by
+// both PC side and target side source code, this is an easy place to put
+// these difinitions.
+enum ChipIdCodes {
+    // Ulysses and Hercules
+    CHIP_ID_ULYSSES_0  = 0xB2B5,
+    CHIP_ID_ULYSSES_A  = 0xB335,
+    CHIP_ID_HERCULES_A = 0xB334, // Correct revision designation?
+    CHIP_ID_HERCULES_B = 0xB32C, // Correct revision designation?
+
+    // Samson and Calypso
+    CHIP_ID_CALYPSO_A  = 0xB2AC,
+    CHIP_ID_CALYPSO_B  = 0xB396,
+    CHIP_ID_CALYPSO_C  = 0xB496,
+    CHIP_ID_CALYPSO_L  = 0xB4FB,
+
+    CHIP_ID_CALYPSO_PLUS   = 0xB512,
+    CHIP_ID_CALYPSO_PLUS_A = 0xB608
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/serial.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,334 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Serial/UART driver
+ *
+ * $Id: serial.c 1.23 Fri, 18 Oct 2002 08:53:12 +0200 mmj $
+ *
+ ******************************************************************************/
+
+#include "fluid.h"
+#include "serial.h"
+#include "trace.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#if defined(MSC) || defined(BCC)
+  #include <windows.h> // for Sleep()
+#else
+//  #error Not compiling for MSC or BCC?
+#endif
+
+
+extern void target_recv_push(char *buf, int size);
+
+
+/******************************************************************************
+ * OS Independent
+ ******************************************************************************/
+
+static void serial_listener(void);
+
+#if (OS == WIN32)
+
+/******************************************************************************
+ * Win32 Driver
+ ******************************************************************************/
+
+#include <windows.h>
+
+static HANDLE     hCom;
+static HANDLE     thread_handle = NULL;
+static DWORD      thread_id;
+static OVERLAPPED read_overlapped;
+static OVERLAPPED write_overlapped;
+static DCB        dcb;
+
+const char PORT_NAME_PRE[] = "COM";
+// A special syntax is required when accessing com ports greater than 9, e.g., "\\.\COM10"
+const char PORT_NAME_PREFIX[] = "\\\\.\\COM";
+
+int serial_init(int uart, int bps, char *flowcontrol)
+{
+    int error;
+    COMMTIMEOUTS timeouts;
+    char pc_comport[32];
+
+    sprintf(pc_comport, "%s%d", PORT_NAME_PREFIX, uart);
+
+    hCom = CreateFile(pc_comport,
+                      GENERIC_READ | GENERIC_WRITE,
+                      0,    // comm devices must be opened w/exclusive-access
+                      NULL, // no security attributes
+                      OPEN_EXISTING, // comm devices must use OPEN_EXISTING
+                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+                      NULL  // hTemplate must be NULL for comm devices
+        );
+    if (hCom == INVALID_HANDLE_VALUE)
+        return E_OS + E_UART_INIT;
+
+    // We will build on the current configuration, and skip setting the size
+    // of the input and output buffers with SetupComm.
+    if (!GetCommState(hCom, &dcb))
+        return E_OS + E_UART_INIT;
+
+    dcb.fAbortOnError = FALSE; // Hmm? (Dont't remember exactly what this is)
+    dcb.ByteSize = 8;          // Data size, xmit, and rcv
+    dcb.Parity = NOPARITY;     // No parity bit
+    dcb.StopBits = ONESTOPBIT; // One stop bit
+    dcb.fOutxCtsFlow = 0;      // Disable CTS HW handshaking!
+    dcb.fOutxDsrFlow = 0;      // Disable DSR HW handshaking!
+    dcb.fDsrSensitivity = 0;   // Disable DSR HW handshaking!
+
+    // Note the DTR = +12V and RTS = -12V is needed to power the serial
+    // level converter!
+
+    switch (flowcontrol[0]) {
+    case 'n': dcb.fDtrControl = DTR_CONTROL_DISABLE; break;
+    case 'h': dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; break;
+    case 'p':
+    default:
+        dcb.fDtrControl = DTR_CONTROL_ENABLE; break;
+    }
+    switch (flowcontrol[1]) {
+    case 'p': dcb.fRtsControl = RTS_CONTROL_ENABLE; break;
+    case 'h': dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; break;
+    case 'n':
+    default:
+        dcb.fRtsControl = RTS_CONTROL_DISABLE; break;
+    }
+
+    if (!SetCommState(hCom, &dcb))
+        return E_OS + E_UART_INIT;
+
+    if ((error = serial_baudrate_set(bps)) < 0)
+        return error;
+
+    timeouts.ReadIntervalTimeout = 0;
+    timeouts.ReadTotalTimeoutMultiplier = 0;
+    timeouts.ReadTotalTimeoutConstant = 0;
+    timeouts.WriteTotalTimeoutMultiplier = 0;
+    timeouts.WriteTotalTimeoutConstant = 0;
+
+    assert(SetCommTimeouts (hCom, &timeouts));
+    assert(SetCommMask (hCom, EV_RXCHAR));
+    //assert(SetupComm (hCom, INPUT_BUFFER_SIZE, OUTPUT_BUFFER_SIZE));
+
+    sprintf(pc_comport, "read%s%d", PORT_NAME_PRE, uart);
+    read_overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, pc_comport);
+
+    sprintf(pc_comport, "write%s%d", PORT_NAME_PRE, uart);
+    write_overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, pc_comport);
+
+    thread_handle =
+        CreateThread (NULL,
+                      0,
+                      (LPTHREAD_START_ROUTINE) serial_listener,
+                      NULL,
+                      0,
+                      &thread_id);
+
+    if (thread_handle == NULL)
+        return E_OS + E_UART_INIT;
+
+    serial_reset();
+
+    return 0;
+}
+
+int serial_is_baudrate(int bps)
+{
+    int i;
+    const struct rate_s {
+        int bps;
+        int baudrate;
+    } rates[] = {
+        {   9600,   9600 }, {   9,      9600 },
+        {  14400,  14400 }, {  14,     14400 },
+        {  19200,  19200 }, {  19,     19200 },
+        {  38400,  38400 }, {  38,     38400 },
+        {  57600,  57600 }, {  57,     57600 },
+        { 115200, 115200 }, { 115,    115200 },
+        { 203125, 203125 }, { 203,    203125 }, // 13MHz clock
+        { 230400, 230400 }, { 230,    230400 },
+        { 406250, 406250 }, { 406,    406250 }, // 13MHz clock
+        { 460800, 460800 }, { 460,    460800 },
+        { 812500, 812500 }, { 812,    812500 }, // 13MHz clock
+        { 921600, 921600 }, { 921,    921600 },
+        {      0,      0 } // terminator
+    };
+
+    for (i = 0; i < sizeof(rates) / sizeof(struct rate_s) - 1; i++)
+        if (rates[i].bps == bps)
+            break;
+
+    tr(TrTargetDrv, "serial_is_baudrate(%d) %d\n", bps, rates[i].baudrate);
+
+    return rates[i].baudrate;
+}
+
+int serial_baudrate_set(int bps)
+{
+#if 0
+    if (!GetCommState(hCom, &dcb))
+        return E_OS + E_UART_PARAM;
+#endif
+
+    bps = serial_is_baudrate(bps);
+    if (bps == 0)
+        return E_OS + E_UART_PARAM;
+
+    /* Replace 812K with 827K. Otherwise, the chip will automatically select 800K. */ 
+    /* 800K is OK, but we might as well gain the extra 3% speed :-) */
+    if (bps == 812500)
+        dcb.BaudRate = 827586;
+    else
+        dcb.BaudRate = bps;
+
+    if (!SetCommState(hCom, &dcb))
+        return E_OS + E_UART_PARAM;
+
+    return bps;
+}
+
+int serial_baudrate_get(void)
+{
+    return dcb.BaudRate;
+}
+
+void serial_exit(void)
+{
+    DWORD exit_code;
+
+    serial_reset();
+
+    (void) GetExitCodeThread (thread_handle, &exit_code);
+    (void) TerminateThread (thread_handle, exit_code);
+
+    (void) CloseHandle (hCom);
+    (void) CloseHandle (read_overlapped.hEvent);
+    (void) CloseHandle (write_overlapped.hEvent);
+}
+
+// Clear buffers and transactions.
+void serial_reset(void)
+{
+    PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
+}
+
+// Return the number of milli-seconds it takes to transfer <n> bytes.
+int serial_transfer_time(int size)
+{
+    return 1000 * 10 * size / serial_baudrate_get();
+}
+
+
+/***************************************
+ * Send
+ ***************************************/
+
+int serial_send(char *buf, int size)
+{
+    DWORD written;
+
+    ResetEvent(write_overlapped.hEvent); // why?
+
+    if (!WriteFile(hCom, buf, size, &written, &write_overlapped)) {
+        if (GetLastError() == ERROR_IO_PENDING) {
+            if (GetOverlappedResult(hCom, &write_overlapped,
+                                    &written, TRUE) == FALSE)
+                written = E_OS + E_UART_DRV_SEND;
+        }
+    }
+
+    return written;
+}
+
+
+/***************************************
+ * Receive
+ ***************************************/
+
+void serial_recv_reset(void)
+{
+    PurgeComm(hCom, PURGE_RXABORT|PURGE_RXCLEAR);
+}
+
+static void serial_listener(void)
+{
+    DWORD event_mask;
+    char buf[64];
+    DWORD size;
+
+    while (1)
+    {
+        // Wait the event signalling characters received.
+        if (WaitCommEvent (hCom, &event_mask, NULL) != TRUE) {
+            main_msg("WaitCommEvent(): error %d\n", GetLastError());
+            return;
+        }
+        tr(TrTargetDrv, "|");
+
+        // Read all characters received in the buffer.  Mysteriously, it
+        // does NOT work with a buffer size greater than one!
+        do {
+            if (!ReadFile(hCom, buf, 1, &size, &read_overlapped))
+            {
+                if (GetLastError() == ERROR_IO_PENDING) {
+                    GetOverlappedResult(hCom, &read_overlapped, &size, TRUE);
+                }
+                else {
+                    main_msg("ReadFile(): error %d\n", GetLastError());
+                    serial_recv_reset();
+                    break;
+                }
+            }
+            // Push the data to upper layer
+            target_recv_push(buf, size);
+
+        } while (size);
+    }
+}
+
+
+/******************************************************************************
+ * Control of Delta cable special outputs
+ ******************************************************************************/
+
+void serial_rts(char state)
+{
+    if (state)
+        EscapeCommFunction(hCom, SETRTS);
+    else
+        EscapeCommFunction(hCom, CLRRTS);
+}
+
+void serial_dtr(char state)
+{
+    if (state)
+        EscapeCommFunction(hCom, SETDTR);
+    else
+        EscapeCommFunction(hCom, CLRDTR);
+}
+
+void serial_break(char state)
+{
+    if (state)
+        SetCommBreak(hCom);
+    else
+        ClearCommBreak(hCom);
+}
+
+#else // (OS == WIN32)
+
+
+/******************************************************************************
+ * Unix driver
+ ******************************************************************************/
+
+
+#endif // (OS == WIN32)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/serial.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Serial/UART driver
+ *
+ * $Id: serial.h 1.8 Wed, 04 Sep 2002 16:32:18 +0200 mmj $
+ *
+ ******************************************************************************/
+
+int serial_init(int uart, int baudrate, char *flowcontrol);
+int serial_is_baudrate(int bps);
+int serial_baudrate_set(int baudrate);
+int serial_baudrate_get(void);
+void serial_exit(void);
+void serial_reset(void);
+
+int serial_transfer_time(int size);
+
+int serial_send(char *buf, int size);
+int serial_putchar(unsigned char ch);
+int serial_recv(char *buf, int size);
+void serial_recv_reset(void);
+
+void serial_rts(char state);
+void serial_dtr(char state);
+void serial_break(char state);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/target.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,425 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Target Connection and Control
+ *
+ * $Id: target.c 1.20 Mon, 21 Oct 2002 18:39:13 +0200 mmj $
+ *
+ ******************************************************************************/
+
+#include "serial.h"
+#include "fluid.h"
+#include "trace.h"
+
+#include <stdio.h>
+
+#if defined(MSC) || defined(BCC)
+  #include "windows.h"
+#endif
+
+int target_trace(unsigned char ch);
+
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+
+HANDLE hEvent;
+
+#define RECVBUF_SIZE  (65536)
+
+static unsigned char recvbuf[RECVBUF_SIZE];
+static int recvbuf_size_target;
+static int recvbuf_put;
+static int recvbuf_get;
+
+#define recvbuf_size() (recvbuf_put - recvbuf_get + \
+                        ((recvbuf_put - recvbuf_get) < 0 ? RECVBUF_SIZE : 0))
+
+
+/******************************************************************************
+ * Error Functions
+ ******************************************************************************/
+
+void error_proto(char ch, char chx)
+{
+    char chd, chxd;
+
+    chd  = (' ' <= ch  && ch  < 127 ? ch  : '.');
+    chxd = (' ' <= chx && chx < 127 ? chx : '.');
+
+    flowf(NORMAL, "(protocol error: got '%c' 0x%02X, expected '%c' 0x%02X)\n",
+                 chd, ch, chxd, chx);
+
+    main_fatal(E_PROTO_ERROR);
+}
+
+
+/******************************************************************************
+ * Target Dependencies
+ ******************************************************************************/
+
+// <clk> is the target's clock frequency 
+int target_uart_baudrate_divider_get(int clk, int bps)
+{
+    int divider = clk / bps / 16;
+
+    tr(TrTargetDrv, "target_uart_baudrate_divider_get(%d, %d) %d\n",
+       clk, bps, divider);
+
+    return divider;
+}
+
+
+/******************************************************************************
+ * Target Init and Send
+ ******************************************************************************/
+
+static int target_trace_timer;
+
+void target_recv_reset(void)
+{
+    tr(TrTargetDrv, "recv_reset()\n");
+
+    recvbuf_get = recvbuf_put = 0;
+
+    memset(recvbuf, 0x77, RECVBUF_SIZE);
+
+    serial_recv_reset();
+}
+
+int target_driver_init(int uart, int baudrate, char *flowcontrol)
+{
+    int error;
+
+    target_recv_reset();
+
+    hEvent = CreateEvent(NULL,  // lpEventAttributes
+                         FALSE, // bManualReset (OFF)
+                         FALSE, // bInitialstate (OFF)
+                         NULL); // lpName
+
+    if (hEvent == NULL) {
+        error = E_DRIVER_INIT + E_OS;
+    }
+    else {
+        error = serial_init(uart, baudrate, flowcontrol);
+    }
+    return error;
+}
+
+int target_driver_baudrate(int baudrate)
+{
+    return serial_baudrate_set(baudrate);
+}
+    
+int target_putchar(char ch)
+{
+    char trch;
+
+    trch = (ch < ' ' || ch == 127 ? '.' : ch);
+    tr(TrPutChar, "s '%c'/0x%02X\n", trch, ch & 0xFF);
+
+    return serial_send(&ch, 1);
+}
+
+int target_send(char *buf, int size)
+{
+    tr(TrPutChar, "s (%d bytes)\n", size);
+
+    return serial_send(buf, size);
+}
+
+
+/******************************************************************************
+ * Target Wait and Receive
+ ******************************************************************************/
+
+void target_recv_signal(void)
+{
+    // Notify waiting thread when we have received the requested number of
+    // bytes. Note that we use auto-resetting events, so you have to be VERY
+    // careful to wait for the exact number of bytes you want. Otherwise you
+    // might trigger the event twice in quick succession and this will
+    // result in the next call of target_wait()'s to return immediately
+    // without waiting!
+
+    if (recvbuf_size() >= recvbuf_size_target && recvbuf_size_target > 0) {
+        // When we have triggered the event, disable further triggering
+        // until next call of target_wait()
+        recvbuf_size_target = 0;
+        tr(TrDriverGet, "!");
+        if (SetEvent(hEvent) == 0)
+            fprintf(stderr, "FATAL: recv_push_tm(): SetEvent() failed with Win32 error %d\n", GetLastError());
+    }
+}
+
+void target_recv_push(char *buf, int size)
+{
+    if (size == 0) {
+        tr(TrDriverGet, " G?");
+        return;
+    }
+
+    while (size--) {
+        recvbuf[recvbuf_put++] = *buf++;
+        recvbuf_put &= (RECVBUF_SIZE - 1);
+    }
+    tr(TrDriverGet, " G%d", recvbuf_size());
+
+    target_recv_signal();
+}
+
+// Wait maximum <timeout> milli-seconds for <size> bytes to arrive. If
+// <size> is zero, we unconditionally wait for <time_ms> milli-seconds
+// (quite simply a delay). The transfer time is automatically added to the
+// total waiting time.
+int target_wait(int size, int timeout)
+{
+    int result = 0;
+
+    tr(TrTargetWait, "target_wait(%d, %d)\n", size, timeout);
+
+    if (size > 0)
+        timeout += serial_transfer_time(size);
+
+    recvbuf_size_target = size;
+    target_trace_timer = timeout;
+
+    if (size == 0) {
+        Sleep(timeout);
+    }
+    else {
+        target_recv_signal();
+
+        switch (WaitForSingleObject(hEvent, timeout)) {
+        case WAIT_OBJECT_0: result = recvbuf_size(); break;
+        case WAIT_TIMEOUT:  result = E_RECV_TIMEOUT; break;
+        default:            result = E_OS + E_DRIVER_WAIT; break;
+        }
+    }
+    recvbuf_size_target = 0;
+
+    return result;
+}
+
+int target_recv(void *outbuf, int size)
+{
+    int i, bufsize;
+    char *buf = (char *) outbuf;
+
+    bufsize = recvbuf_size();
+    if (bufsize < size)
+        size = bufsize;
+
+    for (i = 0; i < size; i++) {
+        *buf++ = recvbuf[recvbuf_get++];
+        recvbuf_get &= (RECVBUF_SIZE - 1);
+    }
+
+    tr(TrGetChar, "r (%d bytes)\n", size);
+    return size;
+}
+
+int target_getchar(void)
+{
+    int trace_in_progress;
+    char ch;
+    
+    do {
+        ch = recvbuf[recvbuf_get++];
+        recvbuf_get &= (RECVBUF_SIZE - 1);
+        tr(TrGetChar, "r '%c' %02X\n",
+           (ch >= ' ' && ch <= 126 ? ch : '.'), ch & 0xFF);
+
+        if ((trace_in_progress = target_trace((char) ch)) != 0) {
+            if (target_wait(1, target_trace_timer) < 1)
+                main_fatal(E_RECV_TIMEOUT);
+        }
+    } while (trace_in_progress);
+    
+    return (ch & 0xFF);
+}
+
+int target_expect_char(char ch, int timeout)
+{
+    char mych;
+
+    if (target_wait(1, timeout) < 1) {
+        flowf(NORMAL, "(Waited for '%c' 0x%02X)\n", ch, ch);
+        main_fatal(E_RECV_TIMEOUT);
+    }
+
+    if ((mych = target_getchar()) != ch)
+        error_proto(mych, ch);
+
+    return ch;
+}
+
+
+/******************************************************************************
+ * Target Buffer Put
+ ******************************************************************************/
+
+int buf_put1(char *buf, unsigned char data)
+{
+    tr(TrPutChar, "buf_put1(0x%02X) '%c'\n", data, data);
+
+    *buf   = (data      ) & 0xFF;
+    return 1;
+}
+
+int buf_put2(char *buf, unsigned short data)
+{
+    tr(TrPutChar, "buf_put2(0x%04X)\n", data);
+
+    *buf++ = (data      ) & 0xFF;
+    *buf   = (data >>  8) & 0xFF;
+    return 2;
+}
+
+int buf_put4(char *buf, unsigned int data)
+{
+    tr(TrPutChar, "buf_put4(0x%08X)\n", data);
+
+    *buf++ = (data      ) & 0xFF;
+    *buf++ = (data >>  8) & 0xFF;
+    *buf++ = (data >> 16) & 0xFF;
+    *buf   = (data >> 24) & 0xFF;
+    return 4;
+}
+
+// Put 2-byte integer in network order
+int buf_put2no(char *buf, unsigned short data)
+{
+    tr(TrPutChar, "buf_put2no(0x%04X)\n", data);
+
+    *buf++ = (data >>  8) & 0xFF;
+    *buf   = (data      ) & 0xFF;
+    return 2;
+}
+
+// Put 4-byte integer in network order
+int buf_put4no(char *buf, unsigned int data)
+{
+    tr(TrPutChar, "buf_put4no(0x%08X)\n", data);
+
+    *buf++ = (data >> 24) & 0xFF;
+    *buf++ = (data >> 16) & 0xFF;
+    *buf++ = (data >>  8) & 0xFF;
+    *buf   = (data      ) & 0xFF;
+    return 4;
+}
+
+
+/******************************************************************************
+ * Special Target Control Functions
+ ******************************************************************************/
+
+// Control target power. Works *only* with special cable! If <state> is
+// non-zero, the power is on. Otherwise, it is off.
+void target_power(char state)
+{
+    if (arg_uart_level_convert)
+        return;
+
+    if (state) {
+        serial_rts(0);
+    }
+    else {
+        serial_rts(1);
+        serial_dtr(1);
+        serial_break(1);
+        serial_break(0);
+    }
+}
+
+// Control target reset line. Works *only* with special cable!  If <state>
+// is non-zero, the reset line is asserted. Otherwise, it is negated.
+void target_reset(char state)
+{
+    if (arg_uart_level_convert)
+        return;
+
+    if (state) {
+        serial_rts(1);
+        serial_dtr(0);
+        serial_rts(0);
+        serial_break(0);
+    }
+    else {
+        serial_break(1);
+        serial_rts(1);
+        serial_dtr(1);
+        serial_rts(0);
+    }
+}
+
+
+/******************************************************************************
+ * Target Trace/Debug Functions
+ ******************************************************************************/
+
+static int target_trace_enable_flag = 0;
+
+int target_trace_enable(int flag)
+{
+    int old = target_trace_enable_flag;
+
+    target_trace_enable_flag = flag;
+
+    if (arg_target_trace_enable)
+        flowf(DEBUG, "{%s}", (flag ? "enable" : "disable"));
+
+    return old;
+}
+
+// Interpret and display target trace message. Return zero if <ch> was not
+// intercepted. Otherwise, if it was intercepted, return non-zero.
+int target_trace(unsigned char ch)
+{
+    int i;
+    unsigned int number = 0;
+    char buf[80], *p;
+
+    // If target is not supposed to transmit any tracing at this point in
+    // the state machine(s), the flag will be zero and thus we return.
+    if (target_trace_enable_flag && ch == '$') {
+        if (target_wait(1, 100) < 0)
+            main_fatal(E_RECV_TIMEOUT);
+        ch = target_getchar();
+        switch (ch) {
+        case 'S':
+            p = buf;
+            while (ch != 0) {
+                if (target_wait(1, 100) < 0)
+                    main_fatal(E_RECV_TIMEOUT);
+                ch = target_getchar();
+                *p++ = ch;
+            }
+            *p = 0;
+            if (arg_target_trace_enable)
+                printf("{'%s'} ", buf);
+            break;
+        case 'N':
+            for (i = 0; i < 4; i++) {
+                if (target_wait(1, 100) < 0)
+                    main_fatal(E_RECV_TIMEOUT);
+                ch = target_getchar();
+                number = (number >> 8) + (ch << 24);
+            }
+            if (arg_target_trace_enable)
+                printf("{0x%X/%dd} ", number, number);
+            break;
+        default:
+            fprintf(stderr, "WARNING: Bad TargetTrace char received! (0x%X)\n",
+                    ch & 0xFF);
+            break;
+        }
+        return 1;
+    }
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/target.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * FLUID (Flash Loader Utility Independent of Device)
+ *
+ * Copyright Texas Instruments, 2001.
+ * Mads Meisner-Jensen, mmj@ti.com.
+ *
+ * Target Connection and Control
+ *
+ * $Id: target.h 1.8 Thu, 01 Aug 2002 11:17:20 +0200 mmj $
+ *
+ ******************************************************************************/
+
+
+int target_uart_baudrate_divider_get(int clk, int bps);
+
+int target_driver_init(int uart, int baudrate, char *flowcontrol);
+int target_driver_baudrate(int baudrate);
+
+int target_send(char *buf, int size);
+int target_putchar(char ch);
+
+int target_wait(int size, int time);
+int target_recv(void *buf, int size);
+int target_getchar(void);
+int target_expect_char(char ch, int time);
+void target_recv_reset(void);
+
+int buf_put1(char *buf, unsigned char);
+int buf_put2(char *buf, unsigned short data);
+int buf_put4(char *buf, unsigned int data);
+int buf_put2no(char *buf, unsigned short data);
+int buf_put4no(char *buf, unsigned int data);
+
+void error_proto(char ch, char chx);
+
+void target_power(char state);
+void target_reset(char state);
+
+int target_trace_enable(int flag);
+int target_trace(unsigned char ch);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/trace.c	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,134 @@
+/******************************************************************************
+ * Generic tracing library
+ *
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * $Id: trace.c 1.5 Fri, 11 Oct 2002 08:40:21 +0200 mmj $
+ *
+ ******************************************************************************/
+
+#include "trace.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+
+#define TRACE_MODS 2
+
+
+/******************************************************************************
+ * 
+ *****************************************************************************/
+
+static struct trace_s {
+    int spaces;    // number of spaces to indent per level
+    int level;     // current indentation level (private)
+    int enable;    // global trace enable/disable flag
+    FILE *fp;      // file descriptor of file to write traces to
+    int mask[TRACE_MODS];  // bitmask for each module
+} trace;
+
+int tr_init(int spaces, char *filename)
+{
+    trace.spaces = spaces;
+    trace.level = 0;
+    trace.enable = 1;
+    trace.fp = stdout;
+    memset(trace.mask, 0, sizeof(trace.mask));
+
+    if (filename != NULL && (trace.fp = fopen(filename, "w")) == NULL) {
+        return -1;
+    }
+    return 0;
+}
+
+int tr_mask(int mask)
+{
+    int module, old;
+
+    module = ((mask & TrModMask) >> 24) - 1;
+    if (module < 0 || module >= TRACE_MODS)
+        return -1;
+
+    old = trace.mask[module];
+    trace.mask[module] = mask & TrBitMask;
+
+    return old;
+}
+
+void tr_enable(int onoff)
+{
+    trace.enable = onoff;
+}
+
+// return current indentation if this trace type is enabled, otherwise
+// return zero.
+int tr_query(int mask)
+{
+    int module;
+
+    module = (mask & TrModMask) >> 24;
+    if (module < 0 || module >= TRACE_MODS)
+        return 0;
+
+    return (trace.mask[module] & (mask & TrBitMask) ?
+            trace.level * trace.spaces : 0);
+}
+
+extern void hexdump(const char *p, int size, unsigned int address, int unitsize);
+
+void tr_hexdump(int mask, const void *p, int size)
+{
+    unsigned int module;
+
+    module = mask & TrModMask;
+    mask   = mask & TrBitMask;
+
+    if ((mask & trace.mask[module >> 24]) == 0)
+        return;
+    
+    hexdump(p, size, 0, 1);
+}
+
+void tr(int mask, char *format, ...)
+{
+    va_list args;
+    unsigned int type, module;
+    int indent;
+    static char buf[256];
+    const char spaces[160 + 1] =
+        "                                        "
+        "                                        "
+        "                                        "
+        "                                        ";
+
+    if (!trace.enable)
+        return;
+
+    type   = mask & TrTypeMask;
+    module = mask & TrModMask;
+    mask   = mask & TrBitMask;
+
+    if ((mask & trace.mask[(module >> 24) - 1]) == 0)
+        return;
+
+    if (type == TrEnd)
+        trace.level--;
+
+    indent = (type == TrCont ? 0 : trace.level);
+
+    if (indent < 0 || indent > 40) {
+        indent = trace.level = 0;
+        fprintf(stderr, "WARNING: trace indent out of range!\n");
+    }
+    if (strlen(format) > 0) {
+        va_start(args, format);
+        vsprintf(buf, format, args);
+        indent *= trace.spaces;
+        fprintf(trace.fp, "%s%s", &spaces[sizeof(spaces) - 1 - indent], buf);
+        fflush(trace.fp);
+    }
+    if (type == TrBegin)
+        trace.level++;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fluid-mnf/trace.h	Sat Feb 29 05:36:07 2020 +0000
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Generic tracing library
+ *
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * $Id: trace.h 1.4 Fri, 11 Oct 2002 08:40:21 +0200 mmj $
+ *
+ ******************************************************************************/
+
+#ifndef _TRACE_H_
+#define _TRACE_H_
+
+
+/******************************************************************************
+ * Common
+ *****************************************************************************/
+
+enum {
+    TrF        = 0x00000000,
+    TrC        = 0x40000000,
+    TrB        = 0x80000000,
+    TrE        = 0xC0000000,
+    TrTypeMask = 0xC0000000,
+
+    TrFunc     = TrF,
+    TrCont     = TrC,        // Tracing continue
+    TrBegin    = TrB,
+    TrEnd      = TrE,
+
+    // Trace Module
+    TrAny      = 0x3F000000,
+    TrModMask  = 0x3F000000,
+
+    // Trace Mask
+    TrAll      = 0x00FFFFFF,
+    TrBitMask  = 0x00FFFFFF
+};
+
+typedef void (* pf_tr_t) (int, char *, ...);
+typedef void (* pf_tr_hexdump_t) (int, const void *, int);
+
+typedef struct tr_functions_s {
+    pf_tr_t         tr;
+    pf_tr_hexdump_t hexdump; //Fixme tr_hexdump?
+} tr_functions_t;
+
+
+// Trace Wrapper. Used for quickly removing tracing from output code.
+#define tw(wrapping) wrapping
+//#define tw(wrapping)
+
+int  tr_init(int spaces, char *filename);
+void tr_enable(int onoff);
+int  tr_mask(int mask);
+void tr(int mask, char *format, ...);
+void tr_hexdump(int mask, const void *p, int size);
+
+#endif // _TRACE_H_