|
I have implemented OP_WAIT and a variant of OP_WAIT which takes a variable
rather than an immediate numeric value (which in nbc is called "waitv"). I also
modified NBC to accept a command line switch that tells it whether the firmware
supports waits or not.
Here's the code:
// in cCmdInterpUnop1 (c_cmd.c)
case OP_WAIT:
case OP_WAITV:
{
ULONG WaitMS;
CLUMP_REC* pClumpRec = &(VarsCmd.pAllClumps[VarsCmd.CallerClump]);
pClumpRec->Sleeping = TRUE;
if (opCode == OP_WAITV) {
pArg1 = cCmdResolveDataArg(Arg1, 0, &TypeCode1);
WaitMS = cCmdGetVal(pArg1, TypeCode1);
}
else
WaitMS = Arg1;
pClumpRec->WakeTick = IOMapCmd.Tick + WaitMS;
}
break;
// in cCmdActivateProgram (c_cmd.c)
VarsCmd.pAllClumps[i].Sleeping = FALSE;
VarsCmd.pAllClumps[i].WakeTick = 0;
// in cCmdInterpFromClump (c_cmd.c)
//Resolve clump record structure and current instruction pointer
pClumpRec = &(VarsCmd.pAllClumps[Clump]);
// is this clump waiting?
if (pClumpRec->Sleeping)
{
// should it wake up?
if (pClumpRec->WakeTick <= dTimerRead())
{
// wake up clump
pClumpRec->Sleeping = FALSE;
// go on executing code as before
}
else {
// if it should not wake up then return from this routine now
return NO_ERR;
}
}
pInstr = (VarsCmd.pCodespace + pClumpRec->CodeStart + pClumpRec->PC);
// in c_cmd.h
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;
ULONG WakeTick; // JCH
UBYTE Sleeping; // JCH
} CLUMP_REC;
// in c_cmd_bytecodes.h
#define OPCODE_COUNT 0x37
#define OP_WAITV 0x36 // var
I also fixed a major bug in OP_REPLACE. Here's the code:
// in c_cmd.c
UWORD cCmdArrayDimensions(DS_ELEMENT_ID DSElementID)
{
NXT_ASSERT(cCmdIsDSElementIDSane(DSElementID));
UWORD result = 0;
while (cCmdDSType(DSElementID) == TC_ARRAY)
{
result++;
DSElementID = INC_ID(DSElementID);
}
return result;
}
// in cCmdInterpOther (c_cmd.c)
case OP_REPLACE:
{
//Arg1 - Dst
//Arg2 - Src
//Arg3 - Index
//Arg4 - New val / array of vals
UWORD SrcDims, NewValDims;
Arg1 = pCode[1];
Arg2 = pCode[2];
Arg3 = pCode[3];
Arg4 = pCode[4];
NXT_ASSERT(cCmdDSType(Arg1) == TC_ARRAY);
NXT_ASSERT(cCmdDSType(Arg2) == TC_ARRAY);
//Copy Src to Dst
//!!! Could avoid full data copy if we knew which portion to overwrite
if (Arg1 != Arg2)
{
Status = cCmdInterpPolyUnop2(OP_MOV, Arg1, 0, Arg2, 0);
if (IS_ERR(Status))
return Status;
}
DVIndex1 = cCmdGetDVIndex(Arg1, 0);
//Copy new val to Dst
if (Arg3 != NOT_A_DS_ID)
{
pArg3 = cCmdResolveDataArg(Arg3, 0, &TypeCode3);
ArgVal3 = cCmdGetVal(pArg3, TypeCode3);
}
else
{
//Index input unwired
ArgVal3 = 0;
}
ArrayCount1 = cCmdArrayCount(Arg1, 0);
//Bounds check
//If array index (ArgVal3) is out of range, just pass out the copy of Src
(effectively no-op)
if (ArgVal3 >= ArrayCount1)
return (NO_ERR);
SrcDims = cCmdArrayDimensions(Arg2);
NewValDims = cCmdArrayDimensions(Arg4);
// if the new value argument has an array dimension that is 1 less than
// the array dimension of the source array then use MOV to copy data
// if (cCmdDSType(Arg4) != TC_ARRAY)
if (NewValDims == (SrcDims-1))
{
Status = cCmdInterpPolyUnop2(OP_MOV, INC_ID(Arg1),
ARRAY_ELEM_OFFSET(DVIndex1, ArgVal3), Arg4, 0);
if (IS_ERR(Status))
return Status;
}
else if (NewValDims == SrcDims)
{
DVIndex4 = cCmdGetDVIndex(Arg4, 0);
ArrayCount4 = cCmdArrayCount(Arg4, 0);
if (ArrayCount1 - ArgVal3 < ArrayCount4)
MinCount = (UWORD)(ArrayCount1 - ArgVal3);
else
MinCount = ArrayCount4;
for (i = 0; i < MinCount; i++)
{
Status = cCmdInterpPolyUnop2(OP_MOV, INC_ID(Arg1),
ARRAY_ELEM_OFFSET(DVIndex1, ArgVal3 + i), INC_ID(Arg4),
ARRAY_ELEM_OFFSET(DVIndex4, i));
if (IS_ERR(Status))
return Status;
}
}
else
{
// any other situation is unsupported
NXT_BREAK;
return 0;
}
}
break;
I will be uploading a copy of the firmware with these enhancements later today.
John Hansen
|
|
1 Message in This Thread:
- Entire Thread on One Page:
- Nested:
All | Brief | Compact | Dots
Linear:
All | Brief | Compact
|
|
|
|