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 

Specify synthesized module name?

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



Joined: 20 Aug 2007
Posts: 18

PostPosted: Fri Apr 17, 2015 2:10 pm    Post subject: Specify synthesized module name? Reply with quote

I'm fighting a combination of our build environment's inflexibility and the same in Bluespec.

The basic problem is that my build environment requires that I emit two synthesized Verilog modules as a side-effect of compiling a certain module. Let's call them mkMod0 and mkMod1. Based on a preprocessor variable (the `ifdef variety, not cpp), mkMod1 is either real code or a dummy stub.

The real problem: the mkMod1 interface is very complicated and contains an Inout. The interface is imported from some other module and that module comes from elsewhere and may change. I don't want to build a dummy instance of that interface -- too complicated and too many variations.

I can't figure out how to generate a dummy instance of mkMod1 based on a preprocessor variable. When the variable is > 1 mkMod1 is real. I can't use "?" as a dummy interface because of the Inout. The preprocessor doesn't have syntax for value comparison. I can't use "if" at top level to describe two possible mkMod1's -- one with an empty interface in the dummy case and one with a real interface. That last possibility would be acceptable if the syntax existed.

Is there a way to say something like:

(* synthesize = "mkFoo" *)
module mkBar ();
endmodule

and have the Verilog file be named mkFoo.v? In that case I could define both mkFoo() and mkBar() and then instantiate the one I want, both generating mkFoo.v.

Any other suggestions? Any suggestion that emits either a real or a dummy mkFoo.v as a side effect of compilation is acceptable as long as I can do it from the same source file and the interface to the real one can contain an Inout.
Back to top
View user's profile Send private message
quark
Site Admin


Joined: 02 Nov 2007
Posts: 500

PostPosted: Fri Apr 17, 2015 2:36 pm    Post subject: Re: Specify synthesized module name? Reply with quote

I'm not following. Can you show what you'd like to write if ifdefs could compare values? Or if "?" could be used for Inout?

Are there two separate issues here? One issue seems to be that you can't even write the stub module (the "?" issue). And the second issue is that, once you're able to write the stub, you want the pre-processor to select between the two versions based on a variable value (not just the existence of the variable). Or am I misunderstanding?

I'm also not clear on what flexibility you have in the build -- when you say that you could define both mkFoo and mkBar and instantiate the one you want, what does that mean? If you're able to include or not include files, then you could put the two versions of mkFoo into separate files and point to the one you want. Your build system could also define or not define a second preprocessor variable based on the value of the first variable, and then BSC wouldn't need to compare the value.

BSC synthesizes all modules with the "synthesize" attribute regardless of whether they are instantiated, so this code wouldn't work:
Code:
(* synthesize = "mkFoo" *)
module mkBar ();
endmodule
because it'd just overwrite the code generated by this:
Code:
(* synthesize *)
module mkFoo (...);
...
endmodule
I'm not following how this renaming syntax would help.
Back to top
View user's profile Send private message
mcadler



Joined: 20 Aug 2007
Posts: 18

PostPosted: Fri Apr 17, 2015 2:43 pm    Post subject: Reply with quote

What I want is basically this:

Code:

