├── BluespecIntroGuide.md ├── BluespecQuickReference.md ├── BluespecQuickReference.pdf ├── BluespecQuickReferenceTemplate.tex └── README.md /BluespecIntroGuide.md: -------------------------------------------------------------------------------- 1 | # Intro Bluespec User Guide 2 | 3 | - [Overview](#overview) 4 | - [Bluespec Syntax](#bluespec-syntax) 5 | * [Capitalization](#capitalization) 6 | * [Whitespace and comments](#whitespace-and-comments) 7 | * [Semicolons and blocks](#semicolons-and-blocks) 8 | - [Bluespec Variables, Types, and Operators](#bluespec-variables-types-and-operators) 9 | * [Data Types](#data-types) 10 | + [Literals](#literals) 11 | + [Predefined Types](#predefined-types) 12 | + [User-defined types](#user-defined-types) 13 | + [Type conversions](#type-conversions) 14 | + [Working with Bits](#working-with-bits) 15 | * [Operators](#operators) 16 | + [Bitwise operators](#bitwise-operators) 17 | + [Logical operators](#logical-operators) 18 | + [Ternary operator](#ternary-operator) 19 | + [Arithmetic operators](#arithmetic-operators) 20 | + [Numeric type operators](#numeric-type-operators) 21 | - [Combinational Circuits](#combinational-circuits) 22 | * [Variables](#variables) 23 | + [Variable declaration](#variable-declaration) 24 | + [Variable assignment](#variable-assignment) 25 | + [let keyword](#let-keyword) 26 | + [Order of execution](#order-of-execution) 27 | * [Function structure](#function-structure) 28 | + [Function Declaration](#function-declaration) 29 | + [Parameterization](#parameterization) 30 | + [Higher-level programming constructs](#higher-level-programming-constructs) 31 | + [Return statements](#return-statements) 32 | + [Note on Calling Functions](#note-on-calling-functions) 33 | - [Sequential Circuits](#sequential-circuits) 34 | * [Interfaces](#interfaces) 35 | + [Method Types](#method-types) 36 | + [Empty Interface](#empty-interface) 37 | * [Modules](#modules) 38 | + [Module Declaration](#module-declaration) 39 | + [Internal State](#internal-state) 40 | + [Methods and Rules](#methods-and-rules) 41 | - [Additional Topics](#additional-topics) 42 | * [Maybe values](#maybe-values) 43 | * [Case matches](#case-matches) 44 | * [Common errors](#common-errors) 45 | * [Debugging with `$display`](#debugging-with-display) 46 | * ["Don't care" values](#dont-care-values) 47 | 48 | 49 | ## Overview 50 | 51 | This document is an introductory guide to learning Bluespec. It's intended for 6.004 students, and is structured mostly in the order that the class is taught. It will cover the basic language syntax, data types, and how to write combinational circuits (functions) and sequential circuits (modules). 52 | 53 | This isn't a complete (or official!) reference for the Bluespec language, so it's missing a lot of advanced topics and may have mistakes. If you do notice any mistakes or want to contribute content, feel free to open a pull request or issue, or just shoot me an email at kcamenzi@mit.edu. 54 | 55 | I've listed some other resoures to learn Bluespec below: 56 | 57 | * [Bluespec Manual](http://www.bluespec.com/forum/download.php?id=157): A comprehensive guide of the language. 58 | * [Bluespec Reference Card](http://www.bluespec.com/forum/download.php?id=98): A short document (3 pages) good for looking up syntax. 59 | * [Online tutorial](http://wiki.bluespec.com/Home): An online walk-through of some of the common features of Bluespec, along with examples. 60 | 61 | If you just want to briefly review Bluespec syntax or quickly look up a particular piece of syntax, you may want to consult the [Quick Reference](BluespecQuickReference.md). 62 | 63 | ## Bluespec Syntax 64 | 65 | ### Capitalization 66 | 67 | Capitalization is important in Bluespec, and your program will not compile if you do not follow the capitalization conventions. The required capitalization of the first letter is as follows: 68 | 69 | **Foo**: Type names, Typeclass names, Interface names, Enum labels, 70 | Tagged union labels, Package names 71 | 72 | **foo**: bit, int, module names, instance names, all variables, 73 | all type variables, rule names 74 | 75 | ### Whitespace and comments 76 | 77 | Whitespace can be used freely in Bluespec! 78 | 79 | Comments are treated as whitespace, and can either be one-line comments: 80 | 81 | `// Your comment here` 82 | 83 | or multiline comments 84 | ```bluespec 85 | /* You can 86 | write comments 87 | across however many 88 | lines! */ 89 | ``` 90 | 91 | ### Semicolons and blocks 92 | 93 | Semicolons are needed after any expression. They are not needed, however, after **begin** and **end** keywords. Here are some examples for your reference: 94 | 95 | ```bluespec 96 | // Needs semicolon 97 | x = 5; 98 | 99 | // Needs semicolon 100 | if (y) x = 5; 101 | 102 | // Whitespace doesn't matter, this is still 1 expression = 1 semicolon 103 | if (y) 104 | x = 5; 105 | 106 | // Semicolons not needed after keywords begin and end 107 | if (y) begin 108 | x = 5; 109 | end 110 | 111 | // For loops work similarly to if statements 112 | for (Integer i = 0; i < max; i = i + 1) begin 113 | do_something(); 114 | do_something_else(); 115 | end 116 | 117 | // Function declarations need semicolons, end statements do not. 118 | function ReturnType fnName(Type var1, Type var2); 119 | some_stuff(); 120 | endfunction 121 | 122 | // Module declarations need semicolons, endmodule does not 123 | module mkMyModule(); 124 | // State declarations also need semicolons 125 | Reg#(Bit#(n)) myReg <- mkRegU; 126 | 127 | // Same thing with rules 128 | rule doSomething; 129 | do_some_stuff(); 130 | endrule 131 | 132 | // And with methods! 133 | method Type myMethod(); 134 | do_some_other_stuff(); 135 | endmethod 136 | endmodule 137 | 138 | ``` 139 | 140 | The keywords `begin` and `end` are how we can lump multiple statements into one statement, mostly used in conditionals, loops, and case statements. For example, to assign two variables in an if statement, we need to write: 141 | 142 | ```bluespec 143 | // Correct syntax 144 | if (cond) begin 145 | x = 1; 146 | y = 2; 147 | end 148 | 149 | // Incorrect syntax, y is not part of the conditional 150 | // and will always be assigned 2 151 | if (cond) 152 | x = 1; 153 | y = 2; 154 | ``` 155 | 156 | ## Bluespec Variables, Types, and Operators 157 | 158 | ### Data Types 159 | 160 | Bluespec has both built-in data types and user-defined data types. No matter what data type you're using in your code, when it gets synthesized to hardware everything is just stored as bits. However, types allow us to focus on the value of our variables rather than how they'll translate into bits. 161 | 162 | #### Literals 163 | 164 | When we write programs, we often have to assign hard-coded numeric values to variables. It's good practice to write all Bluespec literals with explicit sizes, but it is possible to write both sized and unsized literals. Unsized literals are most useful when you want set a variable (or some section of a variable) to all 0's or all 1's, or when using Integers (since the Integer type is unsized anyway, more on that below). 165 | 166 | **Sized literals:** 167 | ```bluespec 168 | 4'd10 // Decimal value 10, stored in 4 bits 169 | 170 | 4'b1010 // Decimal value 10, stored in 4 bits 171 | 8'b00001010 // Decimal value 10, stored in 8 bits 172 | 8'b1010 // Decimal value 10, stored in 8 bits 173 | 174 | 4'ha // Hex value 10, stored in 4 bits 175 | 8'h0a // Hex value 10, stored in 8 bits 176 | 8'h0A // Capitalization of hex digits doesn't matter 177 | ``` 178 | 179 | **Unsized literals:** 180 | ```bluespec 181 | 10 // Decimal value 10, unsized 182 | 0 // Decimal value 0, unsized 183 | 1 // Decimal value 1, unsized 184 | '0 // Enough 0's to fill the needed width 185 | '1 // Enough 1's to fill the needed width 186 | 187 | ``` 188 | 189 | We need to be careful when using `'0` or `'1` or the compiler will be unhappy. Only use these when both the size of the variable is defined, and the size of the space we're filling with 0's or 1's is unambiguous. 190 | 191 | #### Predefined Types 192 | 193 | Almost all variables in Bluespec represent, in the eventual circuit, some number of bits. The exception to this is the Integer type, which is only used in static elaboration. This means that you cannot have Integer be the type of your inputs or outputs; it's exclusively used by the compiler, for example, as a loop variable. 194 | 195 | Here are some of Bluespec's built-in types: 196 | 197 | ```bluespec 198 | Bit#(n) // n bits 199 | Int#(n) // n bits, interpreted as a signed number 200 | UInt#(n) // n bits, interpreted as an unsigned number 201 | Bool // True or False (1 bit) 202 | Integer // unsized number, only used in static elaboration 203 | ``` 204 | 205 | ##### Tuples 206 | 207 | Tuples are built-in types that are made up of other types that you specify. For example, `Tuple2#(Bit#(1), Bit#(2))` is the type of a 2-tuple that contains a `Bit#(1)` and a `Bit#(2)`. 208 | 209 | Tuples can be constructed with the special functions `tuple2`, `tuple3`, and so on: 210 | 211 | ```bluespec 212 | Tuple2#(Bit#(1), Bit#(2)) pair = tuple2(1, 0); 213 | ``` 214 | 215 | To access individual elements of tuples, you can use the special functions `tpl_1`, `tpl_2`, and so on. For example `tpl_1(pair)` gets the first element from the tuple we constructed above, which would be 1. You can also use pattern-matching to get all values from a tuple at once: 216 | 217 | ```bluespec 218 | match {.a, .b} = pair; 219 | ``` 220 | 221 | ##### Other Types 222 | 223 | There are some built-in types that will be explained in the sequential section. 224 | 225 | #### User-defined types 226 | 227 | ##### Type synonyms 228 | 229 | You can give types new names with the following syntax: 230 | 231 | ```bluespec 232 | typedef OldType NewType; 233 | ``` 234 | 235 | For example, you may want to rename `Bit#(8)` as `Byte`. 236 | 237 | ```bluespec 238 | typedef Bit#(8) Byte; 239 | ``` 240 | 241 | After this, you can write `Byte` instead of `Bit#(8)`. (You can also keep using the old `Bit#(8)` name.) 242 | 243 | ##### Structs 244 | 245 | You can also define your own types by defining a new type that is made up of other types. The syntax is: 246 | 247 | ```bluespec 248 | typedef struct { 249 | OldType1 member1; 250 | OldType2 member2; 251 | } NewType; 252 | ``` 253 | 254 | You can instantiate this variable and access its fields as follows: 255 | 256 | ```bluespec 257 | OldType1 m1 = 2'b00; 258 | OldType2 m2 = some_value; 259 | 260 | // Declare the variable 261 | NewType myNewVar = NewType{member1: m1, member2: m2}; 262 | 263 | // Read a field 264 | OldType2 m2_copy = myNewVar.m2; 265 | 266 | // Set a field 267 | myNewVar.m1 = 2'b11; 268 | ``` 269 | 270 | Similar to tuples, you can also get all fields from a struct with pattern matching as follows: 271 | 272 | ```bluespec 273 | match tagged NewType {m1: .myM1, m2: .myM2} = myNewVar; 274 | // you can use variables myM1 and myM2 here 275 | ``` 276 | 277 | ##### Enums 278 | 279 | Enums are how we can define custom types that are defined by the compiler as bits, but we don't explicitly have to understand how they translate into bits. For example, if you want to define a type Color, which can take values Red, Green, Yellow and Blue, we can write 280 | 281 | ```bluespec 282 | typedef enum Color { Red, Green, Yellow, Blue } deriving (Bits, Eq); 283 | ``` 284 | 285 | Deriving `Bits` means that the values `Red`, `Green`, `Yellow` and `Blue` will be automatically assigned an underlying representation in bits. Deriving `Eq` means that the equality operator is derived for the type as well, so if you have a `Color` variable, you can check if it's `Red` or `Green` or `Yellow` or `Blue` using the `==` comparator. You will generally want to include both of these in your enum declarations. 286 | 287 | #### Type conversions 288 | 289 | ##### Converting between numeric types, Integers, and Bits 290 | 291 | To extract the Integer value of a numeric type, use `Integer i = valueOf(n)`, where `n` is the numeric type. 292 | 293 | To convert an Integer to a `Bit#(n)` value, use `Bit#(n) x = fromInteger(i)`, where `i` is an `Integer`. 294 | 295 | You can chain these together to store the value of a numeric type into a `Bit#(n)` as follows: 296 | 297 | ```bluespec 298 | Bit#(m) x = fromInteger(valueOf(n)); 299 | ``` 300 | 301 | (Note: `n` and `m` could be the same value, they're just different numeric type names to illustrate that they don't have to be the same value.) 302 | 303 | Lastly, you can extract the size of a Type (in bits) by using `SizeOf`. `SizeOf` returns a numeric type, which then you can then further convert into an `Integer` or `Bit#` depending on your use case. For example: 304 | 305 | ```bluespec 306 | Bit#(3) x = 0; // Size of x is 3 bits 307 | Integer i = valueOf(SizeOf(x)); // i = 3, converted from numeric type -> Integer 308 | ``` 309 | 310 | ##### Converting between Bits and other types 311 | 312 | If a type is represented by `Bits`, then we can convert between these types and their bit representations. Examples of this are `Int`, `UInt`, and any user-defined type deriving `Bits`. 313 | 314 | To convert from `Bit` to any other type, use `unpack`: 315 | 316 | ```bluespec 317 | Bit#(3) x = 3'b101; // x is the binary value 101 318 | UInt#(3) y = unpack(x); // y = 5, the UInt represented by the bits 101 319 | Int#(3) z = unpack(x); // z = -3, the Int represented by the bits 101 320 | ``` 321 | 322 | To convert from any type to `Bit`, use `pack`: 323 | 324 | ```bluespec 325 | typedef enum Color { Red, Green, Blue, Yellow } deriving (Bits, Eq); 326 | 327 | Color red = Red; 328 | Color yellow = Yellow; 329 | 330 | Bit#(2) x = pack(red); // x = 2'b00, the binary representation of Red 331 | Bit#(2) y = pack(yellow); // y = 2'b11, the binary representation of Yellow 332 | ``` 333 | 334 | #### Working with Bits 335 | 336 | ##### Indexing Bits 337 | 338 | `Bit#`s are stored as a string of bits, indexed from the least significant bit (LSB) to the most significant bit (MSB). That is, more significant bits correspond to higher indices. Note that this is **backwards** from what you might expect based on how binary literals are normally written, since the literals go from most significant bits to least significant bits! (It's done this way so that `x[i]` in a binary number corresponds nicely to 2i.) For example, if you have a `Bit#(4) x = 4'b1010`, then `x[0] = 0` (the LSB or rightmost bit), `x[1] = 1`, `x[2] = 0`, and `x[3] = 1` (the MSB or leftmost bit). In general, for a `Bit#(n)`, we can index it from `0` to `n-1`. When you index a `Bit#`, you get a `Bit#(1)`. 339 | 340 | To access a parameterized Bit, we can use the numeric type -> `Integer` conversion discussed above. For example: 341 | 342 | ```bluespec 343 | Bit#(n) x_param = 1; // x = 1, has n-1 leading zeros 344 | Bit#(1) x_msb = x_param[valueOf(n)-1]; // x_msb is the top bit of x_param 345 | ``` 346 | 347 | We can also take slices of `Bit#`s with the syntax `x[hi:lo]`. This means to get the bits from `hi` to `lo` **inclusive**, and the first index `hi` should be greater than or equal to the second index `lo`. The result will have type `Bit#(hi - lo + 1)` (if you do the math, you'll see that `hi - lo + 1` is just the number of bits sliced). For example: 348 | 349 | ```bluespec 350 | Bit#(4) x = 4'b1010; 351 | Bit#(4) y = x; // y = 4'b1010 352 | Bit#(4) z = x[3:0]; // z = 4'b1010 353 | Bit#(3) lower_bits = x[2:0]; // lower_bits = { x[2], x[1], x[0] } = 3'b010; 354 | Bit#(3) upper_bits = x[3:1]; // upper_bits = { x[3], x[2], x[1] } = 3'b101; 355 | ``` 356 | 357 | Note that with bit indexing, it's generally recommended to use constants as the indices (or `Integer`s, since they're elaborated to constants at compile-time). It's generally ok to extract bits with a variable, but requires more hardware. 358 | 359 | Some examples: 360 | 361 | ```bluespec 362 | Integer fixed_i = 2; // Value of fixed_i known at compile time because it's an Integer 363 | Bit#(2) dynamic_i = 3; // Value of dynamic_i not known at compile time because it's a Bit# 364 | Bit#(4) x = 4'b1001; 365 | 366 | // Indexing 367 | Bit#(1) a = x[fixed_i]; // OK, fixed_i is a fixed value 368 | Bit#(1) b = x[fixed_i-1]; // OK, fixed_i-1 is a fixed value 369 | Bit#(1) c = x[dynamic_i]; // OK but inefficient, dynamic_i isn't a fixed value 370 | 371 | // Slicing 372 | Bit#(2) d = x[i:i-1]; // OK, fixed-size and fixed-value slice 373 | Bit#(2) e = x[dynamic_i:dynamic_i-1]; // OK but inefficient, fixed-size but non-fixed-value slice 374 | Bit#(2) f = x[fixed_i:0]; // ONLY OK if i=1 to guarantee sizes match 375 | Bit#(2) g = x[dynamic_i:0]; // BAD, no guarantee that sizes will match 376 | ``` 377 | 378 | When indexing with dynamic values, there's also always the danger of the indexing out of range. For example, if you have a `Bit#(3)`, you have to index with at least 2 bits to cover values `2'b00`, `2'b01`, and `2'b10`. However, if the index takes the value `2'b11`, then this is out of the range of the bit string. 379 | 380 | *Additional Note on Bit slicing* 381 | 382 | While it's legal to use operators in the expressions for indexing (for example, `x[i-1:i-2]`), the compiler doesn't type check on slices with operators. In that example, it would be unable to determine the size of the slice. (In fact, even if you wrote `x[3-1:0]`, it would be unable to determine the size of the slice.) So be particularly careful that you match your slice width to the assigned variable widths. If there is a size mismatch, the compiler will truncate the left-most bits, or pad on the left with 0's. 383 | 384 | ##### Concatenating Bits 385 | 386 | We can combine strings of bits into longer strings of bits. To concatenate two (or more) `Bit#`s, surround them with curly braces `{ }` and separate by commas, as in the following notation: 387 | 388 | ```bluespec 389 | Bit#(2) a = 2'b11; 390 | Bit#(3) b = 3'b001; 391 | 392 | // Concatenation 393 | Bit#(5) c = { x, y }; // c = 5'b11001; 394 | 395 | // It's ok to use slices 396 | Bit#(4) d = { x, y[2:1] }; // d = 4'b1100; 397 | 398 | // It's ok to write bits explicitly 399 | Bit#(5) e = { 1'b0, x, 2'b00 }; // e = 5'b01100; 400 | ``` 401 | 402 | ##### Extending Bits 403 | 404 | Sometimes it can be useful to add arbitrary numbers of 0's or 1's to the beginning or end (usually beginning) of Bits to change the size but retain the numeric value. The first way that we can do this is by concatenating our original number with `'1` or `'0`, which represent "as many 0's or 1's as needed to fill the specified width". 405 | 406 | For example: 407 | 408 | ```bluespec 409 | Bit#(4) x = 4'b1001; 410 | 411 | // Extend x to 6 bits 412 | Bit#(6) a = { '0, x }; // a = 6'b001001; 413 | Bit#(7) b = { '0, x }; // b = 7'b0001001; 414 | Bit#(7) c = { '1, x }; // c = 7'b1111001; 415 | Bit#(7) d = { x, '0 }; // d = 7'b1001000; 416 | Bit#(7) e = { x, '1 }; // e = 7'b1001111; 417 | 418 | Bit#(7) f = { '0, x, '1 }; // NOT ALLOWED, not clear how many 0's vs 1's to fill 419 | ``` 420 | 421 | We can also accomplish the functionality through two built-in Bluespec functions, zeroExtend and signExtend. 422 | 423 | * `zeroExtend(x)`: equivalent to `{ '0, x }` 424 | * `signExtend(x)`: 425 | * equivalent to `{ '0, x }` if the MSB of x is 0 426 | * equivalent to `{ '1, x }` if the MSB of x is 1 427 | 428 | ##### Truncating Bits 429 | 430 | We can truncate bits by explicitly indexing the number of bits that we want. However, we can also use the built-in truncate function. For example: 431 | 432 | ```bluespec 433 | Bit#(5) x = 5'b10011; 434 | Bit#(4) y = truncate(x); // y = 4'b0011 435 | Bit#(2) z = truncate(x); // z = 2'b11 436 | ``` 437 | 438 | ##### Other Bit Functions 439 | 440 | Bluespec has several more functions for working with bits, but it's unlikely you will need them. 441 | 442 | ```bluespec 443 | function Bit#(1) parity(Bit#(n) v); // even or odd number of 1's 444 | function Bit#(n) reverseBits(Bit#(n) v); 445 | function UInt#(lgn1) countOnes(Bit#(n) bin) provisos (...); // number of 1's 446 | function UInt#(lgn1) countZerosMSB(Bit#(n) bin) provisos (...); // number of 0's from MSB until first 1 447 | function UInt#(lgn1) countZerosLSB(Bit#(n) bin) provisos (...); // number of 0's from LSB until first 1 448 | function Bit#(n) truncateLSB(Bit#(m) x) provisos (...); // truncate from LSB 449 | ``` 450 | 451 | ### Operators 452 | 453 | There are several built-in operators for built-in Bluespec types. 454 | 455 | #### Bitwise operators 456 | 457 | Bitwise operators operate bit-by-bit on numbers, including `Bit#(n)`, `Int#(n)`, and `UInt#(n)`. If the operator takes two arguments, so `a = b OP c`, then this is equivalent to writing `a[i] = b[i] OP c[i]` for every i from 0 to n-1. (Notice that a, b, and c must all be the same size.) 458 | 459 | - `&`: bitwise-AND 460 | - `|`: bitwise-OR 461 | - `^`: bitwise-XOR 462 | - `~`: bitwise-NOT 463 | 464 | ```bluespec 465 | Bit#(4) a = 4'b0011; 466 | Bit#(4) b = 4'b0101; 467 | Bit#(4) c = a & b; // c = 4'b0001; 468 | Bit#(4) d = a | b; // d = 4'b0111; 469 | Bit#(4) e = a ^ b; // e = 4'b0110; 470 | Bit#(4) f = ~a; // f = 4'b1100; 471 | ``` 472 | 473 | You cannot use bitwise operators on booleans; booleans have their own logical operators. 474 | 475 | #### Logical operators 476 | 477 | The AND, OR, and NOT bitwise operators have logical equivalents. Logical operators perform the same operations as the bitwise operators, but they take two boolean arguments (`True` or `False`) and produce a boolean result. 478 | 479 | - `&&`: logical AND 480 | - `||`: logical OR 481 | - `!`: logical NOT 482 | 483 | ```bluespec 484 | Bool a = True; 485 | Bool b = False; 486 | 487 | Bool d = a || b; // d = True since a == True 488 | Bool e = a && b; // e = False since b == False 489 | Bool f = !a; // f = False since a != False 490 | ``` 491 | 492 | There is no separate logical XOR operator, but the not-equals operator `!=` has the exact behavior of logical XOR. 493 | 494 | #### Ternary operator 495 | 496 | The ternary statement mimics the behaviour of a multiplexer, and is shorthand for an if-else statement. The expression `(cond) ? val1 : val2` evaluates to `val1` if `cond==True`, and `val2` if `cond==False`. The cond must evaluate to the `Bool` (**not `Bit#(1)`**) type. 497 | 498 | Example: 499 | ```bluespec 500 | Bit#(1) s = 1'b0; 501 | Bit#(2) a = 2'b11; 502 | Bit#(2) b = 2'b01; 503 | 504 | Bit#(2) x = (s==1'b0) ? a : b; // x = a since s==1'b0 505 | Bit#(2) y = (s==1'b1) ? a : b; // y = b since s!=1'b1 506 | ``` 507 | 508 | #### Arithmetic operators 509 | 510 | You can use arithmetic operators on many types. If the operator does different things depending on whether the number is signed or unsigned, then you probably want to specify the value explicitly as an Int or UInt. 511 | 512 | `a + b` : Addition 513 | 514 | `a - b` : Subtraction 515 | 516 | `a * b` : Multiplication 517 | 518 | `a / b` : Division 519 | 520 | `a % b` : Modulus 521 | 522 | `a << b` : Left shift 523 | 524 | `a >> b` : Right shift 525 | 526 | TODO: Describe the rules for what happens when there are size mismatches, sign mismatches, etc. 527 | 528 | ##### Comparators 529 | 530 | `a <= b` : Less than or equal to 531 | 532 | `a < b` : Less than 533 | 534 | `a >= b` : Greater than or equal to 535 | 536 | `a > b ` : Greater than 537 | 538 | `a == b` : Equals 539 | 540 | `a != b` : Not equals 541 | 542 | 543 | #### Numeric type operators 544 | 545 | When we have parameterized types, we sometimes want to define variable widths based on some function of the the parameter width. There are built-in functions for doing basic arithemetic operations on numeric types. 546 | 547 | ```bluespec 548 | Bit#(n) x; Bit#(m) y; // x is n bits wide, y is m bits wide 549 | 550 | Bit#(TAdd#(n, m)) a; // a is n + m bits wide 551 | Bit#(TAdd#(n, 1)) b; // b is n + 1 bits wide 552 | Bit#(TSub#(n, 1)) c; // c is n - 1 bits wide 553 | Bit#(TLog#(n)) d; // d is log(n) bits wide (ceiling) 554 | Bit#(TExp#(n)) e; // e is 2^n bits wide 555 | Bit#(TMul#(n, m)) f; // f is n*m bits wide 556 | Bit#(TDiv#(n, m)) g; // g is n/m bits wide 557 | 558 | Bit#(n+1) h; // ILLEGAL: Cannot use + operator with numeric type n 559 | Bit#(valueOf(n) + 1) i; // ILLEGAL: Bit parameter needs to be a type, not an Integer 560 | ``` 561 | 562 | ## Combinational Circuits 563 | 564 | Now we know how to define types and variables and write basic expressions. The next question is, how we can put these expressions together into code that actually does something? 565 | 566 | In Bluespec, we can create representations of combinational (stateless and unclocked) circuits by writing functions. The function inputs are the inputs to the combinational circuit, the function outputs are the outputs from the combinational circuit, and the body of the function describes the combinational logic that converts the inputs to outputs. This section describes the basic components needed to write Bluespec functions. 567 | 568 | ### Variables 569 | 570 | #### Variable declaration 571 | 572 | Variables are declared in code as follows: 573 | 574 | `TypeName variableName;` 575 | 576 | Variables must be declared in the function definition, or within the function. You cannot declare a global variable in a file, as there is no such thing as a "global variable" in hardware, since the function itself should encapsulate an entire combinational circuit. (This isn't entirely true once we move onto sequential circuits, but more on that later.) 577 | 578 | This also means that the scope of a declared variable is only within the function that it is declared in. 579 | 580 | #### Variable assignment 581 | 582 | Variables must be assigned values to be used. Generally, you will include an initial value in its declaration. If you don't, then you should always make sure that the variable is assigned a value before it's used. 583 | 584 | ```bluespec 585 | TypeName variableName = initialValue; // Initializes variableName to initialValue 586 | 587 | // Alternate way of assigning initalValue 588 | TypeName var1; 589 | if (cond1) var1 = init1; 590 | else var1 = init2; 591 | 592 | // BAD 593 | TypeName var2; 594 | if (cond) var2 = init1; 595 | ... 596 | y = f(var2); // var2 doesn't have a value if cond=False 597 | ``` 598 | 599 | #### let keyword 600 | 601 | It's good practice to explicitly declare your variable sizes. However, you can also allow the compiler to infer the type instead of writing it explicitly, by using the keyword `let` instead of declaring a variable type. 602 | 603 | For example 604 | 605 | ```bluespec 606 | Bit#(5) a = 0; 607 | let b = a; // b will be a Bit#(5) 608 | let c = { 1'b0, a }; // c will be a Bit#(6) since we added a bit to a 609 | let d = 2'b11; // d will be a Bit#(2) 610 | 611 | // INVALID 612 | let e = { '0, a }; // size of e can't be determined since '0 is unsized 613 | let f = 1; // size of f can't be determined since 1 is unsized 614 | 615 | ``` 616 | 617 | #### Order of execution 618 | 619 | One thing to note is that in these functions, statements execute like they would in many other programming languages: top to bottom. Re-assigning a variable another value will update its value for and only for future statements. 620 | 621 | ```bluespec 622 | Bit#(2) x = 2'b10; // x = 2'b10 623 | Bit#(2) y = x; // y = 2'b10 624 | x = 2'b11; // x = 2'b11, y = 2'b10 625 | Bit#(2) z = x; // z = 2'b11 626 | ``` 627 | 628 | ### Function structure 629 | 630 | Now that we know how to write variables in our function, let's talk about how the function is actually structured. A function consists of a declaration, variables, body, return value, and potentially some parameterization. 631 | 632 | #### Function Declaration 633 | 634 | A function is declared as followed: 635 | 636 | ```bluespec 637 | function ReturnType functionName(ArgType1 argName1, ArgType2 argnName2, ... , ArgTypeN argNameN); 638 | // Body of function here 639 | endfunction 640 | ``` 641 | 642 | A function can return exactly 1 value. If you want to return multiple values, then you can pack them into a [tuple](#tuples) or a user-defined [struct](#structs) and extract the separate values from the values or fields of the return value. 643 | 644 | `function` and `endfunction` are Bluespec keywords that define the beginning and end of the function declaration. 645 | 646 | You can pass in any number of arguments to a function, including 0. The names you give to the arguments are the variable names for accessing the input values in the body of the function. Again, the scope of these variables is only inside the function. 647 | 648 | Below is an example declaration of a 4-bit adder function. The function take two 4-bit numbers (`a` and `b`) and a carry-in 1-bit value (`c`), and returns a 5-bit number that is equal to a+b+c. 649 | 650 | ```bluespec 651 | function Bit#(5) add4(Bit#(4) a, Bit#(4) b, Bit#(1) c); 652 | // body 653 | endfunction 654 | ``` 655 | 656 | #### Parameterization 657 | 658 | It's possible that you want to write multiple functions that do the exact same thing, but for different Bit widths. For example, in the adder example above, you might want to have an add2, add4, add8, and add16 function. Instead of rewriting the function for every Bit width, we can often generalize it by parameterizing the function, and then specifying when we pass in arguments to the function what value we want the parameter to take. 659 | 660 | We parameterize the function by replacing certain numeric types with variables. For our adder example, we could generalize it by writing 661 | 662 | ```bluespec 663 | function Bit#(TAdd#(n,1)) addN(Bit#(n) a, Bit#(n) b, Bit#(1) c); 664 | // body 665 | endfunction 666 | ``` 667 | 668 | This says that inputs `a` and `b` will be Bits of size n, c is a Bit of size 1, and the function will return a Bit of size n+1. (If you don't remember how the `TAdd#` function works, refer to the section on [numeric type operators](#numeric-type-operators).) 669 | 670 | You can then actually call your function by just passing in arguments of compatible bit widths. This can be done in several ways, as shown below. 671 | 672 | ```bluespec 673 | // Here are your variables to add 674 | Bit#(4) a, b; 675 | Bit#(1) c; 676 | 677 | ... 678 | ... // assume variables are initialized to values somewhere :) 679 | ... 680 | 681 | // You can call the general function as long sizeOf(a) = sizeOf(b) = sizeOf(sum) - 1 682 | Bit#(5) sum = addN(a, b, c); 683 | 684 | // The compiler can infer the size of the return type from the size of the inputs 685 | let sum = addN(a, b, c); 686 | 687 | // Alternatively, you can declare a specifically parameterized function 688 | function Bit#(5) add4(Bit#(4) a, Bit#(4) b, Bit#(1) c); 689 | return addN(a, b, c); 690 | endfunction 691 | 692 | // Can now call the specific add4 function 693 | Bit#(5) sum = add4(a, b, c); 694 | 695 | // Again, the compiler can determine the size of the return type 696 | let sum = add4(a, b, c); 697 | 698 | // INVALID: The first two arguments need to be the same width 699 | let sum = addN(a, c, c); 700 | 701 | // INVALID: the return type needs to be 1 bit wider than the arguments 702 | Bit#(6) sum = addN(a, b, c); 703 | ``` 704 | 705 | #### Higher-level programming constructs 706 | 707 | ##### For loops 708 | 709 | You can add for loops to your program! Syntax is as follows: 710 | 711 | ```bluespec 712 | // General syntax 713 | for (Type iter_val = initial_val; cond; iter_val = f(iter_val)) begin 714 | // Stuff to do in for loop. 715 | // Loop will continue if cond==True, and will apply f(iter_val) at the end of every loop cycle 716 | end 717 | 718 | // Example for loop. Will initialize i to 0, and then execute as long as i < 10, 719 | // with i incrementing at the end of every loop execution. 720 | for (Integer i = 0; i < 5; i = i + 1) begin 721 | count = count + i; 722 | end 723 | 724 | // Example for loop in a parameterized function (where n is a numeric type). 725 | for (Integer i = 0; i < valueOf(n); i = i + 1) begin 726 | // Do something 727 | end 728 | ``` 729 | 730 | One thing to note is that loops are *unrolled at compile-time*. This means that what the second for-loop above actually does is the following: 731 | 732 | ```bluespec 733 | i = 0; // i = 0 734 | count = count + i; 735 | i = i + 1; // i = 1 736 | count = count + i; 737 | i = i + 1; // i = 2 738 | count = count + i; 739 | i = i + 1; // i = 3 740 | count = count + i; 741 | i = i + 1; // i = 4 742 | count = count + i; 743 | ``` 744 | 745 | Another thing to note is the use of the `Integer` type in the for loop. We use `Integer`s because they're unsized so we don't have to worry about if we're using enough bits. At the same time, since the loop is unrolled, it's ok to use an Integer because `i` won't ever actually change values in the compiled circuit, it just becomes a hard-coded constant for each iteration of the loop. 746 | 747 | We generally want to keep the bounds of our `for` loop to a constant, because otherwise our circuit has to unroll every possible iteration of the for loop and put a mux on every iteration deciding whether that iteration is the final one or not. In code: 748 | 749 | ```bluespec 750 | Bit#(5) max = get_max(); // value of max is unknown at compile time 751 | 752 | // BAD: Compiler has to unroll 2^5 loops and then dynamically 753 | // decide after which iteration to take the value of res 754 | for (Integer i = 0; i < max; i = i + 1) 755 | res = f(res); 756 | end 757 | ``` 758 | 759 | ##### If-else statements 760 | 761 | If-else statements are just like any other language. 762 | 763 | ```bluespec 764 | if (cond1) begin 765 | // Will execute if cond1==True 766 | end else if (cond2) begin 767 | // Will execute if cond1==False and cond2==True 768 | end else begin 769 | // Will execute if cond1==False and cond2==False 770 | end 771 | 772 | // We can also one-line these statements if only one action needs to happen. 773 | if (cond1) doSomething; 774 | else if (cond2) doSomethingElse; 775 | // Default else statement is optional. 776 | ``` 777 | 778 | ##### Case 779 | 780 | The `case` statement is a shorthand way of writing long `if`/`else` blocks. The syntax is as follows: 781 | 782 | ```bluespec 783 | Type switch = some_val; 784 | 785 | // This case conditionally executes statements based on which value switch matches. 786 | // The default value executes if no other value is matches, and is not always needed. 787 | case (switch) 788 | val1: do1(); // do1() executes if (switch==val1) 789 | val2: begin // do2() and do3() execute if (switch==val2) 790 | do2(); 791 | do3(); 792 | end 793 | default: do4(); // do4() executes if (switch!=val1) && (switch!=val2) 794 | endcase 795 | 796 | // This case conditionally sets to a value based on which value switch matches. 797 | let x = case (switch) 798 | val1: xval1; // x = xval1 if (switch==val1) 799 | val2: xval2; // x = xval2 if (switch==val2) 800 | val3: (xval1 + xval2); // Need to wrap multi-term expressions in parentheses 801 | default: xval3; // x = xval3 if (switch!=val1) && (switch!=val2) 802 | endcase; // Note the semicolon here 803 | ``` 804 | 805 | #### Return statements 806 | 807 | `return` statements specify the return value of your function. You can only have return statements at the very end of your function (there can't be any statements after them, not even other return statements), although they can be at the end of branches in an if-else conditional. In addition, you must have a return statement at the end of every path of execution, so there cannot be a possible path where your function will not return a value. 808 | 809 | ```bluespec 810 | // Best to put your return value at the end. 811 | function ReturnType fnName(args...); 812 | ReturnType res; 813 | if (cond1) res = val1; 814 | else res = val2; 815 | return res; 816 | endfunction 817 | 818 | // Also ok to return from every branch of an if-else 819 | function ReturnType fnName(args...); 820 | if (cond1) return val1; 821 | else return val2; 822 | endfunction 823 | 824 | // BAD: the return statements in the if/else come before the return statement at the very end 825 | // (This is easy to fix by just adding `else` before `return val3;`) 826 | function ReturnType fnName(args...); 827 | if (cond1) return val1; 828 | else if (cond2) return val2; 829 | return val3; 830 | endfunction 831 | 832 | // BAD: if cond1==False and cond2==False, no return statement 833 | function ReturnType fnName(args...); 834 | if (cond1) return val1; 835 | else if (cond2) return val2; 836 | endfunction 837 | ``` 838 | 839 | #### Note on Calling Functions 840 | 841 | You can call a function from within another function, or from within a module's rule or method (to be explained in the next function). Every time you write a function call, it generates a new instance of that combinational circuit; there's no sharing of an instance of a function across separate calls. This means if you have the following code, generating an instance of `myOtherFunc` will have in it two instances of `myFunc`. 842 | 843 | ```bluespec 844 | function ReturnType1 myFunc(ArgType arg1); 845 | // Some stuff 846 | endfunction 847 | 848 | function ReturnType myOtherFunc(); 849 | if (cond1) myFunc(val1); 850 | else myFunc(val2); 851 | endfunction 852 | ``` 853 | 854 | ## Sequential Circuits 855 | 856 | Up to this point, we've only talked about writing code to generate circuits that have no concept of time or state. We'll now take a look at how we can use Bluespec to describe sequential circuits, which are cycle-driven (by an implicit clock—we're going to skip in this guide talking about designs that use multiple clocks) and can store state across cycles. 857 | 858 | ### Interfaces 859 | 860 | Interfaces define the inputs and outputs to class of sequential circuits. An interface consists of 1 or more method declarations, where each method defines a subset of the inputs and outputs to the circuit, and has a specific function. The exact implementation of the function is not defined in the interface, it will be defined later by a module (talked about in the next section) that implements the interface. 861 | 862 | ```bluespec 863 | // Basic interface declaration 864 | interface InterfaceName; 865 | method MethodType method1name(ArgType1 arg1, ArgType2 arg2 ... ); 866 | method MethodType method2name(ArgType3 arg1, ArgType4 arg2 ... ); 867 | ... 868 | method MethodType methodNname(); // methods don't have to have inputs 869 | endinterface 870 | ``` 871 | 872 | You can also parameterize interfaces as shown below. This can be a parameterization similar to function we've seen where we want to use the interface for varying Bit widths, but can also be used for things like FIFOs where you want to have an interface that describes all FIFOs regardless of the data type stored in it. 873 | 874 | ```bluespec 875 | // Parameterized interface declaration 876 | interface ParamInterfaceName#(type typeName); // type is a keyword, typeName is your name for the type 877 | method MethodType regularMethodName; 878 | method MethodType#(typeName) paramMethodName; // Pass the type parameter into methods as needed 879 | endinterface 880 | ``` 881 | 882 | #### Method Types 883 | 884 | There are three different types of methods. The type of method defines some implicit inputs/outputs to the sequential circuit, specifically whether there is an enable signal and whether there is a return value (output). 885 | 886 | All methods have an implicit *ready* signal. This signal tells the outside world when the sequential circuit is in a valid state for the method to be called. Some circuits may have their ready signals always set to True, but that's unrelated to the interface, so more on that later. 887 | 888 | ##### Action Methods 889 | 890 | Action methods alter the internal state of the circuit, which means that there is an enable signal. When the method is called, the enable signal will go high, which tells the circuit to change its state based on its current state and the method inputs. An Action method is declared as follows: 891 | 892 | ```bluespec 893 | method Action actionMethodName(ArgType1 arg1, ArgType2 arg2...); // Can have 0 or more args 894 | ``` 895 | 896 | You can call such methods as: 897 | 898 | ```bluespec 899 | module.actionMethodName(arg1, arg2, ...); 900 | ``` 901 | 902 | ##### Value Methods 903 | 904 | Value methods do not alter the internal state of the circuit, so there's no enable signal because nothing in the circuit needs to change when the method is called. Instead, value methods just output some value generated in the circuit. Value methods are declared as follows: 905 | 906 | ```bluespec 907 | method ReturnType valueMethodName(ArgType1 arg1, ArgType2 arg2...); // Can have 0 or more args 908 | ``` 909 | 910 | You can call such methods and just use the return value in an expression or assign it to a variable: 911 | 912 | ```bluespec 913 | ReturnType r = module.valueMethodName(arg1, arg2, ...); 914 | ``` 915 | 916 | ##### ActionValue Methods 917 | 918 | ActionValue methods both alter the internal state of the circuit and return a value from the circuit. This means there is both an enable signal, and an output (return) value. ActionValue methods are declared as follows: 919 | 920 | ```bluespec 921 | method ActionValue#(ReturnType) avMethodName(ArgType1 arg1, ArgType2 arg2...); // Can have 0 or more args 922 | ``` 923 | 924 | You can call such methods with the same syntax, but to use the return value, you must use the single arrow operator `<-`: 925 | 926 | ```bluespec 927 | ReturnType r <- module.avMethodName(arg1, arg2, ...); 928 | ``` 929 | 930 | **If you write `=` instead of `<-`, `r` will still have the special type `ActionValue#(ReturnType)`,** which you can't perform computations on like `ReturnType`. 931 | 932 | #### Empty Interface 933 | 934 | An interface with no methods is built into Bluespec, and is called `Empty`. This is useful for creating top-level modules and testbenches. 935 | 936 | ### Modules 937 | 938 | Modules are implementation of interfaces, and so they are how we actually define how the sequential circuit works. Modules have three components: 939 | 940 | * Internal state (registers) 941 | * Methods (inputs and outputs) 942 | * Rules (internal logic) 943 | 944 | Again, we're going to only talk about sequential circuits that use one clock domain, so the clock is implicit and we can think of modules on a timestep basis. What this means is that on every clock cycle (or timestep), the internal state and inputs are read, and then some actions are conditionally executed, and the some new values are conditionally written back to the internal state. Then, on the next timestep, the same thing repeats, using the new state and new inputs. 945 | 946 | #### Module Declaration 947 | 948 | A module declaration and implementation follows the following structure. Note that the name of a module is always prefixed by mk, which stands for "make". 949 | 950 | ```bluespec 951 | // Basic module declaration 952 | module mkModuleName(InterfaceName); 953 | // Internal state here 954 | 955 | // Rules here 956 | 957 | // Methods here 958 | endmodule 959 | ``` 960 | 961 | If our module or interface includes parameterizations, here are alternate module declarations: 962 | 963 | ```bluespec 964 | // Interface is parameterized, module is not. For example, if the module implements 965 | // a specific parameterization of the interface. 966 | module mkModuleName(InterfaceName#(InterfaceParamType)); 967 | 968 | // Interface and module are both parameterized. Often ModuleParamType and InterfaceParamType 969 | // will be the same. For example, a parameterized FIFO module that can be instantiated 970 | // to store any data type. 971 | module mkModuleName#(ModuleParamType) (Interface#(InterfaceParamType)); 972 | 973 | // Module is parameterized, interface is not. For example, a non-parameterizable interface, 974 | // but the module that implements it includes a FIFO with parameterizable depth. 975 | module mkModuleName#(ModuleParamType) (Interface); 976 | ``` 977 | 978 | #### Internal State 979 | 980 | Any module instantiated within a module is considered internal state, since every sequential module has internal state. The most basic unit of internal state in Bluespec is the register (a built-in Bluespec module), which only consists of two methods, read and write, and stores whatever values are written to it. However, the module can have any collection of registers, vectors of registers, or other modules as internal state. 981 | 982 | ##### Instantiating Internal State 983 | 984 | Internal state should be instantiated at the beginning of a module. We need to declare the internal state just like we would any variable in a function, but to initialize the value, we use a new operator, the left arrow `<-`, to actually create an instantiation of the module. 985 | 986 | ```bluespec 987 | Reg#(Bit#(1)) myReg <- mkRegU(); // Creates a register storing 1 bit, undefined initial value 988 | Reg#(Bool) myRegFlag <- mkReg(False); // Creates a register storing a Bool, initialized to False 989 | Reg#(Bit#(4)) myRegValue <- mkReg(4'b1001); // Creates a register storing 4 bits, initialzed to 4'b1001 990 | 991 | ModuleName myModule <- mkModuleName(); // Creates an instance of the module ModuleName 992 | ``` 993 | 994 | The initial values stored in registers are the reset values for the registers, and are only relevant when you first instantiate the circuit. As soon as you write to the register, the initial value becomes irrelevant. For registers that store data, we often can just not specify an initial value (as this results in less hardware). Sometimes, however, we need to define an initial state so that our circuit starts up correctly. For example, if we have an FSM that uses a `busy` flag, and the `start` method can't be called while `busy=True`, then we need to make sure that `busy` is initialized to `False`. 995 | 996 | ##### Registers 997 | 998 | The most basic module in Bluespec is the register: `Reg#(Type)`. A register can hold any type in the Bits class (including user-defined types deriving Bits, etc.) and we can instantiate any number of registers in our module. 999 | 1000 | A register has only two methods: `_read` and `_write`. Since it's such a commonly used module, however, there's a shorthand for these two methods. If we have a 2-bit register `x`: 1001 | 1002 | - `let y = x;` is equivalent to `let y = x._read();` 1003 | - `x <= 2'b00;` is equivalent to `x._write(2'b00);` Note that writing to a register uses the double arrow `<=`, which is distinct from the single arrow `<-` used for instantiating modules (above) or calling `ActionValue#` methods (below). 1004 | 1005 | When you read from a register, it returns the value of the data stored in the register. When you write data to a register, the new data value does not appear until the next cycle. So if a 1-bit register `x` is currently `0`, and in some rule/method (explained later) we have: 1006 | 1007 | ```bluespec 1008 | x <= 1; // write 1 to x 1009 | y = x; // read x into y 1010 | ``` 1011 | 1012 | this is the same as 1013 | 1014 | ```bluespec 1015 | x._write(1); 1016 | y = x._read(); 1017 | ``` 1018 | 1019 | and the end value of `y` will be 0, not 1, because writes to `x` don't happen until the end of the cycle, while reads happen at the beginning of the cycle. Note that `y` has to be a variable (corresponding to an intermediate wire), not a register, because we're using `=` assignment, which isn't valid for registers. If `y` was a register and we wanted to read the value of `x` into `y`, we would need to do: 1020 | 1021 | ```bluespec 1022 | x <= 1; // write 1 to x 1023 | y <= x; // read x into y 1024 | ``` 1025 | 1026 | Note: In this second example, **the old value of `x` will not appear in `y` until the end of the cycle**, since this operation is a write to the register `y`! So if we were to read from `y` on the next line, it would still return the old value of `y`. 1027 | 1028 | `ConfigReg`s are a small variant that behave just like normal registers, except that they don't enforce reads to be scheduled before writes. This does *not* mean that reads will see the value written by writes! All reads will still see old values. Import them with `import ConfigReg :: *;` and create them with `mkConfigReg` or `mkConfigRegU`. 1029 | 1030 | ##### Vectors 1031 | 1032 | Sometimes we want to declare an array of registers of the same size. For example, if we have a buffer of length n, we need an array of n registers to store our data. Bluespec has another built-in type, `Vector`, that we can use for this purpose, that has the following declaration: 1033 | 1034 | ```bluespec 1035 | Vector#(n, ElementType); 1036 | ``` 1037 | where `n` is the number of elements in the array, and `ElementType` is the type of elements in the array. 1038 | 1039 | If we want to actually instantiate a Vector of Registers, we would do so as follows: 1040 | 1041 | ```bluespec 1042 | // Instantiate a 5-element Vector of n-bit registers with uninitialized values 1043 | Vector#(5, Reg#(Bit#(n))) myVec1 <- replicateM(mkRegU()); 1044 | 1045 | // Instantiate an n-element Vector of 5-bit registers initialized to all 0's 1046 | Vector#(n, Reg#(Bit#(5))) myVec2 <- replicateM(mkReg(0)); 1047 | ``` 1048 | 1049 | Note: To use Vectors, you have to import the Vector package by adding the following line to the top of your file: 1050 | 1051 | ```bluespec 1052 | import Vector :: * ; 1053 | ``` 1054 | 1055 | ##### FIFO Queues 1056 | 1057 | There are other, more complex modules that can be used to store internal state. A FIFO (first-in-first-out) queue stores some amount of data. A producer can enqueue (`enq`) data, putting it into the queue, and a consumer can dequeue (`deq`) data, taking it out of the queue; this can happen in the same cycle or in different cycles. The consumer always dequeues data in the same order that the producer produces it, hence first-in-first-out. FIFOs are useful for flexibly storing data between pipeline stages. 1058 | 1059 | ```bluespec 1060 | interface FIFO#(type a); 1061 | method Action enq (a x); 1062 | method Action deq; 1063 | method a first; // data that was enqueued the earliest 1064 | method Action clear; 1065 | endinterface; 1066 | ``` 1067 | 1068 | You must `import FIFO :: *;` to use FIFOs. 1069 | 1070 | ```bluespec 1071 | FIFO#(datatype) fifo <- mkFIFO; 1072 | ``` 1073 | 1074 | To enqueue data you will usually write: 1075 | 1076 | ```bluespec 1077 | fifo.enq(data); 1078 | ``` 1079 | 1080 | To dequeue data you will usually write: 1081 | 1082 | ```bluespec 1083 | let data = fifo.first; 1084 | fifo.deq; 1085 | ``` 1086 | 1087 | But you don't need to call both methods. You can choose to call just `fifo.first` to examine the data at the front of the queue, or just `fifo.deq;` to dequeue something and get rid of it. 1088 | 1089 | There are also "FIFOFs", which are just like FIFOs except that they also have methods to explicitly determine if they are (not) full or empty: `notFull` and `notEmpty` methods, which return `Bool`. You should `import FIFOF :: *;` to use them. 1090 | 1091 | ```bluespec 1092 | FIFOF#(datatype) fifof <- mkFIFOF; 1093 | ``` 1094 | 1095 | If you want to specify exactly how large your FIFO or FIFOF should be, You can call `mkSizedFIFO` or `mkSizedFIFOF` with a positive integer argument. 1096 | 1097 | ```bluespec 1098 | FIFOF#(datatype) fifof <- mkSizedFIFOF(3); 1099 | ``` 1100 | 1101 | Finally, there are a variety of more specialized FIFOs/FIFOFs if you `import SpecialFIFOs :: *;`. The most likely ones to be used: 1102 | 1103 | - A *pipeline FIFO* (`mkPipelineFIFO` or `mkPipelineFIFOF`, which is size 1) is a FIFO where you can enqueue into a full FIFO if you also dequeue from it in the same cycle. It forces dequeueing to happen before enqueueing in each cycle. 1104 | - A *bypass FIFO* (`mkBypassFIFO` or `mkBypassFIFOF`, which is size 1) is a FIFO where you can dequeue from an empty FIFO if you also enqueue into it in the same cycle. It forces enqueueing to happen before dequeueing in each cycle. 1105 | 1106 | If you are curious about these FIFOs' implementation or need to customize them, you can look at the Bluespec source in `$BLUESPECDIR/BSVSource/Misc` directory. (Here `$BLUESPECDIR` is an environment variable. You can type `cd $BLUESPEDIR/BSVSource/Misc` in a terminal to go to that directory.) 1107 | 1108 | ##### Wires 1109 | 1110 | A basic but less 6.004-relevant module are "wires", which are modules with a value that can be written in a cycle and then have the value read out later in that cycle (so reads are constrained to be scheduled later than writes). The most primitive is the `RWire` (created with `mkRWire`) module supports a `wset` action and a `wget` method, where `wget` returns a `Maybe#` value that is valid only if it was written earlier in the cycle. The `Wire` interface module supports `_read` and `_write`, so it can be operated on with the same syntax as a register, and has more variants: 1111 | 1112 | - `mkWire` or `mkUnsafeWare` produces a `Wire` in which reads are implicitly guarded on whether a write occurred earlier. (`mkUnsafeWire` allows the write and read to be in the same rule, but `mkWire` does not.) 1113 | - `mkBypassWire` produces a `Wire` with no implicit guard; the compiler warns if the wire is not written in every cycle. 1114 | - `mkDWire(defaultValue)` produces a `Wire` with no implicit guard. Reading from this wire is always valid and will read the default value if no writes occurred. 1115 | 1116 | ##### Ephemeral History Registers 1117 | 1118 | Ephemeral history registers, or EHRs, are basically registers that can be read/written several times in a cycle such that writes can be observed by later reads. In recent Bluespec versions, they can be found under the name `CReg`, for "concurrent register". The syntax to create one looks like: 1119 | 1120 | ```bluespec 1121 | Reg#(datatype) regs[3] <- mkCReg(3, defaultval); 1122 | ``` 1123 | 1124 | You can now read and write to `regs[0]`, `regs[1]`, and `regs[2]`. Of course, the number 3 can be changed and the rules are similar to the above, but only small integers (up to 5?) are supported. 1125 | 1126 | The rules are: 1127 | 1128 | - Reads to `regs[i]` must happen before writes to the same `regs[i]`. The individual registers behave like normal registers in this regard. 1129 | - All the writes must happen in order: if `i < j`, then writes to `regs[i]` must happen before writes to `regs[j]`. The last of these writes that occurs becomes the value of the `CReg` at the start of the next cycle. 1130 | - Writes must come before, and are seen by, later reads: if `i < j`, then writes to `regs[i]` must happen before reads from `regs[j]`, and the last of all values written to `regs[i]` for `i < j` will be read by `regs[j]` (or, if no such write occurred, then the register's value at the start of the cycle will be read.) 1131 | - Note, however, that if you don't write `reg[i]`, say, then there's no conflict between `reg[i]` and `reg[i+1]`. 1132 | 1133 | 6.004 students may also be provided with an implementation called `Ehr`. Consult lecture slides/notes on usage. 1134 | 1135 | #### Methods and Rules 1136 | 1137 | Methods and rules are how we define the combinatorial logic that decides when/how to change the internal state of the sequential circuit. Methods are how the outside world gives the circuit inputs and reads outputs. Rules, on the other hand, are invisible to the outside world and describe the rest of the combinational logic in the circuit. 1138 | 1139 | Methods and rules consist of method calls to their internal modules, function calls, and assignments of temporary variables (wires). Both rules and methods are atomic, which means that either all or none of their actions are executed, where "actions" are calls to internal modules or writes to internal state. 1140 | 1141 | ##### Methods 1142 | 1143 | Methods are defined as follows: 1144 | 1145 | ```bluespec 1146 | method ReturnType methodName(ArgType1 arg1, ...) if (guard); 1147 | statement1; 1148 | statement2; 1149 | ... 1150 | statementN; 1151 | endmethod 1152 | ``` 1153 | 1154 | A method can only be executed if `guard=True`. This is an explicit guard, and usually depends on the internal state of the module. If the method is executed, then statement1 through statementN will all be executed. Otherwise, none of them will be executed. 1155 | 1156 | If these statements include calls to internal modules, then they can also generate implicit guards. Take the following example. The `start` method in mkTwoModules only has one guard, `!busy`. However, since `mod1.start` and `mod2.start` also have guards, and can only execute when their guards are true, `mkTwoModules.start` can only execute if `mod1.busy=False` and `mod2.busy=False`. Since mkTwoModules doesn't have any visibility into the internal implementation of mkMyModule, we can't write them explicitly in mkTwoModules; they're instead implicit and get generated later by the compiler. 1157 | 1158 | ```bluespec 1159 | // Module that does something 1160 | module mkMyModule(IfcType); 1161 | // Some internal state 1162 | ... 1163 | Reg#(Bool) busy <- mkReg(False); 1164 | 1165 | method Action start() if (!busy); 1166 | doStuff(); 1167 | ... 1168 | endmethod 1169 | 1170 | ... 1171 | 1172 | endmodule 1173 | 1174 | // Module that instantiates two MyModules 1175 | module mkTwoModules(IfcType); 1176 | MyModule mod1 <- mkMyModule; 1177 | MyModule mod2 <- mkMyModule; 1178 | Reg#(Bool) busy <- mkReg(False); 1179 | 1180 | ... 1181 | 1182 | method Action start() if (!busy); 1183 | mod1.start(); 1184 | mod2.start(); 1185 | ... 1186 | endmethod 1187 | 1188 | ... 1189 | 1190 | endmodule 1191 | ``` 1192 | 1193 | ##### Rules 1194 | 1195 | Rules are similar to methods in that they are a collection of method calls, function calls, and use of temporary variables. However, they do not take inputs or generate outputs, and they do not interact with the outside world. Instead, they define how the sequential circuit is continuously updating its internal state. While methods only execute when they are called, rules execute all the time when they can. 1196 | 1197 | A rule is implemented as follows: 1198 | 1199 | ```bluespec 1200 | rule ruleName if (guard); // The word `if` is optional for rules 1201 | statement1; 1202 | statement2; 1203 | ... 1204 | statementN; 1205 | endrule 1206 | ``` 1207 | 1208 | Just like methods, a rule has implicit guards. If any statement is a method call with guards, then any guards on that method call are an implicit guard on this rule. If any implicit or explicit guard is false, then no statements will execute, otherwise all statements will execute. 1209 | 1210 | ##### Avoiding Double Writes 1211 | 1212 | Since everything in a rule or method happens on the same cycle, we have to make sure that we don't try to double write to a register. Examples of double writes are: 1213 | 1214 | ```bluespec 1215 | // BAD: Double write 1216 | method Action doubleWrite; 1217 | x <= 1; 1218 | x <= 0; 1219 | endmethod 1220 | 1221 | // BAD: Conditional double write 1222 | method Action condDoubleWrite; 1223 | x <= 1; 1224 | if (y) x <= 0; 1225 | endmethod 1226 | 1227 | // OK: Two exclusive writes 1228 | method Action condExclusiveWrite; 1229 | if (y) x <= 1; 1230 | else x <= 0; 1231 | endmethod; 1232 | ``` 1233 | 1234 | We also can't call conflicting methods in the same cycle. This includes double calling to the same method, or calling two methods that both write to the same register. For example: 1235 | 1236 | ```bluespec 1237 | module mkSubmodule; 1238 | // Internal state 1239 | ... 1240 | Reg#(Bit#(1)) x <- mkRegU; 1241 | 1242 | method Action writeValueA; 1243 | x <= valA; 1244 | endmethod 1245 | 1246 | method Action writeValueB; 1247 | x <= valB; 1248 | endmethod 1249 | endmodule 1250 | 1251 | module mkMyModule; 1252 | // Internal state 1253 | ... 1254 | Submodule submod <- mkSubmodule; 1255 | 1256 | // BAD: If this method executes, it would cause a double write 1257 | // to the register submod.x 1258 | method Action doSomething; 1259 | submod.writeValueA(); 1260 | submod.writeValueB(); 1261 | endmethod 1262 | endmodule 1263 | ``` 1264 | 1265 | ##### Scheduling 1266 | 1267 | **Scheduling** concerns how the Bluespec compiler determines which rules will fire in each cycle. Generally, in every cycle, Bluespec will try to fire every rule whose guard is True, in some order. If it can't do that, which could happen if two rules both interact with the same registers or conflicting methods of the same module, Bluespec will issue a warning. No matter what, each rule will execute at most once each cycle. 1268 | 1269 | Some constraints from basic modules: 1270 | 1271 | - For a normal register, all reads (including e.g. in the guards of rules) must be scheduled before all writes in each cycle. 1272 | - For a normal FIFO queue, only one rule can `enq` and only one rule can `deq` each cycle, but the two could happen in either order. `first` must happen before `deq`. In a pipeline FIFO, `deq` must come before `enq`. In a bypass FIFO, `enq` must come before `deq`. 1273 | 1274 | If the `-show-schedule` flag is passed to Bluespec, which it should be in 6.004 makefiles, you can see the generated schedule of rules in the `.sched` file. There are also some *scheduling attributes* that you can write before rules to affect their scheduling. They are rather advanced but can be useful to make sure that methods are fired under the conditions you expect them to, and scheduled in the order you expect them to. Consult the Bluespec reference guide for more information. 1275 | 1276 | ```bluespec 1277 | (* fire_when_enabled *) // the immediately following rule *must* fire if its guard is enabled. If the compiler can't make this happen, it errors. 1278 | (* no_implicit_conditions *) // The immediately following rule must not have any implicit guards, caused by calling a method with a guard. That is, it must be able to fire if its guard is enabled. 1279 | (* descending_urgency = "rule1, rule2, rule3" *) // rule1 is more urgent than rule2, which is more urgent than rule3, etc.; which means that if the guard of multiple of these rules is enabled and they conflict, the earlier (more urgent) rules will fire 1280 | (* execution_order = "rule1, rule2, rule3" *) // in each cycle, rule1 should be scheduled before rule2, which should be scheduled before rule3. If this can't happen, the compiler will consider them to conflict, even if they could have executed in the other order without this attribute. 1281 | (* mutually_exclusive = "rule1, rule2, rule3" *) // Tells the compiler that these rules' guards are mutually exclusive, even if Bluespec can't determine it. Bluespec will insert code so that there will be an error if this fails during runtime simulation. 1282 | (* conflict_free = "rule1, rule2, rule3" *) // Tells the compiler that these rules are conflict-free, i.e. they will never call conflicting methods when running, even if Bluespec can't determine it. Bluespec will insert code so that there will be an error if this fails during runtime simulation. 1283 | (* preempts = "rule1, rule2" *) // Tells the compiler that if rule1 fires, rule2 must not fire; equivalent to forcing the two rules to conflict and then annotating with descending_urgency. 1284 | ``` 1285 | 1286 | ## Additional Topics 1287 | 1288 | #### Maybe values 1289 | 1290 | Given a type `Type`, you can create a type called `Maybe#(Type)`. Values of the type `Maybe#(Type)` could either be `Valid` and contain a value of type `Type`, or be `Invalid` (and not contain anything --- there's exactly one possible `Invalid` value). The syntax for a valid `Maybe` value is `tagged Valid value` and the syntax for the invalid `Maybe` value is `tagged Invalid`. For example, here are all possible values of the type `Maybe#(Bit#(2))`: 1291 | 1292 | ```bluespec 1293 | Maybe#(Bit#(2)) invalid = tagged Invalid; 1294 | Maybe#(Bit#(2)) valid00 = tagged Valid 2'b00; 1295 | Maybe#(Bit#(2)) valid01 = tagged Valid 2'b01; 1296 | Maybe#(Bit#(2)) valid10 = tagged Valid 2'b10; 1297 | Maybe#(Bit#(2)) valid11 = tagged Valid 2'b11; 1298 | ``` 1299 | 1300 | To use a `Maybe` value, you might want to use the built-in functions `fromMaybe` and `isValid`. 1301 | 1302 | - If `defaultVal` is a value of some type `Type` and `maybeVal` is a value of type `Maybe#(Type)`, then `fromMaybe(defaultVal, maybeVal)` returns the value inside `maybeVal` if `maybeVal` is Valid, and `defaultVal` if `maybeVal` is invalid. 1303 | - `isValid(maybeVal)` returns `True` if `maybeVal` is Valid and `False` if `maybeVal` is Invalid. 1304 | 1305 | However, the most generally useful way of handling a `Maybe` value is to use a case matching statement or expression. 1306 | 1307 | #### Case matches 1308 | 1309 | ```bluespec 1310 | Maybe#(Bit#(2)) foo = // ... 1311 | 1312 | case (foo) matches 1313 | tagged Valid .x: 1314 | // foo is Valid and x is the value of type Bit#(2) inside foo 1315 | tagged Invalid: 1316 | // foo is Invalid 1317 | endcase 1318 | ``` 1319 | 1320 | #### Common Errors 1321 | 1322 | Most of Bluespec's error messages have line and column numbers, so it can often help you track down the error sooner if you enable line numbers on your text editor. 1323 | 1324 | ##### Bluespec doesn't respond for a long time 1325 | 1326 | Check if you have Internet access inside the VM and that you're not on MIT GUEST, since Bluespec needs Internet access to check out a license and run. 1327 | 1328 | ##### "Type error ... Expected type ... Inferred type ..." 1329 | 1330 | That means that Bluespec wanted some expression to be a particular ("expected") type, but the expression was a different ("inferred") type, so Bluespec couldn't compile the expression. Try to figure out why they are different and what you can do to both sides to make them the same. Common possible type errors: 1331 | 1332 | - **The two types are `Bit#(n)` and `Bit#(m)` for different numbers `n` and `m`, or one of the types is `Bit#(n)` and the other is `Integer`**: Remember that most of Bluespec's bitwise and arithmetic operators only operate between two operands of the same number of bits, or between two `Integer`s. If you have two `Bit` types of different lengths, you may want to `extend`/`zeroExtend`/`signExtend`, `truncate`, or slice one or both of them so they match. If you have an `Integer` (in particular, the result of calling `valueOf` on a numeric type variable), you can call `fromInteger` on it to turn it into an arbitrary `Bit#(n)`. 1333 | 1334 | - **One of the types is `Bool` and the other is some `Bit#(n)`**: Remember that `Bool`s and `Bit#(1)`s are different types, and that Bluespec's boolean and bitwise operators are different. 1335 | 1336 | - For `Bool`s, you use `&&` `||` and `!`. 1337 | - For `Bit#(n)`, you use `&` `|` and `~`. 1338 | 1339 | You can convert a `Bit#(1) b` to a `Bool` with `b == 1` and you can convert a `Bool b` to a `Bit#(1)` with `b ? 1 : 0`. 1340 | 1341 | ##### "The numeric types ... could not be shown to be equal" 1342 | 1343 | This usually arises because you are using type variables in some way that only works if they are equal to some fixed type or to each other. For example, if you try to assign a value of type `Bit#(m)` to a variable of type `Bit#(2)` where `m` is an actual type variable, Bluespec will complain that it doesn't know if `m` equals `2`. You may be able to resolve this by extending or truncating. 1344 | 1345 | One particular reason you might encounter this error is if you're trying to write a recursive function with a base case depending on a type variable. For example, in order to reverse the bits in a sequence, you might try to write a recursive function like this: 1346 | 1347 | ```bluespec 1348 | function Bit#(w) myReverseBits(Bit#(w) bits); 1349 | if (valueOf(w) == 1) 1350 | return bits[0]; 1351 | else begin 1352 | Bit#(TSub#(w, 1)) rest = bits[valueOf(w)-1:1]; 1353 | return {bits[0], myReverseBits(rest)}; 1354 | end 1355 | endfunction 1356 | ``` 1357 | 1358 | Unfortunately Bluespec doesn't work this way: when compiling it will not treat the condition `valueOf(w) == 1` specially, and it will still require both branches of the if/else to match the claimed return value. That is, even if `w > 1` and you know the top branch of the if/else will not be taken, Bluespec will still require that the return value from the top branch (which is `Bit#(1)`) match the return type (which is `Bit#(w)`) of the function, and it will complain that it can't show that `w` equals `1`. You should probably just try to write functions like this iteratively. (For this particular use case, Bluespec has a built-in `reverseBits` function that returns a reversed copy of the bits of a `Bit#(n)`.) 1359 | 1360 | ##### "The provisos for this expression are too general" 1361 | 1362 | This error means you are using type variables in some more complicated way that Bluespec doesn't have enough information to see will work, most commonly numeric type variables. A "proviso" is some kind of constraint on the type variables that has to be satisfied in order for your code to make sense. For example, if you try to assign a value of type `Bit#(TAdd#(m, 1))` to a variable of type `Bit#(n)` where `m` and `n` are actual different type variables, this is only possible if `m + 1` equals `n`, and Bluespec will complain that it wants a proviso that translates to `m + 1 == n`. 1363 | 1364 | Some example errors: 1365 | 1366 | - **"`The following provisos are needed: Add#(w, 1, w)`"**: The proviso `Add#(w, 1, w)` mwans that Bluespec wants `w + 1 = w` to be true. Obviously, this is mathematically impossible, but unfortunately Bluespec is not smart enough to figure this out. It typically means you are trying to assign a value of type `Bit#(TAdd#(w, 1))` to a variable of type `Bit#(w)` or vice versa. The way around is usually the same as when you have a type error between `Bit#(m)` and `Bit#(n)` for actual numbers `m` and `n`; you should try to extend or truncate. 1367 | 1368 | - **"`The following provisos are needed: Add#(a__, 1, w)`"**: If there's a variable that ends in two underscores, it's usually a made-up name internal to Bluespec. In this case this proviso just means that Bluespec thinks `w` has to be greater than or equal to 1. In this case you may actually want to add this proviso to your function; see the section below on provisos (TODO). 1369 | 1370 | 1371 | #### Debugging with `$display` 1372 | 1373 | The `$display` statement (formally a "system task") is useful for debugging. It prints any number of strings or other things. (Of course this only happens during simulation of the circuit, not in a real circuit that would be synthesized.) 1374 | 1375 | ```bluespec 1376 | $display("Hello!", "Goodbye!"); 1377 | ``` 1378 | 1379 | You can also display numbers and other things: 1380 | 1381 | ```bluespec 1382 | $display("n is ", n); 1383 | ``` 1384 | 1385 | `$display` can also be used like `printf` if you've ever encountered it in C. If you have a number `n`, you could print it using a `%` format specifier like this: 1386 | 1387 | ```bluespec 1388 | $display("n is %d in decimal", n); 1389 | $display("n is %b in binary", n); 1390 | $display("n is %o in octal", n); 1391 | $display("n is %x in hexadecimal", n); 1392 | ``` 1393 | 1394 | You can use multiple format specifiers for multiple numbers, like if you have another number: 1395 | 1396 | ```bluespec 1397 | $display("n is %d and m is %d", n, m); 1398 | ``` 1399 | 1400 | Note that `$display` prints a newline after the string you give it. If you don't want that, you can use `$write` instead, with the same syntax. 1401 | 1402 | If you have a more complicated structure, though, you probably won't be happy with just displaying it directly. Instead, you should make the structure derive `FShow` and call `fshow` on it to get a nice format: 1403 | 1404 | ```bluespec 1405 | typedef struct { 1406 | Bit#(32) a; 1407 | Bit#(32) b; 1408 | } Foo deriving (Bits, Eq, FShow); 1409 | 1410 | // later 1411 | 1412 | Foo foo = Foo { a: 1, b: 2 }; 1413 | $display("foo is ", fshow(foo)); 1414 | ``` 1415 | 1416 | This will print something like `Foo { a: 'h00000001, b: 'h00000002 }` instead of just a garbage hex string. 1417 | 1418 | `fshow` returns a `Fmt` object. You can also convert strings directly to `Fmt` objects by calling `$format`, and concatenate `Fmt` objects, like so: 1419 | 1420 | ```bluespec 1421 | $display($format("foo is ") + fshow(foo)); 1422 | ``` 1423 | 1424 | #### Don't care values 1425 | 1426 | The question mark `?` can be used as an expression. It means that you don't care about what the value is, and allows Bluespec to synthesize a more optimized circuit. For example, if you have a struct where sometimes one of the values doesn't matter, you can set it to `?` when it doesn't and a concrete value when it does. 1427 | 1428 | Note that the `?` value doesn't necessarily obey common-sense invariants, so you should really only use it when you're sure it won't affect anything you care about. For example, if you write `if (?)` then either of the two branches of the `if`/`else` statement could occur, or both or neither. 1429 | 1430 | ## TODO 1431 | 1432 | #### Program Structure (scoping, visibility, file structure, etc.) 1433 | #### Rule conflicts and scheduling 1434 | #### Testbenches 1435 | #### Synthesis / synthesize keyword 1436 | #### Provisos 1437 | #### Recursion 1438 | #### Tagged Unions 1439 | -------------------------------------------------------------------------------- /BluespecQuickReference.md: -------------------------------------------------------------------------------- 1 | # Bluespec Quick Reference 2 | 3 | A heavily abbreviated Bluespec reference accompanying the [Intro Guide](BluespecIntroGuide.md). Covers more basic syntax than the [Bluespec Reference Card](http://www.bluespec.com/forum/download.php?id=98) (which doesn't even have for loops?) 4 | 5 | ## Comments 6 | 7 | ```bluespec 8 | // single line comment 9 | /* multiline 10 | comment */ 11 | ``` 12 | 13 | ## Types 14 | 15 | ```bluespec 16 | Bit#(n) 17 | Int#(n) // signed 18 | Uint#(n) // unsigned 19 | Integer // static elaboration only 20 | Bool 21 | 22 | Action 23 | ActionValue#(t) 24 | Rules 25 | Tuple2#(t1, t2) ... Tuple7#(t1,..., t7) 26 | ``` 27 | 28 | ## Values 29 | 30 | ```bluespec 31 | 0 // constant zero 32 | 42 // decimal 42 of arbitrary size 33 | '1 // Enough 1 bits to fill the needed width 34 | 4'b1010 // 4-bit value 1010 in binary 35 | 36 | True // Bool 37 | False // Bool 38 | ``` 39 | 40 | ## Operators and Built-In Functions 41 | 42 | If `a` and `b` are variables of type `Bit#(n)`, expressions include: 43 | 44 | ```bluespec 45 | a & b a | b a ^ b ~a 46 | 47 | a + b a - b a * b a / b a % b 48 | 49 | a << b a >> b 50 | 51 | {a, b} // Bit concatenation 52 | a[0] // Bit indexing (0 is the least significant bit, i.e. the right!) 53 | a[7:0] // Bit slicing (inclusive of both indices, so this has 8 bits) 54 | 55 | // Add or remove bits from the left; you may need to put them into a variable 56 | // with explicitly declared type 57 | signExtend(a) zeroExtend(a) truncate(a) 58 | 59 | // Comparisons give values of type Bool 60 | a == b a != b a < b a > b a <= b a >= b 61 | ``` 62 | 63 | If `p` and `q` are variables of type `Bool`, expressions include: 64 | 65 | ```bluespec 66 | p && q p || q !p 67 | 68 | p ? a : b 69 | ``` 70 | 71 | If `i` is an `Integer`, you can use `fromInteger(i)` to convert it to a `Bits#(n)` 72 | 73 | `pack` converts from various types to `Bit#(n)`, `unpack` converts from `Bit#(n)` to various types. 74 | 75 | ## Type-Level Operations 76 | 77 | ```bluespec 78 | Type-level Equivalent math 79 | TAdd#(a, b) a + b 80 | TSub#(a, b) a - b 81 | TMul#(a, b) a * b 82 | TDiv#(a, b) ceiling(a / b) 83 | TLog#(a) ceiling(log_2 a) 84 | TExp#(a) 2^a (2 to the power of a, not 2 xor a) 85 | TMax#(a, b) max(a, b) 86 | TMin#(a, b) min(a, b) 87 | ``` 88 | 89 | If `a` is a numeric type, you can use `valueOf(n)` to convert it to an `Integer`. 90 | 91 | ## Variable Declarations 92 | 93 | ``` 94 | Bit#(3) a = 7; // a has explicit type Bit#(3) 95 | let b = {a, a}; // type of b is inferred 96 | ``` 97 | 98 | ## Tuples 99 | 100 | ```bluespec 101 | Tuple2#(Bit#(1), Bit#(2)) pair = tuple2(1, 0); 102 | 103 | Bit#(1) first = tpl_1(pair); 104 | Bit#(2) second = tpl_2(pair); 105 | // or 106 | match {.first, .second} = pair; 107 | ``` 108 | 109 | ## Structs 110 | 111 | ```bluespec 112 | typedef struct { 113 | Bit#(1) foo; 114 | Bit#(2) bar; 115 | } NewType; 116 | 117 | NewType myNewVar = NewType{foo: 1, bar: 2}; 118 | 119 | let newFoo = myNewVar.foo; 120 | let newBar = myNewVar.bar; 121 | // or 122 | match tagged NewType {foo: .newFoo, bar: .newBar} = myNewVar; 123 | ``` 124 | 125 | ## Enums 126 | 127 | ```bluespec 128 | typedef enum Color { Red, Green, Yellow, Blue } deriving (Bits, Eq); 129 | Color color = Red; 130 | ``` 131 | 132 | ## Control Flow 133 | 134 | ```bluespec 135 | if (condition) begin 136 | x = 5; 137 | end 138 | 139 | for (Integer i = 0; i < max; i = i + 1) begin 140 | do_something(); 141 | end 142 | ``` 143 | 144 | ## Switch 145 | 146 | ```bluespec 147 | case (someValue) 148 | 1: do1(); 149 | 2: do2(); 150 | default: do3(); 151 | endcase 152 | 153 | let foo = case (someValue) 154 | 1: bar; 155 | 2: baz; 156 | default: quux; 157 | endcase; 158 | ``` 159 | 160 | ## Functions 161 | 162 | ```bluespec 163 | function ReturnType fnName(Type var1, Type var2); // semicolon! 164 | some_stuff(); 165 | return other_stuff(); 166 | endfunction 167 | ``` 168 | 169 | ## Modules 170 | 171 | ```bluespec 172 | interface MyInterface; 173 | method Action myAction(Bit#(1) flag); 174 | method ActionValue#(Bool) getMyResult; 175 | endinterface 176 | 177 | module mkMyModule(MyInterface); 178 | Reg#(Bool) myReg <- mkRegU; 179 | 180 | rule doSomething; 181 | do_some_stuff(); 182 | endrule 183 | 184 | method Action myAction(Bit#(1) flag) if (myReg); 185 | do_some_other_stuff(); 186 | endmethod 187 | 188 | method ActionValue#(Bool) getMyResult if (!myReg); 189 | return True; 190 | endmethod 191 | endmodule 192 | ``` 193 | 194 | ## Registers 195 | 196 | In a module, outside rules and methods, use `<-` to create registers and modules. 197 | 198 | ```bluespec 199 | Reg#(Bit#(1)) myReg <- mkRegU(); 200 | Reg#(Bool) myRegFlag <- mkReg(False); 201 | ``` 202 | 203 | In a module rule or method, use `<-` to perform `ActionValue`s. 204 | 205 | ```bluespec 206 | let result <- someModule.someMethod(someArg); 207 | ``` 208 | 209 | In a module rule or method, use `<=` to write into registers. Reading from registers is implicit. 210 | 211 | ```bluespec 212 | myReg <= 1; // write 1 to x 213 | ``` 214 | 215 | ## Module Example 216 | 217 | ```bluespec 218 | interface Tripler; 219 | method Action start(Bit#(32) n); 220 | method ActionValue#(Bit#(32)) getResult; 221 | endinterface 222 | 223 | module mkTripler(Tripler); 224 | Reg#(Bit#(32)) x <- mkRegU; 225 | Reg#(Bit#(32)) y <- mkRegU; 226 | Reg#(Bool) busy <- mkReg(False); 227 | rule tripleStep if (busy && x > 0); 228 | x <= x - 1; 229 | y <= y + 3; 230 | endrule 231 | method Action start(Bit#(32) n) if (!busy); 232 | x <= n; 233 | y <= 0; 234 | busy <= True; 235 | endmethod 236 | method ActionValue#(Bit#(32)) getResult if (busy && x == 0); 237 | busy <= False; 238 | return y; 239 | endmethod 240 | endmodule 241 | ``` 242 | -------------------------------------------------------------------------------- /BluespecQuickReference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcamenzind/BluespecIntroGuide/733e391e9d972bd126cef1d300f6d6d7c457e5b4/BluespecQuickReference.pdf -------------------------------------------------------------------------------- /BluespecQuickReferenceTemplate.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{article} 2 | \usepackage[landscape,top=0.75in,bottom=0.75in,left=0.75in,right=0.75in]{geometry} 3 | \usepackage{amsfonts} 4 | \usepackage{amsmath} 5 | \usepackage{booktabs} 6 | \usepackage{fancyvrb} 7 | \usepackage{fontspec} 8 | \usepackage{hyperref} 9 | \usepackage{ifluatex} 10 | \usepackage{ifxetex} 11 | \usepackage{listings} 12 | \usepackage{longtable} 13 | \usepackage{multicol} 14 | \usepackage{unicode-math} 15 | \usepackage[compact]{titlesec} 16 | \setlength{\columnsep}{24pt} 17 | 18 | \begin{document} 19 | \begin{multicols*}{2} % starred uses full page 20 | \footnotesize 21 | $body$ 22 | \end{multicols*} 23 | \end{document} 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bluespec Intro Guide 2 | 3 | This repository contains some information for learning and writing Bluespec (that is, the hardware description language Bluespec™ SystemVerilog), intended for students of the MIT class 6.004. It was started and mostly written by Kathy Camenzind in Fall 2018. Brian Chen contributed some material, including this README. You can view the [**Intro Guide**](BluespecIntroGuide.md) or the [**Quick Reference**](BluespecQuickReference.md). 4 | --------------------------------------------------------------------------------