HDLRuby 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/HDLRuby.gemspec +1 -0
- data/README.html +2330 -2670
- data/README.md +400 -100
- data/ext/hruby_sim/hruby_rcsim_build.c +402 -3
- data/ext/hruby_sim/hruby_sim.h +2 -1
- data/ext/hruby_sim/hruby_sim_calc.c +34 -7
- data/ext/hruby_sim/hruby_sim_core.c +15 -5
- data/ext/hruby_sim/hruby_sim_tree_calc.c +112 -23
- data/lib/HDLRuby/hdr_samples/c_program/echo.c +33 -0
- data/lib/HDLRuby/hdr_samples/comparison_bench.rb +2 -2
- data/lib/HDLRuby/hdr_samples/counter_bench.rb +1 -1
- data/lib/HDLRuby/hdr_samples/counter_dff_bench.rb +8 -7
- data/lib/HDLRuby/hdr_samples/dff_properties.rb +2 -0
- data/lib/HDLRuby/hdr_samples/enum_as_param.rb +52 -0
- data/lib/HDLRuby/hdr_samples/linear_test.rb +2 -0
- data/lib/HDLRuby/hdr_samples/logic_bench.rb +6 -0
- data/lib/HDLRuby/hdr_samples/mei8.rb +6 -6
- data/lib/HDLRuby/hdr_samples/mei8_bench.rb +6 -6
- data/lib/HDLRuby/hdr_samples/memory_test.rb +2 -0
- data/lib/HDLRuby/hdr_samples/named_sub.rb +9 -5
- data/lib/HDLRuby/hdr_samples/ram.rb +7 -6
- data/lib/HDLRuby/hdr_samples/ruby_fir_hw.rb +2 -0
- data/lib/HDLRuby/hdr_samples/ruby_program/echo.rb +9 -0
- data/lib/HDLRuby/hdr_samples/ruby_program/stdrw.rb +6 -0
- data/lib/HDLRuby/hdr_samples/ruby_program/sw_cpu_terminal.rb +614 -0
- data/lib/HDLRuby/hdr_samples/ruby_program/sw_inc_mem.rb +32 -0
- data/lib/HDLRuby/hdr_samples/ruby_program/sw_log.rb +33 -0
- data/lib/HDLRuby/hdr_samples/struct.rb +15 -3
- data/lib/HDLRuby/hdr_samples/with_board.rb +63 -0
- data/lib/HDLRuby/hdr_samples/with_bram.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_bram_frame_stack.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_bram_stack.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_channel.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_channel_other.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_class.rb +3 -1
- data/lib/HDLRuby/hdr_samples/with_clocks.rb +42 -0
- data/lib/HDLRuby/hdr_samples/with_connector.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_connector_memory.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_fixpoint.rb +6 -0
- data/lib/HDLRuby/hdr_samples/with_fixpoint_adv.rb +73 -0
- data/lib/HDLRuby/hdr_samples/with_leftright.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_of.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_program_c.rb +28 -0
- data/lib/HDLRuby/hdr_samples/with_program_ruby.rb +28 -0
- data/lib/HDLRuby/hdr_samples/with_program_ruby_cpu.rb +234 -0
- data/lib/HDLRuby/hdr_samples/with_program_ruby_io.rb +23 -0
- data/lib/HDLRuby/hdr_samples/with_program_ruby_mem.rb +58 -0
- data/lib/HDLRuby/hdr_samples/with_program_ruby_threads.rb +56 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer.rb +17 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_channel.rb +58 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb +10 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb +18 -4
- data/lib/HDLRuby/hdr_samples/with_sequencer_func.rb +2 -4
- data/lib/HDLRuby/hdr_samples/with_sequencer_sync.rb +2 -1
- data/lib/HDLRuby/hdrcc.rb +72 -21
- data/lib/HDLRuby/hruby_error.rb +13 -0
- data/lib/HDLRuby/hruby_high.rb +125 -26
- data/lib/HDLRuby/hruby_low.rb +171 -3
- data/lib/HDLRuby/hruby_low2programs.rb +47 -0
- data/lib/HDLRuby/hruby_low_resolve.rb +3 -2
- data/lib/HDLRuby/hruby_low_without_namespace.rb +133 -5
- data/lib/HDLRuby/hruby_low_without_subsignals.rb +1 -1
- data/lib/HDLRuby/hruby_rcsim.rb +113 -6
- data/lib/HDLRuby/hruby_serializer.rb +2 -1
- data/lib/HDLRuby/hruby_verilog.rb +94 -20
- data/lib/HDLRuby/hruby_verilog_name.rb +3 -17
- data/lib/HDLRuby/std/clocks.rb +118 -50
- data/lib/HDLRuby/std/fixpoint.rb +2 -2
- data/lib/HDLRuby/std/function_generator.rb +1 -1
- data/lib/HDLRuby/std/linear.rb +7 -7
- data/lib/HDLRuby/std/sequencer.rb +263 -13
- data/lib/HDLRuby/std/sequencer_channel.rb +90 -0
- data/lib/HDLRuby/std/sequencer_func.rb +28 -15
- data/lib/HDLRuby/std/std.rb +6 -0
- data/lib/HDLRuby/ui/hruby_board.rb +1079 -0
- data/lib/HDLRuby/version.rb +1 -1
- data/lib/c/Rakefile +8 -0
- data/lib/c/cHDL.h +12 -0
- data/lib/c/extconf.rb +7 -0
- data/lib/rubyHDL.rb +33 -0
- data/tuto/gui_accum.png +0 -0
- data/tuto/gui_board.png +0 -0
- data/tuto/tutorial_sw.html +2263 -1890
- data/tuto/tutorial_sw.md +957 -62
- metadata +43 -5
- data/README.pdf +0 -0
- data/tuto/tutorial_sw.pdf +0 -0
data/README.md
CHANGED
|
@@ -7,10 +7,35 @@ __Note__:
|
|
|
7
7
|
|
|
8
8
|
If you are new to HDLRuby, it is recommended that you consult first the following tutorial (even if you are a hardware person):
|
|
9
9
|
|
|
10
|
-
* [HDLRuby tutorial for software people](tuto/tutorial_sw.md)
|
|
10
|
+
* [HDLRuby tutorial for software people](tuto/tutorial_sw.md) [md]
|
|
11
|
+
|
|
12
|
+
* [HDLRuby tutorial for software people](tuto/tutorial_sw.html) [html]
|
|
11
13
|
|
|
12
14
|
__What's new__
|
|
13
15
|
|
|
16
|
+
For HDLRuby version 3.3.0:
|
|
17
|
+
|
|
18
|
+
* Remade the description of software components using the program construct.
|
|
19
|
+
Now the Code objects are deprecated.
|
|
20
|
+
|
|
21
|
+
* Added HW-SW co-simulation capability for Ruby and compiled C-compatible
|
|
22
|
+
software programs.
|
|
23
|
+
|
|
24
|
+
* Added a browser-based graphical interface simulating simulates a development board that interacts with the HDLRuby simulator.
|
|
25
|
+
|
|
26
|
+
* Updated the documentation and tutorial accordingly and fixed several typos.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
For HDLRuby version 3.2.0:
|
|
30
|
+
|
|
31
|
+
* Added component for declaring BRAM and BRAM-based stacks.
|
|
32
|
+
The goal is to allocate memories inside FPGAs efficiently.
|
|
33
|
+
|
|
34
|
+
* Inner code overhaul for preparing version 4.0.0
|
|
35
|
+
|
|
36
|
+
* Multiple bug fixes
|
|
37
|
+
|
|
38
|
+
|
|
14
39
|
For HDLRuby version 3.1.0:
|
|
15
40
|
|
|
16
41
|
* [Functions for sequencers](#sequencer-specific-function-std-sequencer_func-rb) supporting recursion;
|
|
@@ -36,7 +61,7 @@ For HDLRuby version 3.0.0:
|
|
|
36
61
|
|
|
37
62
|
__Install__:
|
|
38
63
|
|
|
39
|
-
The recommended installation method is from
|
|
64
|
+
The recommended installation method is from rubygems as follows:
|
|
40
65
|
|
|
41
66
|
```
|
|
42
67
|
gem install HDLRuby
|
|
@@ -51,7 +76,7 @@ git clone HDLRuby
|
|
|
51
76
|
__Warning__:
|
|
52
77
|
|
|
53
78
|
- This is still preliminary work which may change before we release a stable version.
|
|
54
|
-
- It is highly recommended to have both basic
|
|
79
|
+
- It is highly recommended to have both basic knowledge of the Ruby language and hardware description languages before using HDLRuby.
|
|
55
80
|
|
|
56
81
|
|
|
57
82
|
# Compiling HDLRuby descriptions
|
|
@@ -98,7 +123,7 @@ __Notes__:
|
|
|
98
123
|
|
|
99
124
|
* If no top system is given, it is automatically looked for from the input file.
|
|
100
125
|
* If no option is given, it simply checks the input file.
|
|
101
|
-
* If you are new to HDLRuby, or if you want to see how new features work, we strongly encourage to get a local copy of the test HDLRuby sample using:
|
|
126
|
+
* If you are new to HDLRuby, or if you want to see how new features work, we strongly encourage you to get a local copy of the test HDLRuby sample using:
|
|
102
127
|
|
|
103
128
|
```bash
|
|
104
129
|
hdrcc --get-samples
|
|
@@ -155,7 +180,7 @@ hdrcc -I pry
|
|
|
155
180
|
|
|
156
181
|
## Using HDLRuby in interactive mode
|
|
157
182
|
|
|
158
|
-
When running in interactive mode, the HDLRuby framework starts a REPL prompt and creates a working directory called
|
|
183
|
+
When running in interactive mode, the HDLRuby framework starts a REPL prompt and creates a working directory called `HDLRubyWorkspace`. By default, the REPL is `irb`, but it can be set to `pry`. Within this prompt, HDLRuby code can be written like in an HDLRuby description file. However, to process this code the following commands are added:
|
|
159
184
|
|
|
160
185
|
* Compile an HDLRuby module:
|
|
161
186
|
|
|
@@ -374,7 +399,7 @@ system :reg do |typ|
|
|
|
374
399
|
end
|
|
375
400
|
```
|
|
376
401
|
|
|
377
|
-
Wait... I have just realized that D-FF without any inverted output does not look very serious. So, let us extend the existing `dff` to provide an inverted output. There are three ways
|
|
402
|
+
Wait... I have just realized that D-FF without any inverted output does not look very serious. So, let us extend the existing `dff` to provide an inverted output. There are three ways to do this. First, inheritance can be used: a new system is built inheriting from `dff` as it is done in the following code.
|
|
378
403
|
|
|
379
404
|
```ruby
|
|
380
405
|
system :dff_full, dff do
|
|
@@ -432,7 +457,7 @@ system :shifter do |n|
|
|
|
432
457
|
end
|
|
433
458
|
```
|
|
434
459
|
|
|
435
|
-
As can be seen in the above examples, in HDLRuby, any construct is an object and therefore
|
|
460
|
+
As can be seen in the above examples, in HDLRuby, any construct is an object and therefore includes methods. For instance, declaring a signal of a given `type` and direction (input, output, or inout) is done as follows so that `direction` is a method of the type, and the signal names are the arguments of this method (symbols or string are supported.)
|
|
436
461
|
|
|
437
462
|
```ruby
|
|
438
463
|
<type>.<direction> <list of symbols representing the signal>
|
|
@@ -483,7 +508,7 @@ end
|
|
|
483
508
|
In the code above, there are two generic parameters,
|
|
484
509
|
`typ`, which indicates the data type of the circuit, and `coefs`, which is assumed to be an array of coefficients. Since the number of inputs depends on the number of provided coefficients, it is declared as an array of `width` bit signed whose size is equal to the number of coefficients.
|
|
485
510
|
|
|
486
|
-
The description of the sum of products may be more difficult to understand for people not familiar with the Ruby language. The `each_with_index` method iterates over the coefficients adding their index as an iteration variable, the resulting operation (i.e., the iteration loop) is then modified by the `reduce` method that accumulates the code passed as arguments. This code, starting by `|sum,coef,i|`
|
|
511
|
+
The description of the sum of products may be more difficult to understand for people not familiar with the Ruby language. The `each_with_index` method iterates over the coefficients adding their index as an iteration variable, the resulting operation (i.e., the iteration loop) is then modified by the `reduce` method that accumulates the code passed as arguments. This code, starting by `|sum,coef,i|` performs the addition of the current accumulation result (`sum`) with the product of the current coefficient (`coef`) and input (`ins[i]`, where `i` is the index) in the iteration. The argument `_b0` initializes the sum to `0`.
|
|
487
512
|
|
|
488
513
|
While slightly longer than the previous description, this description allows declaring a circuit implementing a sum of products with any bit width and any number of coefficients. For instance, the following code describes a signed 32-bit sum of products with 16 coefficients (just random numbers here).
|
|
489
514
|
|
|
@@ -491,7 +516,7 @@ While slightly longer than the previous description, this description allows dec
|
|
|
491
516
|
sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit)
|
|
492
517
|
```
|
|
493
518
|
|
|
494
|
-
As seen in the code above, when passing a generic argument for instantiating a generic system, the name of the instance is put between brackets
|
|
519
|
+
As seen in the code above, when passing a generic argument for instantiating a generic system, the name of the instance is put between brackets to avoid confusion.
|
|
495
520
|
|
|
496
521
|
While the description `sumprod` is already usable in a wide range of cases, it still uses standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for the sake of performance, compliance with constraints, or because functionally different operations are required (e.g., saturated computations). This can be solved by using functions implementing such computation in place of operators, for example, as follows:
|
|
497
522
|
|
|
@@ -537,7 +562,7 @@ hdef :add do |max, x, y|
|
|
|
537
562
|
end
|
|
538
563
|
```
|
|
539
564
|
|
|
540
|
-
It would however be necessary to add this argument when invoking the function, e.g., `add(1000,sum,mult(...))`. While this argument is relevant for addition with saturation, it is not for the other
|
|
565
|
+
It would however be necessary to add this argument when invoking the function, e.g., `add(1000,sum,mult(...))`. While this argument is relevant for addition with saturation, it is not for the other kinds of addition operations, and hence, the code of `sumprod` has no general purpose.
|
|
541
566
|
|
|
542
567
|
HDLRuby provides two ways to address such issues. First, it is possible to pass code as an argument. In the case of `sumprod`, it would then be enough to add two arguments that perform the required addition and multiplication. The example is below:
|
|
543
568
|
|
|
@@ -582,7 +607,7 @@ sat16_1000.define_operator(:+) do |x,y|
|
|
|
582
607
|
end
|
|
583
608
|
```
|
|
584
609
|
|
|
585
|
-
In the code above, the first line defines the new type `sat16_1000` to be 16-bit signed and the remaining overloads (redefines) the `+` operator for this type (the same should be done for the `*` operator).
|
|
610
|
+
In the code above, the first line defines the new type `sat16_1000` to be 16-bit signed, and the remaining overloads (redefines) the `+` operator for this type (the same should be done for the `*` operator).
|
|
586
611
|
Then, the initial version of `sumprod` can be used with this type to achieve saturated computations as follows:
|
|
587
612
|
|
|
588
613
|
```ruby
|
|
@@ -658,7 +683,7 @@ Several constructs in HDLRuby are referred to by name, e.g., systems and signals
|
|
|
658
683
|
After being declared, the construct can be referred to by using the name directly (i.e., without the `:` of Ruby symbols). For example, if a construct
|
|
659
684
|
has been declared with `:hello` as the name, it will be afterward referred to by `hello`.
|
|
660
685
|
|
|
661
|
-
## Systems and
|
|
686
|
+
## Systems and Signals
|
|
662
687
|
|
|
663
688
|
A system represents a digital system and corresponds to a Verilog HDL module. A system has an interface comprising input, output, and inout signals, and includes structural and behavioral descriptions.
|
|
664
689
|
|
|
@@ -666,7 +691,7 @@ A signal represents a state in a system. It has a data type and a value, the lat
|
|
|
666
691
|
|
|
667
692
|
### Declaring an empty system
|
|
668
693
|
|
|
669
|
-
A system is declared using the keyword `system`. It must be given a Ruby symbol for its name and a block that
|
|
694
|
+
A system is declared using the keyword `system`. It must be given a Ruby symbol for its name and a block that describes its content. For instance, the following code describes an empty system named `box`:
|
|
670
695
|
|
|
671
696
|
```ruby
|
|
672
697
|
system(:box) {}
|
|
@@ -674,7 +699,7 @@ system(:box) {}
|
|
|
674
699
|
|
|
675
700
|
__Notes__:
|
|
676
701
|
|
|
677
|
-
- Since this is Ruby code, the body can also be delimited by the `do` and `end` Ruby keywords (in which case the parentheses can be omitted)
|
|
702
|
+
- Since this is Ruby code, the body can also be delimited by the `do` and `end` Ruby keywords (in which case the parentheses can be omitted) as follows:
|
|
678
703
|
|
|
679
704
|
```ruby
|
|
680
705
|
system :box does
|
|
@@ -850,7 +875,7 @@ end
|
|
|
850
875
|
### Initialization of signals
|
|
851
876
|
<a name="initialization"></a>
|
|
852
877
|
|
|
853
|
-
Output, inner and constant signals of a system can be initialized when declared using the following syntax in place of the usual name of the signal:
|
|
878
|
+
Output, inner, and constant signals of a system can be initialized when declared using the following syntax in place of the usual name of the signal:
|
|
854
879
|
|
|
855
880
|
```ruby
|
|
856
881
|
<signal name>: <intial value>
|
|
@@ -889,7 +914,7 @@ system :div2 do
|
|
|
889
914
|
|
|
890
915
|
```
|
|
891
916
|
|
|
892
|
-
For robustness or, readability
|
|
917
|
+
For robustness or, readability purposes, it is possible to add an inner scope inside the existing scope using the `sub` keyword as follows:
|
|
893
918
|
|
|
894
919
|
```ruby
|
|
895
920
|
sub do
|
|
@@ -971,7 +996,7 @@ end
|
|
|
971
996
|
```
|
|
972
997
|
|
|
973
998
|
In addition, it is possible to declare inner signals within an execution block.
|
|
974
|
-
While such signals will be physically linked to the system, they are only accessible within the block they are declared into. This permits a tighter scope for signals, which improves the readability of the code and
|
|
999
|
+
While such signals will be physically linked to the system, they are only accessible within the block they are declared into. This permits a tighter scope for signals, which improves the readability of the code and makes it possible to declare several signals with identical names provided their respective scopes are different.
|
|
975
1000
|
|
|
976
1001
|
An event represents a specific change in the state of a signal.
|
|
977
1002
|
For example, a rising edge of a clock signal named `clk` will be represented by the event `clk.posedge`. In HDLRuby, events are obtained directly from
|
|
@@ -1014,7 +1039,7 @@ system :with_sequential_behavior do
|
|
|
1014
1039
|
end
|
|
1015
1040
|
```
|
|
1016
1041
|
|
|
1017
|
-
A sub-block can also have a different execution mode if it is declared using `seq`, which will force sequential execution mode and `par` which will force parallel execution mode. For example, in the following code a parallel sub-block is declared within a sequential one:
|
|
1042
|
+
A sub-block can also have a different execution mode if it is declared using `seq`, which will force sequential execution mode, and `par` which will force parallel execution mode. For example, in the following code a parallel sub-block is declared within a sequential one:
|
|
1018
1043
|
|
|
1019
1044
|
```ruby
|
|
1020
1045
|
system :with_sequential_behavior do
|
|
@@ -1123,7 +1148,7 @@ end
|
|
|
1123
1148
|
( a <= b+1 ).at(clk.posedge)
|
|
1124
1149
|
```
|
|
1125
1150
|
|
|
1126
|
-
For sake of consistency, this operator can also be applied to block statements as follows, but it is probably less readable than the standard declaration of behaviors:
|
|
1151
|
+
For the sake of consistency, this operator can also be applied to block statements as follows, but it is probably less readable than the standard declaration of behaviors:
|
|
1127
1152
|
|
|
1128
1153
|
```ruby
|
|
1129
1154
|
( seq do
|
|
@@ -1237,8 +1262,7 @@ __Note:__
|
|
|
1237
1262
|
## Statements
|
|
1238
1263
|
|
|
1239
1264
|
Statements are the basic elements of a behavioral description. They are regrouped in blocks that specify their execution mode (parallel or sequential).
|
|
1240
|
-
There are four kinds of statements: the transmit statement which computes expressions and sends the result to the target signals, the control statement
|
|
1241
|
-
that changes the execution flow of the behavior, the block statement (described earlier), and the inner signal declaration.
|
|
1265
|
+
There are four kinds of statements: the transmit statement which computes expressions and sends the result to the target signals, the control statement which changes the execution flow of the behavior, the block statement (described earlier), and the inner signal declaration.
|
|
1242
1266
|
|
|
1243
1267
|
__Note__:
|
|
1244
1268
|
|
|
@@ -1319,8 +1343,7 @@ end
|
|
|
1319
1343
|
|
|
1320
1344
|
#### About loops
|
|
1321
1345
|
|
|
1322
|
-
HDLRuby does not include any hardware construct for describing loops. This might look poor compared to the other HDL, but it is important to understand
|
|
1323
|
-
that the current synthesis tools do not really synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable loopless hardware. In HDLRuby, such features are natively supported by the Ruby loop constructs (`for`, `while`, and so on), but also by advanced Ruby constructs like the enumerators (`each`, `times`, and so on).
|
|
1346
|
+
HDLRuby does not include any hardware construct for describing loops. This might look poor compared to the other HDL, but it is important to understand that the current synthesis tools do not synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable loopless hardware. In HDLRuby, such features are natively supported by the Ruby loop constructs (`for`, `while`, and so on), but also by advanced Ruby constructs like the enumerators (`each`, `times`, and so on).
|
|
1324
1347
|
|
|
1325
1348
|
__Notes__:
|
|
1326
1349
|
|
|
@@ -1338,10 +1361,9 @@ __Notes__:
|
|
|
1338
1361
|
## Types
|
|
1339
1362
|
<a name="types"></a>
|
|
1340
1363
|
|
|
1341
|
-
Each signal and each expression is associated with a data type that describes the kind of value it can represent. In HDLRuby, the data types represent
|
|
1342
|
-
bit-vectors associated with the way they should be interpreted, i.e., as bit strings, unsigned values, signed values, or hierarchical contents.
|
|
1364
|
+
Each signal and each expression is associated with a data type that describes the kind of value it can represent. In HDLRuby, the data types represent bit-vectors associated with the way they should be interpreted, i.e., as bit strings, unsigned values, signed values, or hierarchical contents.
|
|
1343
1365
|
|
|
1344
|
-
### Type
|
|
1366
|
+
### Type Construction
|
|
1345
1367
|
|
|
1346
1368
|
There are five basic types, `bit`, `signed`, `unsigned`, `integer`, and `float` that represent respectively single bit logical values, single-bit unsigned values, single-bit signed values, Ruby integer values, and Ruby floating-point values (double precision). The first three types are HW and support four-valued logic, whereas the two last ones are SW (but are compatible with HW) and only support Boolean logic. Ruby integers can represent any element of **Z** (the mathematical integers) and have for that purpose a variable bit-width.
|
|
1347
1369
|
|
|
@@ -1444,9 +1466,9 @@ They include [immediate values](#immediate-values), [reference to signals](#refe
|
|
|
1444
1466
|
|
|
1445
1467
|
### Immediate values
|
|
1446
1468
|
|
|
1447
|
-
The immediate values of HDLRuby can represent vectors of `bit`, `unsigned`, and `signed`, and integer or floating-point numbers. They are prefixed by a `_` character and include a header that indicates the vector type and the base used for representing the value, followed by a numeral representing the value. The bit width of a value is obtained by default from the width of the numeral, but it is also possible to specify it in the header. In addition, the character `_` can be put anywhere in the number
|
|
1469
|
+
The immediate values of HDLRuby can represent vectors of `bit`, `unsigned`, and `signed`, and integer or floating-point numbers. They are prefixed by a `_` character and include a header that indicates the vector type and the base used for representing the value, followed by a numeral representing the value. The bit width of a value is obtained by default from the width of the numeral, but it is also possible to specify it in the header. In addition, the character `_` can be put anywhere in the number to increase the readability, but it will be ignored.
|
|
1448
1470
|
|
|
1449
|
-
The vector type specifiers are the
|
|
1471
|
+
The vector type specifiers are the following:
|
|
1450
1472
|
|
|
1451
1473
|
- `b`: `bit` type, can be omitted,
|
|
1452
1474
|
|
|
@@ -1454,7 +1476,7 @@ The vector type specifiers are the followings:
|
|
|
1454
1476
|
|
|
1455
1477
|
- `s`: `signed` type, the last figure is sign-extended if required by the binary, octal, and hexadecimal bases, but not for the decimal base.
|
|
1456
1478
|
|
|
1457
|
-
The base specifiers are the
|
|
1479
|
+
The base specifiers are the following:
|
|
1458
1480
|
|
|
1459
1481
|
- `b`: binary,
|
|
1460
1482
|
|
|
@@ -1500,8 +1522,7 @@ __Notes__:
|
|
|
1500
1522
|
|
|
1501
1523
|
References are expressions used to designate signals or a part of signals.
|
|
1502
1524
|
|
|
1503
|
-
The simplest reference is simply the name of a signal. It designates the signal corresponding to this name in the current scope. For instance, in the
|
|
1504
|
-
following code, inner signal `sig0` is declared, and therefore the name *sig0* becomes a reference to designate this signal.
|
|
1525
|
+
The simplest reference is simply the name of a signal. It designates the signal corresponding to this name in the current scope. For instance, in the following code, inner signal `sig0` is declared, and therefore the name *sig0* becomes a reference to designate this signal.
|
|
1505
1526
|
|
|
1506
1527
|
```ruby
|
|
1507
1528
|
# Declaration of signal sig0.
|
|
@@ -1593,7 +1614,7 @@ __Conversion operators:__
|
|
|
1593
1614
|
| :to\_bit | cast to bit vector |
|
|
1594
1615
|
| :to\_unsigned | cast to unsigned vector |
|
|
1595
1616
|
| :to\_signed | cast to signed vector |
|
|
1596
|
-
| :to\_big | cast to big
|
|
1617
|
+
| :to\_big | cast to big-endian |
|
|
1597
1618
|
| :to\_little | cast to little endian |
|
|
1598
1619
|
| :reverse | reverse the bit order |
|
|
1599
1620
|
| :ljust | increase width from the left, preserves the sign |
|
|
@@ -1605,7 +1626,7 @@ __Selection /concatenation operators:__
|
|
|
1605
1626
|
|
|
1606
1627
|
| symbol | description |
|
|
1607
1628
|
| :--- | :--- |
|
|
1608
|
-
| :[] | sub
|
|
1629
|
+
| :[] | sub-vector selection |
|
|
1609
1630
|
| :@[] | concatenation operator |
|
|
1610
1631
|
| :. | field selection |
|
|
1611
1632
|
|
|
@@ -1683,8 +1704,8 @@ The type puns include `to_bit`, `to_unsigned`, and `to_signed` that convert expr
|
|
|
1683
1704
|
sig.to_bit <= _b01010011
|
|
1684
1705
|
```
|
|
1685
1706
|
|
|
1686
|
-
The type casts change both the type and the value and are used to adjust the width of the types. They can only be applied to vectors of `bit`, `signed`, or `
|
|
1687
|
-
These operators comprise the bit width conversions: `ljust`, `rjust`, `zext
|
|
1707
|
+
The type casts change both the type and the value and are used to adjust the width of the types. They can only be applied to vectors of `bit`, `signed`, or `unsigned` and can only increase the bit width (bit width can be truncated using the selection operator, please refer to the next section).
|
|
1708
|
+
These operators comprise the bit width conversions: `ljust`, `rjust`, `zext`, and `sext`.
|
|
1688
1709
|
|
|
1689
1710
|
More precisely, the bit width conversions operate as follows:
|
|
1690
1711
|
|
|
@@ -1747,7 +1768,7 @@ Concatenation and selection are done using the `[]` operator as follows:
|
|
|
1747
1768
|
#### Implicit conversions
|
|
1748
1769
|
<a name="implicit"></a>
|
|
1749
1770
|
|
|
1750
|
-
When there is no ambiguity, HDLRuby will automatically insert conversion operators when two types are not compatible with one another. The cases where such implicit conversions are applied are summarized in the following tables where:
|
|
1771
|
+
When there is no ambiguity, HDLRuby will automatically insert conversion operators when two types are not compatible with one another. The cases where such implicit conversions are applied are summarized in the following tables, where:
|
|
1751
1772
|
|
|
1752
1773
|
- `operator` is the operator in use
|
|
1753
1774
|
- `result width` is the width of the result's type
|
|
@@ -1844,7 +1865,7 @@ __Notes__:
|
|
|
1844
1865
|
function :one { 1 }
|
|
1845
1866
|
```
|
|
1846
1867
|
|
|
1847
|
-
- Functions can accept any
|
|
1868
|
+
- Functions can accept any object as an argument, including variadic arguments or blocks of code as shown below with a function that applies the code passed as an argument to all the variadic arguments of `args`:
|
|
1848
1869
|
|
|
1849
1870
|
```ruby
|
|
1850
1871
|
function :apply do |*args, &code|
|
|
@@ -1852,7 +1873,7 @@ __Notes__:
|
|
|
1852
1873
|
end
|
|
1853
1874
|
```
|
|
1854
1875
|
|
|
1855
|
-
Such a function can be used for example for connecting a signal to a set of other signals as follows (where `sig` is connected to `x`, `y
|
|
1876
|
+
Such a function can be used for example for connecting a signal to a set of other signals as follows (where `sig` is connected to `x`, `y`, and `z`):
|
|
1856
1877
|
```ruby
|
|
1857
1878
|
apply(x,y,z) { |v| v <= sig }
|
|
1858
1879
|
```
|
|
@@ -1905,7 +1926,7 @@ As another example, the following function will add an alternative code that gen
|
|
|
1905
1926
|
|
|
1906
1927
|
```ruby
|
|
1907
1928
|
def too_bad
|
|
1908
|
-
helse {
|
|
1929
|
+
helse { rst <= 1 }
|
|
1909
1930
|
end
|
|
1910
1931
|
```
|
|
1911
1932
|
|
|
@@ -1926,6 +1947,308 @@ end
|
|
|
1926
1947
|
Ruby functions can be compared to the macros of the C languages: they are more flexible since they edit the code they are invoked in, but they are also dangerous to use. In general, it is not recommended to use them, unless when designing a library of generic code for HDLRuby.
|
|
1927
1948
|
|
|
1928
1949
|
|
|
1950
|
+
## Software code
|
|
1951
|
+
|
|
1952
|
+
It is possible to describe hardware-software components in HDLRuby using the `program` construct that encapsulates some software code a provides an interface for communicating with the hardware. This interface is composed of three kinds of components:
|
|
1953
|
+
|
|
1954
|
+
* The activation events: 1-bit signal that triggers the execution of a given software function when the switch from 0 to 1 (or for negative ones, from 1 to 0).
|
|
1955
|
+
|
|
1956
|
+
* The reading ports: bit-vector signals that can be read from a software function.
|
|
1957
|
+
|
|
1958
|
+
* The writing ports: bit-vector signals that can be written from a software function.
|
|
1959
|
+
|
|
1960
|
+
__Note:__
|
|
1961
|
+
|
|
1962
|
+
The same signal can be used at the same time by multiple ports for both reading and writing, however, from the software point of view, it will correspond to two different ports.
|
|
1963
|
+
|
|
1964
|
+
### Declaring a software component
|
|
1965
|
+
|
|
1966
|
+
A software component is declared like a hardware process within a system. The syntax is the following:
|
|
1967
|
+
|
|
1968
|
+
```ruby
|
|
1969
|
+
program(<programming language>, <function name>) do
|
|
1970
|
+
<location of the software files and description of its interface>
|
|
1971
|
+
end
|
|
1972
|
+
```
|
|
1973
|
+
|
|
1974
|
+
In the code above, `programming language` is a symbol representing the programming language used for the software. For now, only two languages are supported:
|
|
1975
|
+
|
|
1976
|
+
* `:ruby`: for programs in Ruby.
|
|
1977
|
+
|
|
1978
|
+
* `:c`: for programs in C. However, for this case, any language that can be compiled to a shared library linkable with C is supported.
|
|
1979
|
+
|
|
1980
|
+
The `function name` parameter indicates which function is to be executed when an activation event occurs. There can be only one such function per program, but any number of programs can be declared inside the same module.
|
|
1981
|
+
|
|
1982
|
+
The `location of the software files and description of its interface` part can include the following declaration statements:
|
|
1983
|
+
|
|
1984
|
+
* `actport <list of events>`: for declaring the list of events that activates the program, i.e., that will trigger the execution of the program's start function.
|
|
1985
|
+
|
|
1986
|
+
* `inport <list of port names associated with a signal>`: for declaring the list of ports that the software code of the program can read.
|
|
1987
|
+
|
|
1988
|
+
* `outport <list of port names associated with a signal>`: for declaring the list of ports that the software code of the program can write to.
|
|
1989
|
+
|
|
1990
|
+
* `code <list of filenames>`: for declaring the source code files.
|
|
1991
|
+
|
|
1992
|
+
For example the following declares a program in the Ruby language whose start function is `echo` that is activated on the positive edge of signal `req`, has a read port called `inP` that is connected to signal `count` and a write port called `outP` that is connected to signal `val`, finally the code of this program is given in a file named `echo.rb`:
|
|
1993
|
+
|
|
1994
|
+
```ruby
|
|
1995
|
+
system :my_system do
|
|
1996
|
+
inner :req
|
|
1997
|
+
[8].inner :count, :val
|
|
1998
|
+
|
|
1999
|
+
...
|
|
2000
|
+
|
|
2001
|
+
program(:ruby,'echo') do
|
|
2002
|
+
actport req.posedge
|
|
2003
|
+
inport inP: count
|
|
2004
|
+
outport outP: val
|
|
2005
|
+
code "echo.rb"
|
|
2006
|
+
end
|
|
2007
|
+
end
|
|
2008
|
+
```
|
|
2009
|
+
|
|
2010
|
+
|
|
2011
|
+
__Note:__
|
|
2012
|
+
|
|
2013
|
+
The size of the input and output ports is one of the signals they give access to. However, from the software side, their values are converted to `long long` types.
|
|
2014
|
+
|
|
2015
|
+
|
|
2016
|
+
|
|
2017
|
+
### About the software code used in HDLRuby programs
|
|
2018
|
+
|
|
2019
|
+
#### Location and format of the files
|
|
2020
|
+
|
|
2021
|
+
The file names indicating the software code to use must indicate the path to these files relative to where the HDLRuby tools are used. In the example above, that would mean that the `echo.rb` program must be in the same directory as the HDLRuby description. If this code were to be into a `ruby` directory under the current directory, the declaration would become: `code "ruby/echo.rb"`.
|
|
2022
|
+
For the Ruby language, any number of source files can be declared, and plain Ruby code can be used as is. However, for the C language, the software code must first be compiled, and it is the resulting file that must be declared in the code declaration. For example, if for the example above, C had to be used, then the program description would be the following:
|
|
2023
|
+
|
|
2024
|
+
```ruby
|
|
2025
|
+
program(:c, :echo) do
|
|
2026
|
+
actport req.posedge
|
|
2027
|
+
inport inP: count
|
|
2028
|
+
outport outP: val
|
|
2029
|
+
code "echo"
|
|
2030
|
+
end
|
|
2031
|
+
```
|
|
2032
|
+
|
|
2033
|
+
Then, for this program to work, the C code must be compiled to a file named `echo`. Please notice that, in the example, the extension is omitted, to allow the system to look for the valid file type (e.g., `.so` for a Linux shared library).
|
|
2034
|
+
|
|
2035
|
+
__Note:__
|
|
2036
|
+
|
|
2037
|
+
The same software file can be used for several different program constructs, however the functions it contains will be unique for the whole device.
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
#### The hardware interface
|
|
2041
|
+
|
|
2042
|
+
From the software point of view, the hardware interface consists only of a list of ports that can either be read or written. However, the implementation of this interface depends on the language.
|
|
2043
|
+
|
|
2044
|
+
##### For Ruby
|
|
2045
|
+
|
|
2046
|
+
For ruby, the interface is accessed by requiring the `rubyHDL` library. It gives provides the `RubyHDL` module that provides accessors to ports of the program.
|
|
2047
|
+
For example, the following program reads on port `inP` and writes the results on port `outP`:
|
|
2048
|
+
|
|
2049
|
+
```ruby
|
|
2050
|
+
require 'rubyHDL'
|
|
2051
|
+
|
|
2052
|
+
def echo
|
|
2053
|
+
val = RubyHDL.inP
|
|
2054
|
+
RubyHDL.outP = val
|
|
2055
|
+
end
|
|
2056
|
+
```
|
|
2057
|
+
|
|
2058
|
+
__Note:__
|
|
2059
|
+
|
|
2060
|
+
As long as a port has been declared in the HDLRuby description of the program, it will be available to the software as a module accessor without the need for any additional declaration or configuration.
|
|
2061
|
+
|
|
2062
|
+
##### For C
|
|
2063
|
+
|
|
2064
|
+
For C (and C-compatible compiled languages), the interface is accessed by including the `cHDL.h` file. This file must be generated using the following command:
|
|
2065
|
+
|
|
2066
|
+
```bash
|
|
2067
|
+
hdrcc --ch <destination project>
|
|
2068
|
+
```
|
|
2069
|
+
|
|
2070
|
+
In the command above, `<destination project>` is the directory where the C code is meant to be.
|
|
2071
|
+
|
|
2072
|
+
|
|
2073
|
+
Once generated, this file provides the three following C functions:
|
|
2074
|
+
|
|
2075
|
+
* `void* c_get_port(const char* name)`: returns a pointer to the port whose name is passed as argument.
|
|
2076
|
+
|
|
2077
|
+
* `int c_read_port(void* port)`: reads the port whose pointer is passed as argument and returns its value.
|
|
2078
|
+
|
|
2079
|
+
* `int c_write_port(void* port, int val)`: write the value `val` to the port passed as argument.
|
|
2080
|
+
|
|
2081
|
+
For example, the following program reads on port `inP` and writes the results on port `outP`:
|
|
2082
|
+
|
|
2083
|
+
```c
|
|
2084
|
+
#include "cHDL.h"
|
|
2085
|
+
|
|
2086
|
+
void echo() {
|
|
2087
|
+
void* inP = c_get_port("inP");
|
|
2088
|
+
void* outP = c_get_port("outP");
|
|
2089
|
+
int val;
|
|
2090
|
+
|
|
2091
|
+
val = c_read_port(inP);
|
|
2092
|
+
c_write_port(outP,val);
|
|
2093
|
+
}
|
|
2094
|
+
```
|
|
2095
|
+
|
|
2096
|
+
__Note:__
|
|
2097
|
+
|
|
2098
|
+
* The command for generating the C header file for using the HDLRuby hardware interface also generates files for helping to compile the source code. Please see [compile for simulation](#compiling-the-c-code).
|
|
2099
|
+
|
|
2100
|
+
* **Important:** for windows, dynamically loaded functions must be declared with the following prefix: `__declspec(dllexport)`. If this prefix is not present before each function that is used as an HDLRuby program, the simulation will not work. For example, for Windows, the function echo *must* be written as follows:
|
|
2101
|
+
|
|
2102
|
+
```c
|
|
2103
|
+
#include "cHDL.h"
|
|
2104
|
+
|
|
2105
|
+
__declspec(dllexport) void echo() {
|
|
2106
|
+
void* inP = c_get_port("inP");
|
|
2107
|
+
void* outP = c_get_port("outP");
|
|
2108
|
+
int val;
|
|
2109
|
+
|
|
2110
|
+
val = c_read_port(inP);
|
|
2111
|
+
c_write_port(outP,val);
|
|
2112
|
+
}
|
|
2113
|
+
```
|
|
2114
|
+
|
|
2115
|
+
|
|
2116
|
+
|
|
2117
|
+
#### Hardware-software co-simulation
|
|
2118
|
+
|
|
2119
|
+
As long as your programs a correctly described and the software files provided (and compiled in the case of C), the hardware-software co-simulation will be automatically performed when executing the HDLRuby simulator.
|
|
2120
|
+
|
|
2121
|
+
##### Compiling the C code
|
|
2122
|
+
|
|
2123
|
+
While programs in Ruby can be used directly, programs in C must be compiled first. For that purpose, the required files, including the hardware interface `cHDL.h`, must be generated. This is done by using the following HDLRruby command:
|
|
2124
|
+
|
|
2125
|
+
```bash
|
|
2126
|
+
hdrcc --ch <destination project>
|
|
2127
|
+
```
|
|
2128
|
+
|
|
2129
|
+
In the command above, `<destination project>` is both the directory where the C code is and the name of the resulting shared library.
|
|
2130
|
+
|
|
2131
|
+
For example, if you want to compile the code located in the directory `echo` you need first to execute:
|
|
2132
|
+
|
|
2133
|
+
```bash
|
|
2134
|
+
hdrcc --ch echo
|
|
2135
|
+
```
|
|
2136
|
+
|
|
2137
|
+
Then, you will have to put your C files into the resulting directory and go inside it for compiling. If you have some specific needs for this compiling, or if you do not want to rely on the Ruby environment, you can compile your program there as a shared library like any other project. For example, if you are using GCC, you could type (after entering the `echo` directory):
|
|
2138
|
+
|
|
2139
|
+
```bash
|
|
2140
|
+
gcc -shared -fPIC -undefined dynamic_lookup -o c_program.so echo.c
|
|
2141
|
+
```
|
|
2142
|
+
|
|
2143
|
+
The command above is for compiling a single file project on a Linux system.
|
|
2144
|
+
|
|
2145
|
+
Otherwise, it may be easier to use the Ruby environment by first installing `rake-compiler` as follows:
|
|
2146
|
+
|
|
2147
|
+
```bash
|
|
2148
|
+
gem install rake-compiler
|
|
2149
|
+
```
|
|
2150
|
+
|
|
2151
|
+
And simply type the following command (after entering the `echo` directory):
|
|
2152
|
+
|
|
2153
|
+
```bash
|
|
2154
|
+
rake compile
|
|
2155
|
+
```
|
|
2156
|
+
|
|
2157
|
+
The rake tool will take care of everything for performing the compiling whatever your system may be.
|
|
2158
|
+
|
|
2159
|
+
|
|
2160
|
+
#### Hardware generation
|
|
2161
|
+
|
|
2162
|
+
In the current stage, HDLRuby only generates the hardware part of a description. E.g., when generating Verilog, the programs are simply being ignored. It is therefore up to the user to provide additional code for implementing the hardware-software interface. The reason is that such interfaces are target-dependent, and often comprise licensed software and IP components that cannot be integrated into HDLruby.
|
|
2163
|
+
|
|
2164
|
+
This is less a limitation than it seems since it is possible to write program constructs that wrap such accesses so that the software and HDLRuby code can be used as is in the target system. As an illustration, you can consult the example given in the tutorial: [7.6. Hardware-software co-synthesis](tuto/tutorial_sw.md#7-6-hardware-software-co-synthesis).
|
|
2165
|
+
|
|
2166
|
+
|
|
2167
|
+
### Extended co-simulation
|
|
2168
|
+
|
|
2169
|
+
Since HDLRuby programs can support any compiled software, these components can also be used for executing any kind of application that is not specifically meant to be executed on the target CPU. For instance, some peripheral circuits like a keyboard or a monitor can be modeled using an HDLRuby program, as illustrated in the HDLRuby sample `with_program_ruby_cpu.rb`.
|
|
2170
|
+
|
|
2171
|
+
|
|
2172
|
+
|
|
2173
|
+
### Development board simulation graphical interface
|
|
2174
|
+
|
|
2175
|
+
HDLRuby provides a web browser-based GUI for the simulator as an extension of the co-design platform presented in this section. This GUI is to be declared as follows within a module:
|
|
2176
|
+
|
|
2177
|
+
```ruby
|
|
2178
|
+
board(:<board name>,<server port>) do
|
|
2179
|
+
actport <event>
|
|
2180
|
+
<description of the GUI>
|
|
2181
|
+
end
|
|
2182
|
+
```
|
|
2183
|
+
|
|
2184
|
+
In the code above, `board name` is the name of the board, `server port` is the local port the browser has to connect to for accessing the GUI (by default it is set to 8000), and `event` is the event (e.g., the rising edge of a clock) that activates the synchronization of the GUI with the simulator.
|
|
2185
|
+
|
|
2186
|
+
Then the description of the GUI consists of a list of the following possible development board-oriented elements. Active elements are to be given a name and attached to a HDLRuby signal as follows:
|
|
2187
|
+
|
|
2188
|
+
```ruby
|
|
2189
|
+
<element> <element name>: <HDLRuby signal>
|
|
2190
|
+
```
|
|
2191
|
+
|
|
2192
|
+
The list of possible elements is as follows:
|
|
2193
|
+
|
|
2194
|
+
* `sw`: represents a set of slide switches, their number is set to match the bit-width of the attached signal.
|
|
2195
|
+
|
|
2196
|
+
* `bt`: represents a set of push buttons, their number is set to match the bit-width of the attached signal.
|
|
2197
|
+
|
|
2198
|
+
* `led`: represents a set of LEDs, their number is set to match the bit-width of the attached signal.
|
|
2199
|
+
|
|
2200
|
+
* `hexa`: represents a hexadecimal number display, its character width is set to match the width of the largest possible value of the attached signal.
|
|
2201
|
+
|
|
2202
|
+
* `digit`: represents a decimal number display, its character width is set to match the width of the largest possible positive or the smallest possible negative value of the attached signal.
|
|
2203
|
+
|
|
2204
|
+
* `scope`: represents an oscilloscope display, the vertical axis represents the value of the attached signal, its range is determined by its data type, and the horizontal axis represents the time is number of synchronization of the GUI.
|
|
2205
|
+
|
|
2206
|
+
* `row`: inserts a new line in the GUI.
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
For example, for a GUI presenting an interface to an adder with input signals `x` and `y` and output signal `z` displayed as LEDs, a digit display, and an oscilloscope, the following description can be used:
|
|
2210
|
+
|
|
2211
|
+
```ruby
|
|
2212
|
+
system :adder_with_gui do
|
|
2213
|
+
[8].inner :x, :y, :z
|
|
2214
|
+
|
|
2215
|
+
z <= x + y
|
|
2216
|
+
|
|
2217
|
+
inner :gui_sync
|
|
2218
|
+
|
|
2219
|
+
board(:adder_gui) do
|
|
2220
|
+
actport gui_sync.posedge
|
|
2221
|
+
sw x: x
|
|
2222
|
+
sw y: y
|
|
2223
|
+
row
|
|
2224
|
+
led z_led: z
|
|
2225
|
+
digit z_digit: z
|
|
2226
|
+
row
|
|
2227
|
+
scope z_scope: z
|
|
2228
|
+
end
|
|
2229
|
+
|
|
2230
|
+
timed do
|
|
2231
|
+
clk <= 0
|
|
2232
|
+
repeat(10000) do
|
|
2233
|
+
!10.ns
|
|
2234
|
+
clk <= ~clk
|
|
2235
|
+
end
|
|
2236
|
+
end
|
|
2237
|
+
end
|
|
2238
|
+
```
|
|
2239
|
+
|
|
2240
|
+
With the code above, the GUI will show a row containing two sets of slide switches for input `x` and `y`, a row containing a set of LEDs and a digital display for showing `z`, and a row containing an oscilloscope for showing the evolution `z`.
|
|
2241
|
+
|
|
2242
|
+
This code is simulated exactly like any other HDLRuby description, e.g., the following command will start the simulation and generate a VCD wave file:
|
|
2243
|
+
|
|
2244
|
+
```bash
|
|
2245
|
+
hdrcc --sim --vcd my_adder.rb my_adder
|
|
2246
|
+
```
|
|
2247
|
+
|
|
2248
|
+
However, the simulator will wait until a browser connects to it. For that, you can open a web browser, and go to the local url: `http://localhost:8000`. The simulation will then start and you can interact with the GUI.
|
|
2249
|
+
|
|
2250
|
+
|
|
2251
|
+
|
|
1929
2252
|
## Time
|
|
1930
2253
|
|
|
1931
2254
|
### Time values
|
|
@@ -1968,7 +2291,7 @@ There are two kinds of such statements:
|
|
|
1968
2291
|
!10.ns
|
|
1969
2292
|
```
|
|
1970
2293
|
|
|
1971
|
-
- The `repeat` statements: such a statement takes as argument
|
|
2294
|
+
- The `repeat` statements: such a statement takes as argument the number of iterations and a block. The execution of the block is repeated the given number of times. For example, the following code executes 10 times the inversion of the `clk` signal every 10 nanoseconds:
|
|
1972
2295
|
|
|
1973
2296
|
```ruby
|
|
1974
2297
|
repeat(10) do
|
|
@@ -1992,7 +2315,7 @@ sequential blocks. The execution semantic is the following:
|
|
|
1992
2315
|
|
|
1993
2316
|
1. Statements are grouped in sequence until a time statement is met.
|
|
1994
2317
|
|
|
1995
|
-
2. The grouped
|
|
2318
|
+
2. The grouped sequences are executed in parallel.
|
|
1996
2319
|
|
|
1997
2320
|
3. The time statement is executed.
|
|
1998
2321
|
|
|
@@ -2136,8 +2459,7 @@ In the code above, `some_sig` is a signal available in the current context. This
|
|
|
2136
2459
|
|
|
2137
2460
|
#### Basics
|
|
2138
2461
|
|
|
2139
|
-
In HDLRuby, a system can inherit from the content of one or several other parent systems using the `include` command as follows: `include <list of
|
|
2140
|
-
systems>`. Such an include can be put anywhere in the body of a system, but the resulting content will be accessible only after this command.
|
|
2462
|
+
In HDLRuby, a system can inherit from the content of one or several other parent systems using the `include` command as follows: `include <list of systems>`. Such an include can be put anywhere in the body of a system, but the resulting content will be accessible only after this command.
|
|
2141
2463
|
|
|
2142
2464
|
For example, the following code describes first a simple D-FF, and then uses it to describe a FF with an additional reversed output (`qb`):
|
|
2143
2465
|
|
|
@@ -2183,8 +2505,7 @@ __Note__:
|
|
|
2183
2505
|
|
|
2184
2506
|
#### About inner signals and system instances
|
|
2185
2507
|
|
|
2186
|
-
By default, inner signals and instances of a parent system are not accessible by its child systems. They can be made accessible using the `export` keyword as follows: `export <symbol 0>, <symbol 1>,
|
|
2187
|
-
code exports signals `clk` and `rst` and instance `dff0` of system `exporter` so that they can be accessed in child system `importer`.
|
|
2508
|
+
By default, inner signals and instances of a parent system are not accessible by its child systems. They can be made accessible using the `export` keyword as follows: `export <symbol 0>, <symbol 1>, ...`. For example, the following code exports signals `clk` and `rst` and instance `dff0` of system `exporter` so that they can be accessed in child system `importer`.
|
|
2188
2509
|
|
|
2189
2510
|
```ruby
|
|
2190
2511
|
system :exporter do
|
|
@@ -2346,7 +2667,7 @@ end
|
|
|
2346
2667
|
Please notice, that in the code above, the left value has been cast to a plain bit-vector to avoid the infinite recursive call of the `*` operator.
|
|
2347
2668
|
|
|
2348
2669
|
Operators can also be overloaded with generic types. However, in such a case, the generic argument must also be present in the list of arguments of the overloaded operators.
|
|
2349
|
-
For instance, let us consider the following fixed-point type of variable width (
|
|
2670
|
+
For instance, let us consider the following fixed-point type of variable width (whose decimal point is set at half of its bit range):
|
|
2350
2671
|
|
|
2351
2672
|
```ruby
|
|
2352
2673
|
typedef(:fixed) do |width|
|
|
@@ -2392,22 +2713,6 @@ Several enumerators are also provided for accessing the internals of the current
|
|
|
2392
2713
|
| `each_statement` | statements of the current block |
|
|
2393
2714
|
| `each_inner` | inner signals of the current block (or system if not within a block) |
|
|
2394
2715
|
|
|
2395
|
-
### Global signals
|
|
2396
|
-
|
|
2397
|
-
HDLRuby allows the declaration of global signals the same way system's signals are declared but outside the scope of any system. After being declared, these signals are accessible directly from within any hardware construct.
|
|
2398
|
-
|
|
2399
|
-
To ease the design of standardized libraries, the following global signals are defined by default:
|
|
2400
|
-
|
|
2401
|
-
| signal name | signal type | signal function |
|
|
2402
|
-
| :--- | :--- | :--- |
|
|
2403
|
-
| `$reset` | bit | global reset |
|
|
2404
|
-
| `$resetb` | bit | global reset complement |
|
|
2405
|
-
| `$clk` | bit | global clock |
|
|
2406
|
-
|
|
2407
|
-
__Note__:
|
|
2408
|
-
|
|
2409
|
-
- When not used, the global signals are discarded.
|
|
2410
|
-
|
|
2411
2716
|
|
|
2412
2717
|
|
|
2413
2718
|
### Defining and executing Ruby methods within HDLRuby constructs
|
|
@@ -2487,7 +2792,7 @@ end
|
|
|
2487
2792
|
While requiring caution, a properly designed method can be very useful for clean code reuse. For example, the following method allows to start the execution of a block after a given number of cycles:
|
|
2488
2793
|
|
|
2489
2794
|
```ruby
|
|
2490
|
-
def after(cycles,
|
|
2795
|
+
def after(cycles, rst, &code)
|
|
2491
2796
|
sub do
|
|
2492
2797
|
inner :count
|
|
2493
2798
|
hif rst == 1 do
|
|
@@ -2507,34 +2812,28 @@ end
|
|
|
2507
2812
|
|
|
2508
2813
|
In the code above:
|
|
2509
2814
|
|
|
2510
|
-
- the default initialization of `rst` to `$rst` allows resetting the counter even if no such signal is provided as an argument.
|
|
2511
|
-
|
|
2512
2815
|
- `sub` ensures that the `count` signal does not conflict with another signal with the same name.
|
|
2513
2816
|
|
|
2514
2817
|
- the `instance_eval` keyword is a standard Ruby method that executes the block passed as an argument in context.
|
|
2515
2818
|
|
|
2516
|
-
The following is an example that switches
|
|
2819
|
+
The following is an example that switches an LED on after 1000000 clock cycles using the previously defined `after` ruby method:
|
|
2517
2820
|
|
|
2518
2821
|
```ruby
|
|
2519
2822
|
system :led_after do
|
|
2520
2823
|
output :led
|
|
2521
|
-
input :clk
|
|
2824
|
+
input :clk, :rst
|
|
2522
2825
|
|
|
2523
2826
|
par(clk.posedge) do
|
|
2524
|
-
(led <= 0).hif(
|
|
2525
|
-
after(100000) { led <= 1 }
|
|
2827
|
+
(led <= 0).hif(rst)
|
|
2828
|
+
after(100000,rst) { led <= 1 }
|
|
2526
2829
|
end
|
|
2527
2830
|
end
|
|
2528
2831
|
```
|
|
2529
2832
|
|
|
2530
2833
|
__Note__:
|
|
2531
2834
|
|
|
2532
|
-
- Ruby's closure still applies in HDLRuby, hence, the block sent to `after` can use the signals and instances of the current block. Moreover, the
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
### Dynamic description
|
|
2835
|
+
- Ruby's closure still applies in HDLRuby, hence, the block sent to `after` can use the signals and instances of the current block. Moreover, the signals declared in this method will not collide with them.
|
|
2536
2836
|
|
|
2537
|
-
When describing a system, it is possible to disconnect or completely undefine a signal or an instance.
|
|
2538
2837
|
|
|
2539
2838
|
|
|
2540
2839
|
## Extending HDLRuby
|
|
@@ -2572,11 +2871,12 @@ The following table gives the class of each construct of HDLRuby.
|
|
|
2572
2871
|
| transmit | Transmit |
|
|
2573
2872
|
| hif | If |
|
|
2574
2873
|
| hcase | Case |
|
|
2874
|
+
| program | Program |
|
|
2575
2875
|
|
|
2576
2876
|
|
|
2577
2877
|
### Extending HDLRuby constructs locally
|
|
2578
2878
|
|
|
2579
|
-
By local extension of a hardware construct, we mean that while the construct will be changed, all the other constructs will remain unchanged. This is achieved like
|
|
2879
|
+
By local extension of a hardware construct, we mean that while the construct will be changed, all the other constructs will remain unchanged. This is achieved like with Ruby by accessing the Eigen class using the `singleton_class` method and extending it using the `class_eval` method. For example, with the following code, only system `dff` will respond to method `interface_size`:
|
|
2580
2880
|
|
|
2581
2881
|
```ruby
|
|
2582
2882
|
dff.singleton_class.class_eval do
|
|
@@ -2681,7 +2981,7 @@ After the libraries are loaded, the module `Std` must be included as follows:
|
|
|
2681
2981
|
include HDLRuby::High::Std
|
|
2682
2982
|
```
|
|
2683
2983
|
|
|
2684
|
-
> However, `hdrcc` loads the stable components of the standard library by default, so you do not need to require nor include anything more to use them. In the current version, the stable components are the
|
|
2984
|
+
> However, `hdrcc` loads the stable components of the standard library by default, so you do not need to require nor include anything more to use them. In the current version, the stable components are the following:
|
|
2685
2985
|
|
|
2686
2986
|
- `std/clocks.rb`
|
|
2687
2987
|
|
|
@@ -2736,7 +3036,7 @@ Where:
|
|
|
2736
3036
|
* `<clock>` is the clock to use, this argument can be omitted.
|
|
2737
3037
|
* `<reset>` is the signal used to reset the counter used for waiting, this argument can be omitted.
|
|
2738
3038
|
|
|
2739
|
-
This statement can be used
|
|
3039
|
+
This statement can be used inside a clocked behavior where the clock event of the behavior is used for the counter unless specified otherwise.
|
|
2740
3040
|
|
|
2741
3041
|
The second construct is the `before` statement that activates a block until a given number of clock cycles is passed. Its syntax and usage are identical to the `after` statement.
|
|
2742
3042
|
|
|
@@ -2782,7 +3082,7 @@ A finite state machine can be declared anywhere in a system provided it is outsi
|
|
|
2782
3082
|
fsm(<event>,<reset>,<mode>) <block>
|
|
2783
3083
|
```
|
|
2784
3084
|
|
|
2785
|
-
Where `event` is the event (rising or falling edge of a signal) activating the state transitions, `rst` is the reset signal,
|
|
3085
|
+
Where `event` is the event (rising or falling edge of a signal) activating the state transitions, `rst` is the reset signal, `mode` is the default execution mode, and `block` is the execution block describing the states of the FSM. This last parameter can be either `:sync` for synchronous (Moore type) or `:async` for asynchronous (Mealy type).
|
|
2786
3086
|
|
|
2787
3087
|
The states of an FSM are described as follows:
|
|
2788
3088
|
|
|
@@ -2790,12 +3090,12 @@ The states of an FSM are described as follows:
|
|
|
2790
3090
|
<kind>(<name>) <block>
|
|
2791
3091
|
```
|
|
2792
3092
|
|
|
2793
|
-
Where `kind` is the kind of state, `name` is the name of the state, and `block` is the actions to execute for the corresponding state. The kinds of states are the
|
|
3093
|
+
Where `kind` is the kind of state, `name` is the name of the state, and `block` is the actions to execute for the corresponding state. The kinds of states are the following:
|
|
2794
3094
|
|
|
2795
3095
|
* reset: the state reached when resetting the FSM. This state can be forced to be asynchronous by setting the `name` argument to `:async` and forced to be synchronous by setting the `name` argument to `:sync`. By default, the `name` argument is to be omitted.
|
|
2796
|
-
* state: the default kind of state,
|
|
2797
|
-
* sync: the synchronous kind of state,
|
|
2798
|
-
* async: the asynchronous kind of state,
|
|
3096
|
+
* state: the default kind of state, will be synchronous if the FSM is synchronous or asynchronous otherwise.
|
|
3097
|
+
* sync: the synchronous kind of state, will be synchronous whatever the kind of FSM is used.
|
|
3098
|
+
* async: the asynchronous kind of state, will be asynchronous whatever the kind of FSM is used.
|
|
2799
3099
|
|
|
2800
3100
|
In addition, it is possible to define a default action that will be executed whatever the state is using the following statement:
|
|
2801
3101
|
|
|
@@ -2843,7 +3143,7 @@ fsm(clk.posedge,rst,:sync) do
|
|
|
2843
3143
|
end
|
|
2844
3144
|
```
|
|
2845
3145
|
|
|
2846
|
-
__Note__: the goto statements act globally, i.e., they are independent of the place where they are declared within the state. For example for both following statements, the next state will always be `st_a` whatever `cond`
|
|
3146
|
+
__Note__: the goto statements act globally, i.e., they are independent of the place where they are declared within the state. For example for both following statements, the next state will always be `st_a` whatever `cond` may be:
|
|
2847
3147
|
|
|
2848
3148
|
```ruby
|
|
2849
3149
|
state(:st_0) do
|
|
@@ -3000,11 +3300,11 @@ The enumerators can be controlled using the following methods:
|
|
|
3000
3300
|
|
|
3001
3301
|
- `type`: returns the type of the elements accessed by the enumerator.
|
|
3002
3302
|
|
|
3003
|
-
- `seach`: returns the current enumerator. If a block is given, performs the iteration instead of returning an enumerator.
|
|
3303
|
+
- `seach`: returns the current enumerator. If a block is given, it performs the iteration instead of returning an enumerator.
|
|
3004
3304
|
|
|
3005
|
-
- `seach_with_index`: returns an enumerator over the elements of the current enumerator associated with their index position. If a block is given, performs the iteration instead of returning an enumerator.
|
|
3305
|
+
- `seach_with_index`: returns an enumerator over the elements of the current enumerator associated with their index position. If a block is given, it performs the iteration instead of returning an enumerator.
|
|
3006
3306
|
|
|
3007
|
-
- `seach_with_object(<obj>)`: returns an enumerator over the elements of the current enumerator associated with object `obj` (any object, HDLRuby or not, can be used). If a block is given, performs the iteration instead of returning an enumerator.
|
|
3307
|
+
- `seach_with_object(<obj>)`: returns an enumerator over the elements of the current enumerator associated with object `obj` (any object, HDLRuby or not, can be used). If a block is given, it performs the iteration instead of returning an enumerator.
|
|
3008
3308
|
|
|
3009
3309
|
- `with_index`: identical to `seach_with_index`.
|
|
3010
3310
|
|
|
@@ -3026,7 +3326,7 @@ It is also possible to define a custom enumerator using the following command:
|
|
|
3026
3326
|
<enum> = senumerator(<typ>,<size>) <block>
|
|
3027
3327
|
```
|
|
3028
3328
|
|
|
3029
|
-
Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data type
|
|
3329
|
+
Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data type, `size` is the number of the elements to enumerate, and `block` is the block that implements the access to an element by index. For example, an enumerator on a memory could be defined as follows:
|
|
3030
3330
|
|
|
3031
3331
|
```ruby
|
|
3032
3332
|
bit[8][-8].inner mem: [ _h01, _h02, _h03, _h04, _h30, _h30, _h30, _h30 ]
|
|
@@ -3125,7 +3425,7 @@ With this basis, several algorithms have been implemented using enumerators and
|
|
|
3125
3425
|
|
|
3126
3426
|
#### Shared signals
|
|
3127
3427
|
|
|
3128
|
-
Like any other process,
|
|
3428
|
+
Like any other process, several sequencers can't write to the same signal. This is because there would be race competition that may physically destroy the device if such operations were authorized. In standard RTL design, this limitation is overcome by implementing three-state buses, multiplexers, and arbiters. However, HDLRuby sequencers support another kind of signal called the *shared signals* that abstract the implementation details for avoiding race competition.
|
|
3129
3429
|
|
|
3130
3430
|
The shared signals are declared like the other kind of signals from their type. The syntax is the following:
|
|
3131
3431
|
|
|
@@ -3139,14 +3439,14 @@ They can also have an initial (and default) value when declared as follows:
|
|
|
3139
3439
|
<type>.shared <list of names with initialization>
|
|
3140
3440
|
```
|
|
3141
3441
|
|
|
3142
|
-
For example, the following code declares two 8-bit shared signals `x` and `y
|
|
3442
|
+
For example, the following code declares two 8-bit shared signals `x` and `y`, and two signed 16-bit shared signals initialized to 0 `u` and `v`:
|
|
3143
3443
|
|
|
3144
3444
|
```ruby
|
|
3145
3445
|
[8].shared :x, :y
|
|
3146
3446
|
signed[8].shared u: 0, v: 0
|
|
3147
3447
|
```
|
|
3148
3448
|
|
|
3149
|
-
A shared signal can then be read and written to by any sequencer from anywhere in the subsequent code of the current scope. However, they cannot be written
|
|
3449
|
+
A shared signal can then be read and written to by any sequencer from anywhere in the subsequent code of the current scope. However, they cannot be written outside a sequencer. For example, the following code is valid:
|
|
3150
3450
|
|
|
3151
3451
|
```ruby
|
|
3152
3452
|
input :clk, :start
|
|
@@ -3181,7 +3481,7 @@ This default behavior of shared signal avoids race competition but is not very u
|
|
|
3181
3481
|
<shared signal>.select
|
|
3182
3482
|
```
|
|
3183
3483
|
|
|
3184
|
-
The select value starts from 0 for the first sequencer writing to the shared signal
|
|
3484
|
+
The select value starts from 0 for the first sequencer writing to the shared signal and is increased by one per writing sequencer. For example, in the first example, for selecting the second sequencer for writing to `x` the following code can be added after this signal is declared:
|
|
3185
3485
|
|
|
3186
3486
|
```ruby
|
|
3187
3487
|
x.select <= 1
|
|
@@ -3193,12 +3493,12 @@ This value can be changed at runtime too. For example, instead of setting the se
|
|
|
3193
3493
|
par(clk.posedge) { x.select <= x.select + 1 }
|
|
3194
3494
|
```
|
|
3195
3495
|
|
|
3196
|
-
__Note__: this select sub
|
|
3496
|
+
__Note__: this select sub-signal is a standard RTL signal that has the same properties and limitations as the other ones, i.e., this is not a shared signal itself.
|
|
3197
3497
|
|
|
3198
3498
|
|
|
3199
3499
|
#### Arbiters
|
|
3200
3500
|
|
|
3201
|
-
Usually, it is not the signals that we want to share, but the resources they drive. For example,
|
|
3501
|
+
Usually, it is not the signals that we want to share, but the resources they drive. For example, with a CPU, it is the ALU that is shared as a whole rather than each of its inputs separately. To support such cases and ease the handling of shared signals, the library also provides the *arbiter* components. This component is instantiated like a standard module as follows, where `name` is the name of the arbiter instance:
|
|
3202
3502
|
|
|
3203
3503
|
```ruby
|
|
3204
3504
|
arbiter(:<name>).(<list of shared signal>)
|
|
@@ -3237,7 +3537,7 @@ end
|
|
|
3237
3537
|
In the example, both sequencers require access to signals `x` and `y` before accessing them and then releasing the access.
|
|
3238
3538
|
|
|
3239
3539
|
Requiring access does not guarantee that the access will be granted by the arbiter though. In the access is not granted, the write access will be ignored.
|
|
3240
|
-
The default access granting policy of an arbiter is the priority in the order of sequencer declaration. I.e., if several sequencers are requiring one at the same time, then the one declared the earliest in the code gains write access. For example, with the code given above, the first sequencer has to write access to `x` and `y`, and since after five write cycles it releases access, the second sequencer can then write to these signals. However, not obtaining write access does not block the execution of the sequencer, simply, its write access to the corresponding shared signals is
|
|
3540
|
+
The default access granting policy of an arbiter is the priority in the order of sequencer declaration. I.e., if several sequencers are requiring one at the same time, then the one declared the earliest in the code gains write access. For example, with the code given above, the first sequencer has to write access to `x` and `y`, and since after five write cycles it releases access, the second sequencer can then write to these signals. However, not obtaining write access does not block the execution of the sequencer, simply, its write access to the corresponding shared signals is ignored. In the example, the second sequencer will do its first five loop cycles without any effect and have only its five last ones that change the shared signals. To avoid such a behavior, it is possible to check if the write access is granted using arbiter sub signal `acquired`: if this signal is one in the current sequencer, that means the access is granted, otherwise it is 0. For example the following will increase signal `x` only if write access is granted:
|
|
3241
3541
|
|
|
3242
3542
|
```ruby
|
|
3243
3543
|
hif(ctrl_xy.acquired) { x <= x + 1 }
|
|
@@ -3249,7 +3549,7 @@ The policy of an arbiter can be changed using command policy. You can either pro
|
|
|
3249
3549
|
ctrl_xy.policy([1,0])
|
|
3250
3550
|
```
|
|
3251
3551
|
|
|
3252
|
-
It is also possible to set a more complex policy by providing to the policy method a block of code whose argument is a vector indicating which sequencer is currently requiring write access to the shared signals and whose result will be the number of the sequencer to grant the access. This code will be executed each time write access is
|
|
3552
|
+
It is also possible to set a more complex policy by providing to the policy method a block of code whose argument is a vector indicating which sequencer is currently requiring write access to the shared signals and whose result will be the number of the sequencer to grant the access. This code will be executed each time write access is performed. For example, in the previous code, a policy switch priorities at each access can be implemented as follows:
|
|
3253
3553
|
|
|
3254
3554
|
```ruby
|
|
3255
3555
|
inner priority_xy: 0
|
|
@@ -3272,7 +3572,7 @@ ctrl_xy.policy do |acq|
|
|
|
3272
3572
|
end
|
|
3273
3573
|
```
|
|
3274
3574
|
|
|
3275
|
-
As seen in the code above, each bit of the `acq` vector is one when the corresponding sequencer
|
|
3575
|
+
As seen in the code above, each bit of the `acq` vector is one when the corresponding sequencer requires access or 0 otherwise, bit 0 corresponds to sequencer 0, bit 1 to sequencer 1, and so on.
|
|
3276
3576
|
|
|
3277
3577
|
|
|
3278
3578
|
#### Monitors
|
|
@@ -3285,7 +3585,7 @@ The monitor component is instantiated like the arbiters as follows:
|
|
|
3285
3585
|
monitor(:<name>).(<list of shared signals>)
|
|
3286
3586
|
```
|
|
3287
3587
|
|
|
3288
|
-
Monitors are used
|
|
3588
|
+
Monitors are used the same ways as arbiters (including the write access granting policies) but block the execution of the sequencers that require write access until the access is granted. If we take the example of code with two sequencers given as an illustration of arbiter usage, replacing the arbiter with a monitor as follows will lock the second sequencer until it can write to shared variables `x` and `y` ensuring that all its loop cycles have the specified result:
|
|
3289
3589
|
|
|
3290
3590
|
```ruby
|
|
3291
3591
|
monitor(:ctrl_xy).(x,y)
|
|
@@ -3321,7 +3621,7 @@ end
|
|
|
3321
3621
|
|
|
3322
3622
|
### Sequencer-specific function: `std/sequencer_func.rb`
|
|
3323
3623
|
|
|
3324
|
-
HDLRuby function defined by `hdef` can be used in sequencer like any other HDLRuyby construct. But like the process constructs `hif` and so on, the body of these functions cannot include any sequencer-specific constructs.
|
|
3624
|
+
HDLRuby function defined by `hdef` can be used in a sequencer like any other HDLRuyby construct. But like the process constructs `hif` and so on, the body of these functions cannot include any sequencer-specific constructs.
|
|
3325
3625
|
|
|
3326
3626
|
However, it is possible to define functions that do support the sequencer constructs using `sdef` instead of `hdef` as follows:
|
|
3327
3627
|
|
|
@@ -3344,7 +3644,7 @@ end
|
|
|
3344
3644
|
|
|
3345
3645
|
As seen in the code above, a new construct `sreturn` can be used for returning a value from anywhere inside the function.
|
|
3346
3646
|
|
|
3347
|
-
When a recursion is present, HDLRuby automatically defines a stack for storing the return state and the arguments of the function. The size of the stack is heuristically set to the maximum number of bits of the arguments of the function when it is recursively called. For example, for the previous `fact` function, if when called, `n` is 16-bit, the stack will be able to hold 16 recursions. If this heuristic does not match the circuit's needs, the size can be forced as a second argument when defining the function. For example, the following code
|
|
3647
|
+
When a recursion is present, HDLRuby automatically defines a stack for storing the return state and the arguments of the function. The size of the stack is heuristically set to the maximum number of bits of the arguments of the function when it is recursively called. For example, for the previous `fact` function, if when called, `n` is 16-bit, the stack will be able to hold 16 recursions. If this heuristic does not match the circuit's needs, the size can be forced as a second argument when defining the function. For example, the following code sets the size to 32 whatever the arguments are:
|
|
3348
3648
|
|
|
3349
3649
|
```ruby
|
|
3350
3650
|
sdef(:fact,32) do |n|
|
|
@@ -3623,7 +3923,7 @@ The naming convention of the samples is the following:
|
|
|
3623
3923
|
* `<name>.rb`: default type of sample.
|
|
3624
3924
|
* `<name>_gen.rb`: generic parameters are required for processing the sample.
|
|
3625
3925
|
* `<name>_bench.rb`: sample including a simulation benchmark, these are the only samples that can be simulated using `hdrcc -S`. Please notice that such a sample cannot be converted to VHDL or Verilog HDL yet.
|
|
3626
|
-
* `with_<name>.rb`: sample illustrating a single aspect of HDLRuby or one of its
|
|
3926
|
+
* `with_<name>.rb`: sample illustrating a single aspect of HDLRuby or one of its libraries, usually includes a benchmark.
|
|
3627
3927
|
|
|
3628
3928
|
|
|
3629
3929
|
# Contributing
|