Project

General

Profile

[logo] 
 
Home
News
Activity
About/Contact
Major Tools
  Dinotrace
  Verilator
  Verilog-mode
  Verilog-Perl
Other Tools
  BugVise
  CovVise
  Force-Gate-Sim
  Gspice
  IPC::Locker
  Rsvn
  SVN::S4
  Voneline
  WFH
General Info
  Papers

Wait on rising edge from c++

Added by Michal Orsak 6 months ago

Hello,

how can I emulate trigger on rising/falling edge of the signal?

I have clock from DUT and I need to sample output in right time. If I just change main clock and call eval() all combination paths are evaluated and I am not able to read correct value from simulation, because it is too late.

I need somehow call callback if signal value is updated. Or I need to perform combinational and sequential eval() in separate run.


Replies (11)

RE: Wait on rising edge from c++ - Added by Wilson Snyder 6 months ago

Perhaps I misunderstand the problem, but call eval() without changing any clocks, then compute your combo logic, then call eval() again without changing any clocks, repeat your logic and eval() calls until stable.

RE: Wait on rising edge from c++ - Added by Michal Orsak 6 months ago

module Cntr #(parameter  DATA_WIDTH = 2
    )(input clk,
        output clk_out,
        input en,
        input rst,
        output [DATA_WIDTH- 1:0] val
    );

    reg [DATA_WIDTH- 1:0] counter = 2'b00;
    reg [DATA_WIDTH- 1:0] counter_next;
    assign clk_out = clk;
    always @(posedge clk) begin: assig_process_counter
        if(rst == 1'b1) begin
            counter <= 2'b00;
        end else begin
            counter <= counter_next;
        end
    end

    always @(counter or en) begin: assig_process_counter_next
        if((en)==1'b1) begin
            counter_next = counter + 2'(1);
        end else begin
            counter_next = counter;
        end
    end

    assign val = counter;
endmodule

Problem: If I wait in C++ on clk_out == 1 the value of val will be 1, but on rising edge of clk_out it was 0.

Combinational update and sequential update is not separable
void VCntr::_eval(VCntr__Syms* __restrict vlSymsp) {
    VL_DEBUG_IF(VL_DBG_MSGF("+    VCntr::_eval\n"); );
    VCntr* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    vlTOPp->_combo__TOP__2(vlSymsp);
    if (((IData)(vlTOPp->clk) & (~ (IData)(vlTOPp->__Vclklast__TOP__clk)))) {
    vlTOPp->_sequent__TOP__4(vlSymsp);
    vlTOPp->__Vm_traceActivity = (2U | vlTOPp->__Vm_traceActivity);
    }
    vlTOPp->_combo__TOP__5(vlSymsp);
    // Final
    vlTOPp->__Vclklast__TOP__clk = vlTOPp->clk;
}

Possible solutions: use VPI as shown in https://www.veripool.org/projects/verilator/wiki/Manual-verilator#VPI-Example

  • problem: copy of signal memory each time?, multiple simulations, multithreading

hack vlTOPp->_Vclklast_TOP__clk

  • if clk = new val do vlTOPp->_Vclklast_TOP__clk = new val, call eval(), then vlTOPp->_Vclklast_TOP__clk = prev val, call eval()
  • problem: unknown consequences, discovery of all clk signals

Also it is safe to have multiple simulations running in multiple threads?

Cntr.zip - .v, .cpp, .vcd (12.6 KB)

Screenshot.png View (8 KB)

RE: Wait on rising edge from c++ - Added by Michal Orsak 6 months ago

Hello, if you think I am doing something wrong, please tell me.

By combinational update I mean the update of paths before registers. By sequential update I mean the potential update of registers and combinational paths behind registers.

As code for sequential update is always in lower part of _eval() I need just split this function on two. (For arbitrary number of clock signals etc.)

I can create patch for this functionality, do you think this functionality can be part of Verilator?

RE: Wait on rising edge from c++ - Added by Wilson Snyder 6 months ago

Yes, with --threads 1 you can have different simulations in multiple thread.

The fundamental problem is really that generated clocks don't work nicely even in an all-verilator model, much less expecting external code as part of the process.

From a IEEE spec sense there isn't really a difference between combo and sequential code, the real difference is when delayed assignments take effect. However Verilator generally squashes this distinction because to do otherwise would be slow (all delayed assignments would need to be stored.)

However for your case it probably is the case that if you make a separate eval_combo call this would solve your issue. I won't make any claims this will solve more general problems; generally at present with Verilator clocks should be fed in, not out of the model for correct results.

If you want to experiment with an eval_combo() call I'd suggest to reduce performance loss that the eval_combo() replicate most of what is in eval() but without any of the clock detection. (Versus splitting combo out of existing eval() which would cause some optimizations to be lost.) This probably goes in V3Clock.cpp

Note the _combo in the function names isn't necessarily only combo code, you need to check the internal AstActive types to see what code is marked combo or not.

RE: Wait on rising edge from c++ - Added by Michal Orsak 6 months ago

Split of eval() eval_combo/_seq() is not generally possible.
  • Clock can be generated also from the output value of register.
Instead I have found out that different thing is required.
  • Notification before first event condition for each clock.

But that is actually good news as it requires only to add macro which can be empty in default implementation.

if (((IData)(vlTOPp->clk) & (~ (IData)(vlTOPp->__Vclklast__TOP__clk)))) {
    BEFORE_RISING_EDGE(&vlTOPp->clk);
    vlTOPp->_sequent__TOP__4(vlSymsp);
}
...
if (((IData)(vlTOPp->clk2) & (~ (IData)(vlTOPp->__Vclk2last__TOP__clk)))) {
    BEFORE_RISING_EDGE(&vlTOPp->clk2);
    vlTOPp->_sequent__TOP__5(vlSymsp);
}
...
No what features do I expect from simulator.
  • Possibility to write combinational loops in C-code.
  • satisfied, on first clk edge evaluation just break the _eval() and run it again (if required).
  • Possibility to read value on clock edge
  • satisfied, on the BEFORE_RISING_EDGE of specified clock just read the values
  • Clock gating
  • probably can be emulated
  • X, Z, U values
RE:
generated clocks don't work nicely even in an all-verilator model
I think that problem is that Verilator is not discrete event simulator. The problem is that order of events is specified compile time. But it may not be the problem as it can be solved by disabling of segments of eval() and revaluating of the eval(). But it may be quite hard task to find such a conditions for re-evaluation of the segments.

RE: Wait on rising edge from c++ - Added by Wilson Snyder 6 months ago

What do you propose BEFORE_RISING_EDGE will do? Generally this won't work as Verilator assumes all signals are only changed by Verilator itself. Furthermore due to scheduling the same clock may have multiple IF statements.

generated clocks don't work nicely even in an all-verilator model

I think that problem is that Verilator is not discrete event simulator.

Yes, there wasn't a question as to why they didn't work ;)

RE: Wait on rising edge from c++ - Added by Michal Orsak 5 months ago

Hello, how do I add C macro call to AST?

If I use AstCFunc:
auto before_edge_fn = new AstCFunc(nodep->fileline(),       
        "ON_CHANGE", m_topScopep->scopep(), "void");        
before_edge_fn->argTypes(EmitCBaseVisitor::symClassVar());  
before_edge_fn->dontCombine(true);                          
before_edge_fn->slow(true);                                 
before_edge_fn->isStatic(true);                             
before_edge_fn->symProlog(true);                            
auto before_edge_call = new AstCCall(nodep->fileline(),     
        before_edge_fn, nullptr);                           
stmtsp->addPrev(before_edge_call);                          
The function is called on parent object
void Vtop::_eval(Vtop__Syms* __restrict vlSymsp) {
    Vtop* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    vlTOPp->_combo__TOP__2(vlSymsp);
    if (((IData)(vlTOPp->fastclk) & (~ (IData)(vlTOPp->__Vclklast__TOP__fastclk)))) {
    vlTOPp->ON_CHANGE();
    vlTOPp->_sequent__TOP__4(vlSymsp);
    }
   ...
}
I would like to have only:
    if (((IData)(vlTOPp->fastclk) & (~ (IData)(vlTOPp->__Vclklast__TOP__fastclk)))) {
    ON_CHANGE();
    ...

Is there a AST node for c macro call or it can be created? (or is there something like global scope?)

RE: Wait on rising edge from c++ - Added by Wilson Snyder 5 months ago

Easiest is

new AstCStmt(nodep->fileline(), "ON_CHANGE()")

However as I noted earlier I think this ON_CHANGE approach might not do what you expect in general.

RE: Wait on rising edge from c++ - Added by Michal Orsak 5 months ago

Thank you for fast fast responce.

You are right, it will not work as it is. But if we add read/write only restriction in delta step phases it should work. https://github.com/Nic30/pycocotb/blob/master/pycocotb/hdlSimulator.py#L66 Do you see any issue?

RE:
Easiest is
  • Ok, minor problem is that I need clock address as a parameter.

RE: Wait on rising edge from c++ - Added by Wilson Snyder 5 months ago

I suspect it will have trouble with larger designs where multiple if()'s are inserted, but give it a try.

RE: Wait on rising edge from c++ - Added by Michal Orsak 5 months ago

Actually, there is only one first if() for clock signal per circuit and only waiting simulation processes for this clock signals are executed.

( In pure verilog it is not clear which signal is output clock, clock gate etc. But I do have this information as my code is generated. And I can add an extra "if" for each output clock. And drive input clock gates in correct way. And assert correct IO access in specific simulation phases. )

I did only few changes to Verilator but I think that they may not be useful for everyone.

( I only added support for virtual functions and some custom visitor which adds calls of event functions on specified places. And then I am using boost/coroutine2 to pause call of eval() when event is triggered. )

It would be better if we can build verilator as a library so other projects can use it. I hope I can send you patches (minor improvements) in January.

    (1-11/11)