+2003-10-22 Erik Petrich <epetrich@ivorytower.norman.ok.us>
+
+ Extended the semantics of the critical keyword to include
+ individual statements. See RFE #827755 and #799831
+ * src/SDCC.y
+ * src/SDCCicode.c
+ * src/SDCCopt.c
+ * src/SDCCast.c
+ * support/Util/SDCCerr.c
+ * support/Util/SDCCerr.h
+ * src/mcs51/gen.c
+ * src/ds390/gen.c
+ * src/hc08/gen.c
+
2003-10-19 Borut Razem <borut.razem@siol.net>
* src/SDCC.lex: fixed bug #825944 - defined yytext_ptr to make it compile with flex 2.5.31
int reentrant = 0 ;
int blockNo = 0 ; /* sequential block number */
int currBlockno=0 ;
+int inCritical= 0 ;
extern int yylex();
int yyparse(void);
extern int noLineno ;
%token BITWISEAND UNARYMINUS IPUSH IPOP PCALL ENDFUNCTION JUMPTABLE
%token RRC RLC
%token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND ARRAYINIT
-%token DUMMY_READ_VOLATILE
+%token DUMMY_READ_VOLATILE ENDCRITICAL
%type <yyint> Interrupt_storage
%type <sym> identifier declarator declarator2 enumerator_list enumerator
%type <sym> struct_declarator_list struct_declaration struct_declaration_list
%type <sym> declaration init_declarator_list init_declarator
%type <sym> declaration_list identifier_list parameter_identifier_list
-%type <sym> declarator2_function_attributes while do for
+%type <sym> declarator2_function_attributes while do for critical
%type <lnk> pointer type_specifier_list type_specifier type_name
%type <lnk> storage_class_specifier struct_or_union_specifier
%type <lnk> declaration_specifiers sfr_reg_bit type_specifier2
%type <asts> statement_list statement labeled_statement compound_statement
%type <asts> expression_statement selection_statement iteration_statement
%type <asts> jump_statement function_body else_statement string_literal
+%type <asts> critical_statement
%type <ilist> initializer initializer_list
%type <yyint> unary_operator assignment_operator struct_or_union
| selection_statement
| iteration_statement
| jump_statement
+ | critical_statement
| INLINEASM ';' {
ast *ex = newNode(INLINEASM,NULL,NULL);
ex->values.inlineasm = strdup($1);
}
;
+critical
+ : CRITICAL {
+ inCritical++;
+ STACK_PUSH(continueStack,NULL);
+ STACK_PUSH(breakStack,NULL);
+ $$ = NULL;
+ }
+ ;
+
+critical_statement
+ : critical statement {
+ STACK_POP(breakStack);
+ STACK_POP(continueStack);
+ inCritical--;
+ $$ = newNode(CRITICAL,$2,NULL);
+ }
+ ;
+
labeled_statement
// : identifier ':' statement { $$ = createLabel($1,$3); }
: identifier ':' { $$ = createLabel($1,NULL); }
STACK_PEEK(breakStack)->isref = 1;
}
}
- | RETURN ';' { $$ = newNode(RETURN,NULL,NULL) ; }
- | RETURN expr ';' { $$ = newNode(RETURN,NULL,$2) ; }
+ | RETURN ';' {
+ if (inCritical) {
+ werror(E_INVALID_CRITICAL);
+ $$ = NULL;
+ } else {
+ $$ = newNode(RETURN,NULL,NULL);
+ }
+ }
+ | RETURN expr ';' {
+ if (inCritical) {
+ werror(E_INVALID_CRITICAL);
+ $$ = NULL;
+ } else {
+ $$ = newNode(RETURN,NULL,$2);
+ }
+ }
;
identifier
fprintf(outfile,"FOR LOOP BODY \n");
ast_print(tree->left,outfile,indent+2);
return ;
+ case CRITICAL:
+ fprintf(outfile,"CRITICAL (%p) \n",tree);
+ ast_print(tree->left,outfile,indent+2);
default:
return ;
}
PRINTFUNC (picInline);
PRINTFUNC (picReceive);
PRINTFUNC (picDummyRead);
+PRINTFUNC (picCritical);
+PRINTFUNC (picEndCritical);
iCodeTable codeTable[] =
{
{RECEIVE, "recv", picReceive, NULL},
{SEND, "send", picGenericOne, NULL},
{ARRAYINIT, "arrayInit", picGenericOne, NULL},
- {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL}
+ {DUMMY_READ_VOLATILE, "dummy = (volatile)", picDummyRead, NULL},
+ {CRITICAL, "critical_start", picCritical, NULL},
+ {ENDCRITICAL, "critical_end", picEndCritical, NULL}
};
/*-----------------------------------------------------------------*/
fprintf (of, "\n");
}
+PRINTFUNC (picCritical)
+{
+ fprintf (of, "\t");
+ if (IC_RESULT (ic))
+ printOperand (IC_RESULT (ic), of);
+ else
+ fprintf (of, "(stack)");
+ fprintf (of, " = %s ", s);
+ fprintf (of, "\n");
+}
+
+PRINTFUNC (picEndCritical)
+{
+ fprintf (of, "\t");
+ fprintf (of, "%s = ", s);
+ if (IC_RIGHT (ic))
+ printOperand (IC_RIGHT (ic), of);
+ else
+ fprintf (of, "(stack)");
+ fprintf (of, "\n");
+}
+
/*-----------------------------------------------------------------*/
/* piCode - prints one iCode */
/*-----------------------------------------------------------------*/
}
ADDTOCHAIN (ic);
}
+
+/*-----------------------------------------------------------------*/
+/* geniCodeCritical - intermediate code for a critical statement */
+/*-----------------------------------------------------------------*/
+static void
+geniCodeCritical (ast *tree, int lvl)
+{
+ iCode *ic;
+ operand *op = NULL;
+
+ /* If op is NULL, the original interrupt state will saved on */
+ /* the stack. Otherwise, it will be saved in op. */
+
+ /* Generate a save of the current interrupt state & disabled */
+ ic = newiCode (CRITICAL, NULL, NULL);
+ IC_RESULT (ic) = op;
+ ADDTOCHAIN (ic);
+
+ /* Generate the critical code sequence */
+ if (tree->left && tree->left->type == EX_VALUE)
+ geniCodeDummyRead (ast2iCode (tree->left,lvl+1));
+ else
+ ast2iCode (tree->left,lvl+1);
+
+ /* Generate a restore of the original interrupt state */
+ ic = newiCode (ENDCRITICAL, NULL, op);
+ ADDTOCHAIN (ic);
+}
/*-----------------------------------------------------------------*/
/* Stuff used in ast2iCode to modify geniCodeDerefPtr in some */
tree->opval.op != GOTO &&
tree->opval.op != SWITCH &&
tree->opval.op != FUNCTION &&
- tree->opval.op != INLINEASM)
+ tree->opval.op != INLINEASM &&
+ tree->opval.op != CRITICAL)
{
if (IS_ASSIGN_OP (tree->opval.op) ||
case ARRAYINIT:
geniCodeArrayInit(tree, ast2iCode (tree->left,lvl+1));
return NULL;
+
+ case CRITICAL:
+ geniCodeCritical (tree, lvl);
}
return NULL;
if (SKIP_IC (ic) ||
ic->op == IFX ||
ic->op == RETURN ||
- ic->op == DUMMY_READ_VOLATILE)
+ ic->op == DUMMY_READ_VOLATILE ||
+ ic->op == CRITICAL ||
+ ic->op == ENDCRITICAL)
continue;
/* if the result is volatile then continue */
/* if critical function then turn interrupts off */
if (IFFUNC_ISCRITICAL (ftype))
{
- emitcode ("mov", "c,ea");
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitcode ("", "%05d$:", (tlbl->key + 100));
emitcode ("push", "psw"); /* save old ea via c in psw */
- emitcode ("clr", "ea");
}
}
freeAsmop (right, NULL, ic, TRUE);
}
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ D(emitcode("; genCritical",""));
+
+ if (IC_RESULT (ic))
+ aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitcode ("", "%05d$:", (tlbl->key + 100));
+
+ if (IC_RESULT (ic))
+ outBitC (IC_RESULT (ic)); /* save old ea in an operand */
+ else
+ emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
+
+ if (IC_RESULT (ic))
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+ D(emitcode("; genEndCritical",""));
+
+ if (IC_RIGHT (ic))
+ {
+ aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+ if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
+ emitcode ("mov", "ea,c");
+ }
+ else
+ {
+ MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ emitcode ("mov", "ea,c");
+ }
+ freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+ }
+ else
+ {
+ emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
+ emitcode ("mov", "ea,c");
+ }
+}
+
+
+
/*-----------------------------------------------------------------*/
/* genBuiltIn - calls the appropriate function to generating code */
/* for a built in function */
genDummyRead (ic);
break;
+ case CRITICAL:
+ genCritical (ic);
+ break;
+
+ case ENDCRITICAL:
+ genEndCritical (ic);
+ break;
+
#if 0 // obsolete, and buggy for != xdata
case ARRAYINIT:
genArrayInit(ic);
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
+/*-----------------------------------------------------------------*/
+/* genDummyRead - generate code for dummy read of volatiles */
+/*-----------------------------------------------------------------*/
+static void
+genDummyRead (iCode * ic)
+{
+ operand *right;
+ int size, offset;
+
+ D(emitcode("; genDummyRead",""));
+
+ right = IC_RIGHT (ic);
+
+ aopOp (right, ic, FALSE);
+
+ /* bit variables done */
+ /* general case */
+ size = AOP_SIZE (right);
+ offset = 0;
+
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (right), offset);
+ hc08_freeReg (hc08_reg_a);
+ offset++;
+ }
+
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+ D(emitcode("; genCritical",""));
+
+ if (IC_RESULT (ic))
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ emitcode ("tpa", "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ emitcode ("sei", "");
+
+ if (IC_RESULT (ic))
+ storeRegToAop (hc08_reg_a, AOP (IC_RESULT (ic)), 0);
+ else
+ pushReg (hc08_reg_a, FALSE);
+
+ hc08_freeReg (hc08_reg_a);
+ if (IC_RESULT (ic))
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+ D(emitcode("; genEndCritical",""));
+
+ if (IC_RIGHT (ic))
+ {
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ loadRegFromAop (hc08_reg_a, AOP (IC_RIGHT (ic)), 0);
+ emitcode ("tap", "");
+ hc08_freeReg (hc08_reg_a);
+ freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+ }
+ else
+ {
+ pullReg (hc08_reg_a);
+ emitcode ("tap", "");
+ }
+}
+
+
/*-----------------------------------------------------------------*/
/* genhc08Code - generate code for HC08 based controllers */
/*-----------------------------------------------------------------*/
addSet (&_G.sendSet, ic);
break;
+ case DUMMY_READ_VOLATILE:
+ genDummyRead (ic);
+ break;
+
+ case CRITICAL:
+ genCritical (ic);
+ break;
+
+ case ENDCRITICAL:
+ genEndCritical (ic);
+ break;
+
default:
ic = ic;
}
/* if critical function then turn interrupts off */
if (IFFUNC_ISCRITICAL (ftype))
{
- emitcode ("mov", "c,ea");
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitcode ("", "%05d$:", (tlbl->key + 100));
emitcode ("push", "psw"); /* save old ea via c in psw */
- emitcode ("clr", "ea");
}
}
freeAsmop (right, NULL, ic, TRUE);
}
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ D(emitcode("; genCritical",""));
+
+ if (IC_RESULT (ic))
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitcode ("", "%05d$:", (tlbl->key + 100));
+
+ if (IC_RESULT (ic))
+ outBitC (IC_RESULT (ic)); /* save old ea in an operand */
+ else
+ emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
+
+ if (IC_RESULT (ic))
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+ D(emitcode("; genEndCritical",""));
+
+ if (IC_RIGHT (ic))
+ {
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
+ emitcode ("mov", "ea,c");
+ }
+ else
+ {
+ MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ emitcode ("mov", "ea,c");
+ }
+ freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+ }
+ else
+ {
+ emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
+ emitcode ("mov", "ea,c");
+ }
+}
+
+
/*-----------------------------------------------------------------*/
/* gen51Code - generate code for 8051 based controllers */
/*-----------------------------------------------------------------*/
genDummyRead (ic);
break;
+ case CRITICAL:
+ genCritical (ic);
+ break;
+
+ case ENDCRITICAL:
+ genEndCritical (ic);
+ break;
+
default:
ic = ic;
}
"function attribute following non-function declaration"},
{ W_SAVE_RESTORE, ERROR_LEVEL_PEDANTIC,
"unmatched #pragma SAVE and #pragma RESTORE" },
+{ E_INVALID_CRITICAL, ERROR_LEVEL_ERROR,
+ "not allowed in a critical section" },
};
/*
#define W_BITFLD_NAMED 168 /* declarator used with 0 length bitfield */
#define E_FUNC_ATTR 169 /* function attribute without function */
#define W_SAVE_RESTORE 170 /* unmatched #pragma SAVE and #pragma RESTORE */
+#define E_INVALID_CRITICAL 171 /* operation invalid in critical sequence */
/** Describes the maximum error level that will be logged. Any level
* includes all of the levels listed after it.