if (`DRAM_NUM_BANKS > 1)
begin
    (* synthesize *)
    module mkDDRBankSynth1#(Clock ddrClock, Reset ddrReset)
        // interface:
        (DDR_BANK_SYNTH);

        DDR_BANK_SYNTH b1 <- mkDDRBankCtrl(ddrClock, ddrReset, 1);
        return b1;
    endmodule
end
else
begin
    (* synthesize *)
    module mkDDRBankSynth1#(Clock ddrClock, Reset ddrReset)
        // interface:
        ();

        return ?;
    endmodule
end


I'd just return ? from the first one and put the "if" inside the first module declaration, but DDR_BANK_SYNTH contains Inout buried in a messy interface.
Back to top
View user's profile Send private message
quark
Site Admin


Joined: 02 Nov 2007
Posts: 500

PostPosted: Fri Apr 17, 2015 2:45 pm    Post subject: Re: Specify synthesized module name? Reply with quote

Is this what you would like to write?
Code:
(* synthesize *)
module mkFoo (Ifc);
`if (VAR > 1)
  ...
`endif
endmodule

This always generates a module mkFoo with the full interface, but sometimes the body is empty. (It requires both "?" for Input and a more powerful preprocessor check.)

And you're willing to settle for the stub module having an empty interface (to avoid the Inout issue):
Code:
(* synthesize *)
`if (VAR > 1)
module mkFoo (IFC);
  ...
endmodule
`else
module mkFoo ();
endmodule
`endif

I think that you might be able to implement the second version with a typeclass. Let me work on an example and get back.
Back to top
View user's profile Send private message
mcadler



Joined: 20 Aug 2007
Posts: 18

PostPosted: Fri Apr 17, 2015 2:48 pm    Post subject: Reply with quote

I'm fine settling for the semantics of the 2nd one. The interface can change. The code instantiating the dummy instances doesn't expect any particular interface.
Back to top
View user's profile Send private message
quark
Site Admin


Joined: 02 Nov 2007
Posts: 500

PostPosted: Fri Apr 17, 2015 3:25 pm    Post subject: Reply with quote

BSC currently gives an error if you use "?" to generate a Clock, Reset, or Inout. Now that BSC has command-line flags for demoting particularly errors, we could add these to the list of demotable errors. In those cases, the "?" would become noClock, noReset, or an unconnected Inout. (We could also make this a warning by default, and the user can promote it to an error.) Would this be helpful?

If "?" could be used for Inout, then the preprocessor part could be handled with a typeclass:
Code:
typeclass MkFoo#(numeric type n);
  module mkFooN #(Bit#(n) param) (Ifc);
endtypeclass

instance MkFoo#(1);
  module mkFooN #(Bit#(1) param) (Ifc);
  endmodule
endinstance

instance MkFoo#(n);
  module mkFooN #(Bit#(n) param) (Ifc);
    ...
  endmodule
endinstance

(* synthesize *)
module mkFoo (Ifc);
  Bit#(`VAR) param = 0;
  Ifc _ifc <- mkFooN(param);
  return _ifc;
endmodule

In the above code, the typeclass always returns a module with the same interface.

Since the above code doesn't work (without support for demoting the error), I started exploring whether the typeclass instances could have different interfaces. We can definitely write the typeclass that way, but I was unsure whether we could write the "mkFoo" module to put the "synthesize" attribute on, because it would need to vary the interface type. It turns out that we can use a proviso to fill in the type for us! (As long as the typeclass has a "dependencies" clause.) This code works:
Code:
typeclass MkFoo#(numeric type n, type ifc)
  dependencies (n determines ifc);
  module mkFooN #(Bit#(n) param) (ifc);
endtypeclass

instance MkFoo#(1, Empty);
  module mkFooN #(Bit#(1) param) ();
  endmodule
endinstance

instance MkFoo#(n, Ifc);
  module mkFooN #(Bit#(n) param) (Ifc);
    ...
  endmodule
endinstance

(* synthesize *)
module mkFoo (ifc) provisos (MkFoo#(`VAR,ifc));
  Bit#(`VAR) param = 0;
  let _ifc <- mkFooN(param);
  return _ifc;
endmodule

Will that work for you? (I do also think that we should extend the preprocessor support to include value comparisons; this isn't part of the SystemVerilog spec, so we'd need to come up with our own spec for what we'd want to support.)
Back to top
View user's profile Send private message
mcadler



Joined: 20 Aug 2007
Posts: 18

PostPosted: Fri Apr 17, 2015 7:59 pm    Post subject: Reply with quote

If ? could be used for Inout then I wouldn't need typeclasses at all. Instead of the first option I could just declare multiple synthesized wrappers that either return ? or a true instance, using an "if" inside the module.

The second option will work though it makes my head hurt and still requires a hack. All that is known in the source is that all instances over some integer threshold defined in a preprocessor macro are Empty. Since I can't write a for loop or conditional statement at top level, I will have to write:

Code:

instance MkFoo#(`VAR, Empty);
    module mkFooN #(Bit#(`VAR) param) ();
    endmodule
endinstance

instance MkFoo#(TAdd#(`VAR, 1)), Empty);
    module mkFooN #(Bit#(TAdd#(`VAR, 1)) param) ();
    endmodule
endinstance


up to the threshold of possible real instances. Since I'm dealing with memory controllers and the maximum is currently two this isn't a big deal. It will work fine.

The most important thing you said was your last sentence. The preprocessor desperately needs value comparison operators. It would eliminate a growing collection of hacks, this one included.

Thank you.
Back to top
View user's profile Send private message
mcadler



Joined: 20 Aug 2007
Posts: 18

PostPosted: Fri Apr 17, 2015 9:36 pm    Post subject: Reply with quote

Close, but I hit a snag up one level. What I have is now:

Code:


(* synthesize *)
module mkFoo0 (ifc) provisos (MkFoo#(0,ifc));
  Bit#(0) param = 0;
  let _ifc <- mkFooN(param);
  return _ifc;
endmodule

(* synthesize *)
module mkFoo1 (ifc) provisos (MkFoo#(1,ifc));
  Bit#(1) param = 0;
  let _ifc <- mkFooN(param);
  return _ifc;
endmodule


This compiles and generates either real code or stub, depending on the typeclass instances.

Now I have to instantiate these. I'm going to build a vector of the real instances, so I need something like:

Code:

let foo = ?;
case (idx)
    0: foo <- mkFoo0();
    1: foo <- mkFoo1();
endcase

<use foo for something>


This, of course, blows up when mkFoo0 and mkFoo1 don't resolve to the same interface. Despite the fact that dynamically mkFoo1() is never called when the types differ, statically the test fails.

I could probably solve this with another typeclass, but that just becomes recursive with no termination.

Am I missing something?
Back to top
View user's profile Send private message
mcadler



Joined: 20 Aug 2007
Posts: 18

PostPosted: Sat Apr 18, 2015 9:05 am    Post subject: Reply with quote

I figured it out. I hadn't realized that the Inout restriction is only at synthesis, so returning ? for an interface with Inout is fine as long as it isn't synthesized.

I added the following typeclass to bury any Empty interface and return a ? version of the desired interface:

Code:

typeclass BuryEmptyIfc#(type t_IN, type t_OUT)
    dependencies (t_IN determines t_OUT);

    module buryEmptyIfc#(t_IN obj) (t_OUT);

    module [m] buryEmptyIfcM#(function m#(t_IN) f) (t_OUT)
        provisos (IsModule#(m, _m));
endtypeclass

instance BuryEmptyIfc#(t_OUT, t_OUT);
    module buryEmptyIfc#(t_OUT obj) (t_OUT);
        return obj;
    endmodule

    module [m] buryEmptyIfcM#(function m#(t_OUT) f) (t_OUT)
        provisos (IsModule#(m, _m));
        let _obj <- f();
        return _obj;
    endmodule
endinstance

instance BuryEmptyIfc#(Empty, t_OUT);
    module buryEmptyIfc#(t_IN obj) (t_OUT);
        return ?;
    endmodule

    module [m] buryEmptyIfcM#(function m#(Empty) f) (t_OUT)
        provisos (IsModule#(m, _m));
        return ?;
    endmodule
endinstance


Then the case statement becomes:

Code:

let foo = ?;
case (idx)
    0: foo <- buryEmptyIfcM(mkFoo0);
    1: foo <- buryEmptyIfcM(mkFoo1);
endcase
Back to top
View user's profile Send private message
quark
Site Admin


Joined: 02 Nov 2007
Posts: 500

PostPosted: Sat Apr 18, 2015 2:37 pm    Post subject: Reply with quote

Ah, yes, in order to use the module "mkFoo" (which can have either Empty or Ifc interface type), you would need a typeclass to convert to a single type. And the insight about "?" being prohibited only on synthesis boundaries is a good one. Here's what I would write:
Code:
typeclass CvtIfc#(type t_IN, type t_OUT);
  function t_OUT cvtIfc(t_IN ifc);
endtypeclass

instance CvtIfc#(t,t);
  function cvtIfc(ifc) = ifc;
endinstance

instance CvtIfc#(Empty,t);
  function cvtIfc(ifc) = ?;
endinstance

module mkTop (...);
  Bit#(`VAR) param = 0;
  let foo <- mkFoo(param);
  Ifc foo_actual = cvtIfc(foo);
  ... use "foo_actual" ...
endmodule

I guess this equivalent to your "buryEmptyIfc", except you don't need a module for that. Your "buryEmptyIfcM" is good, too. Here's how I'd use it:
Code:
module mkTop (...);
  Bit#(`VAR) param = 0;
  let foo <- buryEmptyIfcM(mkFoo(param));
  ... use "foo" ...
endmodule

Here, a typeclass is needed because we want to apply a function to an argument whose type is not known, it could be one of many possible types. In your example using "mkFoo0" and "mkFoo1", though, we know the types. So no type class is needed:
Code:
Ifc foo_actual;
case (idx)
  0: begin
        Empty foo <- mkFoo0;
        foo_actual = ?;
      end
  1: begin
        Ifc foo <- mkFoo1;
        foo_actual = foo;
      end
   ...
endcase

Also, you don't need a typeclass to define mkFoo0 and mkFoo1, if their interfaces are fixed:
Code:
(* synthesize *)
module mkFoo0 ();
endmodule

(* synthesize *)
module mkFoo1 (Ifc);
  ...
endmodule

The reason for the MkFoo typeclass was to be able to define a single module named "mkFoo" so that the file "mkFoo.v" could have a different interface and implementation based on a preprocessor macro. If you intend to have separate mkFoo0.v and mkFoo1.v, then there's no need for the typeclass.
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