Jump to content

Eyck

Members
  • Content Count

    152
  • Joined

  • Last visited

  • Days Won

    46

Eyck last won the day on May 19

Eyck had the most liked content!

8 Followers

About Eyck

  • Rank
    Advanced Member

Contact Methods

  • Website URL
    http://www.minres.com/

Profile Information

  • Gender
    Male
  • Location
    Munich, Germany

Recent Profile Visitors

856 profile views
  1. First: I'm not going to solve your problems. I only propose possible solutions. So don't expect read-to-use models Second: doing wait() in an SC_THREAD or SC_CTHREAD creates an implicit FSM. I guess this is not what you want. And as you already noticed, it does not solve you problem. You have a syncronous design and you should model it like that. Third: if your latency is not what you want you need to change your model. Maybe there is a stage to much, maybe there aren't enough. This is left to the modeler....
  2. Just as explanation: pos() returns an event_finder (a proxy object which allows to use an event which is not yet available) while posedge_event() returns the event itself. And the operator|() is ony defined for sc_event.
  3. You are writing to ports in the constructor of server. At this point they are not bound. Since you initialize them in the beginning of your thread this is not needed anyways. Aside of that you also do not need the sensitivity list for the monitor thread as you never use the default sensitivity (by using wait() ). And if you use C++11 or newer you should use In-class member initializers which eases the naming of signals (and you should name them to make debugging easier): sc_in<bool> begin1{"begin1"}, begin2{"begin2"}, begin3{"begin3"}; sc_in<bool> end1{"end1"}, end2{"end2"}, end3{"end3"}; sc_in<bool> incoming1{"incoming1"}, incoming2{"incoming2"}, incoming3{"incoming3"}; sc_out<bool> free{"free"}, outgoing1{"outgoing1"}, outgoing2{"outgoing2"}, outgoing3{"outgoing3"};
  4. Eyck

    Queue fifo

    Actually you created an array of inputs of type int, not a pipe. Without more code it is hard to give any advise
  5. You should seriously read the SystemC standard or related books. Neither SC_METHOD nor SC_THREAD pass time, time advances only in the SystemC kernel and the kernel returns control to them at certain time points. The difference is that SC_THREAD preserves state when returning control to the kernel by calling wait(). SC_METHOD cannot preserve the state (it is always called as a function) and is therefore not allowed to call wait(). next_trigger() tells the SC kernel when to invoke the SC_METHOD next time. Calling next_trigger() several times in the same method as you do it is meaningless as the last call to next_trigger() prevails. Again: next_trigger() does not stop execution rather tells the kernel when to start the method next time.
  6. sc_time_stamp() returns a sc_time objec, not a string. It seems the use in a particular context (e.g. cout<<sc_time_stamp()) triggers an implicit type conversion. Pls. refer to the standard how to convert to particular unit.
  7. As the error message says: you forgot to bind a port. Since the are no names given (which I always suggest to do) it is a generated name. Moreover the sc_vector is not initialized to a certain size. So for your module do (C++11 assumed) it should look like: // Module defintion SC_MODULE (mux) { //inputs sc_in<bool> clk{"clk"}; sc_in<bool> reset{"reset"}; sc_in<bool> enable{"enable"}; sc_in<sc_uint<8> > in{"in"}; //output ports sc_vector<sc_out<sc_uint<8> > > out{"out", 8}; and sc_main should look like int sc_main(int argc, char* argv[]) { // Ports sc_signal <bool> reset{"reset"}; sc_signal <bool> clock{"clock"}; sc_signal <bool> enable{"enable"}; sc_signal<sc_uint<8> > input{"input"}; sc_vector<sc_signal<sc_uint<8>>> output{"output", 8}; //instance and port binding mux bind("mux"); bind.reset(reset); bind.clk(clock); bind.enable(enable); bind.in(input); bind.out(output); // Open VCD file sc_trace_file *wf = sc_create_vcd_trace_file("mux"); ... ...
  8. If you setup SC_THREADs the SystemC kernel invokes them and you do not have any control in which order SC_METHODS and SC_THREADS get invoked/resumed. SystemC gives no guarantee about the order of within a delta cycle. So the 2nd or 3rd stage of your pipeline could be executed before or after the 1st stage. If you use POD (C++ types and classes) they immediately change their value when being written. If you now have a variable V between the 1st and the 2nd stage it depends on the order of invocation if the 2nd stage reads the value in the same delta-cycle (1st stage is invoked before 2nd stage) or at the next clock cycle (2nd is invokde first reading the value before 1st stages updates it). This approach is largely used in C++ performance models and works as long as you don't have loops. This should answer your 1st question: txProcess should read its inputs before intermediateProcess updates them and intermediateProcess reads its inputs before rxProcess updates them. This way you model the syncronous nature of a pipeline. For the sake of simplicity I would model it using the means of SystemC: primitive channels and SC_METHODS: SC_MODULE(Design) { sc_in_clk clock; sc_in <bool> reset; sc_vector<sc_in <Flit>> flit_rx{"flit_rx", DIRECTIONS + 2}; sc_vector<sc_out <Flit>> flit_tx{"flit_tx", DIRECTIONS + 2}; static sc_fifo* fifo_creator(char const* name, size_t idx){ return new sc_fifo(name, BUFFER_SIZE); } sc_vector<sc_fifo<Flit>> buffer{"buffer", (DIRECTIONS + 2) * GlobalParams::n_virtual_channels, &Design::fifo_creator}; sc_vector<sc_fifo<Flit>> intermediate_buffer{"intermediate_buffer", (DIRECTIONS + 2) * GlobalParams::n_virtual_channels, &Design::fifo_creator}; void rxProcess(); void intermediateProcess(); void txProcess(); SC_CTOR(Design) { SC_METHOD(rxProcess); sensitive << reset; sensitive << clock.pos(); SC_METHOD(intermediateProcess); sensitive << reset; sensitive << clock.pos(); SC_METHOD(txProcess); sensitive << reset; sensitive << clock.pos(); } }; And the stage processes would look like: void Design::intermediateProcess() { if (reset.read()){ // put your reset stuff here } else if(clk_i.posedge()){ for (int i = 0; i < DIRECTIONS + 2; i++) { for (int vc = 0;vc < GlobalParams::n_virtual_channels; vc++) { if (buffer[i][vc].num_available()>0 && intermediate_buffer[i].num_free()>0) { Flit f; // get the incoming flit from buffer, check that the read is successfull sc_assert(buffer[i].nb_read(f)); // Store the incoming flit in the circular buffer, check that the read is successfull sc_assert(intermediate_buffer[i].nb_write(f)); } } } } } HTH
  9. You would do it like this: int sc_main(int argc, char* argv[]) { // Ports sc_signal <bool> reset; sc_signal <bool> clock; sc_signal<sc_uint<8> > input; sc_vector<sc_signal<sc_uint<8>>> output; //instance and port binding mux bind("mux"); bind.reset(reset); bind.clk(clock); bind.in(input); bind.out(output); // Open VCD file sc_trace_file *wf = sc_create_vcd_trace_file("mux"); ... ... But you cannot call sc_start before opening the VCD database. sc_start initializes the VCD output so you cannot add things to trace. When you write 'Both the methods dont seem to work' what is the problem you are seeing?
  10. Eyck

    syntax problems

    You can access elements using array index operator like this: in2[0][1]=42.0; But you write you want to put values onto the array. You cannot write onto ports as these are only proxys and do not hold values. You need to create a similar sc_signal array and connect it to the ports. sc_signals hold values so you can put values on them using write(). A side node: you should declare your vectors as: sc_vector<sc_vector<sc_in<float>>> in2{"in2", 4, [](char const* name, size_t idx) -> sc_vector<sc_in<float>>*{ return new sc_vector<sc_in<float>>(name, 4); }}; This names your ports (very helpful when tracing values) and you don't need to call init() separately.
  11. When implementing some simulation control I usually have the logic as part of a SC_THREAD. Once the thread is active it is save to access all the other data structures as -like @David Black mentioned- SystemC is cooperative multi tasking. Based on the GUI thread you can then decide to run for a certain time, until a certain event, or stop simulation entirely using sc_stop()
  12. Your problem is the use of POD (plain old datatype) for communication between the processes. Why? As soon as you write onto it all other processes see the update. So the behavior of your design depends on the scheduling of the processes. If Design::process is scheduled before Design::second_stage_process the second_stage_process sees the updates of process. Actually there are 2 ways out: you just have one thread and call the function from the output to the input: void Design::process() { txProcess(); intermediateProcess(); rxProcess(); } Although it will work in your case this approach will not scale. As soon as you cross sc_module boundaries you cannot control the order of calling. you use a primitive channel instead of POD. In your case you might use a sc_core::sc_fifo with a depth of one. And you should use sc_vector instead of the POD array type since they need the proper initialization. Why does it help? New values being written will be visible at the output of the fifo in the next delta cycle. So no matter in which order the threads and methods are invoked they will read the 'old' values despite 'new' values have been written. HTH
  13. Esp. as educational project you should implement it in 2 threads which communicate with each other. Since they run in the same process space you can access data safely once the simulation is in paused state. But you cannot restart the simulation without restarting the process it self. SystemC uses static global variables storing the simulation state and those get only initialized at program start.
  14. Actually there is a default time unit in sc_time.h: // ---------------------------------------------------------------------------- // STRUCT : sc_time_params // // Struct that holds the time resolution and default time unit. // ---------------------------------------------------------------------------- struct SC_API sc_time_params { double time_resolution; // in femto seconds bool time_resolution_specified; bool time_resolution_fixed; sc_time::value_type default_time_unit; // in time resolution bool default_time_unit_specified; sc_time_params(); ~sc_time_params(); }; Instantiating it you get the default values....
  15. Basically there are other ways if you have a process handle. But for this you need to get a emthod handle. To do this you have 2 options: You don't use SC_METHOD rather use sc_spawn directly (my _handle is a the part of you rmodule: sc_core::sc_spawn_options opt; opt.dont_initialize(); opt.spawn_method(); my_handle = sc_core::sc_spawn(func, name, &opt); this->sensitive << my_handle; this->sensitive_pos << my_handle; (if you don't use satic sensitivity you can skipe the last 2 liens). Using the handle you can change the sensitivity: reinterpret_cast<sc_method_process*>(my_handle.get_process_object())->next_trigger( sensitivity_change_event ); The other option is to retrieve the process handle upon the first invocation of your method using 'reinterpret_cast<sc_method_handle>(sc_get_current_process_handle()), store it in your module and then call next_trigger for it. But I'm not sure it this is cleaner...
×
×
  • Create New...