// // Date init 14.12.2004 // // Revision date $Date: 10-07-08 13:22 $ // // Filename $Workfile:: c_cmd.h $ // // Version $Revision: 8 $ // // Archive $Archive:: /LMS2006/Sys01/Main_V02/Firmware/Source/c_cmd. $ // // 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 48 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 #undef ARM_DEBUG // //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; #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, TC_LAST_INT_SCALAR= TC_SLONG, //Aggregate types containing one or more scalar TC_ARRAY, TC_CLUSTER, //Mutex tracks current holder and any waiting clumps TC_MUTEX, TC_FLOAT, TC_LAST_VALID= TC_FLOAT }; //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 #define SIZE_FLOAT 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. typedef struct { UWORD Offset; UWORD ElemSize; UWORD Count; DV_INDEX BackLink; // points to previous DV DV_INDEX Link; // points to next DV } 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 25 //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)) // // Datalog Queuing // // The datalog queue is loosely modeled around the message queue except that there is only one queue, not an array of them. // // A datalog has one less byte of 'header' info so different max size #define MAX_DATALOG_SIZE 60 // The number of datalog messages to buffer #define DATALOG_QUEUE_DEPTH 30 // A DATALOG_MESSAGE is a dynamically sized string, so we use a DV_INDEX to get to its information typedef DV_INDEX DATALOG_MESSAGE; // // DATALOG_QUEUE keeps track of last messages read and written (acts as a circular buffer) typedef struct { UWORD ReadIndex; UWORD WriteIndex; DATALOG_MESSAGE Datalogs[DATALOG_QUEUE_DEPTH]; } DATALOG_QUEUE; //Handy macros for accessing the DATALOG_QUEUE #define GET_WRITE_DTLG() (VarsCmd.DatalogBuffer.Datalogs[VarsCmd.DatalogBuffer.WriteIndex]) #define GET_READ_DTLG() (VarsCmd.DatalogBuffer.Datalogs[VarsCmd.DatalogBuffer.ReadIndex]) #define SET_WRITE_DTLG(DVIndex) (VarsCmd.DatalogBuffer.Datalogs[VarsCmd.DatalogBuffer.WriteIndex] = (DVIndex)) #define SET_READ_DTLG(DVIndex) (VarsCmd.DatalogBuffer.Datalogs[VarsCmd.DatalogBuffer.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 #define INSTR_MAX_COUNT 20 //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, absolute address // CodeEnd: End of this clump's bytecodes, absolute address // 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. // // clumpScalarDispatchHints: this clump only uses scalar data args, can be interpretted with faster dispatch tables // // pDependents: pointer to list of downstream dependents' ClumpIDs // awakenTime: If a clump is on rest queue for sleep, this is the time at which it will return to runQueue // DependentCount: Count of downstream dependents // typedef struct { CODE_WORD* CodeStart; CODE_WORD* CodeEnd; CODE_WORD* PC; UBYTE InitFireCount; UBYTE CurrFireCount; //AKA ShortCount CLUMP_ID Link; UBYTE clumpScalarDispatchHints; CLUMP_ID* pDependents; ULONG awakenTime; 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) // //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; CLUMP_Q RestQ; 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; DATALOG_QUEUE DatalogBuffer; #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(); UBYTE cCmdIsClumpOnQ(CLUMP_Q * Queue, CLUMP_ID Clump); UBYTE cCmdIsQSane(CLUMP_Q * Queue); // Rest queue functions NXT_STATUS cCmdSleepClump(ULONG time); UBYTE cCmdCheckRestQ(ULONG currTime); //Mutex queuing NXT_STATUS cCmdAcquireMutex(MUTEX_Q * Mutex); NXT_STATUS cCmdReleaseMutex(MUTEX_Q * Mutex); //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(wd) ((wd) >> 12) & 0x0F; #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) (UBYTE) (((pInstr)[0]) & 0x00FF) // //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); NXT_STATUS cCmdFreeDopeVector(DV_INDEX DVIndex); NXT_STATUS cCmdGrowDopeVectorArray(UWORD NewCount); 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); // // Datalog Queue management // NXT_STATUS cCmdDatalogWrite(UBYTE * pData, UWORD Length); NXT_STATUS cCmdDatalogRead(UBYTE * pData, UWORD Length, UBYTE Remove); NXT_STATUS cCmdDatalogGetSize(UWORD * Size); // // Color Sensor // NXT_STATUS cCmdColorSensorRead (UBYTE Port, SWORD* SensorValue, UWORD* RawArray, UWORD* NormalizedArray, SWORD* ScaledArray, UBYTE* InvalidData); // //Dataspace management // #define IS_AGGREGATE_TYPE(TypeCode) ((TypeCode == TC_ARRAY) || (TypeCode == TC_CLUSTER)) // use carefully, only where tc will be a scalar int #define QUICK_UNSIGNED_TEST(TypeCode) ((TypeCode) & 0x1) #define IS_SIGNED_TYPE(TypeCode) (((TypeCode) == TC_SBYTE) || ((TypeCode) == TC_SWORD) || ((TypeCode) == TC_SLONG)) //!!!BDUGGAN add TC_FLOAT? //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); //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); UBYTE cCmdCompareFlt(UBYTE CompCode, float Val1, float 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); void * cCmdResolveIODataArg(DATA_ARG DataArg, ULONG Offset, TYPE_CODE * TypeCode); ULONG cCmdGetVal(void * pVal, TYPE_CODE TypeCode); void cCmdSetVal(void * pVal, TYPE_CODE TypeCode, ULONG NewVal); // Calibration routines void cCmdLoadCalibrationFiles(void); NXT_STATUS cCmdComputeCalibratedValue(UBYTE *nm, SWORD *raw); void cCmdUpdateCalibrationCache(UBYTE *nm, SWORD min, SWORD max); // //Interpreter functions // //Clump-based "master" interpreter NXT_STATUS cCmdInterpFromClump(); //Function pointer typedef for sub-interpreters typedef NXT_STATUS (*pInterp)(CODE_WORD * const); typedef NXT_STATUS (*pInterpShort)(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 cCmdInterpScalarUnop2(CODE_WORD * const pCode); NXT_STATUS cCmdInterpBinop(CODE_WORD * const pCode); NXT_STATUS cCmdInterpScalarBinop(CODE_WORD * const pCode); NXT_STATUS cCmdInterpOther(CODE_WORD * const pCode); NXT_STATUS cCmdInterpShortError(CODE_WORD * const pCode); NXT_STATUS cCmdInterpShortSubCall(CODE_WORD * const pCode); NXT_STATUS cCmdInterpShortMove(CODE_WORD * const pCode); NXT_STATUS cCmdInterpShortAcquire(CODE_WORD * const pCode); NXT_STATUS cCmdInterpShortRelease(CODE_WORD * const pCode); NXT_STATUS cCmdMove(DATA_ARG Arg1, DATA_ARG Arg2); //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); float cCmdUnop2Flt(CODE_WORD const Code, float 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); float cCmdBinopFlt(CODE_WORD const Code, float LeftOp, float RightOp, TYPE_CODE LeftType, TYPE_CODE RightType); void cCmdSetValFlt(void * pVal, TYPE_CODE TypeCode, float NewVal); float cCmdGetValFlt(void * pVal, TYPE_CODE TypeCode); // //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 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 cCmdWrapDatalogWrite(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[]); NXT_STATUS cCmdWrapColorSensorRead (UBYTE * ArgV[]); NXT_STATUS cCmdWrapDatalogGetTimes(UBYTE * ArgV[]); NXT_STATUS cCmdWrapSetSleepTimeout(UBYTE * ArgV[]); NXT_STATUS cCmdWrapListFiles(UBYTE * ArgV[]); // Handlers for dynamically added syscalls NXT_STATUS cCmdWrapCommHSWrite(UBYTE * ArgV[]); NXT_STATUS cCmdWrapCommHSRead(UBYTE * ArgV[]); NXT_STATUS cCmdWrapCommHSCheckStatus(UBYTE * ArgV[]); NXT_STATUS cCmdWrapCommBTOnOff(UBYTE * ArgV[]); NXT_STATUS cCmdWrapCommBTConnection(UBYTE * ArgV[]); NXT_STATUS cCmdWrapReadSemData(UBYTE * ArgV[]); NXT_STATUS cCmdWrapWriteSemData(UBYTE * ArgV[]); NXT_STATUS cCmdWrapUpdateCalibCacheInfo(UBYTE * ArgV[]); NXT_STATUS cCmdWrapComputeCalibValue(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