summaryrefslogtreecommitdiff
path: root/AT91SAM7S256/Source/c_cmd.h
diff options
context:
space:
mode:
Diffstat (limited to 'AT91SAM7S256/Source/c_cmd.h')
-rw-r--r--AT91SAM7S256/Source/c_cmd.h804
1 files changed, 804 insertions, 0 deletions
diff --git a/AT91SAM7S256/Source/c_cmd.h b/AT91SAM7S256/Source/c_cmd.h
new file mode 100644
index 0000000..04f10a3
--- /dev/null
+++ b/AT91SAM7S256/Source/c_cmd.h
@@ -0,0 +1,804 @@
+//
+// Date init 14.12.2004
+//
+// Revision date $Date:: 24-07-06 8:52 $
+//
+// Filename $Workfile:: c_cmd.h $
+//
+// Version $Revision:: 43 $
+//
+// Archive $Archive:: /LMS2006/Sys01/Main/Firmware/Source/c_cmd.h $
+//
+// Platform C
+//
+
+//
+// File Description:
+// This file contains definitions and prototypes for the VM which runs bytecode
+// programs compatible with LEGO MINDSTORMS NXT Software 1.0.
+//
+
+#ifndef C_CMD
+#define C_CMD
+
+//!!! MAX_HANDLES also defined in m_sched.h
+#ifndef MAX_HANDLES
+#define MAX_HANDLES 16
+#endif
+
+#include "c_cmd_bytecodes.h"
+#define SYSCALL_COUNT 34
+
+extern const HEADER cCmd;
+
+//
+//Standard interface to other modules
+//
+void cCmdInit(void* pHeader);
+void cCmdCtrl(void);
+void cCmdExit(void);
+
+//
+//ARM_NXT vs SIM_NXT
+//These definitions are set up to allow compiling this code for use in a simulated (non-ARM7) environment.
+//If your toolchain doesn't automatically use the __ICCARM__ token, define it to ensure normal compilation.
+//
+#ifdef __ICCARM__
+#define ARM_NXT
+#else
+#define SIM_NXT
+#endif
+
+//
+//ENABLE_VM toggles compilation the main body of VM code.
+//Define it as 0 to compile alternate implementation for testing (see bottom of c_cmd.c)
+//
+#define ENABLE_VM 1
+
+//
+//VM_BENCHMARK enables extra instrumentation code to measure VM performance.
+//When enabled, a file named "benchmark.txt" is produced every time a program completes.
+//
+#define VM_BENCHMARK (ENABLE_VM && 0) //<-- Toggle to turn on benchmark calculations
+
+#if VM_BENCHMARK
+//Prototype for benchmark recording function
+void cCmdWriteBenchmarkFile();
+#endif
+
+//
+//Run-time assert macros
+//Use these to test for unexpected conditions
+//If expr evaluates as false while running under a debugger,
+// a software breakpoint exception is thrown.
+//NXT_BREAK is just a shortcut for unconditional break.
+//
+//Assert definitions behind WIN_DEBUG only make sense when compiling SIM_NXT
+// under an x86 Windows debugger.
+//
+#if defined WIN_DEBUG
+//"int 3" is a break exception on x86
+#define NXT_ASSERT(expr) if (expr) {} else { __asm {int 3} }
+#define NXT_BREAK NXT_ASSERT(0)
+//
+//Assert definitions behind ARM_DEBUG aren't quite as handy as WIN_DEBUG,
+// but they do record the code line causing the last assert failure.
+//
+#elif defined ARM_DEBUG
+#define NXT_ASSERT(expr) if (expr) {}\
+ else\
+ {\
+ VarsCmd.AssertFlag = TRUE;\
+ VarsCmd.AssertLine = __LINE__;\
+ }
+#define NXT_BREAK NXT_ASSERT(0);
+#else
+//Not debugging, so #defined as nothing
+//!!! Note that these definitions means all usages of NXT_ASSERT and NXT_BREAK
+// get stripped out of an unmodified ARM7 build.
+//Unless ARM_DEBUG is enabled, treat them as documentation of expected values.
+#define NXT_ASSERT(expr)
+#define NXT_BREAK
+#endif
+
+//
+//Status byte used to return requests for further action or errors
+//Valid codes #defined in c_cmd.iom
+//!!!JLOFTUS Replace with NXT_STATUS? Same for ASSERTS? Others? Risk factors?
+//
+typedef SBYTE NXT_STATUS;
+
+//dTimerRead() constantly returns latest system MS tick, so empty loop is convenient macro
+#define BUSY_WAIT_NEXT_MS while (IOMapCmd.Tick == dTimerRead())
+
+#if ENABLE_VM
+
+//Intial values for clump records are packed into 4 bytes in the file format.
+#define VM_FILE_CLUMP_REC_SIZE 4
+
+//
+// Definitions for dataspace management, IO Map (IOM) access, and bytecode instruction structure
+//
+
+//Type codes for use in the dataspace table-of-contents (DSTOC)
+typedef UBYTE TYPE_CODE;
+
+enum
+{
+ //VOID type for unused DS elements; never valid to address them from bytecode
+ TC_VOID,
+
+ //Simple scalar integers, equivalent to matching basic types from stdconst.h
+ TC_UBYTE,
+ TC_SBYTE,
+ TC_UWORD,
+ TC_SWORD,
+ TC_ULONG,
+ TC_SLONG,
+
+ //Aggregate types containing one or more scalar
+ TC_ARRAY,
+ TC_CLUSTER,
+
+ //Mutex tracks current holder and any waiting clumps
+ TC_MUTEX
+};
+
+//Sizes (in bytes) of each scalar type
+#define SIZE_UBYTE 1
+#define SIZE_SBYTE 1
+#define SIZE_UWORD 2
+#define SIZE_SWORD 2
+#define SIZE_ULONG 4
+#define SIZE_SLONG 4
+
+//MUTEX record is a struct containing 3 8-bit CLUMP_IDs, packed into 32-bit word
+//See MUTEX_Q typedef
+#define SIZE_MUTEX 4
+
+//Module IDs for IO map addressing
+enum
+{
+ MOD_INPUT,
+ MOD_OUTPUT
+};
+
+//Field IDs for input IOM
+enum
+{
+ IO_IN_TYPE,
+ IO_IN_MODE,
+ IO_IN_ADRAW,
+ IO_IN_NORMRAW,
+ IO_IN_SCALEDVAL,
+ IO_IN_INVALID_DATA
+};
+
+//FPP = Fields Per Port
+#define IO_IN_FPP 6
+#define IO_IN_FIELD_COUNT (IO_IN_FPP * NO_OF_INPUTS)
+
+//Field IDs for input IOM
+enum
+{
+ IO_OUT_FLAGS,
+ IO_OUT_MODE,
+ IO_OUT_SPEED, //AKA "Power"
+ IO_OUT_ACTUAL_SPEED,
+ IO_OUT_TACH_COUNT,
+ IO_OUT_TACH_LIMIT,
+ IO_OUT_RUN_STATE,
+ IO_OUT_TURN_RATIO,
+ IO_OUT_REG_MODE,
+ IO_OUT_OVERLOAD,
+ IO_OUT_REG_P_VAL,
+ IO_OUT_REG_I_VAL,
+ IO_OUT_REG_D_VAL,
+ IO_OUT_BLOCK_TACH_COUNT,
+ IO_OUT_ROTATION_COUNT
+};
+
+#define IO_OUT_FPP 15
+#define IO_OUT_FIELD_COUNT (IO_OUT_FPP * NO_OF_OUTPUTS)
+
+//
+//DS_TOC_ENTRY is a record in the dataspace table of contents
+//The TypeCode describes the data which is stored at Dataspace[DSOffset]
+//
+typedef struct
+{
+ TYPE_CODE TypeCode;
+ UBYTE Flags;
+ SWORD DSOffset;
+} DS_TOC_ENTRY;
+
+//DS_TOC_ENTRY Flags
+//!!! Yes, there's only one flag defined for an 8-bit field.
+//ARM7 alignment rules means those bits would otherwise just be padding, anyway.
+#define DS_DEFAULT_DEFAULT 1 //This entry has no default value in file; fill with zero at activation time
+
+//DS_ELEMENT_ID (AKA "DS item ID") indexes DataspaceTOC
+typedef UWORD DS_ELEMENT_ID;
+
+//Special flag value used for opcode-specific default behavior when real dataspace argument is not provided
+#define NOT_A_DS_ID 0xFFFF
+
+//Macro to bump DS_ELEMENT_IDs +1 with a cast (mostly to quash annoying warnings)
+#define INC_ID(X) ((DS_ELEMENT_ID)(X + 1))
+
+//DATA_ARG may contain a DS_ELEMENT_ID or encoded IO map address
+typedef UWORD DATA_ARG;
+
+//CODE_WORD is a single indexable element of the codespace
+typedef SWORD CODE_WORD;
+
+//CODE_INDEX indexes codespaces for opcodes and args
+//!!! UWORD CODE_INDEX currently limits programs to 128KB code
+// Yes, this is "plenty", but noted here to make sure we think about it
+// when considering code size changes
+typedef UWORD CODE_INDEX;
+
+//Typedef and define to hold and check for valid file handles
+typedef UBYTE FILE_HANDLE;
+
+#define NOT_A_HANDLE 0xFF
+
+//
+// Dynamic Memory Manager
+//
+
+typedef UWORD DV_INDEX; //Dope Vector Index: Index into the DopeVectorArray
+
+//DOPE_VECTOR struct: One instance exists in the DopeVectorArray for every array in the dataspace.
+//!!! BackPtr is an unused field. Intended to enable compaction of DopeVectorArray.
+typedef struct
+{
+ UWORD Offset;
+ UWORD ElemSize;
+ UWORD Count;
+ UWORD BackPtr;
+ DV_INDEX Link;
+} DOPE_VECTOR;
+
+//
+//MEM_MGR struct
+//Head and Tail keep track of the main linked-list of dope vectors,
+// which must be maintained in ascending order according to Offset
+//FreeHead is the head DV of the list of allocated but unused DVs
+//pDopeVectorArray is initialized at activation-time to point to the master DVA
+//
+typedef struct
+{
+ DV_INDEX Head;
+ DV_INDEX Tail;
+ DV_INDEX FreeHead;
+ DOPE_VECTOR * pDopeVectorArray;
+} MEM_MGR;
+
+//Macro to shorten common DVA access code
+#define DV_ARRAY VarsCmd.MemMgr.pDopeVectorArray
+//# of nodes to alloc when the Dope Vector Array is full
+#define DV_ARRAY_GROWTH_COUNT 5
+//Flag value for invalid Offset fields in DVs
+#define NOT_AN_OFFSET 0xFFFF
+//Check for legal index into DVA
+#define IS_DV_INDEX_SANE(X) (((X) > 0) && ((X) < DV_ARRAY[0].Count))
+
+//
+// Message Queuing
+//
+
+//
+//There are 10 incoming and 10 outgoing message queues, each 5 messages deep
+//A "message" is defined as a null-terminated string under MAX_MESSAGE_SIZE
+//
+#define MESSAGES_PER_QUEUE 5
+#define MESSAGE_QUEUE_COUNT 20
+#define INCOMING_QUEUE_COUNT ((MESSAGE_QUEUE_COUNT)/2)
+#define NOT_A_QUEUE 0xFF
+
+//
+//MAX_MESSAGE_SIZE including null-terminator
+//!!! Capped at 59 unless USB protocol assumptions are changed!
+//
+#define MAX_MESSAGE_SIZE 59
+
+//A MESSAGE is a dynamically sized string, so we use a DV_INDEX to get to its information
+typedef DV_INDEX MESSAGE;
+
+//
+//MESSAGE_QUEUE keeps track of last messages read and written (acts as a circular buffer)
+//
+typedef struct
+{
+ UWORD ReadIndex;
+ UWORD WriteIndex;
+ MESSAGE Messages[MESSAGES_PER_QUEUE];
+} MESSAGE_QUEUE;
+
+//Handy macros for accessing MESSAGE_QUEUEs
+#define GET_WRITE_MSG(QueueID) (VarsCmd.MessageQueues[(QueueID)].Messages[VarsCmd.MessageQueues[(QueueID)].WriteIndex])
+#define GET_READ_MSG(QueueID) (VarsCmd.MessageQueues[(QueueID)].Messages[VarsCmd.MessageQueues[(QueueID)].ReadIndex])
+#define SET_WRITE_MSG(QueueID, DVIndex) (VarsCmd.MessageQueues[(QueueID)].Messages[VarsCmd.MessageQueues[(QueueID)].WriteIndex] = (DVIndex))
+#define SET_READ_MSG(QueueID, DVIndex) (VarsCmd.MessageQueues[(QueueID)].Messages[VarsCmd.MessageQueues[(QueueID)].ReadIndex] = (DVIndex))
+
+
+//
+//Definitions related to dataflow scheduling
+//
+
+//CLUMP_IDs are used to index list at pAllClumps
+typedef UBYTE CLUMP_ID;
+
+//
+//The last value in CLUMP_ID's range is reserved as NOT_A_CLUMP
+//This is useful as a queue terminator and general placeholder
+//
+#define NOT_A_CLUMP 0xFF
+#define MAX_CLUMPS 255
+
+//CLUMP_Q struct for tracking head and tail of a queue of clumps
+typedef struct
+{
+ CLUMP_ID Head;
+ CLUMP_ID Tail;
+} CLUMP_Q;
+
+//
+//MUTEX_Q is a struct to be stashed in the dataspace to track state of a mutex
+//If mutex is free, Owner field is NOT_A_CLUMP and WaitQ is empty.
+//The mutex is acquired by stashing a new owner's ID.
+//If others attempt to acquire, they will be put on the WaitQ
+//
+typedef struct
+{
+ CLUMP_ID Owner;
+ CLUMP_Q WaitQ;
+} MUTEX_Q;
+
+//
+// Clump Record, run-time book-keeping for each clump
+//
+// CodeStart: Start of this clump's bytecodes
+// CodeEnd: End of this clump's bytecodes
+// PC: "program counter" -- current offset into codespace relative to CodeStart
+// InitFireCount: Initial count of upstream dependencies
+// CurrFireCount: Run-time count of unsatisfied dependencies
+// Link: ID of next clump in the queue. NOT_A_CLUMP denotes end or bad link.
+//
+// Priority: number of instructions to run per pass on this clump
+//
+// pDependents: pointer to list of downstream dependents' ClumpIDs
+// DependentCount: Count of downstream dependents
+//
+typedef struct
+{
+ CODE_INDEX CodeStart;
+ CODE_INDEX CodeEnd;
+ CODE_INDEX PC;
+ UBYTE InitFireCount;
+ UBYTE CurrFireCount; //AKA ShortCount
+ CLUMP_ID Link;
+
+ UBYTE Priority;
+
+ CLUMP_ID* pDependents;
+ UBYTE DependentCount;
+} CLUMP_REC;
+
+//
+//Definitions for memory pool management
+//
+
+//First valid pointer into the memory pool
+#define POOL_START ((UBYTE*)(VarsCmd.Pool))
+
+//Sentinel points one byte *past* the pool -- i.e. first bad pool pointer
+#define POOL_SENTINEL ((UBYTE*)(VarsCmd.Pool + VarsCmd.PoolSize))
+
+//Alignment mod for Pool and all sub-fields of the Pool
+#define POOL_ALIGN SIZE_SLONG
+
+#define ALIGN_TO_MOD(val,mod) if ((val) % (mod) != 0) { (val) += (mod) - ((val) % (mod)); } else {}
+
+//
+//Internal states of the VM
+//VM_IDLE: Just sitting around. Request to run program will lead to ONE of the VM_RUN* states.
+//VM_RUN_FREE: Attempt to run as many instructions as possible within our timeslice
+//VM_RUN_SINGLE: Run exactly one instruction per timeslice
+//VM_RUN_PAUSE: Program still "active", but someone has asked us to pause
+//VM_RESET2: Final clean up and return to IDLE
+//VM_RESET1: Initialize state variables and some I/O devices -- executed when programs end
+//
+typedef enum
+{
+ VM_IDLE,
+ VM_RUN_FREE,
+ VM_RUN_SINGLE,
+ VM_RUN_PAUSE,
+ VM_RESET1,
+ VM_RESET2,
+} VM_STATE;
+
+//
+// VARSCMD: Private state data for active program and VM system
+//
+//pCodespace: pointer for flat codespace (stored in flash, includes all clumps)
+//CodespaceCount: count of code words
+//
+//pAllClumps: Pointer to list of CLUMP_RECs
+//AllClumpsCount: Count of CLUMP_RECs in list
+//
+//RunQ: Head and tail of run queue (elements in-place in AllClumps list)
+//ScratchPC: Temp PC value for control flow instructions
+//
+//pDataspaceTOC: Pointer to DSTOC entries (stored in flash)
+//DataspaceCount: Count of entries in DSTOC
+//pDataspace: Base pointer of actual dataspace
+//DataspaceSize: Size, in bytes, of dataspace
+//DSStaticSize: Size, in bytes, of static portion of the dataspace (used as an offset to the dynamic dataspace)
+//
+//VMState: Internal state of VM's loader/scheduler (cCmdCtrl())
+//
+//MemMgr: Contains data to manage dynamic arrays
+//
+//PoolSize: Current size of main memory pool, in bytes.
+//Pool: Static pool of bytes for stashing all program run-time data
+//
+//ActiveProgHandle: Handle of the program that is currently running
+//ActiveProgName: Stashed name of currently running program, if any
+//
+//FileHandleTable: Table of file names opened by program while running.
+// First byte of each record is 'r' or 'w' (read or write).
+//
+//MessageQueues: Message buffer tracking data
+//
+//CommStat, CommStatReset, CommCurrConnection, DirtyComm: Helper data for interfacing to c_comm module
+//
+//DirtyDisplay: Boolean reminding us to re-initialize the display if program used it
+//
+//StartTick: MS tick stashed when program started. Used for relative time measurements.
+//
+//Further notes on the memory pool:
+// The main memory pool is used for all clump records, dataspace tracking data,
+// and the dataspace itself. In other words, pAllClumps and
+// pDataspace must all point to memory within the pool. Watch for NXT_ASSERTs
+// to enforce safe indexing into the pool.
+//
+typedef struct
+{
+ CODE_WORD* pCodespace;
+ CLUMP_REC* pAllClumps;
+ DS_TOC_ENTRY* pDataspaceTOC;
+ UBYTE* pDataspace;
+ UBYTE* Pool;
+
+ ULONG PoolSize;
+ UWORD CodespaceCount;
+ CLUMP_ID AllClumpsCount;
+ UWORD DataspaceCount;
+ UWORD DataspaceSize;
+ UWORD DSStaticSize;
+
+ VM_STATE VMState;
+
+ MEM_MGR MemMgr;
+
+ CLUMP_Q RunQ;
+ CODE_INDEX ScratchPC;
+ CLUMP_ID CallerClump;
+
+ UBYTE ActiveProgHandle;
+ UBYTE ActiveProgName[FILENAME_LENGTH + 1];
+
+ UBYTE FileHandleTable[MAX_HANDLES][FILENAME_LENGTH + 2];
+
+ MESSAGE_QUEUE MessageQueues[MESSAGE_QUEUE_COUNT];
+
+ SWORD CommStat;
+ SWORD CommStatReset;
+ UBYTE CommCurrConnection;
+
+ UBYTE DirtyComm;
+ UBYTE DirtyDisplay;
+
+ ULONG StartTick;
+
+#if VM_BENCHMARK
+ ULONG InstrCount;
+ ULONG Average;
+ ULONG OverTimeCount;
+ ULONG MaxOverTimeLength;
+ ULONG CmdCtrlCount;
+ ULONG CompactionCount;
+ ULONG LastCompactionTick;
+ ULONG MaxCompactionTime;
+ ULONG OpcodeBenchmarks[OPCODE_COUNT][4];
+ ULONG SyscallBenchmarks[SYSCALL_COUNT][4];
+ UBYTE Buffer[256];
+#endif
+
+#if defined ARM_DEBUG
+ UBYTE AssertFlag;
+ ULONG AssertLine;
+#endif
+} VARSCMD;
+
+//
+//Activation
+//
+
+//Activate new program by filename (open file and inflate run-time data)
+NXT_STATUS cCmdActivateProgram(UBYTE * pFileName);
+
+//Deactivate currently active program (re-init run-time data and close file)
+void cCmdDeactivateProgram();
+
+//Reset various device state variables
+void cCmdResetDevices(void);
+
+//Parse activation record file header information
+typedef struct
+{
+ UWORD DSTOC;
+ UWORD DSDefaults;
+ UWORD DSDefaultsSize;
+ UWORD DynamicDefaults;
+ UWORD DynamicDefaultsSize;
+ UWORD Clumps;
+ UWORD Codespace;
+} PROG_FILE_OFFSETS;
+
+NXT_STATUS cCmdReadFileHeader(UBYTE* pData, ULONG DataSize,
+ PROG_FILE_OFFSETS* pFileOffsets);
+
+NXT_STATUS cCmdInflateDSDefaults(UBYTE* pDSDefaults, UWORD *pDefaultsOffset, DS_ELEMENT_ID DSElementID);
+
+
+//
+//Clump management
+//
+
+//Clump queuing
+void cCmdEnQClump(CLUMP_Q * Queue, CLUMP_ID NewClump);
+void cCmdDeQClump(CLUMP_Q * Queue, CLUMP_ID Clump);
+void cCmdRotateQ(CLUMP_Q * Queue);
+UBYTE cCmdIsClumpOnQ(CLUMP_Q * Queue, CLUMP_ID Clump);
+UBYTE cCmdIsQSane(CLUMP_Q * Queue);
+
+//Mutex queuing
+NXT_STATUS cCmdAcquireMutex(MUTEX_Q * Mutex, CLUMP_ID Clump);
+NXT_STATUS cCmdReleaseMutex(MUTEX_Q * Mutex, CLUMP_ID Clump);
+
+//Conditionally schedule dependents of given clump (Begin and End specify subset of list)
+NXT_STATUS cCmdSchedDependents(CLUMP_ID Clump, SWORD Begin, SWORD End);
+
+//Conditionally schedule TargetClump
+NXT_STATUS cCmdSchedDependent(CLUMP_ID Clump, CLUMP_ID TargetClump);
+
+//Test if ClumpID is sane at run-time (valid for indexing AllClumps)
+UBYTE cCmdIsClumpIDSane(CLUMP_ID Clump);
+
+//
+//Code stream management
+//
+
+//Instruction masking macros -- get the interesting bits out of an encoded instruction word
+#define COMP_CODE(pInstr) ((UBYTE)((((pInstr)[0]) & 0x0700) >> 8))
+#define INSTR_SIZE(pInstr) ((UBYTE)((((pInstr)[0]) & 0xF000) >> 12))
+
+#ifdef USE_SHORT_OPS
+//!!! IS_SHORT_OP and SHORT_OP_CODE do not check for insane (out of bounds) data. Accessor function would be safer.
+#define IS_SHORT_OP(pInstr) ((UBYTE)((((pInstr)[0]) & 0x0800) >> 8) == 8)
+#define SHORT_OP_CODE(pInstr) COMP_CODE(pInstr)
+#define SHORT_ARG(pInstr) ((SBYTE) (((pInstr)[0]) & 0x00FF))
+//ShortOpMap defined in c_cmd_bytecodes.h
+#define OP_CODE(pInstr) (IS_SHORT_OP(pInstr) ? ShortOpMap[SHORT_OP_CODE(pInstr)] : (UBYTE) (((pInstr)[0]) & 0x00FF))
+#else
+#define OP_CODE(pInstr) ((UBYTE) (((pInstr)[0]) & 0x00FF))
+#endif
+
+//Access count of codewords belonging to Clump. If no clump specified, return count of all codewords in program.
+CODE_INDEX cCmdGetCodespaceCount(CLUMP_ID Clump);
+
+//
+//Memory pool management
+//
+
+//Initialize entire memory pool with default value
+void cCmdInitPool(void);
+
+//Resize dataspace array specified by DSElementID and Offset.
+NXT_STATUS cCmdDSArrayAlloc(DS_ELEMENT_ID DSElementID, UWORD Offset, UWORD NewCount);
+//Resize dataspace array specified by DVIndex. In most cases, call higher-level cCmdDSArrayAlloc instead.
+NXT_STATUS cCmdDVArrayAlloc(DV_INDEX DVIndex, UWORD NewCount);
+
+NXT_STATUS cCmdAllocSubArrayDopeVectors(DS_ELEMENT_ID DSElementID, UWORD Offset);
+NXT_STATUS cCmdFreeSubArrayDopeVectors(DS_ELEMENT_ID DSElementID, UWORD Offset);
+NXT_STATUS cCmdAllocDopeVector(DV_INDEX *pIndex, UWORD ElemSize, UWORD BackPtr);
+NXT_STATUS cCmdFreeDopeVector(DV_INDEX DVIndex);
+NXT_STATUS cCmdGrowDopeVectorArray(UWORD NewCount);
+NXT_STATUS cCmdCompactDopeVectorArray(void);
+
+UWORD cCmdCalcArrayElemSize(DS_ELEMENT_ID DSElementID);
+
+NXT_STATUS cCmdMemMgrMoveToTail(DV_INDEX DVIndex);
+NXT_STATUS cCmdMemMgrInsertAtTail(DV_INDEX DVIndex);
+
+//Utility function to check sanity of MemMgr data structure. Boolean result.
+UBYTE cCmdVerifyMemMgr();
+
+NXT_STATUS cCmdDSCompact(void);
+
+//
+// Message Queue management
+//
+
+NXT_STATUS cCmdMessageWrite(UWORD QueueID, UBYTE * pData, UWORD Length);
+NXT_STATUS cCmdMessageRead(UWORD QueueID, UBYTE * pData, UWORD Length, UBYTE Remove);
+NXT_STATUS cCmdMessageGetSize(UWORD QueueID, UWORD * Size);
+
+//
+//Dataspace management
+//
+
+#define IS_AGGREGATE_TYPE(TypeCode) ((TypeCode == TC_ARRAY) || (TypeCode == TC_CLUSTER))
+#define IS_SIGNED_TYPE(TypeCode) (((TypeCode) == TC_SBYTE) || ((TypeCode) == TC_SWORD) || ((TypeCode) == TC_SLONG))
+
+//Test if DS_ELEMENT_ID is sane at run-time (valid for indexing DS TOC)
+UBYTE cCmdIsDSElementIDSane(DS_ELEMENT_ID Index);
+
+DS_ELEMENT_ID cCmdGetDataspaceCount(void);
+TYPE_CODE cCmdDSType(DS_ELEMENT_ID DSElementID);
+
+//Pointer accessors to resolve actual data locations in RAM
+void* cCmdDSPtr(DS_ELEMENT_ID DSElementID, UWORD Offset);
+void* cCmdDVPtr(DV_INDEX DVIndex);
+
+//Helper to walk the DSTOC to the next entry at the same aggregate nesting level as CurrID
+DS_ELEMENT_ID cCmdNextDSElement(DS_ELEMENT_ID CurrID);
+
+//Recursively compare two complete data type descriptors
+UBYTE cCmdCompareDSType(DS_ELEMENT_ID DSElementID1, DS_ELEMENT_ID DSElementID2);
+
+//Functions for managing data flattened to byte arrays
+UWORD cCmdCalcFlattenedSize(DS_ELEMENT_ID DSElementID, UWORD Offset);
+NXT_STATUS cCmdFlattenToByteArray(UBYTE * pByteArray, UWORD * pByteOffset, DS_ELEMENT_ID DSElementID, UWORD Offset);
+NXT_STATUS cCmdUnflattenFromByteArray(UBYTE * pByteArray, UWORD * pByteOffset, DS_ELEMENT_ID DSElementID, UWORD Offset);
+
+//Comparison evaluation. Comparison codes defined in c_cmd_bytecodes.h.
+//cCmdCompare operates on scalars passed as ULONGs -- type-specific comparisons done inside function.
+UBYTE cCmdCompare(UBYTE CompCode, ULONG Val1, ULONG Val2, TYPE_CODE TypeCode1, TYPE_CODE TypeCode2);
+//cCmdCompareAggregates does polymorphic comparisons (with recursive helper function).
+NXT_STATUS cCmdCompareAggregates(UBYTE CompCode, UBYTE *ReturnBool, DATA_ARG Arg2, UWORD Offset2, DATA_ARG Arg3, UWORD Offset3);
+NXT_STATUS cCmdRecursiveCompareAggregates(UBYTE CompCode, UBYTE *ReturnBool, UBYTE *Finished, DATA_ARG Arg2, UWORD Offset2, DATA_ARG Arg3, UWORD Offset3);
+
+//Cluster functions
+UWORD cCmdClusterCount(DS_ELEMENT_ID DSElementID);
+
+//Array functions
+#define ARRAY_ELEM_OFFSET(DVIndex, Index) ((UWORD)(DV_ARRAY[(DVIndex)].Offset + DV_ARRAY[(DVIndex)].ElemSize * (Index)))
+UWORD cCmdGetDVIndex(DS_ELEMENT_ID DSElementID, UWORD Offset);
+UWORD cCmdArrayCount(DS_ELEMENT_ID DSElementID, UWORD Offset);
+TYPE_CODE cCmdArrayType(DS_ELEMENT_ID DSElementID);
+
+//!!! DATA_ARG masks are for internal use only! (Bytecode programs should never contain them)
+// See cCmdResolveDataArg() calls in the interpreter code for OP_GETOUT, OP_SETIN, and OP_GETIN.
+#define DATA_ARG_ADDR_MASK 0x3FFF
+#define DATA_ARG_IMM_MASK 0x7FFF
+
+//General data accessors (DS and IO Map)
+void * cCmdResolveDataArg(DATA_ARG DataArg, UWORD Offset, TYPE_CODE * TypeCode);
+ULONG cCmdGetVal(void * pVal, TYPE_CODE TypeCode);
+void cCmdSetVal(void * pVal, TYPE_CODE TypeCode, ULONG NewVal);
+UWORD cCmdSizeOf(TYPE_CODE TypeCode);
+
+//
+//Interpreter functions
+//
+
+//Clump-based "master" interpreter
+NXT_STATUS cCmdInterpFromClump(CLUMP_ID Clump);
+
+//Function pointer typedef for sub-interpreters
+typedef NXT_STATUS (*pInterp)(CODE_WORD * const);
+
+//Sub-interpreter dispatch functions
+NXT_STATUS cCmdInterpNoArg(CODE_WORD * const pCode);
+NXT_STATUS cCmdInterpUnop1(CODE_WORD * const pCode);
+NXT_STATUS cCmdInterpUnop2(CODE_WORD * const pCode);
+NXT_STATUS cCmdInterpBinop(CODE_WORD * const pCode);
+NXT_STATUS cCmdInterpOther(CODE_WORD * const pCode);
+
+#define INTERP_COUNT 5
+
+//Polymorphic interpreter functions
+NXT_STATUS cCmdInterpPolyUnop2(CODE_WORD const Code, DATA_ARG Arg1, UWORD Offset1, DATA_ARG Arg2, UWORD Offset2);
+ULONG cCmdUnop2(CODE_WORD const Code, ULONG Operand, TYPE_CODE TypeCode);
+
+NXT_STATUS cCmdInterpPolyBinop(CODE_WORD const Code, DATA_ARG Arg1, UWORD Offset1, DATA_ARG Arg2, UWORD Offset2, DATA_ARG Arg3, UWORD Offset3);
+ULONG cCmdBinop(CODE_WORD const Code, ULONG LeftOp, ULONG RightOp, TYPE_CODE LeftType, TYPE_CODE RightType);
+
+//
+//Support functions for lowspeed (I2C devices, i.e. ultrasonic sensor) communications
+//
+
+NXT_STATUS cCmdLSCheckStatus(UBYTE Port);
+UBYTE cCmdLSCalcBytesReady(UBYTE Port);
+NXT_STATUS cCmdLSWrite(UBYTE Port, UBYTE BufLength, UBYTE *pBuf, UBYTE ResponseLength);
+NXT_STATUS cCmdLSRead(UBYTE Port, UBYTE BufLength, UBYTE * pBuf);
+
+//
+//Support for OP_SYSCALL
+//
+
+//
+//Each cCmdWrap<SysCallName> funtion below implements one system call.
+//The OP_SYSCALL interpreter wrangles the argument vector, ArgV,
+// then calls the appropriate wrapper function according to the SysCallID.
+//Wrapper functions write directly back into the dataspace via ArgV.
+//
+#define MAX_CALL_ARGS 16
+
+typedef NXT_STATUS (*pSysCall)(UBYTE * ArgV[]);
+
+NXT_STATUS cCmdWrapFileOpenRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileOpenWrite(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileOpenAppend(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileWrite(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileClose(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileResolveHandle (UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileRename (UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapFileDelete (UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapSoundPlayFile(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapSoundPlayTone(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapSoundGetState(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapSoundSetState(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawText(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawPoint(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawLine(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawCircle(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawRect(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapDrawPicture(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapSetScreenMode(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapReadButton(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommLSWrite(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommLSRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommLSCheckStatus(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapRandomNumber(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapGetStartTick(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapMessageWrite(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapMessageRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommBTCheckStatus(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommBTWrite(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapCommBTRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapKeepAlive(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapIOMapRead(UBYTE * ArgV[]);
+NXT_STATUS cCmdWrapIOMapWrite(UBYTE * ArgV[]);
+
+//Handler for remote control protocol packets -- called from comm module via IO map function pointer
+UWORD cCmdHandleRemoteCommands(UBYTE * pInBuf, UBYTE * pOutBuf, UBYTE * pLen);
+
+#ifdef SIM_NXT
+//
+// Helper functions to provide simulator library access to VM internals
+//
+SWORD cCmdGetCodeWord(CLUMP_ID Clump, CODE_INDEX Index);
+UBYTE * cCmdGetDataspace(UWORD *DataspaceSize);
+DOPE_VECTOR * cCmdGetDopeVectorPtr(void);
+ULONG cCmdGetPoolSize(void);
+MEM_MGR cCmdGetMemMgr(void);
+#endif
+
+#else //!ENABLE_VM
+
+//Placeholder VARSCMD for alternate implementation (see bottom of c_cmd.c for usage notes)
+typedef struct
+{
+ UBYTE Tmp;
+} VARSCMD;
+
+#endif //ENABLE_VM
+
+#endif //C_CMD