/* Copyright (c) 1995-2003 Pragmatic C Software Corp. */ /* * test of all action call backs * shows sequences of events for action user callbacks */ #include #include #include #include "vpi_user.h" #include "cv_vpi_user.h" /* local prototypes */ static char *cb_val_to_nam(char *, int); static void prt_reg_cbs(char *); /* global prototypes */ extern PLI_INT32 remove_all_actions(p_vpi_systf_data); extern PLI_INT32 reg_all_actions(p_vpi_systf_data); extern int setup_callbacks(struct t_cb_data *); extern int cb_compend(p_cb_data); extern int cbsimstart(p_cb_data); extern int cbsimstart2(p_cb_data); extern int cbresetstart(p_cb_data); extern int cbresetend(p_cb_data); extern int cbsimend(p_cb_data); extern int cbtchkerr(p_cb_data); extern int cbenteriact(p_cb_data); extern int cbexitiact(p_cb_data); extern int cbiactscopchg(p_cb_data); extern int my_error_handler(struct t_cb_data *); extern void register_cbs(void); extern void register_systfs(void); vpiHandle action_cbtab[64]; /* * remove all register action cbs */ PLI_INT32 remove_all_actions(p_vpi_systf_data tfdatp) { vpiHandle cbhref; prt_reg_cbs("callbacks before $remove_all_actions"); /* can't remove start of sim reset? */ if ((cbhref = action_cbtab[cbStartOfReset]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbStartOfReset] = NULL; } if ((cbhref = action_cbtab[cbEndOfReset]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbEndOfReset] = NULL; } if ((cbhref = action_cbtab[cbEndOfSimulation]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbEndOfSimulation] = NULL; } if ((cbhref = action_cbtab[cbTchkViolation]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbTchkViolation] = NULL; } if ((cbhref = action_cbtab[cbEnterInteractive]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbEnterInteractive] = NULL; } if ((cbhref = action_cbtab[cbExitInteractive]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbExitInteractive] = NULL; } if ((cbhref = action_cbtab[cbInteractiveScopeChange]) != NULL) { vpi_remove_cb(cbhref); action_cbtab[cbInteractiveScopeChange] = NULL; } prt_reg_cbs("callbacks after $remove_all_actions"); return(0); } /* * print all register call backs */ static void prt_reg_cbs(char *label) { vpiHandle iter, cbref; s_cb_data cb_inf; p_cb_data cbinfp; char s1[1025]; vpi_printf(">>> %s <<<\n", label); /* get iterator of all registered callbacks */ if ((iter = vpi_iterate(vpiCallback, NULL)) == NULL) { vpi_printf(" **NONE**\n"); return; } /* user provides record that is filled but following current semantics */ /* values pointed to by contents are shared (i.e. must be left as is) */ cbinfp = &cb_inf; cbinfp->obj = NULL; cbinfp->time = NULL; cbinfp->value = NULL; cbinfp->index = 0; for (;;) { if ((cbref = vpi_scan(iter)) == NULL) break; vpi_get_cb_info(cbref, cbinfp); vpi_printf(" vpi_ callback type %s registered\n", cb_val_to_nam(s1, cbinfp->reason)); } } /* * convert a callback reason constant to a name * * some here not supported by Cver - will just never see */ static char *cb_val_to_nam(char *s, int cbtyp) { switch (cbtyp) { case cbValueChange: strcpy(s, "cbValueChange"); break; case cbStmt: strcpy(s, "cbStmt"); break; case cbForce: strcpy(s, "cbForce"); break; case cbRelease: strcpy(s, "cbRelease"); break; case cbAtStartOfSimTime: strcpy(s, "cbAtStartOfSimTime"); break; case cbReadWriteSynch: strcpy(s, "cbReadWriteSynch"); break; case cbReadOnlySynch: strcpy(s, "cbReadOnlySynch"); break; case cbNextSimTime: strcpy(s, "cbNextSimTime"); break; case cbAfterDelay: strcpy(s, "cbAfterDelay"); break; case cbEndOfCompile: strcpy(s, "cbEndOfCompile"); break; case cbStartOfSimulation: strcpy(s, "cbStartOfSimulation"); break; case cbEndOfSimulation: strcpy(s, "cbEndOfSimulation"); break; case cbError: strcpy(s, "cbError"); break; case cbPLIError: strcpy(s, "cbPLIError"); break; case cbTchkViolation: strcpy(s, "cbTchkViolation"); break; case cbStartOfSave: strcpy(s, "cbStartOfSave"); break; case cbEndOfSave: strcpy(s, "cbEndOfSave"); break; case cbStartOfRestart: strcpy(s, "cbStartOfRestart"); break; case cbEndOfRestart: strcpy(s, "cbEndOfRestart"); break; case cbStartOfReset: strcpy(s, "cbStartOfReset"); break; case cbEndOfReset: strcpy(s, "cbEndOfReset"); break; case cbEnterInteractive: strcpy(s, "cbEnterInteractive"); break; case cbExitInteractive: strcpy(s, "cbExitInteractive"); break; case cbInteractiveScopeChange: strcpy(s, "cbInteractiveScopeChange"); break; case cbUnresolvedSystf: strcpy(s, "cbUnresolvedSystf"); break; default: strcpy(s, "**unknown**"); break; } return(s); } /* * reg all action cbs * if user does not call after remove - will have 2 registerd */ int reg_all_actions(p_vpi_systf_data tfdatp) { prt_reg_cbs("callbacks before $reg_all_actions"); setup_callbacks(NULL); prt_reg_cbs("callbacks after $reg_all_actions"); return(0); } /* * routine to setup call backs (called from start of simulation cb) */ int setup_callbacks(struct t_cb_data *cbp) { vpiHandle cbhref; struct t_cb_data cbrec; /* these must be NULL or given well formed records maybe vpiSuppress... */ cbrec.obj = NULL; cbrec.time = NULL; cbrec.value = NULL; cbrec.user_data = NULL; /* this schedules event so same action cb from action routine should work? */ if (action_cbtab[cbStartOfSimulation] == NULL) { cbrec.reason = cbStartOfSimulation; cbrec.cb_rtn = cbsimstart2; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbStartOfSimulation] = cbhref; } if (action_cbtab[cbStartOfReset] == NULL) { cbrec.reason = cbStartOfReset; cbrec.cb_rtn = cbresetstart; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbStartOfReset] = cbhref; } if (action_cbtab[cbEndOfReset] == NULL) { cbrec.reason = cbEndOfReset; cbrec.cb_rtn = cbresetend; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbEndOfReset] = cbhref; } if (action_cbtab[cbEndOfSimulation] == NULL) { cbrec.reason = cbEndOfSimulation; cbrec.cb_rtn = cbsimend; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbEndOfSimulation] = cbhref; } if (action_cbtab[cbTchkViolation] == NULL) { cbrec.reason = cbTchkViolation; cbrec.cb_rtn = cbtchkerr; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbTchkViolation] = cbhref; } if (action_cbtab[cbEnterInteractive] == NULL) { cbrec.reason = cbEnterInteractive; cbrec.cb_rtn = cbenteriact; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbEnterInteractive] = cbhref; } if (action_cbtab[cbExitInteractive] == NULL) { cbrec.reason = cbExitInteractive; cbrec.cb_rtn = cbexitiact; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbExitInteractive] = cbhref; } if (action_cbtab[cbInteractiveScopeChange] == NULL) { cbrec.reason = cbInteractiveScopeChange; cbrec.cb_rtn = cbiactscopchg; cbhref = vpi_register_cb(&cbrec); action_cbtab[cbInteractiveScopeChange] = cbhref; } return(0); } int cb_compend(p_cb_data cbp) { vpi_printf("*** at end of compilation callback ***\n"); return(0); } int cbsimstart(p_cb_data cbp) { vpi_printf("*** at start of simulation callback (from vlog startup) ***\n"); return(0); } int cbsimstart2(p_cb_data cbp) { vpi_printf("*** at start of simulation callback ***\n"); return(0); } int cbresetstart(p_cb_data cbp) { vpi_printf("*** at start of reset callback ***\n"); return(0); } int cbresetend(p_cb_data cbp) { vpi_printf("*** at end of reset callback ***\n"); return(0); } int cbsimend(p_cb_data cbp) { vpi_printf("*** at end of simulation callback ***\n"); return(0); } int cbtchkerr(p_cb_data cbp) { char s1[1024]; if (cbp->obj != NULL) strcpy(s1, vpi_get_str(vpiFullName, cbp->obj)); vpi_printf("*** timing check violation at **%s(%d) in %s callback\n", vpi_get_str(vpiFile, cbp->obj), vpi_get(vpiLineNo, cbp->obj), s1); return(0); } int cbenteriact(p_cb_data cbp) { vpi_printf("*** entering interactive mode callback ***\n"); return(0); } int cbexitiact(p_cb_data cbp) { vpi_printf("*** exiting interactive mode callback ***\n"); return(0); } int cbiactscopchg(p_cb_data cbp) { vpi_printf("*** changing interactive scope to %s callback ***\n", vpi_get_str(vpiFullName, cbp->obj)); return(0); } /* * routine to build an error indication string */ int my_error_handler(struct t_cb_data *cbp) { struct t_vpi_error_info einfotab; struct t_vpi_error_info *einfop; char s1[128]; einfop = &einfotab; vpi_chk_error(einfop); if (einfop->state == vpiCompile) strcpy(s1, "vpiCompile"); else if (einfop->state == vpiPLI) strcpy(s1, "vpiPLI"); else if (einfop->state == vpiRun) strcpy(s1, "vpiRun"); else strcpy(s1, "**unknown**"); vpi_printf("**ERR(%s) %s (level %d) at **%s(%d):\n %s\n", einfop->code, s1, einfop->level, einfop->file, einfop->line, einfop->message); /* if serious error give up, ingore normal errors */ if (einfop->level == vpiError || einfop->level == vpiSystem || einfop->level == vpiInternal) { vpi_printf("**FATAL: encountered error - giving up\n"); vpi_sim_control(vpiFinish, 0); } return(0); } /* Template functin table for added user systf tasks and functions. See file vpi_user.h for structure definition Note only vpi_register_systf and vpi_ or tf_ utility routines that do not access the simulation data base may be called from these routines */ /* all routines are called to register cbs */ /* called just after all PLI 1.0 tf_ veriusertfs table routines are set up */ /* before source is read */ void (*vlog_startup_routines[]) () = { register_cbs, register_systfs, 0 }; /* routine to do the systf registering - probably should go in other file */ /* usually only vpi_ PLI 2.0 systf or cb registering is done here */ /* * register start of sim call backs and set up error handling * * since handle not save (passed back?), no way to find out cb info * start of sim is first when internal data base completed */ void register_cbs(void) { vpiHandle href; struct t_cb_data *ecbp, *cbp; struct t_cb_data cbrec; /* notice cb records must be in global storage */ ecbp = &cbrec; ecbp->reason = cbError; ecbp->cb_rtn = my_error_handler; ecbp->obj = NULL; ecbp->time = NULL; ecbp->value = NULL; ecbp->user_data = NULL; /* probably should check for error here */ if ((href = vpi_register_cb(ecbp)) == NULL) vpi_printf("**ERR: can not register register error handler callback.\n"); /* for this test only - setup cbs before start of sim */ cbp = &cbrec; cbp->cb_rtn = cb_compend; cbp->reason = cbEndOfCompile; /* notice rest already initialized from ecbp register */ href = vpi_register_cb(cbp); action_cbtab[cbEndOfCompile] = href; cbp->reason = cbStartOfSimulation; cbp->cb_rtn = setup_callbacks; /* notice rest already initialized from ecbp register */ /* probably should check for error here */ if ((href = vpi_register_cb(cbp)) == NULL) vpi_printf("**ERR: cannot register start of sim callback.\n"); action_cbtab[cbStartOfSimulation] = href; } /* * register remove call back system task - to be called interactively */ void register_systfs(void) { static struct t_vpi_systf_data tfdat, tfdat2; char s1[1024]; tfdat.type = vpiSysTask; strcpy(s1, "$remove_all_actions"); tfdat.tfname = malloc(strlen(s1) + 1); strcpy(tfdat.tfname, s1); tfdat.calltf = remove_all_actions; vpi_register_systf(&tfdat); tfdat2.type = vpiSysTask; strcpy(s1, "$reg_all_actions"); tfdat2.tfname = malloc(strlen(s1) + 1); strcpy(tfdat2.tfname, s1); tfdat2.calltf = reg_all_actions; vpi_register_systf(&tfdat2); } /* dummy +loadvpi= boostrap routine - mimics old style exec all routines */ /* in standard PLI vlog_startup_routines table */ void vpi_compat_bootstrap(void) { int i; for (i = 0;; i++) { if (vlog_startup_routines[i] == NULL) break; vlog_startup_routines[i](); } }