Jump to content

apfitch

Members
  • Posts

    613
  • Joined

  • Last visited

  • Days Won

    121

Everything posted by apfitch

  1. If you notify an event called e, then just use sensitive << e; to trigger when the event is notified. regards Alan
  2. If everything works in zero time, then no conflict is possible, and no arbitration is needed. However you can, as you say, wait in your model, in which case it will take time. To test how the model reacts, you can send two transactions to the same target port (i.e. from two initiators). b_transport must be re-entrant according to the LRM, so that's allowed. It's then up to you in your model to build some kind of locking mechanism to represent when the model is busy. regards Alan
  3. Yes, but you need to write the constructors yourself (don't use the SC_CTOR macro). Something like #include "systemc.h" SC_MODULE(mod) { int i; mod(sc_module_name nm) : sc_module(nm) { // ... } mod(sc_module_name nm, int i_) : sc_module(nm), i(i_) { // ... } }; If you use SC_THREAD or SC_METHOD you must also include the SC_HAS_PROCESS macro. Try looking up SC_HAS_PROCESS in 1666-2011 and you should find an example near there, regards Alan
  4. C++ before C++11 does not allow initialisation of non-static class members at declaration (which is what your red example is trying to do). So you must use a member initializer list (your blue example) regards Alan
  5. You can't call wait inside nb_transport_fw or nb_transport_bw, so you need some parallel thread or callback, in both the initiator and the target. One approach is to use the payload event queues that are in the TLM2 utilities. So in the target (for instance) as a transaction arrives, you post it into the payload event queue (peq). When the appropriate time has passed the peq notifies an event and a thread that's been waiting for that event calls nb_transport_bw with the response. Or you can use the peq with callback. Then the callback is called at the appropriate time by the PEQ. If you're using PEQ with callback in the target (for instance) then you might not need a thread in the target. But of course there's got to be a thread somewhere, or no time will pass, regards Alan
  6. Yes you don't have to use the dmi hint - it's just an optimization to avoid repeated polling should the call to get_direct_mem_ptr not return any access. See 11.2.9 in the LRM. Regarding the size of memory request, your second option is the case, i.e. this statement you made... "Or is the idea that the initiator just sends the start address x for the requested region, and the target then grants access to a region [x,x+l] with l as large as the target deems possible?" regards Alan
  7. I think you need `uvm_component_param_utils because you've got a parameter. Have a look for `uvm_component_param_utils in the documentation, regards Alan
  8. There's no built-in way of handling interrupts. There has been some discussion in the Working Group of creating some special channel. One possibility that John Aynsley used to suggest was to use analysis ports to send a transaction representing an interrupt. However it's up to you to use sc_event or whatever to actually implement the interrupt behaviour. It might be worth looking on the verification academy website in case there are some ideas there, regards Alan
  9. Since SystemC 2.1 (I think) it's been possible to set a port binding policy when creating a port. It is a template argument which defaults to SC_ONE_OR_MORE_BOUND, i.e. you must bind at least once. You can change it to SC_ZERO_OR_MORE_BOUND. See the LRM for details. Another trick that is sometimes used is to instance dummy channels in the before_end_of_elaboration() callback, and bind them to any unbound ports. regards Alan
  10. Ah, that's a different question! :-) When you want to be sensitive to something, you need to get a reference to the event. In the constructor of a module, the ports are not yet bound, so it is not possible to get a reference to the event directly. Instead you must use an "event finder". The event finder is a bit of magic code that defers returning a reference until after binding is complete. If you look at the LRM, you'll see that the sc_in port has an event finder called "value_changed()". Also the bool and sc_logic specialisations have pos() and neg() as event finders. You can call default_event() or value_changed_event() inside an SC_THREAD if you like, because at that point the signal is bound, and so the event can be returned. regards Alan P.S. It's educational to look at sc_in<bool> and sc_signal<bool> and see the difference between pos(), posedge(), and posedge_event().
  11. You just need one b_transport, but you have access to the tag so you know which initiator called you. Have a look at simple_target_socket_tagged and the example on page 531, regards Alan
  12. Have a look at the section on convenience sockets in the LRM. There are some sockets that are described as tagged (see table 59). If you use one of the tagged target sockets, then you can arrange that a socket ID is associated with each initiator, so you can tell them apart. See the example at the bottom of page 531 for instance. If you have two independent register banks accessible from independent ports, why not write one target and make two instances of it? If you do want a single class with two target ports, then it's up to you to decide what to do by checking the address when you receive the generic payload. Remember that TLM2 was intended for memory-mapped busses, so your two register banks would be (I assume) at different memory map locations. regards Alan
  13. See the 1666-20011 LRM, in particular "o) The implementation of get_direct_mem_ptr shall not call wait, directly or indirectly." So your code is not good :-( regards Alan
  14. Or you are *not* using SC_CTOR, you've declared an SC_THREAD, and you've forgotten SC_HAS_PROCESS ? Alan P.S. As Philipp says, the code would help :-)
  15. See my other post here, perhaps that will help? http://forums.accellera.org/topic/1878-tlm2-dmi-interface/?p=7189 There is no automatic switching, it is up to you to look for the DMI Hint in the generic payload, regards Alan
  16. Hi, yes, obviously a transport_dbg write causes a side effect (the written data). So you're correct. However a read should have no effect on the system. You can call transport_dbg from a function, however the transport_dbg call itself must not result in change of simulation time (it returns without calling wait() or notifiying any events). So yes it cannot call wait(). regards Alan
  17. Hi, you don't call get_direct_mem_ptr unless the dmi hint is set. There is an access method to find the dmi hint from the generic payload (is_dmi_allowed or something - I don't have the standard to hand). The idea a) make a normal transfer if dmi hint is set then call get_direct_mem_ptr with the requested access and address range. c) if get_direct_mem_ptr returns a valid dmi region, then use it "forever". If an invalidate is received, and it invalidates your current dmi memory, then go back to step a) above. You only need to call get_direct_mem_ptr() once (unless of course you need to retrieve multiple non-contiguous regions of memory). You don't need to call get_direct_mem_ptr() again *unless* the region of memory you are using is invalidated. Regarding your last question, yes the initiator must keep track of all the dmi regions it has requested. regards Alan
  18. The idea of the dmi hint is that you can look at it after each transfer. So you might as well send the whole 64 bytes using b_transport (you've got to make the function call anyway, and it's using memcpy). On b_transport's return, if the dmi hint is set, you can then request access to a region of memory. On the next transfer to that same region, you check if the address is in the region that dmi is allowed. If it is, you just do a straight memcpy. Regarding invalidation, you have to remember that multiple initiators may have requested dmi access to the same memory region. So any interconnect may have to forward the invalidate call back to multiple initiators. If you have a single target and a single initiator, it's easier, the invalidate call just goes straight back to the initiator and tells it that dmi access to a particular region of memory is no longer allowed. The start and end address in the invalidate call allows the target to specify a particular region of memory that is invalidated. For instance suppose you have three targets 1, 2 and 3 at locations 0->9, 10->19, 20->29 in the memory map. An initiator could request dmi access to location 15. Target 2 might then say "ok, you can have access to locations 15->19". Then an initiator may request access to location 10. Target 2 may say "ok, you can have access to locations 10->12". Now if the target for some reason decides to disallow dmi access to locations 10->14, it could send the invalidate addresses between 10 and 14, which wouldn't affect the initiator which had access to locations 15->19. If there's an interconnect in between, then the target 2 would say "I'm invalidating 0 to 4" and then the interconnect would translate it in the memory map 10->14, then forward the call on to *all* initiators that had requested dmi access in memory map locations 10->14. kind regards Alan
  19. Yes you can read with DMI using memcpy. You can also read with memcpy using b_transport. Regarding which is better for DMI, it depends on the level of modelling accuracy you require, and how your model works. If you are (for instance) modelling the transfer of instruction code from flash memory to RAM at the beginning of your application, then you would be better using DMI and transferring all the data in one go. If you need to model the effect of burst transfers which are interleaved with other initiators, then it might be better to transfer small chunks at a time so you can find interactions between your initiators and fix them. With b_transport, again it depends on the level of modelling accuracy you require (timing accuracy). If you want to model realistic bus bursts (perhaps because you are later going to refine the model to AT) it would make sense to perform small transfers. If you are loading a RAM from flash, it would make sense to do a long burst. The idea of DMI is it is a performance optimisation which speeds up simulation at the expense of accuracy by minimising the number of function calls. regards Alan
  20. Hi Lokesh, there's a basic tutorial on the Doulos website, http://www.doulos.com/knowhow/systemc Probably the best book is "SystemC from the Ground Up" by David Black et al regards Alan
  21. The best thing would be to email Doulos (info@doulos.com) and see if they have a makefile, regards Alan
  22. Your code for the module isn't correct, it should be a derived class of sc_module. Unless of course you don't know that C++ is a case sensitive language... So something like this would be closer class check : public sc_module { public: SC_CTOR(check){ sc_thread(run); } void add_m(int a, int x) { cout<<a+x<<endl; } void sub_m(int b,int y) { cout<<b-y<<endl; } }; void check::run() // no arguments allowed on a static process { int x=10; int y=20; add_m(a,x); sub_m(b,y); } After that it depends how you want to get a and b into the module. You could declare ports for a and b. Also it's not clear to me if you want your run() thread to run repeatedly, or just once. If you need it to run repeatedly, then you need a while loop. And a wait statement. And possibly sensitivity, or a time delay. regards Alan P.S. The other thing that's not clear to me is why you are migrating to SystemC. If your code works in C++, why change it?
×
×
  • Create New...