📄 intcode.cpp
字号:
Op(INT_COPY_BIT_TO_BIT, storeName, stateInOut);
break;
}
case ELEM_LOOK_UP_TABLE: {
// God this is stupid; but it will have to do, at least until I
// add new int code instructions for this.
int i;
Op(INT_IF_BIT_SET, stateInOut);
ElemLookUpTable *t = &(l->d.lookUpTable);
for(i = 0; i < t->count; i++) {
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", i);
Op(INT_IF_VARIABLE_EQUALS_VARIABLE, t->index, "$scratch");
Op(INT_SET_VARIABLE_TO_LITERAL, t->dest, t->vals[i]);
Op(INT_END_IF);
}
Op(INT_END_IF);
break;
}
case ELEM_PIECEWISE_LINEAR: {
// This one is not so obvious; we have to decide how best to
// perform the linear interpolation, using our 16-bit fixed
// point math.
ElemPiecewiseLinear *t = &(l->d.piecewiseLinear);
if(t->count == 0) {
Error(_("Piecewise linear lookup table with zero elements!"));
CompileError();
}
int i;
int xThis = t->vals[0];
for(i = 1; i < t->count; i++) {
if(t->vals[i*2] <= xThis) {
Error(_("x values in piecewise linear table must be "
"strictly increasing."));
CompileError();
}
xThis = t->vals[i*2];
}
Op(INT_IF_BIT_SET, stateInOut);
for(i = t->count - 1; i >= 1; i--) {
Op(INT_IF_VARIABLE_LES_LITERAL, t->index, t->vals[i*2]+1);
int thisDx = t->vals[i*2] - t->vals[(i-1)*2];
int thisDy = t->vals[i*2 + 1] - t->vals[(i-1)*2 + 1];
// The output point is given by
// yout = y[i-1] + (xin - x[i-1])*dy/dx
// and this is the best form in which to keep it, numerically
// speaking, because you can always fix numerical problems
// by moving the PWL points closer together.
// Check for numerical problems, and fail if we have them.
if((thisDx*thisDy) >= 32767 || (thisDx*thisDy) <= -32768) {
Error(_("Numerical problem with piecewise linear lookup "
"table. Either make the table entries smaller, "
"or space the points together more closely.\r\n\r\n"
"See the help file for details."));
CompileError();
}
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", t->vals[(i-1)*2]);
Op(INT_SET_VARIABLE_SUBTRACT, "$scratch", t->index,
"$scratch", 0);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch2", thisDx);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch3", thisDy);
Op(INT_SET_VARIABLE_MULTIPLY, t->dest, "$scratch", "$scratch3",
0);
Op(INT_SET_VARIABLE_DIVIDE, t->dest, t->dest, "$scratch2", 0);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch",
t->vals[(i-1)*2 + 1]);
Op(INT_SET_VARIABLE_ADD, t->dest, t->dest, "$scratch", 0);
Op(INT_END_IF);
}
Op(INT_END_IF);
break;
}
case ELEM_FORMATTED_STRING: {
// Okay, this one is terrible and ineffcient, and it's a huge pain
// to implement, but people want it a lot. The hard part is that
// we have to let the PLC keep cycling, of course, and also that
// we must do the integer to ASCII conversion sensisbly, with
// only one divide per PLC cycle.
// This variable is basically our sequencer: it is a counter that
// increments every time we send a character.
char seq[MAX_NAME_LEN];
GenSymFormattedString(seq);
// The variable whose value we might interpolate.
char *var = l->d.fmtdStr.var;
// This is the state variable for our integer-to-string conversion.
// It contains the absolute value of var, possibly with some
// of the higher powers of ten missing.
char convertState[MAX_NAME_LEN];
GenSymFormattedString(convertState);
// We might need to suppress some leading zeros.
char isLeadingZero[MAX_NAME_LEN];
GenSymFormattedString(isLeadingZero);
// This is a table of characters to transmit, as a function of the
// sequencer position (though we might have a hole in the middle
// for the variable output)
char outputChars[MAX_LOOK_UP_TABLE_LEN];
BOOL mustDoMinus = FALSE;
// The total number of characters that we transmit, including
// those from the interpolated variable.
int steps;
// The total number of digits to convert.
int digits = -1;
// So count that now, and build up our table of fixed things to
// send.
steps = 0;
char *p = l->d.fmtdStr.string;
while(*p) {
if(*p == '\\' && (isdigit(p[1]) || p[1] == '-')) {
if(digits >= 0) {
Error(_("Multiple escapes (\\0-9) present in format "
"string, not allowed."));
CompileError();
}
p++;
if(*p == '-') {
mustDoMinus = TRUE;
outputChars[steps++] = 1;
p++;
}
if(!isdigit(*p) || (*p - '0') > 5 || *p == '0') {
Error(_("Bad escape sequence following \\; for a "
"literal backslash, use \\\\"));
CompileError();
}
digits = (*p - '0');
int i;
for(i = 0; i < digits; i++) {
outputChars[steps++] = 0;
}
} else if(*p == '\\') {
p++;
switch(*p) {
case 'r': outputChars[steps++] = '\r'; break;
case 'n': outputChars[steps++] = '\n'; break;
case 'b': outputChars[steps++] = '\b'; break;
case 'f': outputChars[steps++] = '\f'; break;
case '\\': outputChars[steps++] = '\\'; break;
case 'x': {
int h, l;
p++;
h = HexDigit(*p);
if(h >= 0) {
p++;
l = HexDigit(*p);
if(l >= 0) {
outputChars[steps++] = (h << 4) | l;
break;
}
}
Error(_("Bad escape: correct form is \\xAB."));
CompileError();
break;
}
default:
Error(_("Bad escape '\\%c'"), *p);
CompileError();
break;
}
} else {
outputChars[steps++] = *p;
}
if(*p) p++;
}
if(digits >= 0 && (strlen(var) == 0)) {
Error(_("Variable is interpolated into formatted string, but "
"none is specified."));
CompileError();
} else if(digits < 0 && (strlen(var) > 0)) {
Error(_("No variable is interpolated into formatted string, "
"but a variable name is specified. Include a string like "
"'\\-3', or leave variable name blank."));
CompileError();
}
// We want to respond to rising edges, so yes we need a one shot.
char oneShot[MAX_NAME_LEN];
GenSymOneShot(oneShot);
Op(INT_IF_BIT_SET, stateInOut);
Op(INT_IF_BIT_CLEAR, oneShot);
Op(INT_SET_VARIABLE_TO_LITERAL, seq, (SWORD)0);
Op(INT_END_IF);
Op(INT_END_IF);
Op(INT_COPY_BIT_TO_BIT, oneShot, stateInOut);
// Everything that involves seqScratch is a terrible hack to
// avoid an if statement with a big body, which is the risk
// factor for blowing up on PIC16 page boundaries.
char *seqScratch = "$scratch3";
Op(INT_SET_VARIABLE_TO_VARIABLE, seqScratch, seq);
// No point doing any math unless we'll get to transmit this
// cycle, so check that first.
Op(INT_IF_VARIABLE_LES_LITERAL, seq, steps);
Op(INT_ELSE);
Op(INT_SET_VARIABLE_TO_LITERAL, seqScratch, -1);
Op(INT_END_IF);
Op(INT_CLEAR_BIT, "$scratch");
Op(INT_UART_SEND, "$scratch", "$scratch");
Op(INT_IF_BIT_SET, "$scratch");
Op(INT_SET_VARIABLE_TO_LITERAL, seqScratch, -1);
Op(INT_END_IF);
// So we transmit this cycle, so check out which character.
int i;
int digit = 0;
for(i = 0; i < steps; i++) {
if(outputChars[i] == 0) {
// Note gross hack to work around limit of range for
// AVR brne op, which is +/- 64 instructions.
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", i);
Op(INT_CLEAR_BIT, "$scratch");
Op(INT_IF_VARIABLE_EQUALS_VARIABLE, "$scratch", seqScratch);
Op(INT_SET_BIT, "$scratch");
Op(INT_END_IF);
Op(INT_IF_BIT_SET, "$scratch");
// Start the integer-to-string
// If there's no minus, then we have to load up
// convertState ourselves the first time.
if(digit == 0 && !mustDoMinus) {
Op(INT_SET_VARIABLE_TO_VARIABLE, convertState, var);
}
if(digit == 0) {
Op(INT_SET_BIT, isLeadingZero);
}
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch",
TenToThe((digits-digit)-1));
Op(INT_SET_VARIABLE_DIVIDE, "$scratch2", convertState,
"$scratch", 0);
Op(INT_SET_VARIABLE_MULTIPLY, "$scratch", "$scratch",
"$scratch2", 0);
Op(INT_SET_VARIABLE_SUBTRACT, convertState,
convertState, "$scratch", 0);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", '0');
Op(INT_SET_VARIABLE_ADD, "$scratch2", "$scratch2",
"$scratch", 0);
// Suppress all but the last leading zero.
if(digit != (digits - 1)) {
Op(INT_IF_VARIABLE_EQUALS_VARIABLE, "$scratch",
"$scratch2");
Op(INT_IF_BIT_SET, isLeadingZero);
Op(INT_SET_VARIABLE_TO_LITERAL,
"$scratch2", ' ');
Op(INT_END_IF);
Op(INT_ELSE);
Op(INT_CLEAR_BIT, isLeadingZero);
Op(INT_END_IF);
}
Op(INT_END_IF);
digit++;
} else if(outputChars[i] == 1) {
// do the minus; ugliness to get around the BRNE jump
// size limit, though
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", i);
Op(INT_CLEAR_BIT, "$scratch");
Op(INT_IF_VARIABLE_EQUALS_VARIABLE, "$scratch", seqScratch);
Op(INT_SET_BIT, "$scratch");
Op(INT_END_IF);
Op(INT_IF_BIT_SET, "$scratch");
// Also do the `absolute value' calculation while
// we're at it.
Op(INT_SET_VARIABLE_TO_VARIABLE, convertState, var);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch2", ' ');
Op(INT_IF_VARIABLE_LES_LITERAL, var, (SWORD)0);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch2", '-');
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch",
(SWORD)0);
Op(INT_SET_VARIABLE_SUBTRACT, convertState,
"$scratch", var, 0);
Op(INT_END_IF);
Op(INT_END_IF);
} else {
// just another character
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch", i);
Op(INT_IF_VARIABLE_EQUALS_VARIABLE, "$scratch", seqScratch);
Op(INT_SET_VARIABLE_TO_LITERAL, "$scratch2",
outputChars[i]);
Op(INT_END_IF);
}
}
Op(INT_IF_VARIABLE_LES_LITERAL, seqScratch, (SWORD)0);
Op(INT_ELSE);
Op(INT_SET_BIT, "$scratch");
Op(INT_UART_SEND, "$scratch2", "$scratch");
Op(INT_INCREMENT_VARIABLE, seq);
Op(INT_END_IF);
// Rung-out state: true if we're still running, else false
Op(INT_CLEAR_BIT, stateInOut);
Op(INT_IF_VARIABLE_LES_LITERAL, seq, steps);
Op(INT_SET_BIT, stateInOut);
Op(INT_END_IF);
break;
}
case ELEM_OPEN:
Op(INT_CLEAR_BIT, stateInOut);
break;
case ELEM_SHORT:
// goes straight through
break;
case ELEM_PLACEHOLDER:
Error(
_("Empty row; delete it or add instructions before compiling."));
CompileError();
break;
default:
oops();
break;
}
if(which != ELEM_SERIES_SUBCKT && which != ELEM_PARALLEL_SUBCKT) {
// then it is a leaf; let the simulator know which leaf it
// should be updating for display purposes
SimState(&(l->poweredAfter), stateInOut);
}
}
//-----------------------------------------------------------------------------
// Generate intermediate code for the entire program. Return TRUE if it worked,
// else FALSE.
//-----------------------------------------------------------------------------
BOOL GenerateIntermediateCode(void)
{
GenSymCountParThis = 0;
GenSymCountParOut = 0;
GenSymCountOneShot = 0;
GenSymCountFormattedString = 0;
// The EEPROM addresses for the `Make Persistent' op are assigned at
// int code generation time.
EepromAddrFree = 0;
IntCodeLen = 0;
memset(IntCode, 0, sizeof(IntCode));
if(setjmp(CompileErrorBuf) != 0) {
return FALSE;
}
Op(INT_SET_BIT, "$mcr");
int i;
for(i = 0; i < Prog.numRungs; i++) {
if(Prog.rungs[i]->count == 1 &&
Prog.rungs[i]->contents[0].which == ELEM_COMMENT)
{
// nothing to do for this one
continue;
}
Comment("");
Comment("start rung %d", i+1);
Op(INT_COPY_BIT_TO_BIT, "$rung_top", "$mcr");
SimState(&(Prog.rungPowered[i]), "$rung_top");
IntCodeFromCircuit(ELEM_SERIES_SUBCKT, Prog.rungs[i], "$rung_top");
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -