⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c_cmd.h

📁 乐高机器人的源码,开发平台是IAR_for_AVR.
💻 H
📖 第 1 页 / 共 2 页
字号:
//
// Date init       14.12.2004
//
// Revision date   $Date:: 14-06-06 8:09                                     $
//
// Filename        $Workfile:: c_cmd.h                                       $
//
// Version         $Revision:: 42                                            $
//
// 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,
  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 indexes DataspaceTOC
typedef UWORD DS_ELEMENT_ID;

//Special flag value used for opcode-specific default behavior when real data is not provided
#define NOT_AN_ELEMENT 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 {}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -