1. Run the smallest BSV program first
Before any syntax, run something. The smallest complete BSV design has three parts you will see in every chapter:
| Part | What it is |
|---|---|
package | the file; one package per file, named after it |
module | a piece of hardware; mkTop is the top of the design |
rule | what the hardware does in a clock cycle; a rule with no condition is ready in every cycle |
FirstRule.bsv has one rule, greet, that prints a line and ends the simulation. Read the rule
and decide what will appear before you press Run.
Check
How many times does Hello, BSV appear in the output?
package FirstRule;
(* synthesize *)
module mkTop(Empty);
// A rule with no condition: it is ready in every clock cycle.
rule greet;
$display("Hello, BSV");
$finish(0);
endrule
endmodule
endpackagePress Run. The first two lines come from the compiler: Verilog file created: mkTop.v means
bsc turned the BSV module into a Verilog module, and Verilog binary file created: sim.out means
a simulator was built from it. Only the last line, Hello, BSV, comes from the design.
Structure versus simulation. Two different things happened. bsc built hardware: a module
mkTop whose rule greet has an enable signal that is true in every cycle. Then the simulator
ran that hardware clock by clock. $display and $finish are simulation-only system tasks; in a
chip the rule would still fire every cycle, but nothing would print and nothing would stop.
Now change the program and predict each result before you run it.
| Edit | Predict |
|---|---|
Change the text "Hello, BSV" to your own message | only the printed line changes |
Add $display("still the same cycle"); on the line before $finish(0); | how many lines the design prints, and in which order |
Check
With the second $display added before $finish(0), what does the design print?
Check
Predict without running it: you delete the line $finish(0);. What happens?
2. A BSV file is a package of modules
A BSV source file is one package, named after the file: ValueMethod.bsv opens with
package ValueMethod; and closes with endpackage. Inside the package, the unit of hardware is
the module. By convention module names start with mk, short for "make", because a module
definition is a recipe; hardware exists only once something builds an instance from it.
Form
package PackageName;
(* synthesize *)
module mkModuleName(InterfaceType);
// state declarations
// rules
endmodule
endpackageThe type in parentheses is the interface the module offers to the outside. In FirstRule.bsv
every line now has a name:
| Code | Meaning |
|---|---|
package FirstRule; … endpackage | Opens and closes the package; the file must be named FirstRule.bsv |
(* synthesize *) | An attribute asking bsc to emit this module as its own Verilog module |
module mkTop(Empty); | Starts module mkTop; the parenthesized type is the interface it offers |
Empty | An interface with no methods, typical for a top-level module that only drives a simulation |
rule greet; … endrule | A rule with no condition, so it may fire every cycle |
$display, $finish(0) | System tasks that print and end the simulation |
System tasks, the names starting with $, exist for simulation. bsc keeps them in the
generated Verilog between translate_off markers so that synthesis skips them; they never
become hardware. Every example marks its top module (* synthesize *), and the Run command
names that module with -g mkTop. The full package syntax, including import and export, is
in Packages.
Run performs three steps: bsc -verilog -g mkTop compiles the BSV source to Verilog,
bsc -e mkTop -vsim iverilog links a simulator with Icarus Verilog, and vvp runs it.
3. An interface says what a module offers
3.1 Declaring an interface
Verilog describes a module from outside by its ports. BSV describes it by its methods. An
interface is a type made of method prototypes, each with a name, argument types and a
result type, and nothing about how the module works inside. It is declared at the top level of
a package, and several modules may provide the same interface.
Form
interface InterfaceName;
method ReturnType methodName(arguments);
...
endinterfaceinterface Counter;
method Bit#(8) value;
endinterface
interface Accumulator;
method Action add(Bit#(8) x);
method Bit#(8) total;
endinterface| Code | Meaning |
|---|---|
interface Counter; | Declares an interface type named Counter; type names start uppercase |
method Bit#(8) value; | A method with no arguments that returns an 8-bit value; empty parentheses may be omitted |
method Action add(Bit#(8) x); | A method that takes an 8-bit argument and changes state |
endinterface | Closes the declaration |
The interface lists only names and types. Implementations, and the readiness conditions a method may carry, belong to the method definitions inside a module.
3.2 First, value methods
A method's return type decides its kind. This chapter needs only one kind: a method that
returns a value, such as Bit#(8) or Bool, is a value method. Calling it reads the
module's state and returns a result; it never changes anything, so reading it twice is the same
as reading it once.
value in Counter returns Bit#(8), so it is a value method. Methods whose return type is
Action or ActionValue#(t) change state; add in Accumulator above is one. What those two
kinds promise, how a rule calls them, and how to choose among the three for a given contract are
the subject of Methods: value, Action, ActionValue,
after you have written registers and rules yourself.
4. State comes only from module instances
4.1 Instantiation binds an interface to a name
In BSV, anything that remembers a value from one cycle to the next exists only because a module was instantiated. Registers, FIFOs, memories and your own larger components are all created the same way.
Form
InterfaceType instanceName <- moduleName(arguments);Reg#(Bit#(8)) count <- mkReg(42);
FIFO#(Bit#(8)) queue <- mkFIFO;| Code | Meaning |
|---|---|
Reg#(Bit#(8)) | The interface type the instance provides: an 8-bit register interface |
count | The name bound to that interface; you call its methods through count |
<- | Runs the module to create an instance and binds the resulting interface |
mkReg(42) | The module to instantiate and its argument: a register that starts at 42 |
A module with no arguments, such as mkFIFO, may omit the parentheses. mkReg(42) is itself a
module, the register, and Reg#(Bit#(8)) is the interface it provides.
Note. Ordinary variables are not state. Local variables, function arguments, names bound by
patterns and loop variables are names used within one computation. In let x = queue.first;,
x creates no storage; it simply names the value queue is presenting right now.
4.2 Definitions versus instances
A module definition is a recipe for building hardware. A module instance is the hardware built from it. Instantiating one definition twice gives two independent copies of its state.
Reg#(Bit#(8)) a <- mkReg(0);
Reg#(Bit#(8)) b <- mkReg(0); // a second register, independent of aInstances form a strict hierarchy: every instance except the top one has exactly one parent.
The mk prefix on definition names is what lets you tell the recipe from the instances.
4.3 The module keeps state and defines the method
mkCounter provides Counter. Its body has two lines, and they are two different kinds of
thing.
| Line | What it is |
|---|---|
Reg#(Bit#(8)) count <- mkReg(42); | state: a register holding eight bits, built with the initial value 42 |
method Bit#(8) value = count; | wiring: the method's result is the register's current value |
Using count in an expression reads the value the register holds at the start of the current
cycle. Nothing in this design ever writes count, so that value is 42 in every cycle. Writing
a register, and the rule that decides when, is the subject of
Registers and one rule.
5. The testbench instantiates the module and reads the method
A module does nothing on its own. mkTop is the testbench. It builds an instance with
Counter c <- mkCounter; and then declares one rule. A rule is a block of actions that may
run in a clock cycle; this one has no condition, so it is ready from the first cycle. Its body
reads c.value, the dot notation for instance.method, prints the result with $display and
ends the simulation with $finish(0).
ValueMethod.bsv is about the smallest module possible: one value method. Read it in this
order:
- The
Counterinterface has a single method,value. - In
mkCounter, the registercountstarts at 42 and nothing ever writes it. mkTopinstantiatesmkCounterwith<-and readsc.valueinrule show.
Predict before you run.
Check
What number does the value = line print?
Check
How many state transitions does count go through before the simulation ends?
package ValueMethod;
// An interface declares what a module offers. A value method reads state and
// returns a result without changing anything.
interface Counter;
method Bit#(8) value;
endinterface
module mkCounter(Counter);
Reg#(Bit#(8)) count <- mkReg(42);
method Bit#(8) value = count;
endmodule
(* synthesize *)
module mkTop(Empty);
// The module is instantiated with <-, and the result is its interface.
Counter c <- mkCounter;
rule show;
$display("value = %0d", c.value);
$finish(0);
endrule
endmodule
endpackagePractice this concept
Use this concept in a short BSV problem as your next step.
Press Run. The lab compiles the package to Verilog with bsc, links a simulator with Icarus
Verilog and runs it.
| Output line | What it shows |
|---|---|
| Compiler messages | The lines reporting mkTop.v and sim.out mean bsc compiled and linked successfully |
value = 42 | The initial value appears unchanged. c.value is just an expression over state, so there were zero state transitions: the testbench observed the initial value and stopped |
Caution. Output means the design compiled and simulated with bsc 2026.01 and Icarus Verilog
11. Synthesis is not run in this course. (* synthesize *) only decides which modules become
separate Verilog modules; it does not prove the design maps to a chip.
6. Change one thing
Make two edits in the lab's editor, one at a time, and run after each.
| Edit | What to expect |
|---|---|
mkReg(42) to mkReg(7) | Only the printed value changes, to 7; the structure is unchanged and there are still zero transitions |
Counter c <- mkCounter; to Counter c = mkCounter; | Compilation stops with T0020: the expected type is Counter, but mkCounter is a module computation that produces one |
Check
After the second edit, when does the mistake show up?
The second edit is a common mistake, worth reading in the compiler's words.
// Wrong
Counter c = mkCounter;
// Right
Counter c <- mkCounter;mkCounter is not an interface value; it is a module computation that produces one. With =,
error T0020 reports that it expected Counter but inferred a__#(Counter), the type of a
module that yields a Counter once it is run. Only <- runs it.
<- appears again later with a second meaning, running an action that returns a value. Both
uses share one idea: run something, then bind its result.
7. Types and elaboration
Widths are part of types. Reg#(Bit#(8)) is a register interface for 8-bit values, and a width
mismatch is caught by type checking before any hardware exists.
Types, widths and explicit conversion covers
this in detail.
Compilation distinguishes two moments:
| Moment | What is decided |
|---|---|
| Elaboration | Starting from the top module, submodules are instantiated and the hardware structure is fixed |
| Execution | In that fixed hardware, rules become ready and change state cycle by cycle |
<- belongs to the first moment: Counter c <- mkCounter; and mkReg(42) run once, while the
structure is being built. Firing a rule never creates a module. The structure is settled during
elaboration.
Note. Every package automatically imports the Standard Prelude, which supplies basics such
as Reg, Bool and Empty. FIFOs, vectors, memories and similar components come from bsc
library packages that you import. BSV and BH (Bluespec Haskell, also called Bluespec Classic)
differ in syntax but share semantics, and bsc accepts .bsv and .bs packages in one design.
Note. Rules have a formal semantics based on Term Rewriting Systems. Invariants you prove in
the one-rule-at-a-time model still hold for the parallel hardware that bsc generates.
Static and dynamic semantics makes that
model precise.
8. Apply it: a value method must report the state
In the Practice problem below, mkCounter has a second method, set, which writes the
register, and value is defined as count + 1. The testbench loads 8'h2a and reads back 43
instead of 42. A value method observes without changing state; it may compute a result from that
state. This problem specifically requires the stored count unchanged. Repair value so that every representable count is reported
unchanged, then run.
The checkpoint for this chapter is running the example and comparing the printed value with your prediction; the Practice problem is the first exercise of the course.
9. Summary
| Element | Meaning |
|---|---|
package … endpackage | one file, one package, same name |
interface … endinterface | a type listing method prototypes; implementations live in modules |
rule name; … endrule | what happens in a clock cycle; with no explicit condition it may fire every cycle, subject to method readiness and scheduling |
| value method | a method returning a value type; it only observes. Action and ActionValue methods come later |
module mkName(Ifc); … endmodule | a definition providing interface Ifc; a recipe, not hardware |
Reg#(t) r <- mkReg(init); | a register instance holding a t, starting at init; state exists only through instances |
method t name = expr; | a value method: reads, never writes |
Ifc x <- mkName; | an instance built with <-, used as x.method; = binds without running and fails with T0020 |
(* synthesize *) | emit this module as its own Verilog module |
| elaboration, execution | instances are built once while the structure is fixed; rules then fire cycle by cycle |
10. Check your understanding
-
Why do two instances of the same module definition hold separate state?
Show answer
A module definition is only a recipe. State is created each time the definition is instantiated with
<-, so each instance owns its own registers. -
Name one thing that happens during elaboration and one that happens every cycle.
Show answer
During elaboration, modules such as
mkRegandmkCounterare instantiated and the hardware structure is fixed. Every cycle, rule readiness is evaluated and the selected rules' register writes are stored at the clock edge.