bluespec.com Forum Index bluespec.com
Bluespec Forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Prevent a method inheriting preconditions of called methods

 
Post new topic   Reply to topic    bluespec.com Forum Index -> Designing with BSV's Rules, Interfaces, ...
View previous topic :: View next topic  
Author Message
slugonamission



Joined: 09 Nov 2012
Posts: 9

PostPosted: Wed Apr 10, 2013 8:32 am    Post subject: Prevent a method inheriting preconditions of called methods Reply with quote

Suppose I have the following code sample, where both toMem and pfOutBuffer are FIFOF structures:

Code:

        method ActionValue#(BluetreeClientPacket) get() if (toMem.notEmpty() || pfOutBuffer.notEmpty());
            //$display("Memory pulling request packet");                                                                                                                                                                                                                                                                   
            BluetreeClientPacket relay = unpack(0);

            if(toMem.notEmpty()) begin
               toMem.deq();
               relay = toMem.first();
            end
            else begin
               if(pfOutBuffer.notEmpty()) begin
                  pfOutBuffer.deq();
                  relay = pfOutBuffer.first();
               end
            end


Of course, in this case, the method will inherit the preconditions of the deq methods on both FIFOs. Is it possible within the language to prevent the preconditions of these FIFOs being inherited, or rather, is there a way to tell the compiler that both code paths are fully mutually exclusive?

Of course, I could use two rules which push to another FIFO, although this adds another cycle. I could push to a RWire, but this would mean that data is lost if it is not read using the method in that cycle (since I assume that the `deq` operation also has the `notEmpty` precondition), or finally use the `GFIFO` variants, which feels a bit hacky for this case. `(* split *)` looks like it could also work (and move the returns up), although this leads to a scheduling error.

Have I missed something obvious to do this in a single cycle or is GFIFO my only option?
Back to top
View user's profile Send private message
quark
Site Admin


Joined: 02 Nov 2007
Posts: 499

PostPosted: Wed Apr 10, 2013 1:23 pm    Post subject: Re: Prevent a method inheriting preconditions of called meth Reply with quote

If I understand correctly, you want the method to have a ready condition that says that at least one of the two FIFOs is ready, and when called it will deq from one of the FIFOs in a given order.

You should get this behavior if you compile with the -aggressive-conditions option and write the method like this:
Code:
method ActionValue#(BluetreeClientPacket) get();
// note: no explicit condition
   BluetreeClientPacket relay;

   if (toMem.notEmpty()) begin
      toMem.deq();
      relay = toMem.first();
   end
   else begin
      pfOutBuffer.deq();
      relay = pfOutBuffer.first();
   end
   ...

With conservative ready-condition analysis, BSC would just AND together the ready-conditions of the methods, regardless of any if-conditions that guard their calls. With aggressive analysis, BSC should construct the condition:
Code:
(!toMem.notEmpty && RDY_pfOutBuffer_deq) || RDY_toMem_deq

Since the RDY of the deq methods is the notEmpty, this should reduce into the expression:
Code:
pfOutBuffer.notEmpty || toMem.notEmpty

Have you tried this? Does it not work? It's possible that there's one sticking point that prevents this from working, which is that BSC doesn't technically know that the method "notEmpty" and the RDY condition of the method "deq" are actually the same thing. This can prevent BSC from reducing the expression in some cases. However, in this example, it should be fine. I made a module using two FIFOFs, "f1" and "f2" and it produced this Verilog output:
Code:
assign get = f1$EMPTY_N ? f1$D_OUT : f2$D_OUT ;
assign RDY_get = f1$EMPTY_N ? f1$EMPTY_N : f2$EMPTY_N ;

It's not fully optimized, but it's still functionally equivalent.

If you had a more complicated situation where the -aggressive-conditions flag didn't work, then the other options are as you mentioned.

Using an unguarded FIFO seems reasonable, perhaps one that is unguarded on the deq side and not on the enq side.

You could also use wires to split the action up into separate methods. This wouldn't introduce a clock cycle, because the rules would execute in the same cycle as the method; but, yes, the actions in the rules would have conditions on them, so you would need to be very careful to ensure that the conditions of the rules will always be True when the wires are set. (BSC has some attributes for checking this, like "fire_when_enabled" and "no_implicit_conditions", however they may not be what you need in this case; and using an unguarded FIFO is again an option.)

You could even write something like this (the mkPriorityGet module can be pulled out and put in another file, leaving your mkMod module to be very clean -- it's just instantiating the priority mux and calling "get" on it):
Code:
import FIFOF::*;
import GetPut::*;

typedef Bit#(8) T;

interface Ifc;
   method ActionValue#(T) get();
endinterface

(* synthesize *)
module mkMod(Ifc);
  FIFOF#(T) f1 <- mkFIFOF;
  FIFOF#(T) f2 <- mkFIFOF;

  module mkPriorityFIFO(Get#(T));
     // Whether the FIFOs have data
     RWire#(T) rw_first_f1 <- mkRWire;
     RWire#(T) rw_first_f2 <- mkRWire;

     // Rules to set the wire values
     (* fire_when_enabled *)
     rule read_first_f1;
       rw_first_f1.wset(f1.first);
     endrule

     (* fire_when_enabled *)
     rule read_first_f2;
       rw_first_f2.wset(f2.first);
     endrule

     // Acknowledge that the data was taken and should be dequeued
     PulseWire pw_deq_f1 <- mkPulseWire;
     PulseWire pw_deq_f2 <- mkPulseWire;

     // Rules to perform the dequeue
     (* fire_when_enabled *)
     rule ack_deq_f1 (pw_deq_f1);
        f1.deq();
     endrule

     (* fire_when_enabled *)
     rule ack_deq_f2 (pw_deq_f2);
        f2.deq();
     endrule

     Bool has_data = isValid(rw_first_f1.wget) ||
                     isValid(rw_first_f2.wget);

     method ActionValue#(T) get() if (has_data);
        if (rw_first_f1.wget matches tagged Valid .data) begin
          pw_deq_f1.send;
          return data;
        end
        else begin
          // we know that rw_first_f2.wget is Valid, so we don't need to check
          pw_deq_f2.send;
          return validValue(rw_first_f2.wget);
        end
     endmethod
  endmodule

  Get#(T) priFIFO <- mkPriorityFIFO;

  method ActionValue#(T) get();
     T res <- priFIFO.get;
     return res;
  endmethod
endmodule

In this example, without the -aggressive-conditions flag, the generated Verilog looks like this:
Code:
assign get = f1$EMPTY_N ? f1$D_OUT : f2$D_OUT ;
assign RDY_get = f1$EMPTY_N || f2$EMPTY_N ;
Back to top
View user's profile Send private message
slugonamission



Joined: 09 Nov 2012
Posts: 9

PostPosted: Wed Apr 10, 2013 6:45 pm    Post subject: Reply with quote

Wow, thanks. I'll try the -aggressive-conditions option (I didn't know about it before).

I did have a quick think about splitting this into rules as per your second example, but stumbled on dequeuing data (the version in my mind put both the fifo.first() and fifo.deq()) into the same rule. At the moment, I've just used a GFIFO with unguarded dequeue and a large warning comment at the top of the file.

Thanks again, I'll have a play with this tomorrow Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    bluespec.com Forum Index -> Designing with BSV's Rules, Interfaces, ... All times are GMT - 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum
bluespec.com topic RSS feed 


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP