ExtensionMechanism

GreenBus ExtensionMechanism

Requirements

  1. Cost-less mechanism, so that "everything" can be treated as an extension, so we get the mighest interoperability, and it's the nicest interface, and we dont need to worry if it's a memory mapped bus of a debug-to-model interface.
    • this is of course, REALLY hard to achieve! Maybe impossible
  2. it is NOT required that ports can carry dynamic protocol types... in other words, one-port one-protocol, so at run time, you KNOW what the protocol is. If you want a different protocol, you need a different port (or an adapter)....
    • this really simplifies the problem, and so far I see no down side, only good things.
  3. Must work if the objects are shipped in source or binary.
    • This might make the "zero cost" impossible? But, what is the cost?
    • Of course some .h file will always be shipped, some stuff can be in there, but not the whole IP! Can this reduce the cost enough?

Ok, so when some of those fail... we may need to think about "chunking" so that things are chunked together to make access to them faster... i.e. a memory mapped bus "chunk"... with this, can the cost be reduced?

ideas

There seem to be several choices:

  1. Have a "generic" bus and essentially a list of void *'s inside it
  2. Have a "generic" bus, and allow people to inherit from it, expecting them to do dynamic casts to find out if the bus they actually wanted is there.
  3. Have a structure with specific data types in it.
  4. Have a structure with arbitrary data in it, and then a set of set/get functions used by the IP blocks to access the structure.
  5. Use inheritance and virtual functions to implement this in a C++ nice way.

1 and 2 are limited to whatever the generic bus is "limited" to - like memory mapped buses, or whatever.

3,4 and 5 are much more flexible.

4 and 5 are flexible and allow the underlying data to be changed, they mean the "real" interoperability interface moves from the modules ports to the interface between the IP and the data structure.

Interestingly, this interface need not be "set in stone" as the final system integrator could choose to change the data structure, and re-implement the functions.

One thing that I am now convinced about: BIG STATEMENT : ANY INDIVIDUAL PORT IS ONLY PERMITTED TO USE ONE "PROTOCOL" Net result, at bind time, you can determine the data type on each port, this means you can compile time check types...


what I mean is, lets say we have 3 protocols, A B and C. say A<B<C (ie C has everything in it that B has, and B has everything A has).

then, say, the \"SYSTEM\" works with C

So - now, _ALL_ transactions will be of type C, but a master (using only A) will only set the \"A\" parts, and a slave (using will only use/set the A+B parts....

Now, this is fine, IF and ONLY IF the parts of B that are > A are \"optional\" in that they can be ignored, or default values can be used.

If not, then you have to use an adapter (actually, between the master (A) and the system (C).


Some more ideas:

So, my approach is probably something like: - This isn't a nice C++ version, it's a horrid "C" version, but I'm doing it this way to be clear :-)

  1. /* systemTransaction.h SYSTEM INTEGRATOR WRITES THIS*/
  2. struct Transaction
  3. {
  4.   int address;
  5.   void *data;
  6.   char *just_kidding;
  7. }
  8.  
  9. /* myip.h SYSTEM INTEGRATOR MAY MODIFY THIS, BUT IT'S SHIPPED BY IP PROVIDER */
  10. struct transaction;
  11.  
  12. void setAddress64(transaction &t, uint64 address)
  13. {
  14.   // DARN
  15.   t.address = (address>>32); // I happen to know thats whats meant
  16. }
  17.  
  18. /* myip.c IP PROVIDER'S IP */
  19. Sorry this is a .o, you can't see it It calls setAddress64

So, the "interoperability" comes in 2 places, first we construct a nice big repository of functions. If you use setAddress64, then a system designer should know what that means. Then, we provide a library of all these functions, and the data structures that they can work with.

Now - we could easily, I think, provide a version of the library which works on any bus (For instance something provided by OSCI). If that bus did not support some things, they would manifest themselves in run-time errors I guess.

So, in addition, I think we should provide an "extensible" version. i.e. an empty base class

  1. class transactionBase{};

And then a bunch of things to inherit from

  1. class Address {int address;};

Now, the system integrator who wants to define something special says :

  1. /* myTransaction.h */
  2.  
  3. class myTransaction: public Address, Data, Foo, Baa, Whatever {}

Now, _IF_ the System integrator has chosen the super set of all the attributes, then they have no more work to do. If not, they may have to modify some of the .h's. - i.e. the .h's is where the "adapters" happen.

Now it's easy to see how we can also provide a specific-bus, it simply becomes

  1. class XYZ-Bus: public The,List,Of,Attributes,Of,That,Bus {};

And now, the system integrator does not even need to write the myTransaction.h, they just use the one provided (which might come from OSCI, ARM, OCP, wherever), until they use IP that needs more, in which case, the "default" library will spit out an error, and the system integrator will have to decide what to do. Choices will be

  1. provide an adapter in the IPs header file
  2. write their own myTransaction, possibly inheriting all the things from OSCI bus and adding their own to suit the needs of the IP.

I've simplified somewhat, because I think we need to split things up between timing and functionality etc etc... but you see what I mean. Actually, it is this over simplification that causes the problem, because we need to be clear what structures there will be that can be extended... which is where I think Roberts work is so valuable, because I think he clearly identifies the structures we need to support MMB's.


Ideas on the interface: generic programming

Here are some ideas I (MarcusBartholomeu) would like to share and discuss. It is about using the generic programming style with GreenBus.

After reading the example above, with the setAdress64() function, I thought that all the interface could be like that. So, there would be a fixed set of templated functions, which is the interface. This does not solve any of the implementation issues, though. (see bellow 2 implementations).

Some functions as an example of what I mean:

  1. // Set the address of a transaction
  2. template <typename transaction, typename adress>
  3. transaction& setAddress(transaction&, address&);
  4.  
  5. // Set the data of a transaction
  6. template <typename transaction, typename data>
  7. transaction& setData(transaction&, data&);
  8.  
  9. // Get a new transaction from a master port
  10. template <typename transaction, typename port>
  11. transaction& getTransaction(port&);
  12.  
  13. // Send a transaction to the module port,
  14. //    so it will be routed to other module
  15. template <typename transaction, typename port, typename error>
  16. error& sendTransaction(transaction&, port&);
  17.  
  18. // Switch the transaction from one protocol to another
  19. template <typename protocolFrom, typename protocolTo>
  20. protocolTo& switchTransaction(protocolFrom&, protocolTo&);

Then each protocol would implement these functions the way it wants. The default implementation could be an object-oriented one:

  1. // Set the address of a transaction
  2. template <typename transaction, typename adress>
  3. transaction& setAddress(transaction&, address&) {
  4.    transaction.address = address;
  5.    return transaction;
  6. }

But the implementation is not limited to that. It could also be something totally crazy like:

  1. // Set the address of a transaction
  2. template <typename transaction, typename adress>
  3. transaction& setAddress(transaction&, address&) {
  4.    AddressArray[transaction] = address;
  5.    return transaction;
  6. }

This last example is just to show how generic the interface is. :-)