HDLRuby 2.0.9 → 2.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HDLRuby.gemspec +4 -8
- data/README.md +245 -119
- data/lib/HDLRuby/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc8bc67a8b7e6b271c16b81e2b8908b67ba6f3d5
|
4
|
+
data.tar.gz: 067d9c0d93e492c267cd85bb4628d52f064b1844
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8ee4d0e62a0693593fe7a5e703e9e5f0c4f50e1bc8795f02c50b7ef59d3f292331aef3d40a959e6c85cd25930bed7ae831c47f713263932af91a7a429ffe67b
|
7
|
+
data.tar.gz: 4ef5a298983fc31231fcc4c4b534edc163a023028fd491bc4c6e483bacbb34c223539e9824bc51f5abd8bb1b02216bb32a3ad620f6788bc2e29e6c94198370bc
|
data/HDLRuby.gemspec
CHANGED
@@ -14,18 +14,14 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "https://github.com/civol"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
-
# else
|
22
|
-
# raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
-
# "public gem pushes."
|
24
|
-
# end
|
17
|
+
if spec.respond_to?(:metadata) then
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/civol/HDLRuby"
|
19
|
+
end
|
25
20
|
|
26
21
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
22
|
f.match(%r{^(test|spec|features)/})
|
28
23
|
end
|
24
|
+
spec.extra_rdoc_files = ["README.md"]
|
29
25
|
spec.bindir = "exe"
|
30
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
27
|
spec.require_paths = ["lib"]
|
data/README.md
CHANGED
@@ -162,7 +162,7 @@ __Notes__:
|
|
162
162
|
This introduction gives a glimpse of the possibilities of the language.
|
163
163
|
However, we do recommend to consult the section about the [high-level programming features](#highfeat) to have a more complete view of the advanced possibilities of this language.
|
164
164
|
|
165
|
-
At first glance, HDLRuby
|
165
|
+
At first glance, HDLRuby appears like any other HDL languages (like Verilog HDL or VHDL), for instance the following code describes a simple D-FF:
|
166
166
|
|
167
167
|
```ruby
|
168
168
|
system :dff do
|
@@ -175,9 +175,9 @@ system :dff do
|
|
175
175
|
end
|
176
176
|
```
|
177
177
|
|
178
|
-
As it can be seen in the code above, `system` is the keyword used for describing a digital circuit. This keyword is an equivalent of the Verilog HDL `module`. In such a system, signals are declared using a `<type>.<direction>` construct where `type` is the data type of the signal (e.g., `bit` as in the code above) and `direction` indicates if the signal is an input, an output, an inout or an inner one; and executable blocks (similar to `always` block of Verilog HDL) are described using the `par` keyword when they are parallel and `seq` when they are sequential (i.e
|
178
|
+
As it can be seen in the code above, `system` is the keyword used for describing a digital circuit. This keyword is an equivalent of the Verilog HDL `module`. In such a system, signals are declared using a `<type>.<direction>` construct where `type` is the data type of the signal (e.g., `bit` as in the code above) and `direction` indicates if the signal is an input, an output, an inout or an inner one; and executable blocks (similar to `always` block of Verilog HDL) are described using the `par` keyword when they are parallel and `seq` when they are sequential (i.e., with respectively non-blocking and blocking assignments).
|
179
179
|
|
180
|
-
After such a system has been defined, it can be instantiated. For
|
180
|
+
After such a system has been defined, it can be instantiated. For example a single instance of the `dff` system named `dff0` can be declared as follows:
|
181
181
|
|
182
182
|
```ruby
|
183
183
|
dff :dff0
|
@@ -204,8 +204,9 @@ system :counter2 do
|
|
204
204
|
|
205
205
|
q <= dff1.q
|
206
206
|
end
|
207
|
+
```
|
207
208
|
|
208
|
-
The instances can also be connected while being declared. For example the code above can be rewritten as follows:
|
209
|
+
The instances can also be connected while being declared. For example, the code above can be rewritten as follows:
|
209
210
|
|
210
211
|
```ruby
|
211
212
|
system :counter2 do
|
@@ -222,7 +223,7 @@ In the code above, two possible connection methods are shown: for `dff0` ports a
|
|
222
223
|
While a circuit can be generated from the code given above, a benchmark must
|
223
224
|
be provided to test it. Such benchmark as described by constructs called
|
224
225
|
timed behavior that give the evolution of signals depending of the time.
|
225
|
-
For example the following code simulates the previous D-FF for 4 cycles
|
226
|
+
For example, the following code simulates the previous D-FF for 4 cycles
|
226
227
|
of 20ns each, with reset on the first cycle, set of signal `d` to 1 for
|
227
228
|
the third cycle and set of this signal to 0 for the last.
|
228
229
|
|
@@ -258,7 +259,7 @@ end
|
|
258
259
|
|
259
260
|
---
|
260
261
|
|
261
|
-
The code describing a `dff` given above is not much different from its equivalent in other HDL. However, HDLRuby provides several features for achieving a higher productivity when describing hardware. We will now describe a few of them.
|
262
|
+
The code describing a `dff` given above is not much different from its equivalent in any other HDL. However, HDLRuby provides several features for achieving a higher productivity when describing hardware. We will now describe a few of them.
|
262
263
|
|
263
264
|
First, several syntactic sugars exist that allow shorter code, for instance the following code is strictly equivalent to the previous description of `dff`:
|
264
265
|
|
@@ -324,7 +325,7 @@ system :reg do |typ|
|
|
324
325
|
end
|
325
326
|
```
|
326
327
|
|
327
|
-
Wait... I have just realized: a 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 basically three ways for doing this. First, inheritance can be used: a new system is built inheriting from `dff` as it is done in the following code.
|
328
|
+
Wait... I have just realized: a 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 basically three ways for doing this. First, inheritance can be used: a new system is built inheriting from `dff` as it is done in the following code.
|
328
329
|
|
329
330
|
```ruby
|
330
331
|
system :dff_full, dff do
|
@@ -417,7 +418,7 @@ system :sumprod_16_3456 do
|
|
417
418
|
end
|
418
419
|
```
|
419
420
|
|
420
|
-
The description above is straight forward, but it would be necessary to rewrite it if another circuit with different bit width or coefficients is to be designed. Moreover, if the number of
|
421
|
+
The description above is straight forward, but it would be necessary to rewrite it if another circuit with different bit width or coefficients is to be designed. Moreover, if the number of coefficients is large an error in the expression will be easy to make and hard to find. A better approach would be to use a generic description of such a circuit as follows:
|
421
422
|
|
422
423
|
```ruby
|
423
424
|
system :sumprod do |typ,coefs|
|
@@ -443,7 +444,7 @@ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit
|
|
443
444
|
|
444
445
|
As seen in the code above, when passing generic argument for instantiating a generic system, the name of the instance is put between brackets for avoiding confusion.
|
445
446
|
|
446
|
-
While description `sumprod` is already usable in a wide range of cases, it still uses the standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for sake of performance,
|
447
|
+
While description `sumprod` is already usable in a wide range of cases, it still uses the standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for 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:
|
447
448
|
|
448
449
|
```ruby
|
449
450
|
system :sumprod_func do |typ,coefs|
|
@@ -457,7 +458,7 @@ system :sumprod_func do |typ,coefs|
|
|
457
458
|
end
|
458
459
|
```
|
459
460
|
|
460
|
-
Where `add` and `mult` are functions implementing the required specific operations. HDLRuby functions are
|
461
|
+
Where `add` and `mult` are functions implementing the required specific operations. HDLRuby functions are equivalent to the Verilog HDL ones. In our example, an addition that saturates at 1000 could be described as follows:
|
461
462
|
|
462
463
|
```ruby
|
463
464
|
function :add do |x,y|
|
@@ -475,7 +476,7 @@ With HDLRuby functions, the result of the last statement in the return value, in
|
|
475
476
|
hif(res>1000) { res <= 1000 }
|
476
477
|
```
|
477
478
|
|
478
|
-
With functions, it is enough to change their content to
|
479
|
+
With functions, it is enough to change their content to obtain a new kind of circuit without change the main code. This approach suffers for two drawbacks though: first, the level of saturation is hard coded in the function, second, it would be preferable to be able to select the function to execute instead of modifying its code. For the first problem a simple approach is to add an argument to the function given the saturation level. Such an add function would therefore be as follows:
|
479
480
|
|
480
481
|
```ruby
|
481
482
|
function :add do |max, x, y|
|
@@ -489,7 +490,7 @@ end
|
|
489
490
|
|
490
491
|
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 kind of addition operations, and hence, the code of `sumprod` is not general any longer.
|
491
492
|
|
492
|
-
HDLRuby provides two ways to address such issues. First, it is possible to pass code as 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
|
493
|
+
HDLRuby provides two ways to address such issues. First, it is possible to pass code as 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:
|
493
494
|
|
494
495
|
```ruby
|
495
496
|
system :sumprod_proc do |add,mult,typ,coefs|
|
@@ -534,7 +535,7 @@ sat16_1000.define_operator(:+) do |x,y|
|
|
534
535
|
end
|
535
536
|
```
|
536
537
|
|
537
|
-
In the code above, the first line
|
538
|
+
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).
|
538
539
|
Then, the initial version of `sumprod` can be used with this type to achieve saturated computations as follows:
|
539
540
|
|
540
541
|
```ruby
|
@@ -587,18 +588,18 @@ dff_single.systemT.instantiate(:dff_not_single)
|
|
587
588
|
In the above example, `dff_not_single` is declared to be an instance
|
588
589
|
of the same system as `dff_single`.
|
589
590
|
|
590
|
-
This reflection capability can also be used for instance for accessing the
|
591
|
+
This reflection capability can also be used for instance, for accessing the
|
591
592
|
data type of a signal (`sig.type`), but also the current basic block
|
592
593
|
(`cur_block`), the current process (`cur_behavior`) and so on.
|
593
594
|
The standard library of HDLRuby, that includes several hardware constructs
|
594
|
-
like
|
595
|
+
like finite state machine descriptors, is mainly based on using these
|
595
596
|
reflection features.
|
596
597
|
|
597
598
|
|
598
599
|
|
599
600
|
## How does HDLRuby work
|
600
601
|
|
601
|
-
Contrary to descriptions in high-level HDL like SystemVerilog, VHDL or SystemC, HDLRuby descriptions are not software-like description of hardware, but are programs meant to produce hardware descriptions. In other words, while the execution of a common HDL code will result in some simulation of the described hardware, the execution of HDLRuby code will result in some low-level hardware description. This low-level description is synthesizable
|
602
|
+
Contrary to descriptions in high-level HDL like SystemVerilog, VHDL or SystemC, HDLRuby descriptions are not software-like description of hardware, but are programs meant to produce hardware descriptions. In other words, while the execution of a common HDL code will result in some simulation of the described hardware, the execution of HDLRuby code will result in some low-level hardware description. This low-level description is synthesizable and can also be simulated like any standard hardware description.
|
602
603
|
This decoupling of the representation of the hardware from the point of view of the user (HDLRuby), and the actual hardware description (HDLRuby::Low) makes it possible to provide the user with any advanced software features without jeopardizing the synthesizability of the actual hardware description.
|
603
604
|
|
604
605
|
For that purpose, each construct in HDLRuby is not a direct description of some hardware construct, but a program which generates the corresponding description. For example, let us consider the following line of code of HDLRuby describing the connection between signal `a` and signal `b`:
|
@@ -607,7 +608,7 @@ For that purpose, each construct in HDLRuby is not a direct description of some
|
|
607
608
|
a <= b
|
608
609
|
```
|
609
610
|
|
610
|
-
Its execution will produce the actual hardware description of this connection as an object of the HDLRuby::Low library — in this case an instance of the `HDLRuby::Low::Connection` class. Concretely, a HDLRuby system is described by a Ruby block, and the instantiation of this system is
|
611
|
+
Its execution will produce the actual hardware description of this connection as an object of the HDLRuby::Low library — in this case an instance of the `HDLRuby::Low::Connection` class. Concretely, a HDLRuby system is described by a Ruby block, and the instantiation of this system is performed by executing this block. The actual synthesizable description of this hardware is the execution result of this instantiation.
|
611
612
|
|
612
613
|
|
613
614
|
|
@@ -625,7 +626,7 @@ has been declared with `:hello` as name, it will be afterward referred by `hello
|
|
625
626
|
|
626
627
|
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 of structural and behavioral descriptions.
|
627
628
|
|
628
|
-
A signal represents a state in a system. It has a data type and a value, the latter varying with time.
|
629
|
+
A signal represents a state in a system. It has a data type and a value, the latter varying with time. HDLRuby signals can be viewed as abstractions of both wires and registers in a digital circuit. As general rule, a signal whose value is explicitly set all the time models a wire, otherwise it models a register.
|
629
630
|
|
630
631
|
### Declaring an empty system
|
631
632
|
|
@@ -731,7 +732,7 @@ A connection between signals is done using the arrow operator `<=` as follows:
|
|
731
732
|
|
732
733
|
The `<destination>` must be a reference to a signal, and the `<source>` can be any expression.
|
733
734
|
|
734
|
-
For example the following code
|
735
|
+
For example, the following code connects signal `w1` to signal `ready` and signal `clk` to the first bit of signal `w2`:
|
735
736
|
|
736
737
|
```ruby
|
737
738
|
ready <= w1
|
@@ -817,7 +818,7 @@ end
|
|
817
818
|
|
818
819
|
The signals of the interface of signals are accessible from anywhere in a HDLRuby description. This is not the case for inner signals and instances: they are accessible only within the scope they are declared in.
|
819
820
|
|
820
|
-
A scope is a region of the code where locally declared objects are accessible. Each system has its own scope that cannot be accessible from other part of an HDLRuby description. For example in the following code
|
821
|
+
A scope is a region of the code where locally declared objects are accessible. Each system has its own scope that cannot be accessible from other part of an HDLRuby description. For example, in the following code signals `d` and `qb` as well as instance `dffI` cannot be accessed from outside system `div2`:
|
821
822
|
|
822
823
|
```ruby
|
823
824
|
system :div2 do
|
@@ -839,7 +840,7 @@ sub do
|
|
839
840
|
end
|
840
841
|
```
|
841
842
|
|
842
|
-
For example, in the code bellow
|
843
|
+
For example, in the code bellow signal `sig` is not accessible from outside the additional inner scope of system `sys`
|
843
844
|
|
844
845
|
```ruby
|
845
846
|
system :sys do
|
@@ -885,10 +886,10 @@ end
|
|
885
886
|
|
886
887
|
Where:
|
887
888
|
|
888
|
-
|
889
|
-
|
889
|
+
* `<name>` is the name of the scope.
|
890
|
+
* `<code>` is the code within the scope.
|
890
891
|
|
891
|
-
Contrary to the case of scopes without name, signals and instances declared within a named scope can be accessed outside using this name as reference. For example in the code bellow signal `sig` declared within scope named `scop` is accessed outside it using `scop.sig`:
|
892
|
+
Contrary to the case of scopes without name, signals and instances declared within a named scope can be accessed outside using this name as reference. For example, in the code bellow signal `sig` declared within scope named `scop` is accessed outside it using `scop.sig`:
|
892
893
|
|
893
894
|
```ruby
|
894
895
|
sub :scop do
|
@@ -917,7 +918,7 @@ While such signals will be physically linked to the system, they are only access
|
|
917
918
|
|
918
919
|
An event represents a specific change of state of a signal.
|
919
920
|
For example, a rising edge of a clock signal named `clk` will be represented by event `clk.posedge`. In HDLRuby, events are obtained directly from
|
920
|
-
expressions using the following methods: `posedge` for rising
|
921
|
+
expressions using the following methods: `posedge` for rising edge, `negedge` for falling edge, and `edge` for any edge.
|
921
922
|
Events are described in more detail in section [Events](#events).
|
922
923
|
|
923
924
|
When one of the events of the sensitivity list of a behavior occurs, the behavior is executed, i.e., each of its statements is executed in sequence. A statement can represent a data transmission to a signal, a control flow, a nested execution block or the declaration of an inner signal (as stated
|
@@ -929,10 +930,10 @@ A transmission statement is declared using the arrow operator `<=` as follows:
|
|
929
930
|
<destination> <= <source>
|
930
931
|
```
|
931
932
|
|
932
|
-
The `<destination>` must be a reference to a signal, and the `<source>` can be any expression. A transmission has therefore
|
933
|
+
The `<destination>` must be a reference to a signal, and the `<source>` can be any expression. A transmission has therefore the same structure as a connection. However, its execution model is different: whereas a connection is continuously executed, a transmission is only executed during the execution of its block.
|
933
934
|
|
934
935
|
A block comprises a list of statements. It is used for adding hierarchy within a behavior. Blocks can be either parallel or sequential, i.e., their transmission statements are respectively non-blocking or blocking.
|
935
|
-
By default, a top block is created when declaring a behavior, and it inherits from its execution mode. For example, with the following code
|
936
|
+
By default, a top block is created when declaring a behavior, and it inherits from its execution mode. For example, with the following code the top block of the behavior is sequential.
|
936
937
|
|
937
938
|
```ruby
|
938
939
|
system :with_sequential_behavior do
|
@@ -956,7 +957,7 @@ system :with_sequential_behavior do
|
|
956
957
|
end
|
957
958
|
```
|
958
959
|
|
959
|
-
A sub block can also have a different execution mode if it is declared using `seq`, that will force sequential execution mode, and `par` that will force parallel execution mode. For example in the following code
|
960
|
+
A sub block can also have a different execution mode if it is declared using `seq`, that will force sequential execution mode, and `par` that will force parallel execution mode. For example, in the following code a parallel sub block is declared within a sequential one:
|
960
961
|
|
961
962
|
```ruby
|
962
963
|
system :with_sequential_behavior do
|
@@ -969,7 +970,7 @@ system :with_sequential_behavior do
|
|
969
970
|
end
|
970
971
|
```
|
971
972
|
|
972
|
-
Sub blocks have their own scope so that it is possible to declare signals without colliding with existing ones. For example it is possible to
|
973
|
+
Sub blocks have their own scope so that it is possible to declare signals without colliding with existing ones. For example, it is possible to
|
973
974
|
declare three different inner signals all called `sig` as follows:
|
974
975
|
|
975
976
|
```ruby
|
@@ -1010,7 +1011,7 @@ system :shift16 do
|
|
1010
1011
|
end
|
1011
1012
|
```
|
1012
1013
|
|
1013
|
-
In the example above, the order of the transmission statements is of no consequence. This is not the case for the following example, that implements the same register using a sequential block. In this second example, putting statement `reg[0] <= din` in the last place would have
|
1014
|
+
In the example above, the order of the transmission statements is of no consequence. This is not the case for the following example, that implements the same register using a sequential block. In this second example, putting statement `reg[0] <= din` in the last place would have led to an invalid functionality for a shift register.
|
1014
1015
|
|
1015
1016
|
```ruby
|
1016
1017
|
system :shift16 do
|
@@ -1050,7 +1051,7 @@ In such a case, the description can be shortened using the `at` operator as foll
|
|
1050
1051
|
( statement ).at(<list of events>)
|
1051
1052
|
```
|
1052
1053
|
|
1053
|
-
For example the following two code samples are equivalent:
|
1054
|
+
For example, the following two code samples are equivalent:
|
1054
1055
|
|
1055
1056
|
```ruby
|
1056
1057
|
par(clk.posedge) do
|
@@ -1109,24 +1110,24 @@ that changes the execution flow of the behavior, the block statement (described
|
|
1109
1110
|
|
1110
1111
|
__Note__:
|
1111
1112
|
|
1112
|
-
- There is
|
1113
|
+
- There is a fifth type of statement, named the time statement, that will be discussed in section [Time](#time).
|
1113
1114
|
|
1114
1115
|
|
1115
1116
|
### Transmit statement
|
1116
1117
|
|
1117
1118
|
A transmit statement is declared using the arrow operator `<=` within a behavior. Its right value is the expression to compute and its left value is a reference to the target signals (or parts of signals), i.e., the signals (or part of signals) that receive the computation result.
|
1118
1119
|
|
1119
|
-
For example following code transmits the value `3` to signal `s0` and the sum of the values of signals `i0` and `i1` to the first four bits of signal `s1`:
|
1120
|
+
For example, following code transmits the value `3` to signal `s0` and the sum of the values of signals `i0` and `i1` to the first four bits of signal `s1`:
|
1120
1121
|
|
1121
1122
|
```ruby
|
1122
1123
|
s0 <= 3
|
1123
1124
|
s1[3..0] <= i0 + i1
|
1124
1125
|
```
|
1125
1126
|
|
1126
|
-
The
|
1127
|
+
The behavior of a transmit statement depends on the execution mode of the enclosing block:
|
1127
1128
|
|
1128
|
-
|
1129
|
-
|
1129
|
+
* If the mode is parallel, the target signals are updated when all the statements of the current block are processed.
|
1130
|
+
* If the mode is sequential, the target signals are updated immediately after the right value of the statement is computed.
|
1130
1131
|
|
1131
1132
|
|
1132
1133
|
### Control statements
|
@@ -1187,12 +1188,12 @@ end
|
|
1187
1188
|
#### About loops
|
1188
1189
|
|
1189
1190
|
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
|
1190
|
-
that the current synthesis tools do not really synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable
|
1191
|
+
that the current synthesis tools do not really synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable loop less 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).
|
1191
1192
|
|
1192
1193
|
__Notes__:
|
1193
1194
|
|
1194
1195
|
- HDLRuby being based on Ruby, it is highly recommended to avoid `for` or `while` constructs and to use enumerators instead.
|
1195
|
-
- The Ruby `if` and `case` statements can also be used, but they do not represent
|
1196
|
+
- The Ruby `if` and `case` statements can also be used, but they do not represent any hardware. In fact, they are executed when the corresponding system is instantiated. For example, the following code will display `Hello world!` when the described system is instantiated, provided the generic parameter `param` is not nil.
|
1196
1197
|
|
1197
1198
|
```ruby
|
1198
1199
|
system :say_hello do |param = nil|
|
@@ -1206,11 +1207,11 @@ __Notes__:
|
|
1206
1207
|
<a name="types"></a>
|
1207
1208
|
|
1208
1209
|
Each signal and expression is associated with a data type which describes the kind of value it can represent. In HDLRuby, the data types represent
|
1209
|
-
|
1210
|
+
bit vectors associated with the way they should be interpreted, i.e., as bit strings, unsigned values, signed values, or hierarchical contents.
|
1210
1211
|
|
1211
1212
|
### Type construction
|
1212
1213
|
|
1213
|
-
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
|
1214
|
+
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.
|
1214
1215
|
|
1215
1216
|
|
1216
1217
|
The other types are built from them using a combination of the two following
|
@@ -1223,14 +1224,14 @@ __The vector operator__ `[]` is used for building types representing vectors of
|
|
1223
1224
|
```
|
1224
1225
|
|
1225
1226
|
The `<range>` of a vector type indicates the position of the starting and ending bits relatively to the radix point. If the position of the starting bit
|
1226
|
-
is on the left side of the range, the vector is big endian, otherwise it is little endian. Negative values in a range are also possible and indicate positions bellow the radix point. For example the following code describes a big
|
1227
|
+
is on the left side of the range, the vector is big endian, otherwise it is little endian. Negative values in a range are also possible and indicate positions bellow the radix point. For example, the following code describes a big-endian fixed-point type with 8 bits above the radix point and 4 bits
|
1227
1228
|
bellow:
|
1228
1229
|
|
1229
1230
|
```ruby
|
1230
1231
|
bit[7..-4]
|
1231
1232
|
```
|
1232
1233
|
|
1233
|
-
A `n..0` range can also be abbreviated to `n+1`. For instance the two following types are identical:
|
1234
|
+
A `n..0` range can also be abbreviated to `n+1`. For instance, the two following types are identical:
|
1234
1235
|
|
1235
1236
|
```ruby
|
1236
1237
|
bit[7..0]
|
@@ -1243,7 +1244,7 @@ A vector of multiple types, also called tuple, is declared as follows:
|
|
1243
1244
|
[<type 0>, <type 1>, ... ]
|
1244
1245
|
```
|
1245
1246
|
|
1246
|
-
For example the following code declares the type of the vectors made of a 8-bit logical, a 16-bit signed and a 16-bit unsigned values:
|
1247
|
+
For example, the following code declares the type of the vectors made of a 8-bit logical, a 16-bit signed and a 16-bit unsigned values:
|
1247
1248
|
|
1248
1249
|
```ruby
|
1249
1250
|
[ bit[8], signed[16], unsigned[16] ]
|
@@ -1270,7 +1271,7 @@ It is possible to give names to type constructs using the `typedef` keywords as
|
|
1270
1271
|
<type construct>.typedef :<name>
|
1271
1272
|
```
|
1272
1273
|
|
1273
|
-
For example the followings gives the name `char` to a signed 8-bit vector:
|
1274
|
+
For example, the followings gives the name `char` to a signed 8-bit vector:
|
1274
1275
|
|
1275
1276
|
```ruby
|
1276
1277
|
signed[7..0].typedef :char
|
@@ -1292,9 +1293,8 @@ end
|
|
1292
1293
|
|
1293
1294
|
Where:
|
1294
1295
|
|
1295
|
-
|
1296
|
-
|
1297
|
-
- `code` is a description of the content of the type
|
1296
|
+
* `type name` is the name of the type
|
1297
|
+
* `code` is a description of the content of the type
|
1298
1298
|
|
1299
1299
|
For example, the previous `char` could have been declared as follows:
|
1300
1300
|
|
@@ -1308,7 +1308,7 @@ end
|
|
1308
1308
|
|
1309
1309
|
The basis of all the types in HDLRuby is the vector of bits (bitvector) where each bit can have four values: 0, 1, Z and X (for undefined). Bit vectors are by default unsigned but can be set to be signed. When performing computations between signals of different bitvector type, the shorter signal is extended to the size of the larger one preserving its sign if it is signed.
|
1310
1310
|
|
1311
|
-
While the underlying structure of any HDLRuby type is the bitvector, complex types can be
|
1311
|
+
While the underlying structure of any HDLRuby type is the bitvector, complex types can be defined. When using such types in computational expressions and assignments they are first implicitly converted to an unsigned bit vector of the same size.
|
1312
1312
|
|
1313
1313
|
## Expressions
|
1314
1314
|
<a name="expressions"></a>
|
@@ -1320,7 +1320,7 @@ They include [immediate values](#values), [reference to signals](#references) an
|
|
1320
1320
|
### Immediate values
|
1321
1321
|
<a name="values"></a>
|
1322
1322
|
|
1323
|
-
The immediate values of HDLRuby can represent vectors of `bit`, `unsigned` and `signed`, and integer or floating
|
1323
|
+
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 enforce it in the header.
|
1324
1324
|
|
1325
1325
|
The vector type specifiers are the followings:
|
1326
1326
|
|
@@ -1355,7 +1355,7 @@ _s8o144
|
|
1355
1355
|
|
1356
1356
|
__Notes__:
|
1357
1357
|
|
1358
|
-
- Ruby immediate values can also be used, their bit width is automatically adjusted to match the data type of the expression they are used in. Please notice this adjusting may change the value of the immediate, for example the following code will
|
1358
|
+
- Ruby immediate values can also be used, their bit width is automatically adjusted to match the data type of the expression they are used in. Please notice this adjusting may change the value of the immediate, for example the following code will set `sig` to 4 instead of 100:
|
1359
1359
|
|
1360
1360
|
```ruby
|
1361
1361
|
[3..0].inner :sig
|
@@ -1368,7 +1368,7 @@ __Notes__:
|
|
1368
1368
|
|
1369
1369
|
References are expressions used to designate signals, or a part of signals.
|
1370
1370
|
|
1371
|
-
The
|
1371
|
+
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
|
1372
1372
|
following code, inner signal `sig0` is declared, and therefore the name *sig0* becomes a reference to designate this signal.
|
1373
1373
|
|
1374
1374
|
```ruby
|
@@ -1409,7 +1409,7 @@ end
|
|
1409
1409
|
<a name="operators"></a>
|
1410
1410
|
|
1411
1411
|
The following table gives a summary of the operators available in HDLRuby.
|
1412
|
-
More details are given for each group of
|
1412
|
+
More details are given for each group of operators in the subsequent sections.
|
1413
1413
|
|
1414
1414
|
__Assignment operators (left-most operator of a statement):__
|
1415
1415
|
|
@@ -1488,7 +1488,7 @@ __Notes__:
|
|
1488
1488
|
#### Assignment operators
|
1489
1489
|
<a name="assignment"></a>
|
1490
1490
|
|
1491
|
-
The assignment operators can be used with any type. They are
|
1491
|
+
The assignment operators can be used with any type. They are the connection and the transmission operators both being represented by `<=`.
|
1492
1492
|
|
1493
1493
|
__Note__:
|
1494
1494
|
|
@@ -1516,17 +1516,17 @@ __Notes__:
|
|
1516
1516
|
#### Logic and shift operators
|
1517
1517
|
<a name="logic"></a>
|
1518
1518
|
|
1519
|
-
In HDLRuby, the logic operators are all bitwise. For performing
|
1519
|
+
In HDLRuby, the logic operators are all bitwise. For performing Boolean computations it is necessary to use single bit values. The bitwise logic binary operators are `&`, `|`, and `^`, and the unary one is `~`. They have the same meaning as their Ruby equivalents.
|
1520
1520
|
|
1521
|
-
__Note__: there is two reasons why there is no
|
1521
|
+
__Note__: there is two reasons why there is no Boolean operators
|
1522
1522
|
|
1523
|
-
1. Ruby language does not support redefinition of the
|
1523
|
+
1. Ruby language does not support redefinition of the Boolean operators
|
1524
1524
|
|
1525
|
-
2. In Ruby, each value which is not `false` nor `nil` is
|
1525
|
+
2. In Ruby, each value which is not `false` nor `nil` is assumed to be true. This is perfectly relevant for software, but not for hardware where the basic data types are bit vectors. Hence, it seemed preferable to support Boolean computation for one-bit values only, which can be done through bitwise operations.
|
1526
1526
|
|
1527
|
-
The shift operators are `<<` and `>>` and have the same meaning as their Ruby equivalent. They do not change the bit width
|
1527
|
+
The shift operators are `<<` and `>>` and have the same meaning as their Ruby equivalent. They do not change the bit width and preserve the sign for `signed` values.
|
1528
1528
|
|
1529
|
-
The rotation operators are `rl` and `rr` for respectively left and right bit rotations. Like the shifts, they do not change the bit width and preserve the sign for the `signed` values. However, since such operators do not exist in Ruby, they are
|
1529
|
+
The rotation operators are `rl` and `rr` for respectively left and right bit rotations. Like the shifts, they do not change the bit width and preserve the sign for the `signed` values. However, since such operators do not exist in Ruby, they are used like methods as follows:
|
1530
1530
|
|
1531
1531
|
```ruby
|
1532
1532
|
<expression>.rl(<other expression>)
|
@@ -1561,7 +1561,7 @@ These operators comprise the bit width conversions: `ljust`, `rjust`, `zext` and
|
|
1561
1561
|
|
1562
1562
|
More precisely, the bit width conversions operate as follows:
|
1563
1563
|
|
1564
|
-
- `ljust` and `rjust` increase the size from respectively the left or the right side of the bit vector. They take as argument the width of the new type and the value (0 or 1) of the bits to add. For example the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1564
|
+
- `ljust` and `rjust` increase the size from respectively the left or the right side of the bit vector. They take as argument the width of the new type and the value (0 or 1) of the bits to add. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1565
1565
|
|
1566
1566
|
```ruby
|
1567
1567
|
[7..0].inner :sig0
|
@@ -1702,7 +1702,7 @@ __Multiplicative operators:__
|
|
1702
1702
|
|
1703
1703
|
### HDLRuby functions
|
1704
1704
|
|
1705
|
-
|
1705
|
+
Like Verilog HDL, HDLRuby provides function constructs for reusing code. HDLRuby functions are declared as follows:
|
1706
1706
|
|
1707
1707
|
```ruby
|
1708
1708
|
function :<function name> do |<arguments>|
|
@@ -1712,21 +1712,21 @@ Similarly to Verilog HDL, HDLRuby provides function constructs for reusing code.
|
|
1712
1712
|
|
1713
1713
|
Where:
|
1714
1714
|
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1715
|
+
* `function name` is the name of the function.
|
1716
|
+
* `arguments` is the list of arguments of the function.
|
1717
|
+
* `code` is the code of the function.
|
1718
1718
|
|
1719
1719
|
__Notes__:
|
1720
1720
|
|
1721
1721
|
- Functions have their own scope, so that any declaration within a function is local. It is also forbidden to declare interface signals (input, output or inout) within a function.
|
1722
1722
|
|
1723
|
-
-
|
1723
|
+
- Like the Ruby proc objects, the last statement of a function's code serves as return value. For instance, the following function returns `1` (in this example the function does not have any argument):
|
1724
1724
|
|
1725
1725
|
```ruby
|
1726
1726
|
function :one { 1 }
|
1727
1727
|
```
|
1728
1728
|
|
1729
|
-
- Functions can accept any kind of object as argument, including variadic arguments or blocks of code as shown
|
1729
|
+
- Functions can accept any kind of object as argument, including variadic arguments or blocks of code as shown below with a function which apply the code passed as argument to all the variadic arguments of `args`:
|
1730
1730
|
|
1731
1731
|
```ruby
|
1732
1732
|
function :apply do |*args, &code|
|
@@ -1758,12 +1758,12 @@ end
|
|
1758
1758
|
```
|
1759
1759
|
Where:
|
1760
1760
|
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1761
|
+
* `function name` is the name of the function.
|
1762
|
+
* `arguments` is the list of arguments of the function.
|
1763
|
+
* `code` is the code of the function.
|
1764
1764
|
|
1765
|
-
These functions are called the same way HDLRuby functions are called, but this operation
|
1766
|
-
Moreover, these
|
1765
|
+
These functions are called the same way HDLRuby functions are called, but this operation pastes the code of the function as is within the code.
|
1766
|
+
Moreover, these functions do not have any scope so that any inner signal or instance declared within them will be added to the object they are invoked in.
|
1767
1767
|
|
1768
1768
|
For example, the following function will add input `in0` to any system where it is invoked:
|
1769
1769
|
|
@@ -1805,7 +1805,7 @@ system :sys do
|
|
1805
1805
|
end
|
1806
1806
|
```
|
1807
1807
|
|
1808
|
-
Ruby functions can be compared to the macros of the C languages: they
|
1808
|
+
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.
|
1809
1809
|
|
1810
1810
|
|
1811
1811
|
## Time
|
@@ -1814,7 +1814,7 @@ Ruby functions can be compared to the macros of the C languages: they have more
|
|
1814
1814
|
### Time values
|
1815
1815
|
<a name="time_val"></a>
|
1816
1816
|
|
1817
|
-
In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for millisecond, `us` for
|
1817
|
+
In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for millisecond, `us` for microseconds, `ns` for nanoseconds, `ps` for picoseconds. For example, the followings are all indicating one second of time:
|
1818
1818
|
|
1819
1819
|
```ruby
|
1820
1820
|
1.s
|
@@ -1822,14 +1822,13 @@ In HDLRuby, time values can be created using the time operators: `s` for seconds
|
|
1822
1822
|
1000000.us
|
1823
1823
|
1000000000.ns
|
1824
1824
|
1000000000000.ps
|
1825
|
-
1000000000000000.fs
|
1826
1825
|
```
|
1827
1826
|
|
1828
1827
|
|
1829
1828
|
### Time behaviors and time statements
|
1830
1829
|
<a name="time_beh"></a>
|
1831
1830
|
|
1832
|
-
|
1831
|
+
Like the other HDL, HDLRuby provides specific statements that models the advance of time. These statements are not synthesizable and are used for simulating the environment of a hardware component. For sake of clarity, such statements are only allowed in explicitly non-synthesizable behavior declared using the `timed` keyword as follows.
|
1833
1832
|
|
1834
1833
|
```ruby
|
1835
1834
|
timed do
|
@@ -1837,12 +1836,10 @@ timed do
|
|
1837
1836
|
end
|
1838
1837
|
```
|
1839
1838
|
|
1840
|
-
A time behavior
|
1839
|
+
A time behavior does not have any sensitivity list but it can include any statement supported by a standard behavior in addition to the time statements.
|
1841
1840
|
There are two kinds of such statements:
|
1842
1841
|
|
1843
|
-
- The `wait` statements: such a statement blocks the execution of the behavior
|
1844
|
-
for the amount of time given in argument. For example the following code
|
1845
|
-
waits 10ns before proceeding:
|
1842
|
+
- The `wait` statements: such a statement blocks the execution of the behavior for the time given in argument. For example the following code waits 10ns before proceeding:
|
1846
1843
|
|
1847
1844
|
```ruby
|
1848
1845
|
wait(10.ns)
|
@@ -1865,7 +1862,7 @@ There are two kinds of such statements:
|
|
1865
1862
|
|
1866
1863
|
### Parallel and sequential execution
|
1867
1864
|
|
1868
|
-
Time behaviors are by default sequential but they can include both parallel and
|
1865
|
+
Time behaviors are by default sequential, but they can include both parallel and
|
1869
1866
|
sequential blocks. The execution semantic is the following:
|
1870
1867
|
|
1871
1868
|
- A sequential block in a time behavior is executed sequentially.
|
@@ -1926,7 +1923,7 @@ system :something do |t,w,s|
|
|
1926
1923
|
end
|
1927
1924
|
```
|
1928
1925
|
|
1929
|
-
It is also possible to use a variable number of generic parameters using the variadic operator `*` like in the following example. In this
|
1926
|
+
It is also possible to use a variable number of generic parameters using the variadic operator `*` like in the following example. In this example, `args` is an array containing an indefinite number of parameters.
|
1930
1927
|
|
1931
1928
|
```ruby
|
1932
1929
|
system(:variadic) { |*args| }
|
@@ -2005,7 +2002,7 @@ If less values are provided than the number of generic arguments, the type is pa
|
|
2005
2002
|
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
|
2006
2003
|
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.
|
2007
2004
|
|
2008
|
-
For example, the following code describes first a simple D-FF, and then use it to
|
2005
|
+
For example, the following code describes first a simple D-FF, and then use it to describe a FF with an additional reversed output (`qb`):
|
2009
2006
|
|
2010
2007
|
```ruby
|
2011
2008
|
system :dff do
|
@@ -2024,7 +2021,7 @@ system :dff_full do
|
|
2024
2021
|
end
|
2025
2022
|
```
|
2026
2023
|
|
2027
|
-
It is also possible to declare inheritance in a more object
|
2024
|
+
It is also possible to declare inheritance in a more object-oriented fashion by listing the parents of a system just after declaring its name as follows:
|
2028
2025
|
|
2029
2026
|
```ruby
|
2030
2027
|
system :<new system name>, <list of parent systems> do
|
@@ -2044,12 +2041,12 @@ end
|
|
2044
2041
|
|
2045
2042
|
__Note__:
|
2046
2043
|
|
2047
|
-
|
2044
|
+
* As a matter of implementation, HDLRuby systems can be viewed as sets of methods used for accessing various constructs (signals, instances). Hence inheritance in HDLRuby is closer the Ruby mixin mechanism than to a true software inheritance.
|
2048
2045
|
|
2049
2046
|
|
2050
2047
|
#### About inner signals and system instances
|
2051
2048
|
|
2052
|
-
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
|
2049
|
+
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
|
2053
2050
|
code exports signals `clk` and `rst` and instance `dff0` of system `exporter` so that they can be accessed in child system `importer`.
|
2054
2051
|
|
2055
2052
|
```ruby
|
@@ -2088,7 +2085,7 @@ __Note__:
|
|
2088
2085
|
|
2089
2086
|
#### Conflicts when inheriting
|
2090
2087
|
|
2091
|
-
Signals and instances cannot be overridden, this is also the case for signals and instances accessible through inheritance. For example the following code is invalid since `rst` has already been defined in `dff`:
|
2088
|
+
Signals and instances cannot be overridden, this is also the case for signals and instances accessible through inheritance. For example, the following code is invalid since `rst` has already been defined in `dff`:
|
2092
2089
|
|
2093
2090
|
```ruby
|
2094
2091
|
system :dff_bad, dff do
|
@@ -2102,11 +2099,11 @@ section.
|
|
2102
2099
|
|
2103
2100
|
#### Shadowed signals and instances
|
2104
2101
|
|
2105
|
-
It is possible in HDLRuby to declare a signal or an instance whose name is identical to one used in one of the included systems. In such a case, the corresponding construct of the included system is still present, but is not directly accessible even if exported, they are said to be shadowed.
|
2102
|
+
It is possible in HDLRuby to declare a signal or an instance whose name is identical to one used in one of the included systems. In such a case, the corresponding construct of the included system is still present, but it is not directly accessible even if exported, they are said to be shadowed.
|
2106
2103
|
|
2107
2104
|
In order to access to the shadowed signals or instances, a system must be reinterpreted as the relevant parent system using the `as` operator as follows: `as(system)`.
|
2108
2105
|
|
2109
|
-
For example, in the following code signal `db` of system `dff_db` is shadowed by signal `db` of system `dff_shadow`, but is accessed using the `as` operator.
|
2106
|
+
For example, in the following code signal `db` of system `dff_db` is shadowed by signal `db` of system `dff_shadow`, but it is accessed using the `as` operator.
|
2110
2107
|
|
2111
2108
|
```ruby
|
2112
2109
|
system :dff_db do
|
@@ -2153,7 +2150,7 @@ end
|
|
2153
2150
|
### Opening an instance
|
2154
2151
|
<a name="instance_open"></a>
|
2155
2152
|
|
2156
|
-
When there is a modification to apply to an instance, it is sometimes preferable to modify this sole instance rather than declaring a
|
2153
|
+
When there is a modification to apply to an instance, it is sometimes preferable to modify this sole instance rather than declaring a new system to derivate the instance from. For that purpose, it is possible to open an instance for modification as follows:
|
2157
2154
|
|
2158
2155
|
```ruby
|
2159
2156
|
<instance name>.open do
|
@@ -2183,19 +2180,19 @@ Operators can be overloaded for specific types. This allows for instance to supp
|
|
2183
2180
|
An operator is redefined as follows:
|
2184
2181
|
|
2185
2182
|
```ruby
|
2186
|
-
<type>.
|
2183
|
+
<type>.define_operator(:<op>) do |<args>|
|
2187
2184
|
<operation description>
|
2188
2185
|
end
|
2189
2186
|
```
|
2190
2187
|
|
2191
2188
|
Where:
|
2192
2189
|
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2190
|
+
* `type` is the type from which the operation is overloaded.
|
2191
|
+
* `op` is the operator that is overloaded (e.g., `+`)
|
2192
|
+
* `args` are the arguments of the operation.
|
2193
|
+
* `operation description` is an HDLRuby description of the new operation.
|
2197
2194
|
|
2198
|
-
For example, for `fix32` a 32-bit (decimal point at 16-bit) fixed
|
2195
|
+
For example, for `fix32` a 32-bit (decimal point at 16-bit) fixed-point type defined as follows:
|
2199
2196
|
|
2200
2197
|
```ruby
|
2201
2198
|
signed[31..0].typedef(:fix32)
|
@@ -2212,7 +2209,7 @@ end
|
|
2212
2209
|
Please notice, that in the code above, the left value has been casted to a plain bit-vector in order to avoid infinite recursive call of the `*` operator.
|
2213
2210
|
|
2214
2211
|
Operator can also be overloaded for generic types. However, is such a case, the generic argument must also be present in the list of arguments of the overloaded operators.
|
2215
|
-
For instance, let us consider the following fixed
|
2212
|
+
For instance, let us consider the following fixed-point type of variable width (and whose decimal point is set at the half of its bit range):
|
2216
2213
|
|
2217
2214
|
```ruby
|
2218
2215
|
typedef(:fixed) do |width|
|
@@ -2280,7 +2277,7 @@ __Note__:
|
|
2280
2277
|
|
2281
2278
|
Like with any Ruby program it is possible to define and execute methods anywhere in HDLRuby using the standard Ruby syntax. When defined, a method is attached to the enclosing HDLRuby construct. For instance, when defining a method when declaring a system, it will be usable within this system, while when defining a method outside any construct, it will be usable everywhere in the HDLRuby description.
|
2282
2279
|
|
2283
|
-
A method can include HDLRuby code in which case the resulting hardware is appended to the current construct. For example the following code adds a connection between `sig0` and `sig1` in system `sys0`, and transmission between `sig0` and `sig1` in the behavior of `sys1`.
|
2280
|
+
A method can include HDLRuby code in which case the resulting hardware is appended to the current construct. For example, the following code adds a connection between `sig0` and `sig1` in system `sys0`, and transmission between `sig0` and `sig1` in the behavior of `sys1`.
|
2284
2281
|
|
2285
2282
|
```ruby
|
2286
2283
|
def some_arrow
|
@@ -2308,7 +2305,7 @@ __Warning__:
|
|
2308
2305
|
|
2309
2306
|
- In the above example, the semantic of `some_arrow` changes depending on where it is invoked from: within a system, it is a connection, within a behavior it is a transmission.
|
2310
2307
|
|
2311
|
-
- Using Ruby methods for describing hardware might lead to weak code, for example the in following code, the method declares `in0` as input signal. Hence, while used in `sys0` no
|
2308
|
+
- Using Ruby methods for describing hardware might lead to weak code, for example the in following code, the method declares `in0` as input signal. Hence, while used in `sys0` no problem happens, an exception will be raised for `sys1` because a signal `in0` is already declare, and will also be raised for `sys2` because it is not possible to declare an input from within a behavior.
|
2312
2309
|
|
2313
2310
|
```ruby
|
2314
2311
|
def in_decl
|
@@ -2349,7 +2346,7 @@ end
|
|
2349
2346
|
```
|
2350
2347
|
|
2351
2348
|
|
2352
|
-
While requiring care, 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:
|
2349
|
+
While requiring care, 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:
|
2353
2350
|
|
2354
2351
|
```ruby
|
2355
2352
|
def after(cycles,rst = $rst, &code)
|
@@ -2409,7 +2406,7 @@ Like any Ruby classes, the constructs of HDLRuby can be dynamically extended. If
|
|
2409
2406
|
|
2410
2407
|
### Extending HDLRuby constructs globally
|
2411
2408
|
|
2412
|
-
By
|
2409
|
+
By global extension of hardware constructs, we mean the classical extension of Ruby classes by monkey patching the corresponding class. For example, it is possible to add a method giving the number of signals in the interface of a system instance as follows:
|
2413
2410
|
|
2414
2411
|
```ruby
|
2415
2412
|
class SystemI
|
@@ -2498,7 +2495,7 @@ system :some_system, my_base do
|
|
2498
2495
|
end
|
2499
2496
|
```
|
2500
2497
|
|
2501
|
-
However, when generation the low-level description of this system, code
|
2498
|
+
However, when generation the low-level description of this system, code like the following will have to be written for applying `my_generation`:
|
2502
2499
|
|
2503
2500
|
```ruby
|
2504
2501
|
some_system :instance0
|
@@ -2555,7 +2552,7 @@ include HDLRuby::High::Std
|
|
2555
2552
|
|
2556
2553
|
The `clocks` library provides utilities for an easier handling of clock synchronizations.
|
2557
2554
|
|
2558
|
-
It adds the possibility to multiply events by integer. The result is a new event whose frequency is divided by the integer multiplicand. For example the following code describes a D-FF that memorizes each three clock cycle.
|
2555
|
+
It adds the possibility to multiply events by integer. The result is a new event whose frequency is divided by the integer multiplicand. For example, the following code describes a D-FF that memorizes each three clock cycle.
|
2559
2556
|
|
2560
2557
|
```ruby
|
2561
2558
|
require 'std/clocks'
|
@@ -2584,11 +2581,12 @@ after(<number>,<clock>,<reset>)
|
|
2584
2581
|
```
|
2585
2582
|
|
2586
2583
|
Where:
|
2584
|
+
|
2587
2585
|
* `<number>` is the number of cycles to wait.
|
2588
2586
|
* `<clock>` is the clock to use, this argument can be omitted.
|
2589
2587
|
* `<reset>` is the signal used to reset the counter used for waiting, this argument can be omitted.
|
2590
2588
|
|
2591
|
-
This statement can be used
|
2589
|
+
This statement can be used either inside or outside a clocked behavior. When used within a clocked behavior, the clock event of the behavior is used for the counter unless specified otherwise. When used outside such a behavior, the clock is the global default clock `$clk`. In both cases, the reset is the global reset `$rst` unless specified otherwise.
|
2592
2590
|
|
2593
2591
|
The second construct is the `before` statement that activates a block until a given number of clocks cycles is passed. Its syntax and usage is identical to the `after` statement.
|
2594
2592
|
|
@@ -2663,7 +2661,7 @@ State transitions are by default set to be from one state to the following in th
|
|
2663
2661
|
goto(<condition>,<names>)
|
2664
2662
|
```
|
2665
2663
|
|
2666
|
-
Where `condition` is a signal whose value is used as index for selection the target state among the ones specified
|
2664
|
+
Where `condition` is a signal whose value is used as index for selection the target state among the ones specified in the `names` list. For example, the following statement indicate to go to state named `st_a` if the `cond` is 0, `st_b` if condition is 1 and `st_c` if condition is 2, otherwise this specific transition is ignored:
|
2667
2665
|
|
2668
2666
|
```ruby
|
2669
2667
|
goto(cond,:st_a,:st_b,:st_c)
|
@@ -2671,7 +2669,7 @@ goto(cond,:st_a,:st_b,:st_c)
|
|
2671
2669
|
|
2672
2670
|
Several goto statements can be used, the last one having priority provided it is taken (i.e., its condition correspond to one of the target state). If no goto is taken, the next transition is the next declared one.
|
2673
2671
|
|
2674
|
-
For example the following code describes a FSM describing a circuit that checks if two buttons (`but_a` and `but_b`) are pressed and released in sequence for activating an output signal (`ok`):
|
2672
|
+
For example, the following code describes a FSM describing a circuit that checks if two buttons (`but_a` and `but_b`) are pressed and released in sequence for activating an output signal (`ok`):
|
2675
2673
|
|
2676
2674
|
```ruby
|
2677
2675
|
fsm(clk.posedge,rst,:sync) do
|
@@ -2698,19 +2696,16 @@ end
|
|
2698
2696
|
## Channel
|
2699
2697
|
<a name="channel"></a>
|
2700
2698
|
|
2701
|
-
This library provides a unified interface to complex communication protocols
|
2699
|
+
This library provides a unified interface to complex communication protocols through a new kind of components called the channels that abstract the details of communication protocols. The channels an be used similarly to the ports of a system and are used through a unified interface so that changing the kind of channel, i.e., the communication protocol, does not require any modification of the code.
|
2702
2700
|
|
2703
|
-
A channel is used similarly to a pipe: it has an input where data can be written and an output where data can be read. The ordering of the data and the
|
2701
|
+
A channel is used similarly to a pipe: it has an input where data can be written and an output where data can be read. The ordering of the data and the synchronization depend on the internals of the channel, e.g., a channel can be FIFO or LIFO. The interaction with the channel is done using the following methods:
|
2704
2702
|
|
2705
2703
|
* `writer_ports`: generate ports in the system for writing to the channel. This method is used without any argument.
|
2706
|
-
|
2707
2704
|
* `reader_ports`: generate ports in the system for reading from the channel. This method is used without any argument.
|
2708
|
-
|
2709
2705
|
* `write(<value>) <block>`: write `value` to the channel and execute `block` when `write` completes. Both `value` and `block` may be omitted depending on the kind of channel.
|
2710
|
-
|
2711
2706
|
* `read(<target>) <block>`: read the channel, assign the result to signal `target` and execute `block` when the read completes. Both `target` and `block` may be omitted depending on the kind of channel.
|
2712
2707
|
|
2713
|
-
For example a system sending successive 8
|
2708
|
+
For example, a system sending successive 8-bit values through a channel can be described as follows:
|
2714
2709
|
|
2715
2710
|
```ruby
|
2716
2711
|
system :producer8 do |channel|
|
@@ -2739,15 +2734,124 @@ A new channel is declared like using the keyword `channel` as follows:
|
|
2739
2734
|
channel <name> <block>
|
2740
2735
|
```
|
2741
2736
|
|
2742
|
-
Where `name` is the name of the channel and `block` is a procedure block describing the channel. This block can contain any HDLRuby code, and is
|
2737
|
+
Where `name` is the name of the channel and `block` is a procedure block describing the channel. This block can contain any HDLRuby code, and is comparable to the content of a block describing a system with the difference that it does not have standard input, output and inout ports are declared differently and that it supports following additional keywords:
|
2738
|
+
|
2739
|
+
* `reader_input <list of names>`: declares the input ports on the reader side. The list must give the names of the inner signals of the channel that can be read using the reader procedure.
|
2740
|
+
* `reader_output <list of names>`: declares the output ports on the reader side. The list must give the names of the inner signals of the channel that can be written using the reader procedure.
|
2741
|
+
* `writer_input <list of names>`: declares the inputs on the writer side. The list must give the names of the inner signals of the channel that can be read using the writer procedure.
|
2742
|
+
* `writer_output <lust of names>`: declares the outputs on the writer side. The list must give the names of the inner signals of the channel that can be written using the writer procedure.
|
2743
|
+
* `command <name> <block>`: declares a new command for the channel.
|
2744
|
+
* `reader <block>`: defines the reader's access procedure.
|
2745
|
+
This procedure is invoked by method `read` of the channel (please refer to the previous example).
|
2746
|
+
The block takes the following arguments:
|
2747
|
+
- `blk`: the block to execute when the read completes.
|
2748
|
+
- `target`: the signal where to put the read value.
|
2749
|
+
* `writer < block>`: defines the writer's access procedure.
|
2750
|
+
This procedure is invoked by method `write` of the channel (please refer to the previous example).
|
2751
|
+
The block takes the following arguments:
|
2752
|
+
- `blk`: the block to execute when the write completes.
|
2753
|
+
- `target`: the signal that contains the value to write.
|
2754
|
+
|
2755
|
+
For example, a channel implemented by a simple register of generic type `typ`, that can be set to 0 using the `reset` command can be described as follows:
|
2756
|
+
|
2757
|
+
```ruby
|
2758
|
+
channel :regch do |typ|
|
2759
|
+
# The register.
|
2760
|
+
typ.inner :reg
|
2761
|
+
|
2762
|
+
# The reader procedure can read reg
|
2763
|
+
reader_input :reg
|
2764
|
+
# The writer procedure can write reg
|
2765
|
+
writer_output :reg
|
2766
|
+
|
2767
|
+
# Declares a reset
|
2768
|
+
command(:reset) { reg <= 0 }
|
2769
|
+
|
2770
|
+
# Defines the reader procedure.
|
2771
|
+
reader do |blk,target|
|
2772
|
+
target <= reg
|
2773
|
+
blk.call if blk
|
2774
|
+
end
|
2775
|
+
|
2776
|
+
# Defines the writer procedure.
|
2777
|
+
writer do |blk,target|
|
2778
|
+
reg <= target
|
2779
|
+
blk.call if blk
|
2780
|
+
end
|
2781
|
+
end
|
2782
|
+
```
|
2783
|
+
|
2784
|
+
__Notes__:
|
2785
|
+
|
2786
|
+
* The described channel assumes that at the `write` method of the channel is invoked within a clocked process (otherwise, the register will become a latch).
|
2787
|
+
* The described channel supports the `read` and `write` methods to be invoked with or without a block.
|
2788
|
+
|
2789
|
+
|
2790
|
+
Like systems, a channel must be instantiated for being used, and the instantiation procedure is identical:
|
2791
|
+
|
2792
|
+
```ruby
|
2793
|
+
<channel name> :<instance name>
|
2794
|
+
```
|
2795
|
+
|
2796
|
+
And in case there are generic parameter, the instantiation procedure is as follows:
|
2797
|
+
|
2798
|
+
```ruby
|
2799
|
+
<channel name>(:<instance name>).(<generic parameters>)
|
2800
|
+
```
|
2801
|
+
|
2802
|
+
After a channel is instantiated, it must be linked to the circuits that will communicate through it. This is done when instantiating these circuits. If a circuit reads on the channel, it will be instantiated as follows:
|
2803
|
+
|
2804
|
+
```ruby
|
2805
|
+
<system name>(<channel instance>).(:<instance name>).(<circuit standard connections>,*<channel instance>.reader_signals)
|
2806
|
+
```
|
2807
|
+
|
2808
|
+
If the circuit writes on the channel, it has to be instantiated as follows:
|
2809
|
+
|
2810
|
+
```ruby
|
2811
|
+
<system name>(<channel instance>).(:<instance name>).(<circuit standard connections>,*<channel instance>.writer_signals)
|
2812
|
+
```
|
2813
|
+
|
2814
|
+
__Notes__:
|
2815
|
+
|
2816
|
+
* It is possible for a circuit to access several channels. For that purpose, each channel must be passed as generic arguments, and their corresponding `reader_signals` and `writer_signals` are to be put in the order of declaration.
|
2817
|
+
* It is also possible for a circuit to read and write on the same channel. For that purpose, the channel will be passed several times as generic arguments, and the corresponding `reader_signals` and `writer_signals` are to be put in the order of declaration.
|
2818
|
+
|
2819
|
+
The following code is an example instantiating the register channel presented above for connecting an instance of `producer8` and another circuit called `consumer8`:
|
2820
|
+
|
2821
|
+
```ruby
|
2822
|
+
# System wrapping the producer and the consumer circuits.
|
2823
|
+
system :producer_consumer8 do
|
2824
|
+
# The clock and reset of the circuits
|
2825
|
+
input :clk, :rst
|
2826
|
+
|
2827
|
+
# Instance of the channel (using 8-bit data).
|
2828
|
+
regch([8]).(:regchI)
|
2829
|
+
|
2830
|
+
# Reset the channel on positive edges of signal rst.
|
2831
|
+
regchI.reset.at(rst.posedge)
|
2832
|
+
|
2833
|
+
# Instanciate the producer.
|
2834
|
+
producer8(regch).(:producerI).(clk,rst,*regch.writer_signals)
|
2835
|
+
|
2836
|
+
# Instanciate the consummer.
|
2837
|
+
consumer8(regch).(:consumerI).(clk.rst,*regch.reader_signals)
|
2838
|
+
end
|
2839
|
+
```
|
2840
|
+
|
2841
|
+
__Note__:
|
2842
|
+
|
2843
|
+
* The code of the circuits, in the examples `producer8`, `consumer8` and `producer_consummer8` is independent of the content of the channel. For example, the sample `with_channel.rb` (please see [sample](#sample)) use the same circuits with a channel implementing a handshaking.
|
2743
2844
|
|
2744
|
-
* srgg
|
2745
2845
|
|
2746
2846
|
## Reconf
|
2747
2847
|
<a name="reconf"></a>
|
2748
2848
|
|
2749
|
-
This library provides a unified interface to partially (or dynamically)
|
2750
|
-
|
2849
|
+
This library provides a unified interface to partially (or dynamically) reconfigurable devices.
|
2850
|
+
|
2851
|
+
__Warning__:
|
2852
|
+
|
2853
|
+
While the framework of this library is completed, not target reconfigurable device is defined yet.
|
2854
|
+
|
2751
2855
|
|
2752
2856
|
## Pipeline
|
2753
2857
|
<a name="pipeline"></a>
|
@@ -2755,17 +2859,39 @@ reconfigurable devices.
|
|
2755
2859
|
This library provides a construct for an easy description of pipeline architectures.
|
2756
2860
|
|
2757
2861
|
|
2862
|
+
# Sample HDLRuby descriptions
|
2863
|
+
<a name="sample"></a>
|
2758
2864
|
|
2865
|
+
Several samples HDLRuby descriptions are available in the following directory:
|
2759
2866
|
|
2760
|
-
|
2867
|
+
path/to/HDLRuby/lib/HDLRuby/hdr\_samples
|
2761
2868
|
|
2762
|
-
|
2869
|
+
For the gem install, the path to HDLRuby can be found using the following:
|
2870
|
+
|
2871
|
+
```
|
2872
|
+
gem which HDLRuby
|
2873
|
+
```
|
2874
|
+
|
2875
|
+
The naming convention of the samples is the following:
|
2876
|
+
|
2877
|
+
* `<name>.rb`: default type of sample.
|
2878
|
+
* `<name>_gen.rb`: generic parameters are required for processing the sample.
|
2879
|
+
* `<name>_bench.rb`: sample including a simulation benchmark, these are the only samples that can be simulated using `hdrcc -S`. Please notice that such sample cannot be converted to VHDL nor Verlog HDL yet.
|
2763
2880
|
|
2764
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
2765
2881
|
|
2766
2882
|
# Contributing
|
2767
2883
|
|
2768
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
2884
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/civol/HDLRuby.
|
2885
|
+
|
2886
|
+
|
2887
|
+
# To do
|
2888
|
+
|
2889
|
+
* Test the compatibility of the HDLRuby framework with the Microsoft Windows environments.
|
2890
|
+
* Add the generation of VHDL and Verilog code for the time behaviors.
|
2891
|
+
* Provide targets for the `Reconf` library.
|
2892
|
+
* Add a standard wave output for the simulator.
|
2893
|
+
* Find and fix the (maybe) terrifying amount of bugs.
|
2894
|
+
* Add a GUI (any volonteer to do it?).
|
2769
2895
|
|
2770
2896
|
|
2771
2897
|
# License
|
data/lib/HDLRuby/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: HDLRuby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lovic Gauthier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -47,7 +47,8 @@ email:
|
|
47
47
|
executables:
|
48
48
|
- hdrcc
|
49
49
|
extensions: []
|
50
|
-
extra_rdoc_files:
|
50
|
+
extra_rdoc_files:
|
51
|
+
- README.md
|
51
52
|
files:
|
52
53
|
- ".gitignore"
|
53
54
|
- ".travis.yml"
|
@@ -274,7 +275,8 @@ files:
|
|
274
275
|
homepage: https://github.com/civol
|
275
276
|
licenses:
|
276
277
|
- MIT
|
277
|
-
metadata:
|
278
|
+
metadata:
|
279
|
+
source_code_uri: https://github.com/civol/HDLRuby
|
278
280
|
post_install_message:
|
279
281
|
rdoc_options: []
|
280
282
|
require_paths:
|