diff --git a/Changes b/Changes index d75f574f7..1b276018a 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support $fopen and I/O with integer instead of `verilator_file_descriptor. +**** Fix vpi_register_cb using bad s_cb_data, bug370. [by Thomas Watts] + **** Fix $display missing leading zeros in %0d, bug367. [Alex Solomatnikov] **** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++. diff --git a/include/verilated.cpp b/include/verilated.cpp index fa873ee4e..bf911fa4d 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -714,17 +714,21 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) { return got; } -QData VL_FOPEN_QI(QData filename, IData mode) { +IData VL_FOPEN_QI(QData filename, IData mode) { IData fnw[2]; VL_SET_WQ(fnw, filename); return VL_FOPEN_WI(2, fnw, mode); } -QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) { +IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) { char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1]; _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep); char modez[5]; _VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode); - return VerilatedImp::fdNew(fopen(filenamez,modez)); + return VL_FOPEN_S(filenamez,modez); } +IData VL_FOPEN_S(const char* filenamep, const char* modep) { + return VerilatedImp::fdNew(fopen(filenamep,modep)); +} + void VL_FCLOSE_I(IData fdi) { FILE* fp = VL_CVT_I_FP(fdi); if (VL_UNLIKELY(!fp)) return; diff --git a/include/verilated.h b/include/verilated.h index fb60fbc4f..49471c18f 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -324,9 +324,10 @@ extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP r /// File I/O extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi); -extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode); -extern QData VL_FOPEN_QI(QData ofilename, IData mode); -inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); } +extern IData VL_FOPEN_S(const char* filenamep, const char* mode); +extern IData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode); +extern IData VL_FOPEN_QI(QData ofilename, IData mode); +inline IData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); } extern void VL_FCLOSE_I(IData fdi); diff --git a/include/verilated_vpi.h b/include/verilated_vpi.h index 2668997a7..211295851 100644 --- a/include/verilated_vpi.h +++ b/include/verilated_vpi.h @@ -95,9 +95,12 @@ typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *); class VerilatedVpioCb : public VerilatedVpio { t_cb_data m_cbData; + s_vpi_value m_value; QData m_time; public: - VerilatedVpioCb(const t_cb_data* cbDatap, QData time) : m_cbData(*cbDatap), m_time(time) {} + VerilatedVpioCb(const t_cb_data* cbDatap, QData time) : m_cbData(*cbDatap), m_time(time) { + m_cbData.value = &m_value; + } virtual ~VerilatedVpioCb() {} static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast((VerilatedVpio*)h); } vluint32_t reason() const { return m_cbData.reason; } @@ -326,6 +329,7 @@ public: VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n", vop,varop->fullname(), *((CData*)newDatap));); memcpy(prevDatap, newDatap, varop->entSize()); + vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value); (vop->cb_rtnp()) (vop->cb_datap()); } } @@ -735,19 +739,26 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, // I/O routines -//-PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *fileName) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 cd) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *format, ...) { +PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *filenamep) { + return VL_FOPEN_S(filenamep,"wb"); +} + +PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { + VL_FCLOSE_I(mcd); return 0; +} + +//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 mcd) { //- _VL_VPI_UNIMP(); return 0; //-} +PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) { + va_list ap; + va_start(ap,formatp); + int chars = vpi_mcd_vprintf(mcd, formatp, ap); + va_end(ap); + return chars; +} + PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) { va_list ap; va_start(ap,formatp); @@ -760,15 +771,24 @@ PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) { return VL_VPRINTF(formatp, ap); } -//-PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_flush(void) { -//- _VL_VPI_UNIMP(); return 0; -//-} -//-PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { -//- _VL_VPI_UNIMP(); return 0; -//-} +PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) { + FILE* fp = VL_CVT_I_FP(mcd); + if (VL_UNLIKELY(!fp)) return 0; + int chars = vfprintf(fp, format, ap); + return chars; +} + +PLI_INT32 vpi_flush(void) { + Verilated::flushCall(); + return 0; +} + +PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { + FILE* fp = VL_CVT_I_FP(mcd); + if (VL_UNLIKELY(!fp)) return 1; + fflush(fp); + return 0; +} // utility routines diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 9cab34c66..ef540b072 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -28,6 +28,10 @@ // __FILE__ is too long #define FILENM "t_vpi_var.cpp" +unsigned int main_time = false; +unsigned int callback_count = false; +unsigned int callback_count_half = false; + //====================================================================== @@ -72,6 +76,35 @@ public: return __LINE__; \ } +int _mon_check_mcd() { + PLI_INT32 status; + + PLI_UINT32 mcd; + PLI_BYTE8* filename = (PLI_BYTE8*)"mcd_open.tmp"; + mcd = vpi_mcd_open(filename); + CHECK_RESULT_NZ(mcd); + + { // Check it got written + FILE* fp = fopen(filename,"r"); + CHECK_RESULT_NZ(fp); + fclose(fp); + } + + status = vpi_mcd_printf(mcd, (PLI_BYTE8*)"hello %s", "vpi_mcd_printf"); + CHECK_RESULT(status, strlen("hello vpi_mcd_printf")); + + status = vpi_mcd_flush(mcd); + CHECK_RESULT(status, 0); + + status = vpi_mcd_close(mcd); + CHECK_RESULT(status, 0); + + status = vpi_flush(); + CHECK_RESULT(status, 0); + + return 0; +} + int _mon_check_callbacks() { t_cb_data cb_data; cb_data.reason = cbEndOfSimulation; @@ -87,6 +120,46 @@ int _mon_check_callbacks() { return 0; } +int _value_callback(p_cb_data cb_data) { + CHECK_RESULT(cb_data->value->value.integer+10, main_time); + callback_count++; + return 0; +} + +int _value_callback_half(p_cb_data cb_data) { + CHECK_RESULT(cb_data->value->value.integer*2+10, main_time); + callback_count_half++; + return 0; +} + +int _mon_check_value_callbacks() { + vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL); + CHECK_RESULT_NZ(vh1); + + s_vpi_value v; + v.format = vpiIntVal; + vpi_get_value(vh1, &v); + + t_cb_data cb_data; + cb_data.reason = cbValueChange; + cb_data.cb_rtn = _value_callback; + cb_data.obj = vh1; + cb_data.value = &v; + + vpiHandle vh = vpi_register_cb(&cb_data); + CHECK_RESULT_NZ(vh); + + vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.half_count", NULL); + CHECK_RESULT_NZ(vh1); + + cb_data.obj = vh1; + cb_data.cb_rtn = _value_callback_half; + + vh = vpi_register_cb(&cb_data); + CHECK_RESULT_NZ(vh); + return 0; +} + int _mon_check_var() { VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL); CHECK_RESULT_NZ(vh1); @@ -245,7 +318,9 @@ int _mon_check_quad() { int mon_check() { // Callback from initial block in monitor + if (int status = _mon_check_mcd()) return status; if (int status = _mon_check_callbacks()) return status; + if (int status = _mon_check_value_callbacks()) return status; if (int status = _mon_check_var()) return status; if (int status = _mon_check_varlist()) return status; if (int status = _mon_check_getput()) return status; @@ -255,7 +330,6 @@ int mon_check() { //====================================================================== -unsigned int main_time = false; double sc_time_stamp () { return main_time; @@ -288,12 +362,15 @@ int main(int argc, char **argv, char **env) { while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); + VerilatedVpi::callValueCbs(); topp->clk = !topp->clk; //mon_do(); #if VM_TRACE if (tfp) tfp->dump (main_time); #endif } + CHECK_RESULT(callback_count, 501); + CHECK_RESULT(callback_count_half, 250); if (!Verilated::gotFinish()) { vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish"); } diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 6600fab52..8d1aaf00b 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -19,6 +19,9 @@ module t (/*AUTOARG*/ reg [3:2][61:0] quads /*verilator public_flat_rw @(posedge clk) */; + reg [31:0] count /*verilator public_flat_rd */; + reg [31:0] half_count /*verilator public_flat_rd */; + integer status; sub sub(); @@ -34,8 +37,17 @@ module t (/*AUTOARG*/ if (onebit != 1'b1) $stop; if (quads[2] != 62'h12819213_abd31a1c) $stop; if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; - $write("*-* All Finished *-*\n"); - $finish; + end + + always @(posedge clk) begin + count <= count + 2; + if (count[1]) + half_count <= half_count + 2; + + if (count == 1000) begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule