HDLRuby 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (224) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +5 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +4 -0
  6. data/HDLRuby.gemspec +36 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +2774 -0
  9. data/README.pdf +0 -0
  10. data/Rakefile +10 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/exe/hdrcc +3 -0
  14. data/lib/HDLRuby/alcc.rb +137 -0
  15. data/lib/HDLRuby/backend/hruby_allocator.rb +69 -0
  16. data/lib/HDLRuby/backend/hruby_c_allocator.rb +76 -0
  17. data/lib/HDLRuby/hdr_samples/adder.rb +7 -0
  18. data/lib/HDLRuby/hdr_samples/adder_assign_error.rb +11 -0
  19. data/lib/HDLRuby/hdr_samples/adder_bench.rb +27 -0
  20. data/lib/HDLRuby/hdr_samples/adder_gen.rb +7 -0
  21. data/lib/HDLRuby/hdr_samples/adder_nodef_error.rb +7 -0
  22. data/lib/HDLRuby/hdr_samples/addsub.rb +19 -0
  23. data/lib/HDLRuby/hdr_samples/addsubz.rb +22 -0
  24. data/lib/HDLRuby/hdr_samples/alu.rb +47 -0
  25. data/lib/HDLRuby/hdr_samples/calculator.rb +48 -0
  26. data/lib/HDLRuby/hdr_samples/counter_bench.rb +83 -0
  27. data/lib/HDLRuby/hdr_samples/dff.rb +9 -0
  28. data/lib/HDLRuby/hdr_samples/dff_bench.rb +66 -0
  29. data/lib/HDLRuby/hdr_samples/dff_counter.rb +20 -0
  30. data/lib/HDLRuby/hdr_samples/include.rb +14 -0
  31. data/lib/HDLRuby/hdr_samples/instance_open.rb +23 -0
  32. data/lib/HDLRuby/hdr_samples/mei8.rb +256 -0
  33. data/lib/HDLRuby/hdr_samples/mei8_bench.rb +309 -0
  34. data/lib/HDLRuby/hdr_samples/multer_gen.rb +8 -0
  35. data/lib/HDLRuby/hdr_samples/multer_seq.rb +29 -0
  36. data/lib/HDLRuby/hdr_samples/neural/a.rb +9 -0
  37. data/lib/HDLRuby/hdr_samples/neural/a_sub.rb +5 -0
  38. data/lib/HDLRuby/hdr_samples/neural/bw.rb +23 -0
  39. data/lib/HDLRuby/hdr_samples/neural/counter.rb +16 -0
  40. data/lib/HDLRuby/hdr_samples/neural/dadz.rb +9 -0
  41. data/lib/HDLRuby/hdr_samples/neural/dadz_sub.rb +4 -0
  42. data/lib/HDLRuby/hdr_samples/neural/forward.rb +153 -0
  43. data/lib/HDLRuby/hdr_samples/neural/forward_sub.rb +62 -0
  44. data/lib/HDLRuby/hdr_samples/neural/forward_sub_rand.rb +41 -0
  45. data/lib/HDLRuby/hdr_samples/neural/forward_sub_rand_typedef.rb +47 -0
  46. data/lib/HDLRuby/hdr_samples/neural/mem.rb +30 -0
  47. data/lib/HDLRuby/hdr_samples/neural/random.rb +23 -0
  48. data/lib/HDLRuby/hdr_samples/neural/selector.rb +29 -0
  49. data/lib/HDLRuby/hdr_samples/neural/sigmoid.rb +20 -0
  50. data/lib/HDLRuby/hdr_samples/neural/z.rb +33 -0
  51. data/lib/HDLRuby/hdr_samples/prog.obj +256 -0
  52. data/lib/HDLRuby/hdr_samples/ram.rb +18 -0
  53. data/lib/HDLRuby/hdr_samples/register_with_code_bench.rb +98 -0
  54. data/lib/HDLRuby/hdr_samples/rom.rb +10 -0
  55. data/lib/HDLRuby/hdr_samples/struct.rb +14 -0
  56. data/lib/HDLRuby/hdr_samples/sumprod.rb +29 -0
  57. data/lib/HDLRuby/hdr_samples/sw_encrypt_bench.rb +103 -0
  58. data/lib/HDLRuby/hdr_samples/sw_encrypt_cpu_bench.rb +261 -0
  59. data/lib/HDLRuby/hdr_samples/sw_encrypt_cpusim_bench.rb +302 -0
  60. data/lib/HDLRuby/hdr_samples/system_open.rb +11 -0
  61. data/lib/HDLRuby/hdr_samples/tuple.rb +16 -0
  62. data/lib/HDLRuby/hdr_samples/with_channel.rb +118 -0
  63. data/lib/HDLRuby/hdr_samples/with_class.rb +199 -0
  64. data/lib/HDLRuby/hdr_samples/with_decoder.rb +17 -0
  65. data/lib/HDLRuby/hdr_samples/with_fsm.rb +34 -0
  66. data/lib/HDLRuby/hdr_samples/with_reconf.rb +103 -0
  67. data/lib/HDLRuby/hdrcc.rb +623 -0
  68. data/lib/HDLRuby/high_samples/_adder_fault.rb +23 -0
  69. data/lib/HDLRuby/high_samples/_generic_transmission2.rb +146 -0
  70. data/lib/HDLRuby/high_samples/adder.rb +21 -0
  71. data/lib/HDLRuby/high_samples/adder_common_errors.rb +25 -0
  72. data/lib/HDLRuby/high_samples/addsub.rb +33 -0
  73. data/lib/HDLRuby/high_samples/addsubz.rb +37 -0
  74. data/lib/HDLRuby/high_samples/after.rb +28 -0
  75. data/lib/HDLRuby/high_samples/all_signals.rb +29 -0
  76. data/lib/HDLRuby/high_samples/alu.rb +61 -0
  77. data/lib/HDLRuby/high_samples/anonymous.rb +41 -0
  78. data/lib/HDLRuby/high_samples/before.rb +28 -0
  79. data/lib/HDLRuby/high_samples/blockblock.rb +26 -0
  80. data/lib/HDLRuby/high_samples/bugs/dadz.rb +22 -0
  81. data/lib/HDLRuby/high_samples/bugs/misample_instan.rb +20 -0
  82. data/lib/HDLRuby/high_samples/bugs/misample_updown.rb +22 -0
  83. data/lib/HDLRuby/high_samples/bugs/sample_add.rb +16 -0
  84. data/lib/HDLRuby/high_samples/bugs/sample_barrel.rb +13 -0
  85. data/lib/HDLRuby/high_samples/bugs/sample_daice.rb +57 -0
  86. data/lib/HDLRuby/high_samples/bugs/sample_kumiawase.rb +52 -0
  87. data/lib/HDLRuby/high_samples/bugs/sample_multi.rb +18 -0
  88. data/lib/HDLRuby/high_samples/bugs/sample_sub.rb +14 -0
  89. data/lib/HDLRuby/high_samples/bugs/z2.rb +32 -0
  90. data/lib/HDLRuby/high_samples/case.rb +32 -0
  91. data/lib/HDLRuby/high_samples/case2.rb +30 -0
  92. data/lib/HDLRuby/high_samples/change.rb +23 -0
  93. data/lib/HDLRuby/high_samples/clocks.rb +35 -0
  94. data/lib/HDLRuby/high_samples/comparer.rb +21 -0
  95. data/lib/HDLRuby/high_samples/conditionals.rb +29 -0
  96. data/lib/HDLRuby/high_samples/dff.rb +23 -0
  97. data/lib/HDLRuby/high_samples/each.rb +28 -0
  98. data/lib/HDLRuby/high_samples/exporter.rb +42 -0
  99. data/lib/HDLRuby/high_samples/functions.rb +60 -0
  100. data/lib/HDLRuby/high_samples/if_seq.rb +26 -0
  101. data/lib/HDLRuby/high_samples/inherit_as_dff.rb +32 -0
  102. data/lib/HDLRuby/high_samples/inherit_dff.rb +36 -0
  103. data/lib/HDLRuby/high_samples/instance.rb +37 -0
  104. data/lib/HDLRuby/high_samples/memory.rb +64 -0
  105. data/lib/HDLRuby/high_samples/multi_file.rb +27 -0
  106. data/lib/HDLRuby/high_samples/overload.rb +32 -0
  107. data/lib/HDLRuby/high_samples/paper_after.rb +49 -0
  108. data/lib/HDLRuby/high_samples/ram.rb +27 -0
  109. data/lib/HDLRuby/high_samples/registers.rb +139 -0
  110. data/lib/HDLRuby/high_samples/rom.rb +23 -0
  111. data/lib/HDLRuby/high_samples/scopeblockname.rb +37 -0
  112. data/lib/HDLRuby/high_samples/scopescope.rb +26 -0
  113. data/lib/HDLRuby/high_samples/shift.rb +31 -0
  114. data/lib/HDLRuby/high_samples/shift2.rb +40 -0
  115. data/lib/HDLRuby/high_samples/simple_instance.rb +31 -0
  116. data/lib/HDLRuby/high_samples/test_all.sh +10 -0
  117. data/lib/HDLRuby/high_samples/typedef.rb +24 -0
  118. data/lib/HDLRuby/high_samples/values.rb +70 -0
  119. data/lib/HDLRuby/high_samples/vector.rb +22 -0
  120. data/lib/HDLRuby/high_samples/with_decoder.rb +30 -0
  121. data/lib/HDLRuby/high_samples/with_fsm.rb +46 -0
  122. data/lib/HDLRuby/high_samples/with_pipe.rb +43 -0
  123. data/lib/HDLRuby/high_samples/with_seq.rb +25 -0
  124. data/lib/HDLRuby/hruby_bstr.rb +1085 -0
  125. data/lib/HDLRuby/hruby_check.rb +317 -0
  126. data/lib/HDLRuby/hruby_db.rb +432 -0
  127. data/lib/HDLRuby/hruby_error.rb +44 -0
  128. data/lib/HDLRuby/hruby_high.rb +4103 -0
  129. data/lib/HDLRuby/hruby_low.rb +4735 -0
  130. data/lib/HDLRuby/hruby_low2c.rb +1986 -0
  131. data/lib/HDLRuby/hruby_low2high.rb +738 -0
  132. data/lib/HDLRuby/hruby_low2seq.rb +248 -0
  133. data/lib/HDLRuby/hruby_low2sym.rb +126 -0
  134. data/lib/HDLRuby/hruby_low2vhd.rb +1437 -0
  135. data/lib/HDLRuby/hruby_low_bool2select.rb +295 -0
  136. data/lib/HDLRuby/hruby_low_cleanup.rb +193 -0
  137. data/lib/HDLRuby/hruby_low_fix_types.rb +437 -0
  138. data/lib/HDLRuby/hruby_low_mutable.rb +1803 -0
  139. data/lib/HDLRuby/hruby_low_resolve.rb +165 -0
  140. data/lib/HDLRuby/hruby_low_skeleton.rb +129 -0
  141. data/lib/HDLRuby/hruby_low_with_bool.rb +141 -0
  142. data/lib/HDLRuby/hruby_low_with_port.rb +167 -0
  143. data/lib/HDLRuby/hruby_low_with_var.rb +302 -0
  144. data/lib/HDLRuby/hruby_low_without_bit2vector.rb +88 -0
  145. data/lib/HDLRuby/hruby_low_without_concat.rb +162 -0
  146. data/lib/HDLRuby/hruby_low_without_connection.rb +113 -0
  147. data/lib/HDLRuby/hruby_low_without_namespace.rb +718 -0
  148. data/lib/HDLRuby/hruby_low_without_outread.rb +107 -0
  149. data/lib/HDLRuby/hruby_low_without_select.rb +206 -0
  150. data/lib/HDLRuby/hruby_serializer.rb +398 -0
  151. data/lib/HDLRuby/hruby_tools.rb +37 -0
  152. data/lib/HDLRuby/hruby_types.rb +239 -0
  153. data/lib/HDLRuby/hruby_values.rb +64 -0
  154. data/lib/HDLRuby/hruby_verilog.rb +1888 -0
  155. data/lib/HDLRuby/hruby_verilog_name.rb +52 -0
  156. data/lib/HDLRuby/low_samples/adder.yaml +97 -0
  157. data/lib/HDLRuby/low_samples/after.yaml +228 -0
  158. data/lib/HDLRuby/low_samples/before.yaml +223 -0
  159. data/lib/HDLRuby/low_samples/blockblock.yaml +48 -0
  160. data/lib/HDLRuby/low_samples/bugs/sample_add.yaml +97 -0
  161. data/lib/HDLRuby/low_samples/bugs/sample_daice.yaml +444 -0
  162. data/lib/HDLRuby/low_samples/bugs/sample_kumiawase.yaml +332 -0
  163. data/lib/HDLRuby/low_samples/bugs/sample_sub.yaml +97 -0
  164. data/lib/HDLRuby/low_samples/bugs/seqpar.yaml +184 -0
  165. data/lib/HDLRuby/low_samples/case.yaml +327 -0
  166. data/lib/HDLRuby/low_samples/change.yaml +135 -0
  167. data/lib/HDLRuby/low_samples/clocks.yaml +674 -0
  168. data/lib/HDLRuby/low_samples/cloner.rb +22 -0
  169. data/lib/HDLRuby/low_samples/comparer.yaml +85 -0
  170. data/lib/HDLRuby/low_samples/conditionals.yaml +133 -0
  171. data/lib/HDLRuby/low_samples/dff.yaml +107 -0
  172. data/lib/HDLRuby/low_samples/each.yaml +1328 -0
  173. data/lib/HDLRuby/low_samples/exporter.yaml +226 -0
  174. data/lib/HDLRuby/low_samples/functions.yaml +298 -0
  175. data/lib/HDLRuby/low_samples/generic_transmission.yaml +597 -0
  176. data/lib/HDLRuby/low_samples/inherit_as_dff.yaml +125 -0
  177. data/lib/HDLRuby/low_samples/inherit_dff.yaml +107 -0
  178. data/lib/HDLRuby/low_samples/load_yaml.rb +11 -0
  179. data/lib/HDLRuby/low_samples/memory.yaml +678 -0
  180. data/lib/HDLRuby/low_samples/namespace_extractor.rb +23 -0
  181. data/lib/HDLRuby/low_samples/overload.yaml +226 -0
  182. data/lib/HDLRuby/low_samples/paper_after.yaml +431 -0
  183. data/lib/HDLRuby/low_samples/port_maker.rb +14 -0
  184. data/lib/HDLRuby/low_samples/ram.yaml +207 -0
  185. data/lib/HDLRuby/low_samples/registers.yaml +228 -0
  186. data/lib/HDLRuby/low_samples/rom.yaml +2950 -0
  187. data/lib/HDLRuby/low_samples/shift.yaml +230 -0
  188. data/lib/HDLRuby/low_samples/shift2.yaml +2095 -0
  189. data/lib/HDLRuby/low_samples/simple_instance.yaml +102 -0
  190. data/lib/HDLRuby/low_samples/test_all.sh +43 -0
  191. data/lib/HDLRuby/low_samples/typedef.yaml +115 -0
  192. data/lib/HDLRuby/low_samples/values.yaml +577 -0
  193. data/lib/HDLRuby/low_samples/variable_maker.rb +14 -0
  194. data/lib/HDLRuby/low_samples/vector.yaml +56 -0
  195. data/lib/HDLRuby/low_samples/with_seq.yaml +188 -0
  196. data/lib/HDLRuby/low_samples/yaml2hdr.rb +10 -0
  197. data/lib/HDLRuby/low_samples/yaml2vhd.rb +19 -0
  198. data/lib/HDLRuby/sim/Makefile +19 -0
  199. data/lib/HDLRuby/sim/hruby_sim.h +590 -0
  200. data/lib/HDLRuby/sim/hruby_sim_calc.c +2362 -0
  201. data/lib/HDLRuby/sim/hruby_sim_core.c +589 -0
  202. data/lib/HDLRuby/sim/hruby_sim_list.c +93 -0
  203. data/lib/HDLRuby/sim/hruby_sim_vizualize.c +91 -0
  204. data/lib/HDLRuby/sim/hruby_value_pool.c +64 -0
  205. data/lib/HDLRuby/std/channel.rb +354 -0
  206. data/lib/HDLRuby/std/clocks.rb +165 -0
  207. data/lib/HDLRuby/std/counters.rb +82 -0
  208. data/lib/HDLRuby/std/decoder.rb +214 -0
  209. data/lib/HDLRuby/std/fsm.rb +516 -0
  210. data/lib/HDLRuby/std/pipeline.rb +220 -0
  211. data/lib/HDLRuby/std/reconf.rb +309 -0
  212. data/lib/HDLRuby/test_hruby_bstr.rb +2259 -0
  213. data/lib/HDLRuby/test_hruby_high.rb +594 -0
  214. data/lib/HDLRuby/test_hruby_high_low.rb +99 -0
  215. data/lib/HDLRuby/test_hruby_low.rb +934 -0
  216. data/lib/HDLRuby/v_samples/adder.v +10 -0
  217. data/lib/HDLRuby/v_samples/dff.v +12 -0
  218. data/lib/HDLRuby/v_samples/ram.v +20 -0
  219. data/lib/HDLRuby/v_samples/rom.v +270 -0
  220. data/lib/HDLRuby/version.rb +3 -0
  221. data/lib/HDLRuby.rb +11 -0
  222. data/makedoc +1 -0
  223. data/metadata.yaml +4 -0
  224. metadata +299 -0
data/README.md ADDED
@@ -0,0 +1,2774 @@
1
+ # About HDLRuby
2
+
3
+ HDLRuby is a library for describing and simulating digital electronic
4
+ systems.
5
+
6
+ __Warning__:
7
+
8
+ - This is still preliminary work which may change a before we release a stable version.
9
+ - It is highly recommended to have both basic knowledge of the Ruby language and hardware description languages before using HDLRuby.
10
+
11
+
12
+ # Compiling HDLRuby descriptions
13
+
14
+ ## Using the HDLRuby compiler
15
+
16
+ 'hdrcc.rb' is the HDLRuby compiler. It takes as input a HDLRuby file, checks it, and can produce as output a Verilog HDL or a YAML low-level descriptions of a HW components but also simulate the input description.
17
+
18
+
19
+ __Usage__:
20
+
21
+ ```
22
+ hdrcc.rb [options] <input file> <output directory>
23
+ ```
24
+
25
+ Where:
26
+
27
+ * `options` is a list of options
28
+ * `<input file>` is the initial file to compile (mandatory)
29
+ * `<output directory>` is the directory where the generated files will be put
30
+
31
+ | Options | |
32
+ |:------------------|:-----------------------------------------------------|
33
+ | `-y, --yaml` | Output in YAML format |
34
+ | `-v, --verilog` | Output in Verlog HDL format |
35
+ | `-V, --vhdl` | Output in VHDL format |
36
+ | `-s, --syntax` | Output the Ruby syntax tree |
37
+ | `-C, --clang` | Output the C code of the simulator |
38
+ | `-S, --sim` | Output the executable simulator and execute it |
39
+ | `-d, --directory` | Specify the base directory for loading the HDLRuby files |
40
+ | `-D, --debug` | Set the HDLRuby debug mode |
41
+ | `-t, --top system`| Specify the top system describing the circuit to compile |
42
+ | `-p, --param x,y,z` | Specify the generic parameters |
43
+ | `-h, --help` | Show the help message |
44
+
45
+ __Notes__:
46
+
47
+ * If no top system is given, it is automatically looked for from the input file.
48
+ * If no option is given, simply checks the input file.
49
+
50
+ __Examples__:
51
+
52
+ * Compile system named `adder` from `adder.rb` input file and generate a low-level YAML description into directory `adder`:
53
+
54
+ ```
55
+ hdrcc.rb --yaml --top adder adder.rb adder
56
+ ```
57
+
58
+ * Compile `adder.rb` input file and generate a low-level Verilog HDL description into directory `adder`:
59
+
60
+ ```
61
+ hdrcc.rb -v adder.rb adder
62
+ ```
63
+
64
+ * Compile system `adder` whose bit width is generic from `adder_gen.rb` input file to a 16-bit circuit low-level VHDL description into directory `adder`:
65
+
66
+ ```
67
+ hdrcc.rb -V -t adder --param 16 adder_gen.rb adder
68
+ ```
69
+
70
+ * Compile system `multer` with inputs and output bit width is generic from `multer_gen.rb` input file to a 16x16->32 bit cicruit whose low-level YAML description into directory `multer`:
71
+
72
+ ```
73
+ hdrcc.rb -y -t multer -p 16,16,32 multer_gen.rb multer
74
+ ```
75
+
76
+ * Simulate the circuit described in file `counter_bench.rb` using directory `counter` for
77
+ storing the simulator's files:
78
+
79
+ ```
80
+ hdrcc.rb -S counter_bench.rb counter
81
+ ```
82
+
83
+
84
+ ## Using HDLRuby within Ruby
85
+
86
+ You can also use HDLRuby in a Ruby program by loading `HDLRuby.rb` in your Ruby file:
87
+
88
+ ```ruby
89
+ require 'HDLRuby'
90
+ ```
91
+
92
+ Then, you can set up Ruby for supporting high-level description of hardware components. This is done by adding the following line of code:
93
+
94
+ ```ruby
95
+ configure_high
96
+ ```
97
+
98
+ After this statement, standard HDLRuby code can be written. In order to produce HW descriptions from this code a low-level hardware must then be generated
99
+ from an instance of an HW module (*system* in HDLRuby).
100
+ For example, assuming system 'circuitT' has been described in your Ruby program, an instance named 'circuitI' can be declared as follows:
101
+
102
+ ```ruby
103
+ circuitT :circuitI
104
+ ```
105
+
106
+ From there a low-level description of the circuit is generated using the `to_low` methods as follows (in the following code, this description is assigned to Ruby variable 'circuitL'):
107
+
108
+ ```ruby
109
+ circuitL = circuitI.to_low
110
+ ```
111
+
112
+ This low-level description can then be converted to a YAML format using 'to_yaml' or to a VHDL format using 'to_vhd' as follows:
113
+
114
+ ```ruby
115
+ circuitY = circuitL.to_yaml
116
+ circuitV = circuitL.to_vhdl
117
+ ```
118
+
119
+ In the above examples, 'cricuitY' and 'cricuitV' are Ruby variables referring to the strings containing the respective YAML and Verilog HDL code.
120
+
121
+
122
+ ## Handling the low-level HDLRuby representation
123
+
124
+ You can include `HDLRuby::Low` for gaining access to the classes used for low-level description of hardware components.
125
+
126
+ ```ruby
127
+ include HDLRuby::Low
128
+ ```
129
+
130
+ It is then possible to load a low-level representation of hardware as follows, where `stream` is a stream containing the representation.
131
+
132
+ ```ruby
133
+ hardwares = HDLRuby::from_yaml(stream)
134
+ ```
135
+
136
+ For instance, you can load the sample description of an 8-bit adder as follows:
137
+
138
+ ```ruby
139
+ adder = HDLRuby::from_yaml(File.read("#{$:[0]}/HDLRuby/low_samples/adder.yaml"))
140
+ ```
141
+
142
+ __Note__:
143
+
144
+ - A `HDLRuby::Low` description of hardware can only be built through standard Ruby class constructors, and does not include any validity check of the resulting hardware.
145
+
146
+
147
+
148
+ # HDLRuby programming guide
149
+
150
+ HDLRuby has been designed to bring the high flexibility of the Ruby language to hardware descriptions while ensuring that they remain synthesizable. In this
151
+ context, all the abstractions provided by HDLRuby are in the way of describing hardware, but not in its execution model, this latter being RTL by construction.
152
+
153
+ The second specificity of HDLRuby is that it supports natively all the features of the Ruby language.
154
+
155
+ __Notes__:
156
+
157
+ - It is still possible to extend HDLRuby to support hardware descriptions of higher level than RTL, please refer to section [Extending HDLRuby](#extend) for more details.
158
+ - In this document, HDLRuby constructs will often be compared to their Verilog HDL or VHDL equivalents for simpler explanations.
159
+
160
+ ## Introduction
161
+
162
+ This introduction gives a glimpse of the possibilities of the language.
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
+
165
+ At first glance, HDLRuby is similar to any other HDL languages (like Verilog HDL or VHDL), for instance the following code describes a simple D-FF:
166
+
167
+ ```ruby
168
+ system :dff do
169
+ bit.input :clk, :rst, :d
170
+ bit.output :q
171
+
172
+ par(clk.posedge) do
173
+ q <= d & ~rst
174
+ end
175
+ end
176
+ ```
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, with respectively non-blocking and blocking assignments).
179
+
180
+ After such a system has been defined, it can be instantiated. For axample a single instance of the `dff` system named `dff0` can be declared as follows:
181
+
182
+ ```ruby
183
+ dff :dff0
184
+ ```
185
+
186
+ The ports of this instance can then be accessed to be used like any other signals, e.g., `dff0.d` for access the `d` input of the FF.
187
+
188
+ Several instances can also be declared in a single statement. For example, a 2-bit counter based on the previous `dff` circuits can be described as follows:
189
+
190
+ ```ruby
191
+ system :counter2 do
192
+ input :clk,:rst
193
+ output :q
194
+
195
+ dff [ :dff0, :dff1 ]
196
+
197
+ dff0.clk <= clk
198
+ dff0.rst <= rst
199
+ dff0.d <= ~dff0.q
200
+
201
+ dff1.clk <= ~dff0.q
202
+ dff1.rst <= rst
203
+ dff1.d <= ~dff1.q
204
+
205
+ q <= dff1.q
206
+ end
207
+
208
+ The instances can also be connected while being declared. For example the code above can be rewritten as follows:
209
+
210
+ ```ruby
211
+ system :counter2 do
212
+ input :clk, :rst
213
+ output :q
214
+
215
+ dff(:dff0).(clk: clk, rst: rst, d: ~dff0.q)
216
+ dff(:dff1).(~dff0.q, rst, ~dff1.q, q)
217
+ end
218
+ ```
219
+
220
+ In the code above, two possible connection methods are shown: for `dff0` ports are connected by name, and for `dff1` ports are connected by declaration order. Please notice that it is also possible to connect only a subset of the ports while declaring and to reconnect already connected ports in further statements.
221
+
222
+ While a circuit can be generated from the code given above, a benchmark must
223
+ be provided to test it. Such benchmark as described by constructs called
224
+ 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
+ of 20ns each, with reset on the first cycle, set of signal `d` to 1 for
227
+ the third cycle and set of this signal to 0 for the last.
228
+
229
+ ```ruby
230
+ system :dff_bench do
231
+
232
+ dff :dff0
233
+
234
+ timed do
235
+ dff0.clk <= 0
236
+ dff0.rst <= 1
237
+ !10.ns
238
+ dff0.clk <= 1
239
+ !10.ns
240
+ dff0.clk <= 0
241
+ dff0.rst <= 0
242
+ dff0.d <= 1
243
+ !10.ns
244
+ dff0.clk <= 1
245
+ !10.ns
246
+ dff0.clk <= 0
247
+ !10.ns
248
+ dff0.clk <= 1
249
+ !10.ns
250
+ dff0.clk <= 0
251
+ dff0.d <= 1
252
+ !10.ns
253
+ dff0.clk <= 1
254
+ !10.ns
255
+ end
256
+ end
257
+ ```
258
+
259
+ ---
260
+
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
+
263
+ 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
+ ```ruby
266
+ system :dff do
267
+ input :clk, :rst, :d
268
+ output :q
269
+
270
+ (q <= d & ~rst).at(clk.posedge)
271
+ end
272
+ ```
273
+
274
+ Then, it often happens that a system will end up with only one instance.
275
+ In such a case, the system declaration can be omitted and an instance
276
+ can be directly declared as follows:
277
+
278
+ ```ruby
279
+ instance :dff_single do
280
+ input :clk, :rst, :d
281
+ output :q
282
+
283
+ (q <= d & ~rst).at(clk.posedge)
284
+ end
285
+ ```
286
+
287
+ In the example above, `dff_single` is an instance describing, again, a
288
+ D-FF, but whose system is anonymous.
289
+
290
+ Furthermore, generic parameters can be used for anything in HDLRuby.
291
+ For instance, the following code describes an 8-bit register without any parameterization:
292
+
293
+ ```ruby
294
+ system :reg8 do
295
+ input :clk, :rst
296
+ [7..0].input :d
297
+ [7..0].output :q
298
+
299
+ (q <= d & [~rst]*8).at(clk.posedge)
300
+ end
301
+ ```
302
+
303
+ But it is also possible to describe a register of arbitrary size as follows, where `n` is the parameter giving the number of bits of the register:
304
+
305
+ ```ruby
306
+ system :regn do |n|
307
+ input :clk, :rst
308
+ [n-1..0].input :d
309
+ [n-1..0].output :q
310
+
311
+ (q <= d & [~rst]*n).at(clk.posedge)
312
+ end
313
+ ```
314
+
315
+ Or, even further, it is possible to describe a register of arbitrary type (not only bit vectors) as follows:
316
+
317
+ ```ruby
318
+ system :reg do |typ|
319
+ input :clk, :rst
320
+ typ.input :d
321
+ typ.output :q
322
+
323
+ (q <= d & [~rst]*typ.width).at(clk.posedge)
324
+ end
325
+ ```
326
+
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
+
329
+ ```ruby
330
+ system :dff_full, dff do
331
+ output :qb
332
+ qb <= ~q
333
+ end
334
+ ```
335
+
336
+ The second possibility is to modify `dff` afterward. In HDLRuby, this achieved using the `open` method as it is done the following code:
337
+
338
+ ```ruby
339
+ dff.open do
340
+ output :qb
341
+ qb <= ~q
342
+ end
343
+ ```
344
+
345
+ The third possibility is to modify directly a single instance of `dff` which require an inverted output, using again the `open` method, as in the following code:
346
+
347
+ ```ruby
348
+ # Declare dff0 as an instance of dff
349
+ dff :dff0
350
+
351
+ # Modify it
352
+ dff0.open do
353
+ output :qb
354
+ qb <= ~q
355
+ end
356
+ ```
357
+
358
+ In this later case, only `dff0` will have an inverted output, the other instances of `dff` will not change.
359
+
360
+ Now assuming we opted for the first solution, we have now `dff_full`, a highly advanced D-FF with such unique features as an inverted output. So we would like to use it in other designs, for example a shift register of `n` bits. Such a system will include a generic number of `dff_full` instances, and can be
361
+ described as follows making use of the native Ruby method `each_cons` for connecting them together:
362
+
363
+ ```ruby
364
+ system :shifter do |n|
365
+ input :clk, :rst
366
+ input :i0
367
+ output :o0, :o0b
368
+
369
+ # Instantiating n D-FF
370
+ [n].dff_full :dffIs
371
+
372
+ # Connect the clock and the reset.
373
+ dffIs.each { |ff| ff.clk <= clk ; ff.rst <= rst }
374
+
375
+ # Interconnect them as a shift register
376
+ dffIs[0..-1].each_cons(2) { |ff0,ff1| ff1.d <= ff0.q }
377
+
378
+ # Connects the input and output of the circuit
379
+ dffIs[0].d <= i0
380
+ o0 <= dffIs[-1].q
381
+ o0b <= dffIs[-1].qb
382
+ end
383
+ ```
384
+
385
+ As it can be seen in the above examples, in HDLRuby, any construct is an object and therefore include methods. For instance, declaring a signal of a given `type` and direction (input, output or inout) is done as follows, so that `direction` is actually a method of the type, and the signal names are actually the arguments of this method (symbols or string are supported.)
386
+
387
+ ```ruby
388
+ <type>.<direction> <list of symbols representing the signal>
389
+ ```
390
+
391
+ Of course, if you do not need to use the specific component `dff_full` you can describe a shift register more simply as follows:
392
+
393
+ ```ruby
394
+ system :shifter do |n|
395
+ input :clk, :rst
396
+ input :i0
397
+ output :o0
398
+ [n].inner :sh
399
+
400
+ par (clk.posedge) do
401
+ hif(rst) { sh <= 0 }
402
+ helse { sh <= [sh[n-2..0], i0] }
403
+ end
404
+
405
+ o0 <= sh[n-1]
406
+ end
407
+ ```
408
+
409
+ Now, let us assume you want to design a circuit that performs a sum of products of several inputs with constant coefficients. For the case of 4 16-bit signed inputs and given coefficient as 3, 4, 5 and 6. The corresponding basic code could be as follows:
410
+
411
+ ```ruby
412
+ system :sumprod_16_3456 do
413
+ signed[16].input :i0, :i1, :i2, :i3
414
+ signed[16].output :o
415
+
416
+ o <= i0*3 + i1*4 + i2*5 + i3*6
417
+ end
418
+ ```
419
+
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 coefficient 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
+ ```ruby
423
+ system :sumprod do |typ,coefs|
424
+ typ[coefs.size].input ins
425
+ typ.output :o
426
+
427
+ o <= coefs.each_with_index.reduce(_0) do |sum,(coef,i)|
428
+ sum + ins[i]*coef
429
+ end
430
+ end
431
+ ```
432
+
433
+ In the code above, there are two generic parameters,
434
+ `typ` that indicates the data type of the circuit and `coefs` that 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.
435
+
436
+ The description of the sum of product maybe 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 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|` simply 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 `_0` initializes the sum to `0`.
437
+
438
+ While slightly longer than the previous description, this description allows to declare a circuit implementing a sum of product with any bit width and any number of coefficients. For instance, the following code describes a signed 32-bit sum of product with 16 coefficients (actually just random numbers here).
439
+
440
+ ```ruby
441
+ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit)
442
+ ```
443
+
444
+ 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
+ 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
+ ```ruby
449
+ system :sumprod_func do |typ,coefs|
450
+ typ[coefs.size].input ins
451
+ typ.output :o
452
+
453
+ o <= coefs.each_with_index.reduce(_0) do
454
+ |sum,(coef,i)|
455
+ add(sum, mult(ins[i]*coef))
456
+ end
457
+ end
458
+ ```
459
+
460
+ Where `add` and `mult` are functions implementing the required specific operations. HDLRuby functions are similar to Verilog HDL ones. In our example, an addition that saturates at 1000 could be described as follows:
461
+
462
+ ```ruby
463
+ function :add do |x,y|
464
+ inner :res
465
+ seq do
466
+ res <= x + y
467
+ (res <= 1000).hif(res > 1000)
468
+ end
469
+ end
470
+ ```
471
+
472
+ With HDLRuby functions, the result of the last statement in the return value, in this case that will be the value of res. The code above is also an example of the usage of the postfixed if statement, it an equivalent of the following code:
473
+
474
+ ```ruby
475
+ hif(res>1000) { res <= 1000 }
476
+ ```
477
+
478
+ With functions, it is enough to change their content to obtained 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
+ ```ruby
481
+ function :add do |max, x, y|
482
+ inner :res
483
+ seq do
484
+ res <= x + y
485
+ (res <= max).hif(res > max)
486
+ end
487
+ end
488
+ ```
489
+
490
+ 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
+ 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 bellow:
493
+
494
+ ```ruby
495
+ system :sumprod_proc do |add,mult,typ,coefs|
496
+ typ[coefs.size].input ins
497
+ typ.output :o
498
+
499
+ o <= coefs.each_with_index.reduce(_0) do
500
+ |sum,(coef,i)|
501
+ add.(sum, mult.(ins[i]*coef))
502
+ end
503
+ end
504
+ ```
505
+
506
+ __Note__:
507
+
508
+ - With HDLRuby, when some code is passed as argument, it is invoked using the `.()` operator, and not simple parenthesis like functions.
509
+
510
+ Assuming the addition with saturation is now implemented by a function named `add_sat` and a multiplication with saturation is implemented by a function named `mult_sat` (with similar arguments), a circuit implementing a signed 16-bit sum of product saturating at 1000 with 16 coefficients could be described as follows:
511
+
512
+ ```ruby
513
+ sumprod_proc(
514
+ proc { |x,y| add_sat(1000,x,y) },
515
+ proc { |x,y| mult_sat(1000,x,y) },
516
+ signed[64],
517
+ [3,78,43,246, 3,67,1,8,
518
+ 47,82,99,13, 5,77,2,4]).(:my_circuit)
519
+ ```
520
+
521
+ As seen in the example above, a piece of code is passed as argument using the proc keyword.
522
+
523
+ A second possible approach provided by HDLRuby is to declare a new data type with redefined addition and multiplication operators. For the case of a 16-bit saturated addition and multiplication the following generic data type can be defined (for signed computations):
524
+
525
+ ```
526
+ signed[16].typedef(:sat16_1000)
527
+
528
+ sat16_1000.define_operator(:+) do |x,y|
529
+ [16].inner :res
530
+ seq do
531
+ res <= x + y
532
+ ( res <= 1000 ).hif(res > 1000)
533
+ end
534
+ end
535
+ ```
536
+
537
+ In the code above, the first line define 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
+ Then, the initial version of `sumprod` can be used with this type to achieve saturated computations as follows:
539
+
540
+ ```ruby
541
+ sumprod(sat16_1000,
542
+ [3,78,43,246, 3,67,1,8,
543
+ 47,82,99,13, 5,77,2,4]).(:my_circuit)
544
+ ```
545
+
546
+ It is also possible to declare a generic type. For instance a generic signed type with saturation can be declared as follows:
547
+
548
+ ```ruby
549
+ typedef :sat do |width, max|
550
+ signed[width]
551
+ end
552
+
553
+
554
+ sat.define_operator(:+) do |width,max, x,y|
555
+ [width].inner :res
556
+ seq do
557
+ res <= x + y
558
+ ( res <= max ).hif(res > max)
559
+ end
560
+ end
561
+ ```
562
+
563
+ __Note:__
564
+
565
+ - The generic parameters have also to be declared for the operator redefinitions.
566
+
567
+ With this generic type, the circuit can be declared as follows:
568
+
569
+ ```ruby
570
+ sumprod(sat(16,1000),
571
+ [3,78,43,246, 3,67,1,8,
572
+ 47,82,99,13, 5,77,2,4]).(:my_circuit)
573
+ ```
574
+
575
+
576
+ As final note, HDLRuby is also a language with supports reflection for
577
+ all its constructs. For example, the system of an instance can be accessed
578
+ using the `systemT` method, and this latter can be used to create
579
+ other instances. For example, previously, `dff_single` was declared with
580
+ an anonymous system (i.e., it cannot be accessed by name). This system
581
+ can however be used as follows to generate another instance:
582
+
583
+ ```ruby
584
+ dff_single.systemT.instantiate(:dff_not_single)
585
+ ```
586
+
587
+ In the above example, `dff_not_single` is declared to be an instance
588
+ of the same system as `dff_single`.
589
+
590
+ This reflection capability can also be used for instance for accessing the
591
+ data type of a signal (`sig.type`), but also the current basic block
592
+ (`cur_block`), the current process (`cur_behavior`) and so on.
593
+ The standard library of HDLRuby, that includes several hardware constructs
594
+ like final state machine descriptors, is mainly based on using these
595
+ reflection features.
596
+
597
+
598
+
599
+ ## How does HDLRuby work
600
+
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, and can also be simulated like any standard hardware description.
602
+ 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
+ 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`:
605
+
606
+ ```ruby
607
+ a <= b
608
+ ```
609
+
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 actually performed by executing this block. The actual synthesizable description of this hardware is the execution result of this instantiation.
611
+
612
+
613
+
614
+ From there, we will describe into more details each construct of HDLRuby.
615
+
616
+ ## Naming rules
617
+ <a name="names"></a>
618
+
619
+ Several constructs in HDLRuby are referred to by name, e.g., systems and signals. When such constructs are declared, their names are to be specified by Ruby symbols starting with a lower case. For example, `:hello` is a valid name declaration, but `:Hello` is not.
620
+
621
+ 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
622
+ has been declared with `:hello` as name, it will be afterward referred by `hello`.
623
+
624
+ ## Systems and signals
625
+
626
+ 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
+ A signal represents a state in a system. It has a data type and a value, the latter varying with time. Similarly to VHDL, HDLRuby signals can be viewed as abstractions of both wires and registers in a digital circuit. As a general rule, a signal whose value is explicitly set all the time models a wire, otherwise it models a register.
629
+
630
+ ### Declaring an empty system
631
+
632
+ A system is declared using the keyword `system`. It must be given a Ruby symbol for name and a block that describe its content. For instance, the following code describes an empty system named `box`:
633
+
634
+ ```ruby
635
+ system(:box) {}
636
+ ```
637
+
638
+ __Notes__:
639
+
640
+ - Since this is Ruby code, the body can also be delimited by the `do` and `end`
641
+ Ruby keywords (in which case the parentheses can be omitted) as follows:
642
+
643
+ ```ruby
644
+ system :box do
645
+ end
646
+ ```
647
+
648
+ - Names in HDLRuby are natively stored as Ruby symbols, but strings can
649
+ also be used, e.g., `system("box") {}` is also valid.
650
+
651
+ ### Declaring a system with an interface
652
+
653
+ The interface of a system can be described anywhere in its body, but it is recommended to do it at its beginning. This is done by declaring input, output or inout signals of given data types as follows:
654
+
655
+ ```ruby
656
+ <data type>.<direction> <list of colon-preceded names>
657
+ ```
658
+
659
+ For example, declaring a 1-bit input signal named `clk` can be declared as follows:
660
+
661
+ ```ruby
662
+ bit.input :clk
663
+ ```
664
+
665
+ Now, since `bit` is the default data type in HDLRuby, it can be omitted as follows:
666
+
667
+ ```ruby
668
+ input :clk
669
+ ```
670
+
671
+ The following is a more complete example: it is the code of a system describing an 8-bit data, 16-bit address memory whose interface includes a 1-bit input
672
+ clock (`clk`), a 1-bit signal for selecting reading or writing access (`rwb`), a 16-bit address input (`addr`) and an 8-bit data inout — the remaining of the code describes the content and the behavior of the memory.
673
+
674
+ ```ruby
675
+ system :mem8_16 do
676
+ input :clk, :rwb
677
+ [15..0].input :addr
678
+ [7..0].inout :data
679
+
680
+ bit[7..0][2**16].inner :content
681
+
682
+ par(clk.posedge) do
683
+ hif(rwb) { data <= content[addr] }
684
+ helse { content[addr] <= data }
685
+ end
686
+ end
687
+ ```
688
+
689
+ ### Structural description in a system
690
+
691
+ In a system, structural descriptions consist of subsystems and interconnections among them.
692
+
693
+ A subsystem is obtained by instantiating an existing system as follows, where `<system name>` is the name of the system to instantiate (without any colon):
694
+
695
+ ```ruby
696
+ <system name> :<instance name>
697
+ ```
698
+
699
+ For example, system `mem8_16` declared in the previous section can be instantiated as follows:
700
+
701
+ ```ruby
702
+ mem8_16 :mem8_16I
703
+ ```
704
+
705
+ It is also possible to declare multiple instances of a same system at time as follows:
706
+
707
+ ```ruby
708
+ <system name> [list of colon-separated instance names]
709
+ ```
710
+
711
+ For example, the following code declares two instances of system `mem8_16`:
712
+
713
+ ```ruby
714
+ mem8_16 [ :mem8_16I0, :mem8_16I1 ]
715
+ ```
716
+
717
+ Interconnecting instances may require internal signals in the system.
718
+ Such signals are declared using the `inner` direction.
719
+ For example, the following code declares a 1-bit inner signal named `w1` and a 2-bit inner signal named `w2`:
720
+
721
+ ```ruby
722
+ inner :w1
723
+ [1..0].inner :w2
724
+ ```
725
+
726
+ A connection between signals is done using the arrow operator `<=` as follows:
727
+
728
+ ```ruby
729
+ <destination> <= <source>
730
+ ```
731
+
732
+ The `<destination>` must be a reference to a signal, and the `<source>` can be any expression.
733
+
734
+ For example the following code, connects signal `w1` to signal `ready` and signal `clk` to the first bit of signal `w2`:
735
+
736
+ ```ruby
737
+ ready <= w1
738
+ w2[0] <= clk
739
+ ```
740
+
741
+ As another example, the following code connects to the second bit of `w2` the output of an AND operation between `clk` and `rst` as follows:
742
+
743
+ ```ruby
744
+ w2[1] <= clk & rst
745
+ ```
746
+
747
+ The signals of an instance can be connected through the arrow operator too, provided they are properly referred to. One way to refer them is to use the dot operator `.` on the instance as follows:
748
+
749
+ ```ruby
750
+ <instance name>.<signal name>
751
+ ```
752
+
753
+ For example, the following code connects signal `clk` of instance `mem8_16I` to signal `clk` of the current system:
754
+
755
+ ```ruby
756
+ mem8_16I.clk <= clk
757
+ ```
758
+
759
+ It is also possible to connect multiple signals of an instance using the call operator `.()` as follows, where each target can be any expression:
760
+
761
+ ```ruby
762
+ <intance name>.(<signal name0>: <target0>, ...)
763
+ ```
764
+
765
+ For example, the following code connects signals `clk` and `rst` of instance
766
+ `mem8_16I` to signals `clk` and `rst` of the current system. As seen in this example, this method allows partial connection since the address and the data buses are not connected yet.
767
+
768
+ ```ruby
769
+ mem8_16I.(clk: clk, rst: rst)
770
+ ```
771
+
772
+ This last connection method can be used directly while declaring an instance.
773
+ For example, `mem8_16I` could have been declared and connected to `clk` and `rst` as follows:
774
+
775
+ ```ruby
776
+ mem8_16(:mem8_16I).(clk: clk, rst: rest)
777
+ ```
778
+
779
+ To summarize this section, here is a structural description of a 16-bit memory made of two 8-bit memories (or equivalent) sharing the same address bus, and using respectively the lower and the higher 8-bits of the data bus:
780
+
781
+ ```ruby
782
+ system :mem16_16 do
783
+ input :clk, :rwb
784
+ [15..0].input :addr
785
+ [15..0].inout :data
786
+
787
+ mem8_16(:memL).(clk: clk, rwb: rwb, addr: addr, data: data[7..0])
788
+ mem8_16(:memH).(clk: clk, rwb: rwb, addr: addr, data: data[15..8])
789
+ end
790
+ ```
791
+
792
+ And here is an equivalent code using the arrow operator:
793
+
794
+ ```ruby
795
+ system :mem16_16 do
796
+ input :clk, :rwb
797
+ [15..0].input :addr
798
+ [15..0].inout :data
799
+
800
+ mem8_16 [:memL, :memH]
801
+
802
+ memL.clk <= clk
803
+ memL.rwb <= rwb
804
+ memL.addr <= addr
805
+ memL.data <= data[7..0]
806
+
807
+ memH.clk <= clk
808
+ memH.rwb <= rwb
809
+ memH.addr <= addr
810
+ memH.data <= data[15..8]
811
+ end
812
+ ```
813
+
814
+ ### Scope in a system
815
+
816
+ #### General scopes
817
+
818
+ 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
+ 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
+ ```ruby
823
+ system :div2 do
824
+ input :clk
825
+ output :q
826
+
827
+ inner :d, :qb
828
+ d <= qb
829
+
830
+ dff_full(:dffI).(clk: clk, d: d, q: q, qb: qb)
831
+
832
+ ```
833
+
834
+ For robustness or, readability purpose, it is possible to add inner scope inside existing scope using the `sub` keyword as follows:
835
+
836
+ ```ruby
837
+ sub do
838
+ <code>
839
+ end
840
+ ```
841
+
842
+ For example, in the code bellow, signal `sig` is not accessible from outside the additional inner scope of system `sys`
843
+
844
+ ```ruby
845
+ system :sys do
846
+ ...
847
+ sub
848
+ inner :sig
849
+ <sig is accessible here>
850
+ end
851
+ <sig is not accessible from here>
852
+ end
853
+ ```
854
+
855
+ It is also possible to add an inner scope within another inner scope as follows:
856
+
857
+ ```ruby
858
+ system :sys do
859
+ ...
860
+ sub
861
+ inner :sig0
862
+ <sig0 is accessible here>
863
+ sub
864
+ inner :sig1
865
+ <sig0 and sig1 are accessible here>
866
+ end
867
+ <sig1 is not accessible here>
868
+ end
869
+ <neither sig0 nor sig1 are accessible here>
870
+ end
871
+ ```
872
+
873
+ Within a same scope it is not possible to declared multiple signals or instances with a same name. However, it is possible to declare a signal or an instance with a name identical to one previously declared outside the scope: the inner-most declaration will be used.
874
+
875
+
876
+ #### Named scopes
877
+
878
+ It is possible to declare a scope with a name as follows:
879
+
880
+ ```ruby
881
+ sub :<name> do
882
+ <code>
883
+ end
884
+ ```
885
+
886
+ Where:
887
+
888
+ - `<name>` is the name of the scope.
889
+ - `<code>` is the code within the scope.
890
+
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
+
893
+ ```ruby
894
+ sub :scop do
895
+ inner :sig
896
+ ...
897
+ end
898
+ ...
899
+ scop.sig <= ...
900
+ ```
901
+
902
+
903
+ ### Behavioral description in a system.
904
+
905
+ In a system, parallel behavioral descriptions are declared using the `par` keyword, and sequential behavioral descriptions are declared using the `seq` keyword. They are the equivalent of the Verilog HDL `always` blocks.
906
+
907
+ A behavior is made of a list of events (the sensitivity list) upon which it is activated, and a list of statements. A behavior is declared as follows:
908
+
909
+ ```ruby
910
+ par <list of events> do
911
+ <list of statements>
912
+ end
913
+ ```
914
+
915
+ In addition, it is possible to declare inner signals within an execution block.
916
+ 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 make it possible to declare several signals with identical names provided their respective scopes are different.
917
+
918
+ An event represents a specific change of state of a signal.
919
+ 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 edge, `negedge` for falling edge, and `edge` for any edge.
921
+ Events are described in more detail in section [Events](#events).
922
+
923
+ 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
924
+ earlier). Statements are described in more detail in section [statements](#statements). In this section, we focus on the transmission statements and the block statements.
925
+
926
+ A transmission statement is declared using the arrow operator `<=` as follows:
927
+
928
+ ```ruby
929
+ <destination> <= <source>
930
+ ```
931
+
932
+ The `<destination>` must be a reference to a signal, and the `<source>` can be any expression. A transmission has therefore exactly 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
+ 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, the top block of the behavior is sequential.
936
+
937
+ ```ruby
938
+ system :with_sequential_behavior do
939
+ seq do
940
+ <list of statements>
941
+ end
942
+ end
943
+ ```
944
+
945
+ It is possible to declare new blocks within an existing block.
946
+ For declaring a sub block with the same execution mode as the upper one, the keyword `sub` is used. For example, the following code declare a sub block within a sequential block, with the same execution mode:
947
+
948
+ ```ruby
949
+ system :with_sequential_behavior do
950
+ seq do
951
+ <list of statements>
952
+ sub do
953
+ <list of statements>
954
+ end
955
+ end
956
+ end
957
+ ```
958
+
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, a parallel sub block is declared within a sequential one:
960
+
961
+ ```ruby
962
+ system :with_sequential_behavior do
963
+ seq do
964
+ <list of statements>
965
+ par do
966
+ <list of statements>
967
+ end
968
+ end
969
+ end
970
+ ```
971
+
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
+ declare three different inner signals all called `sig` as follows:
974
+
975
+ ```ruby
976
+ ...
977
+ par(<sensibility list>) do
978
+ inner :sig
979
+ ...
980
+ sub do
981
+ inner :sig
982
+ ...
983
+ sub do
984
+ inner :sig
985
+ ...
986
+ end
987
+ end
988
+ ...
989
+ end
990
+ ```
991
+
992
+ To summarize this section, here is a behavioral description of a 16-bit shift register with asynchronous reset (`hif` and `helse` are keywords used for specifying hardware _if_ and _else_ control statements).
993
+
994
+ ```ruby
995
+ system :shift16 do
996
+ input :clk, :rst, :din
997
+ output :dout
998
+
999
+ [15..0].inner :reg
1000
+
1001
+ dout <= reg[15] # The output is the last bit of the register.
1002
+
1003
+ par(clk.posedge) do
1004
+ hif(rst) { reg <= 0 }
1005
+ helse do
1006
+ reg[0] <= din
1007
+ reg[15..1] <= reg[14..0]
1008
+ end
1009
+ end
1010
+ end
1011
+ ```
1012
+
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 lead to an invalid functionality for a shift register.
1014
+
1015
+ ```ruby
1016
+ system :shift16 do
1017
+ input :clk, :rst, :din
1018
+ output :dout
1019
+
1020
+ [15..0].inner :reg
1021
+
1022
+ dout <= reg[15] # The output is the last bit of the register.
1023
+
1024
+ par(clk.posedge) do
1025
+ hif(rst) { reg <= 0 }
1026
+ helse seq do
1027
+ reg[0] <= din
1028
+ reg <= reg[14..0]
1029
+ end
1030
+ end
1031
+ end
1032
+ ```
1033
+
1034
+ __Note__:
1035
+
1036
+ - `helse seq` ensures that the block of the hardware else is in sequential mode.
1037
+ - `hif(rst)` could also have been set to sequential mode as follows:
1038
+
1039
+ ```ruby
1040
+ hif rst, seq do
1041
+ reg <= 0
1042
+ end
1043
+ ```
1044
+ - Parallel mode can be set the same way using `par`.
1045
+
1046
+ Finally, it often happens that a behavior contains only one statement.
1047
+ In such a case, the description can be shortened using the `at` operator as follows:
1048
+
1049
+ ```ruby
1050
+ ( statement ).at(<list of events>)
1051
+ ```
1052
+
1053
+ For example the following two code samples are equivalent:
1054
+
1055
+ ```ruby
1056
+ par(clk.posedge) do
1057
+ a <= b+1
1058
+ end
1059
+ ```
1060
+
1061
+ ```ruby
1062
+ ( a <= b+1 ).at(clk.posedge)
1063
+ ```
1064
+
1065
+ For sake of consistency, this operator can also be applied on block statements as follows, but it is probably less readable than the standard declaration of behaviors:
1066
+
1067
+ ```ruby
1068
+ ( seq do
1069
+ a <= b+1
1070
+ c <= d+2
1071
+ end ).at(clk.posedge)
1072
+ ```
1073
+
1074
+
1075
+ ## Events
1076
+ <a name="events"></a>
1077
+
1078
+ Each behavior of a system is associated with a list of events, called sensibility list, that specifies when the behavior is to be executed. An event is associated with a signal and represents the instants when the signal reaches a given state.
1079
+
1080
+ There are three kinds of event: positive edge events represent the instants when their corresponding signals vary from 0 to 1, negative edge events
1081
+ represent the instants when their corresponding signals vary from 1 to 0 and the change events represent the instants when their corresponding signals vary.
1082
+ Events are declared directly from the signals, using the `posedge` operator for positive edge, the `negedge` operator for negative edge, and the `change` operator for change. For example the following code declares 3 behaviors activated respectively on the positive edge, the negative edge and any change of the `clk` signal.
1083
+
1084
+ ```ruby
1085
+ inner :clk
1086
+
1087
+ par(clk.posedge) do
1088
+ ...
1089
+ end
1090
+
1091
+ par(clk.negedge) do
1092
+ ...
1093
+ end
1094
+
1095
+ par(clk.change) do
1096
+ ...
1097
+ end
1098
+ ```
1099
+
1100
+ __Note:__
1101
+ - The `change` keyword can be omitted.
1102
+
1103
+ ## Statements
1104
+ <a name="statements"></a>
1105
+
1106
+ Statements are the basic elements of a behavioral description. They are regrouped in blocks that specify their execution mode (parallel or sequential).
1107
+ There are four kinds of statements: the transmit statement that computes expressions and send the result to the target signals, the control statement
1108
+ that changes the execution flow of the behavior, the block statement (described earlier) and the inner signal declaration.
1109
+
1110
+ __Note__:
1111
+
1112
+ - There is actually a fifth type of statement, the time statement. It will be discussed in section [Time](#time).
1113
+
1114
+
1115
+ ### Transmit statement
1116
+
1117
+ 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
+ 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
+ ```ruby
1122
+ s0 <= 3
1123
+ s1[3..0] <= i0 + i1
1124
+ ```
1125
+
1126
+ The comportment of a transmit statement depends on the execution mode of the enclosing block:
1127
+
1128
+ - If the mode is parallel, the target signals are updated when all the statements of the current block are processed.
1129
+ - If the mode is sequential, the target signals are updated immediately after the right value of the statement is computed.
1130
+
1131
+
1132
+ ### Control statements
1133
+
1134
+ There are only two possible control statements: the hardware if `hif` and the hardware case `hcase`.
1135
+
1136
+ #### hif
1137
+
1138
+ The `hif` construct is made of a condition and a block that is executed if and only if the condition is met. It is declared as follows, where the condition can be any expression:
1139
+
1140
+ ```ruby
1141
+ hif <condition> do
1142
+ <block contents>
1143
+ end
1144
+ ```
1145
+
1146
+ #### hcase
1147
+
1148
+ The `hcase` construct is made of an expression and a list of value-block pairs.
1149
+ A block is executed when the corresponding value is equal to the value of the expression of the `hcase`. This construct is declared as follows:
1150
+
1151
+ ```ruby
1152
+ hcase <expression>
1153
+ hwhen <value 0> do
1154
+ <block contents 0>
1155
+ end
1156
+ hwhen <value 1> do
1157
+ <block contents 1>
1158
+ end
1159
+ ...
1160
+ ```
1161
+
1162
+ #### helse
1163
+
1164
+ It is possible to add a block that is executed when the condition of an `hif` is not met, or when no case matches the expression of a `hcase`, using the `helse` keyword as follows:
1165
+
1166
+ ```ruby
1167
+ <hif or hcase construct>
1168
+ helse do
1169
+ <block contents>
1170
+ end
1171
+ ```
1172
+
1173
+ ### helsif
1174
+
1175
+ In addition to `helse` it is possible to set additional conditions to an `hif` using the `helsif` keyword as follows:
1176
+
1177
+ ```ruby
1178
+ hif <condition 0> do
1179
+ <block contents 0>
1180
+ end
1181
+ helsif <condition 1> do
1182
+ <block contents 1>
1183
+ end
1184
+ ...
1185
+ ```
1186
+
1187
+ #### About loops
1188
+
1189
+ 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 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).
1191
+
1192
+ __Notes__:
1193
+
1194
+ - 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 nay hardware. Actually, 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
+ ```ruby
1198
+ system :say_hello do |param = nil|
1199
+ if param != nil then
1200
+ puts "Hello world!"
1201
+ end
1202
+ end
1203
+ ```
1204
+
1205
+ ## Types
1206
+ <a name="types"></a>
1207
+
1208
+ 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
+ basically bit vectors associated with the way they should be interpreted, i.e., as bit strings, unsigned values, signed values, or hierarchical contents.
1210
+
1211
+ ### Type construction
1212
+
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 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
+
1216
+ The other types are built from them using a combination of the two following
1217
+ type operators.
1218
+
1219
+ __The vector operator__ `[]` is used for building types representing vectors of single or multiple other types. A vector whose elements have all the same type are declared as follows:
1220
+
1221
+ ```ruby
1222
+ <type>[<range>]
1223
+ ```
1224
+
1225
+ 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 endian fixed point type with 8 bits above the radix point and 4 bits
1227
+ bellow:
1228
+
1229
+ ```ruby
1230
+ bit[7..-4]
1231
+ ```
1232
+
1233
+ A `n..0` range can also be abbreviated to `n+1`. For instance the two following types are identical:
1234
+
1235
+ ```ruby
1236
+ bit[7..0]
1237
+ bit[8]
1238
+ ```
1239
+
1240
+ A vector of multiple types, also called tuple, is declared as follows:
1241
+
1242
+ ```ruby
1243
+ [<type 0>, <type 1>, ... ]
1244
+ ```
1245
+
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
+
1248
+ ```ruby
1249
+ [ bit[8], signed[16], unsigned[16] ]
1250
+ ```
1251
+
1252
+ __The structure opertor__ `{}` is used for building hierarchical types made of named subtypes. This operator is used as follows:
1253
+
1254
+ ```ruby
1255
+ { <name 0>: <type 0>, <name 1>: <type 1>, ... }
1256
+ ```
1257
+
1258
+ For instance, the following code declares a hierarchical type with an 8-bit sub type named `header` and a 24-bit sub type named `data`:
1259
+
1260
+ ```ruby
1261
+ { header: bit[7..0], data: bit[23..0] }
1262
+ ```
1263
+
1264
+
1265
+ ### Type definition
1266
+
1267
+ It is possible to give names to type constructs using the `typedef` keywords as follows:
1268
+
1269
+ ```ruby
1270
+ <type construct>.typedef :<name>
1271
+ ```
1272
+
1273
+ For example the followings gives the name `char` to a signed 8-bit vector:
1274
+
1275
+ ```ruby
1276
+ signed[7..0].typedef :char
1277
+ ```
1278
+
1279
+ After this statement, `char` can be used like any other type. For example, the following code sample declares a new input signal `sig` whose type is `char`:
1280
+
1281
+ ```ruby
1282
+ char.input :sig
1283
+ ```
1284
+
1285
+ Alternatively, a new type can also be defined using the following syntax:
1286
+
1287
+ ```ruby
1288
+ typedef :<type name> do
1289
+ <code>
1290
+ end
1291
+ ```
1292
+
1293
+ Where:
1294
+
1295
+ - `type name` is the name of the type
1296
+
1297
+ - `code` is a description of the content of the type
1298
+
1299
+ For example, the previous `char` could have been declared as follows:
1300
+
1301
+ ```ruby
1302
+ typedef :char do
1303
+ signed[7..0]
1304
+ end
1305
+ ```
1306
+
1307
+ ### Type compatibility and conversion
1308
+
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
+
1311
+ While the underlying structure of any HDLRuby type is the bitvector, complex types can be 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
+
1313
+ ## Expressions
1314
+ <a name="expressions"></a>
1315
+
1316
+ Expressions are any construct that represents a value associated with a type.
1317
+ They include [immediate values](#values), [reference to signals](#references) and operations among other expressions using [expression operators](#operators).
1318
+
1319
+
1320
+ ### Immediate values
1321
+ <a name="values"></a>
1322
+
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
+
1325
+ The vector type specifiers are the followings:
1326
+
1327
+ - `b`: `bit` type, can be omitted,
1328
+
1329
+ - `u`: `unsigned` type, (equivalent to `b` and can be used for avoiding confusion with the binary specifier),
1330
+
1331
+ - `s`: `signed` type, the last figure is sign extended if required by the binary, octal and hexadecimal bases, but not for the decimal base.
1332
+
1333
+ The base specifiers are the followings:
1334
+
1335
+ - `b`: binary, can be omitted,
1336
+
1337
+ - `o`: octal,
1338
+
1339
+ - `d`: decimal,
1340
+
1341
+ - `h`: hexadecimal.
1342
+
1343
+ For example, all the following immediate values represent an 8-bit `100` (either in unsigned or signed representation):
1344
+
1345
+ ```ruby
1346
+ _bb01100100
1347
+ _b8b1100100
1348
+ _b01100100
1349
+ _01100100
1350
+ _u8d100
1351
+ _s8d100
1352
+ _uh64
1353
+ _s8o144
1354
+ ```
1355
+
1356
+ __Notes__:
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 actually set `sig` to 4 instead of 100:
1359
+
1360
+ ```ruby
1361
+ [3..0].inner :sig
1362
+ sig <= 100
1363
+ ```
1364
+
1365
+
1366
+ ### References
1367
+ <a name="references"></a>
1368
+
1369
+ References are expressions used to designate signals, or a part of signals.
1370
+
1371
+ The most simple 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
+ following code, inner signal `sig0` is declared, and therefore the name *sig0* becomes a reference to designate this signal.
1373
+
1374
+ ```ruby
1375
+ # Declaration of signal sig0.
1376
+ inner :sig0
1377
+
1378
+ # Access to signal sig0 using a name reference.
1379
+ sig0 <= 0
1380
+ ```
1381
+
1382
+ For designating a signal of another system, or a sub signal in a hierarchical signal, you can use the `.` operator as follows:
1383
+
1384
+ ```ruby
1385
+ <parent name>.<signal name>
1386
+ ```
1387
+
1388
+ For example, in the following code, input signal `d` of system instance `dff0` is connected to sub signal `sub0` of hierarchical signal `sig`.
1389
+
1390
+ ```ruby
1391
+ system :dff do
1392
+ input :clk, :rst, :d
1393
+ output :q
1394
+
1395
+ par(clk.posedge) { q <= d & ~rst }
1396
+ end
1397
+
1398
+ system :my_system do
1399
+ input :clk, :rst
1400
+ { sub0: bit, sub1: bit}.inner :sig
1401
+
1402
+ dff(:dff0).(clk: clk, rst: rst)
1403
+ dff0.d <= sig.sub0
1404
+ ...
1405
+ end
1406
+ ```
1407
+
1408
+ ### Expression operators
1409
+ <a name="operators"></a>
1410
+
1411
+ The following table gives a summary of the operators available in HDLRuby.
1412
+ More details are given for each group of operator in the subsequent sections.
1413
+
1414
+ __Assignment operators (left-most operator of a statement):__
1415
+
1416
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1417
+ | :--- | :--- |
1418
+ | :<= | connection, if outside behavior |
1419
+ | :<= | transmission, if inside behavior |
1420
+
1421
+ __Arithmetic operators:__
1422
+
1423
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1424
+ | :--- | :--- |
1425
+ | :+ | addition |
1426
+ | :- | subtraction |
1427
+ | :\* | multiplication |
1428
+ | :/ | division |
1429
+ | :% | modulo |
1430
+ | :\*\* | power |
1431
+ | :+@ | positive sign |
1432
+ | :-@ | negation |
1433
+
1434
+ __Comparison operators:__
1435
+
1436
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1437
+ | :--- | :--- |
1438
+ | :== | equality |
1439
+ | :!= | difference |
1440
+ | :> | greater than |
1441
+ | :< | smaller than |
1442
+ | :>= | greater or equal |
1443
+ | :<= | smaller or equal |
1444
+
1445
+ __Logic and shift operators:__
1446
+
1447
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1448
+ | :--- | :--- |
1449
+ | :& | bitwise / logical and |
1450
+ | :| | bitwise / logical or |
1451
+ | :~ | bitwise / logical not |
1452
+ | :mux | multiplex |
1453
+ | :<< / :ls | left shift |
1454
+ | :>> / :rs | right shift |
1455
+ | :lr | left rotate |
1456
+ | :rr | right rotate |
1457
+
1458
+ __Conversion operators:__
1459
+
1460
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1461
+ | :--- | :--- |
1462
+ | :to\_bit | cast to bit vector |
1463
+ | :to\_unsigned | cast to unsigned vector |
1464
+ | :to\_signed | cast to signed vector |
1465
+ | :to\_big | cast to big endian |
1466
+ | :to\_little | cast to little endian |
1467
+ | :reverse | reverse the bit order |
1468
+ | :ljust | increase width from the left, preserves the sign |
1469
+ | :rjust | increase width from the right, preserves the sign |
1470
+ | :zext | zero extension, converts to unsigned if signed |
1471
+ | :sext | sign extension, converts to sign |
1472
+
1473
+ __Selection /concatenation operators:__
1474
+
1475
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symbol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
1476
+ | :--- | :--- |
1477
+ | :[] | sub vector selection |
1478
+ | :@[] | concatenation operator |
1479
+ | :. | field selection |
1480
+
1481
+
1482
+ __Notes__:
1483
+
1484
+ - The operator precedence is the one of Ruby.
1485
+
1486
+ - Ruby does not allow to override the `&&`, the `||` and the `?:` operators so that they are not present in HDLRuby. Instead of the `?:` operator, HDLRuby provides the more general multiplex operator `mux`. However, HDLRuby does not provides any replacement for the `&&` and the `||` operators, please refer to section [Logic operators](#logic) for a justification about this issue.
1487
+
1488
+ #### Assignment operators
1489
+ <a name="assignment"></a>
1490
+
1491
+ The assignment operators can be used with any type. They are actually the connection and the transmission operators, both being represented by `<=`.
1492
+
1493
+ __Note__:
1494
+
1495
+ - The first operator of a statement is necessarily an assignment operator, while the other occurrences of `<=` represent the usual `less than or equal to` operators.
1496
+
1497
+ #### Arithmetic operators
1498
+ <a name="arithmetic"></a>
1499
+
1500
+ The arithmetic operators can only be used on vectors of `bit`, `unsigned` or `signed` values, `integer` or `float` values. These operators are `+`, `-`, `*`, `%` and the unary arithmetic operators are `-` and `+`. They have the same meaning as their Ruby equivalents.
1501
+
1502
+ #### Comparison operators
1503
+ <a name="comparison"></a>
1504
+
1505
+ Comparison operators are the operators whose result is either true or false.
1506
+ In HDLRuby, true and false are represented by respectively `bit` value 1 and `bit` value 0. This operators are `==`, `!=`, `<`, `>`, `<=`, `>=` . They
1507
+ have the same meaning as their Ruby equivalents.
1508
+
1509
+ __Notes__:
1510
+
1511
+ - The `<`, `>`, `<=` and `>=` operators can only be used on vectors of `bit`, `unsigned` or `signed` values, `integer` or `float` values.
1512
+
1513
+ - When compared, values of type different from vector of `signed` and from `float` are considered as vectors of `unsigned`.
1514
+
1515
+
1516
+ #### Logic and shift operators
1517
+ <a name="logic"></a>
1518
+
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
+
1521
+ __Note__: there is two reasons why there is no boolean operators
1522
+
1523
+ 1. Ruby language does not support redefinition of the boolean operators
1524
+
1525
+ 2. In Ruby, each value which is not `false` nor `nil` is considered 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
+
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
+
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 actually used like methods as follows:
1530
+
1531
+ ```ruby
1532
+ <expression>.rl(<other expression>)
1533
+ <expression>.rr(<other expression>)
1534
+ ```
1535
+
1536
+ For example, for rotating left signal `sig` 3 times, the following code can be used:
1537
+
1538
+ ```ruby
1539
+ sig.rl(3)
1540
+ ```
1541
+
1542
+ It is possible to perform other kinds of shifts or rotations using the selection and the concatenation operators. Please refer to section [Concatenation and
1543
+ selection operators](#concat) for more details about these operators.
1544
+
1545
+
1546
+ #### Conversion operators
1547
+ <a name="conversion"></a>
1548
+
1549
+ The conversion operators are used to change the type of an expression.
1550
+ There are two kinds of such operators: the type pun that do not change the raw value of the expression and the type cast that changes the raw value.
1551
+
1552
+ The type puns include `to_bit`, `to_unsigned` and `to_signed` that convert expressions of any type type to vectors of respectively `bit`, `unsigned` and `signed` elements. For example, the following code converts an expression of hierarchical type to an 8-bit signed vector:
1553
+
1554
+ ```ruby
1555
+ [ up: signed[3..0], down: unsigned[3..0] ].inner :sig
1556
+ sig.to_bit <= b01010011
1557
+ ```
1558
+
1559
+ 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 `unsinged` and can only increase the bit width (bit width can be truncated using the selection operator, please refer to the [next section](#concat)).
1560
+ These operators comprise the bit width conversions: `ljust`, `rjust`, `zext` and `sext`; they also comprise the bit endianness conversions: `to_big`, `to_little` and `reverse`.
1561
+
1562
+ More precisely, the bit width conversions operate as follows:
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:
1565
+
1566
+ ```ruby
1567
+ [7..0].inner :sig0
1568
+ [11..0].inner :sig1
1569
+ sig0 <= 25
1570
+ sig1 <= sig0.ljust(12,1)
1571
+ ```
1572
+
1573
+ - `zext` increases the size by adding several 0 bits on the most significant bit side, this side depending on the endianness of the expression. This conversion takes as argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 0 on the left:
1574
+
1575
+ ```ruby
1576
+ signed[7..0].inner :sig0
1577
+ [11..0].inner :sig1
1578
+ sig0 <= -120
1579
+ sig1 <= sig0.zext(12)
1580
+ ```
1581
+
1582
+ - `sext` increases the size by duplicating the most significant bit, the side of the extension depending on the endianness of the expression. This conversion takes as argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
1583
+
1584
+ ```ruby
1585
+ signed[0..7].inner :sig0
1586
+ [0..11].inner :sig1
1587
+ sig0 <= -120
1588
+ sig1 <= sig0.sext(12)
1589
+ ```
1590
+
1591
+ Finally, the bit endianness conversions operate as follows:
1592
+
1593
+ - `to_big` ensures the type of the converted expression is big endian. If the initial expression is already big endian, it is left as is, otherwise its bits are reversed.
1594
+
1595
+ - `to_little` ensures the type of the converted expression is little endian. If the initial expression is already little endian, it is left as is, otherwise its bits are reversed.
1596
+
1597
+ - `reverse` always reverses the bit order of the expression.
1598
+
1599
+
1600
+ #### Concatenation and selection operators
1601
+ <a name="concat"></a>
1602
+
1603
+ Concatenation and selection are done using the `[]` operator as follows:
1604
+
1605
+ - when this operator takes as arguments several expressions, it concatenates them. For example, the following code concatenates `sig0` to `sig1`:
1606
+
1607
+ ```ruby
1608
+ [3..0].inner :sig0
1609
+ [7..0].inner :sig1
1610
+ [11..0].inner :sig2
1611
+ sig0 <= 5
1612
+ sig1 <= 6
1613
+ sig2 <= [sig0, sig1]
1614
+ ```
1615
+
1616
+ - when this operator is applied to an expression of `bit`, `unsigned` or `signed` vector type while taking as argument a range, it selects the bits corresponding to this range. If only one bit is to select, the offset of this bit can be used instead. For example, the following code selects bits from 3 to 1 of `sig0` and bit 4 of `sig1`:
1617
+
1618
+ ```ruby
1619
+ [7..0].inner :sig0
1620
+ [7..0].inner :sig1
1621
+ [3..0].inner :sig2
1622
+ bit.inner :sig3
1623
+ sig0 <= 5
1624
+ sig1 <= 6
1625
+ sig2 <= sig0[3..1]
1626
+ sig3 <= sig1[4]
1627
+ ```
1628
+
1629
+ #### Implicit conversions
1630
+ <a name="implicit"></a>
1631
+
1632
+ When there is no ambiguity with bit vector types of same endianness, 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:
1633
+
1634
+ - `operator` is the operator in use
1635
+ - `result width` is the width of the result's type
1636
+ - `result base` is the base type of the result's type
1637
+ - `S` is the shortest operand
1638
+ - `L` is the longest operand
1639
+ - `S operand type` is the base type of the shortest operand
1640
+ - `L operand type` is the base type of the longest operand
1641
+ - `operand conversion` is the conversions added to make the operands
1642
+ compatible.
1643
+ - `w` is the width of the operands after conversion
1644
+ - `lw` is the width of the left operand's type before conversion
1645
+ - `rw` is the width of the right operand's type before conversion
1646
+
1647
+
1648
+
1649
+ __Additive and logical operators:__
1650
+
1651
+ | operator | result's width |
1652
+ | :--- | :--- |
1653
+ | <= (assign) | w (error is raised if L.width < R.width) |
1654
+ | +, - | w+1 |
1655
+ | &, \|, ^ | w |
1656
+ | == | 1 |
1657
+ | < | 1 |
1658
+ | > | 1 |
1659
+ | <= (comp.) | 1 |
1660
+ | >= | 1 |
1661
+
1662
+ | S operand base | L operand base | result base | operand conversion |
1663
+ | :--- | :--- | :--- | :--- |
1664
+ | bit | bit | bit | S.zext(L.width) |
1665
+ | bit | unsigned | unsigned | S.zext(L.width).to_unsigned |
1666
+ | bit | signed | signed | S.zext(max(S.width+1,L.width).to_signed |
1667
+ | unsigned | bit | unsigned | S.zext(L.width), L.to_unsigned |
1668
+ | unsigned | unsigned | unsigned | S.zext(L.width) |
1669
+ | unsigned | signed | signed | S.zext(max(S.width+1,L.width).to_signed |
1670
+ | signed | bit | signed | S.sext(L.width+1), L.zext(L.width+1).to_signed |
1671
+ | signed | unsigned | signed | S.sext(L.width+1), L.zext(L.width+1).to_signed |
1672
+ | signed | signed | signed | S.sext(L.width) |
1673
+
1674
+
1675
+ __Multiplicative operators:__
1676
+
1677
+ | operator | result width |
1678
+ | :--- | :--- |
1679
+ | * | lw * rw |
1680
+ | / | lw |
1681
+ | % | rw |
1682
+ | ** | rw |
1683
+ | << / ls | lw |
1684
+ | >> / rs | lw |
1685
+ | lr | lw |
1686
+ | rr | lw |
1687
+
1688
+ | S operand base | L operand base | result base | operand conversion |
1689
+ | :--- | :--- | :--- | :--- |
1690
+ | bit | bit | bit | |
1691
+ | bit | unsigned | unsigned | S.to_unsigned |
1692
+ | bit | signed | signed | S.zext(S.width+1).to_signed |
1693
+ | unsigned | bit | unsigned | L.to_unsigned |
1694
+ | unsigned | unsigned | unsigned | |
1695
+ | unsigned | signed | signed | S.zext(S.width).to_signed |
1696
+ | signed | bit | signed | L.zext(L.width+1).to_signed |
1697
+ | signed | unsigned | signed | L.zext(L.width+1).to_signed |
1698
+ | signed | signed | signed | |
1699
+
1700
+
1701
+ ## Functions
1702
+
1703
+ ### HDLRuby functions
1704
+
1705
+ Similarly to Verilog HDL, HDLRuby provides function constructs for reusing code. HDLRuby functions are declared as follows:
1706
+
1707
+ ```ruby
1708
+ function :<function name> do |<arguments>|
1709
+ <code>
1710
+ end
1711
+ ```
1712
+
1713
+ Where:
1714
+
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
+
1719
+ __Notes__:
1720
+
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
+
1723
+ - Similarly to 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
+
1725
+ ```ruby
1726
+ function :one { 1 }
1727
+ ```
1728
+
1729
+ - Functions can accept any kind of object as argument, including variadic arguments or blocks of code as shown bellow with a function which apply the code passed as argument to all the variadic arguments of `args`:
1730
+
1731
+ ```ruby
1732
+ function :apply do |*args, &code|
1733
+ args.each { |arg| code.call(args) }
1734
+ end
1735
+ ```
1736
+
1737
+ 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`):
1738
+ ```ruby
1739
+ apply(x,y,z) { |v| v <= sig }
1740
+ ```
1741
+
1742
+ A function can be invoked anywhere in the code using its name and passing its argument between parentheses as follows:
1743
+
1744
+ ```ruby
1745
+ <function name>(<list of values>)
1746
+ ```
1747
+
1748
+
1749
+
1750
+ ### Ruby functions
1751
+
1752
+ HDLRuby functions are useful for reusing code, but they cannot interact with the code they are called in. For example, it is not possible to add interface signals through a function nor to modify a control statement (e.g., `hif`) with them. These high-level generic operations can however be performed using the functions of the Ruby language declared as follows:
1753
+
1754
+ ```ruby
1755
+ def <function name>(<arguments>)
1756
+ <code>
1757
+ end
1758
+ ```
1759
+ Where:
1760
+
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
+
1765
+ These functions are called the same way HDLRuby functions are called, but this operation actually pastes the code of the function as is within the code.
1766
+ Moreover, these function do not have any scope so that any inner signal or instance declared within them will actually added to the object they are invoked in.
1767
+
1768
+ For example, the following function will add input `in0` to any system where it is invoked:
1769
+
1770
+ ```ruby
1771
+ def add_in0
1772
+ input :in0
1773
+ end
1774
+ ```
1775
+
1776
+ This function can be used as follows:
1777
+
1778
+ ```ruby
1779
+ system :sys do
1780
+ ...
1781
+ add_in0
1782
+ ...
1783
+ end
1784
+ ```
1785
+
1786
+ As another example, following function will add an alternative code that generates a reset to a condition statement (`hif` or `hcase`):
1787
+
1788
+ ```ruby
1789
+ def too_bad
1790
+ helse { $rst <= 1 }
1791
+ end
1792
+ ```
1793
+
1794
+ This function can be used as follows:
1795
+
1796
+ ```ruby
1797
+ system :sys do
1798
+ ...
1799
+ par do
1800
+ hif(sig == 1) do
1801
+ ...
1802
+ end
1803
+ too_bad
1804
+ end
1805
+ end
1806
+ ```
1807
+
1808
+ Ruby functions can be compared to the macros of the C languages: they have more flexible since they actually edit the code they are invoked in, but 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
+
1810
+
1811
+ ## Time
1812
+ <a name="time"></a>
1813
+
1814
+ ### Time values
1815
+ <a name="time_val"></a>
1816
+
1817
+ In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for millisecond, `us` for microsecond, `ns` for nano second, `ps` for pico second and `fs` for femto second. For example, the followings are all indicating one second of time:
1818
+
1819
+ ```ruby
1820
+ 1.s
1821
+ 1000.ms
1822
+ 1000000.us
1823
+ 1000000000.ns
1824
+ 1000000000000.ps
1825
+ 1000000000000000.fs
1826
+ ```
1827
+
1828
+
1829
+ ### Time behaviors and time statements
1830
+ <a name="time_beh"></a>
1831
+
1832
+ Similarly to 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
+
1834
+ ```ruby
1835
+ timed do
1836
+ <statements>
1837
+ end
1838
+ ```
1839
+
1840
+ A time behavior do not have any sensitivity list but it can include any statement supported by a standard behavior in addition to the time statements.
1841
+ There are two kinds of such statements:
1842
+
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:
1846
+
1847
+ ```ruby
1848
+ wait(10.ns)
1849
+ ```
1850
+
1851
+ This statement can also be abbreviated using the `!` operator as follows:
1852
+
1853
+ ```ruby
1854
+ !10.ns
1855
+ ```
1856
+
1857
+ - The `repeat` statements: such a statement takes as argument a time value and a block. The execution of the block is repeated until the delay given by the time value argument expires. For example, the following code executes repeatedly the inversion of the `clk` signal every 10 nanoseconds for 10 seconds (i.e., it simulates a clock signal for 10 seconds):
1858
+
1859
+ ```ruby
1860
+ repeat(10.s) do
1861
+ !10.ns
1862
+ clk <= ~clk
1863
+ end
1864
+ ```
1865
+
1866
+ ### Parallel and sequential execution
1867
+
1868
+ Time behaviors are by default sequential but they can include both parallel and
1869
+ sequential blocks. The execution semantic is the following:
1870
+
1871
+ - A sequential block in a time behavior is executed sequentially.
1872
+
1873
+ - A parallel block in a time behavior is executed in semi-parallel fashion as follows:
1874
+
1875
+ 1. Statements are grouped in sequence until a time statement is met.
1876
+
1877
+ 2. The grouped sequence are executed in parallel.
1878
+
1879
+ 3. The time statement is executed.
1880
+
1881
+ 4. The subsequent statements are processed the same way.
1882
+
1883
+
1884
+
1885
+ ## High-level programming features
1886
+ <a name="highfeat"></a>
1887
+
1888
+ ### Using Ruby in HDLRuby
1889
+
1890
+ Since HDLRuby is pure Ruby code, the constructs of Ruby can be freely used without any compatibility issue. Moreover, this Ruby code will not interfere with the synthesizability of the design. It is then possible to define Ruby classes, methods or modules whose execution generates constructs of
1891
+ HDLRuby.
1892
+
1893
+
1894
+ ### Generic programming
1895
+
1896
+ #### Declaring
1897
+
1898
+ ##### Declaring generic systems
1899
+
1900
+ Systems can be declared with generic parameters as follows:
1901
+
1902
+ ```ruby
1903
+ system :<system name> do |<list of generic parameters>|
1904
+ ...
1905
+ end
1906
+ ```
1907
+
1908
+ For example, the following code describes an empty system with two generic parameters named respectively `a` and `b`:
1909
+
1910
+ ```ruby
1911
+ system(:nothing) { |a,b| }
1912
+ ```
1913
+
1914
+ The generic parameters can be anything: values, data types, systems, Ruby variables, and so on. For example, the following system uses generic argument
1915
+ `t` as a type for an input signal, generic argument `w` as a bit range for an
1916
+ output signal and generic argument `s` as a system used for creating instance
1917
+ `sI` whose input and output signals `i` and `o` are connected respectively to
1918
+ signals `isig` and `osig`.
1919
+
1920
+ ```ruby
1921
+ system :something do |t,w,s|
1922
+ t.input isig
1923
+ [w].output osig
1924
+
1925
+ s :sI.(i: isig, o: osig)
1926
+ end
1927
+ ```
1928
+
1929
+ It is also possible to use a variable number of generic parameters using the variadic operator `*` like in the following example. In this examples, `args` is an array containing an indefinite number of parameters.
1930
+
1931
+ ```ruby
1932
+ system(:variadic) { |*args| }
1933
+ ```
1934
+
1935
+ ##### Declaring generic types
1936
+
1937
+ Data types can be declared with generic parameters as follows:
1938
+
1939
+ ```ruby
1940
+ typedef :<type name> do |<list of generic parameters>|
1941
+ ...
1942
+ end
1943
+ ```
1944
+
1945
+ For example, the following code describes a bit-vector type with generic number of bits `width`:
1946
+
1947
+ ```ruby
1948
+ type(:bitvec) { |width| bit[width] }
1949
+ ```
1950
+
1951
+ Like with the systems, the generic parameters of types can be any kind of objects, and it is also possible to use variadic arguments.
1952
+
1953
+
1954
+
1955
+ #### Specializing
1956
+
1957
+ ##### Specializing generic systems
1958
+
1959
+ A generic system is specialized by invoking its name and passing as argument the values corresponding to the generic arguments as follows:
1960
+
1961
+ ```ruby
1962
+ <system name>(<generic argument value's list>)
1963
+ ```
1964
+
1965
+ If less values are provided than the number of generic arguments, the system is partially specialized. However, only a fully specialized system can be instantiated.
1966
+
1967
+ A specialized system can also be used for inheritance. For example, assuming system `sys` has 2 generic arguments, it can be specialized and used for building system `subsys` as follows:
1968
+
1969
+ ```ruby
1970
+ system :subsys, sys(1,2) do
1971
+ ...
1972
+ end
1973
+ ```
1974
+
1975
+ This way of inheriting can only be done with fully specialized systems though. For partially specialized systems, `include` must be used instead. For example, if `sys` specialized with only one value, can be used in generic `subsys_gen` as follows:
1976
+
1977
+ ```ruby
1978
+ system :subsys_gen do |param|
1979
+ include sys(1,param)
1980
+ ...
1981
+ end
1982
+ ```
1983
+
1984
+ __Note:__
1985
+
1986
+ - In the example above, generic parameter `param` of `sybsys_gen` is used for specializing system `sys`.
1987
+
1988
+
1989
+ ##### Specializing generic types
1990
+
1991
+ A generic type is specialized by invoking its name and passing as argument the values corresponding to the generic arguments as follows:
1992
+
1993
+ ```ruby
1994
+ <type name>(<generic argument value's list>)
1995
+ ```
1996
+
1997
+ If less values are provided than the number of generic arguments, the type is partially specialized. However, only a fully specialized type can be used for declaring signals.
1998
+
1999
+
2000
+ ### Inheritance
2001
+ <a name="inherit"></a>
2002
+
2003
+ #### Basics
2004
+
2005
+ 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
+ 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
+
2008
+ For example, the following code describes first a simple D-FF, and then use it to described a FF with an additional reversed output (`qb`):
2009
+
2010
+ ```ruby
2011
+ system :dff do
2012
+ input :clk, :rst, :d
2013
+ output :q
2014
+
2015
+ par(clk.posedge) { q <= d & ~rst }
2016
+ end
2017
+
2018
+ system :dff_full do
2019
+ output :qb
2020
+
2021
+ include dff
2022
+
2023
+ qb <= ~q
2024
+ end
2025
+ ```
2026
+
2027
+ 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
+
2029
+ ```ruby
2030
+ system :<new system name>, <list of parent systems> do
2031
+ <additional system code>
2032
+ end
2033
+ ```
2034
+
2035
+ For example, the following code is another to describe `dff_full`:
2036
+
2037
+ ```ruby
2038
+ system :dff_full, dff do
2039
+ output :qb
2040
+
2041
+ qb <= ~q
2042
+ end
2043
+ ```
2044
+
2045
+ __Note__:
2046
+
2047
+ - As a matter of implementation, HDLRuby systems can be seen as set of methods used for accessing various constructs (signals, instances). Hence inheritance in HDLRuby is actually closer the Ruby mixin mechanism than to a true software inheritance.
2048
+
2049
+
2050
+ #### About inner signals and system instances
2051
+
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
2053
+ code exports signals `clk` and `rst` and instance `dff0` of system `exporter` so that they can be accessed in child system `importer`.
2054
+
2055
+ ```ruby
2056
+ system :exporter do
2057
+ input :d
2058
+ inner :clk, :rst
2059
+
2060
+ dff(:dff0).(clk: clk, rst: rst, d: d)
2061
+
2062
+ export :clk, :rst, :dff0
2063
+ end
2064
+
2065
+ system :importer, exporter do
2066
+ input :clk0, :rst0
2067
+ output :q
2068
+
2069
+ clk <= clk0
2070
+ rst <= rst0
2071
+ dff0.q <= q
2072
+ end
2073
+ ```
2074
+
2075
+ __Note__:
2076
+ - export takes as arguments the symbols (or the strings) representing the name of the components to export *and not* a reference to them. For instance, the following code is invalid:
2077
+
2078
+ ```ruby
2079
+ system :exporter do
2080
+ input :d
2081
+ inner :clk, :rst
2082
+
2083
+ dff(:dff0).(clk: clk, rst: rst, d: d)
2084
+
2085
+ export clk, rst, dff0
2086
+ end
2087
+ ```
2088
+
2089
+ #### Conflicts when inheriting
2090
+
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`:
2092
+
2093
+ ```ruby
2094
+ system :dff_bad, dff do
2095
+ input :rst
2096
+ end
2097
+ ```
2098
+
2099
+ Conflicts among several inherited systems can be avoided by renaming the signals and instances that collide with one another as shown in the next
2100
+ section.
2101
+
2102
+
2103
+ #### Shadowed signals and instances
2104
+
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.
2106
+
2107
+ 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
+
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.
2110
+
2111
+ ```ruby
2112
+ system :dff_db do
2113
+ input :clk,:rst,:d
2114
+ inner :db
2115
+ output :q
2116
+
2117
+ db <= ~d
2118
+ (q <= d & ~rst).at(clk.posedge)
2119
+ end
2120
+
2121
+ system :dff_shadow, dff_db do
2122
+ output :qb, :db
2123
+
2124
+ db <= ~d
2125
+ qb <= as(dff_db).db
2126
+ end
2127
+ ```
2128
+
2129
+
2130
+
2131
+ ### Opening a system
2132
+ <a name="system_open"></a>
2133
+
2134
+ It is possible to pursue the definition of a system after it has been declared using the `open` methods as follows:
2135
+
2136
+ ```ruby
2137
+ <system>.open do
2138
+ <additional system description>
2139
+ end
2140
+ ```
2141
+
2142
+ For example `dff`, a system describing a D-FF, can be modified to have an inverted output as follows:
2143
+
2144
+ ```ruby
2145
+ dff.open do
2146
+ output :qb
2147
+
2148
+ qb <= ~q
2149
+ end
2150
+ ```
2151
+
2152
+
2153
+ ### Opening an instance
2154
+ <a name="instance_open"></a>
2155
+
2156
+ When there is a modification to apply to an instance, it is sometimes preferable to modify this sole instance rather than declaring a all new system to derivate the instance from. For that purpose it is possible to open an instance for modification as follows:
2157
+
2158
+ ```ruby
2159
+ <instance name>.open do
2160
+ <additional description for the instance>
2161
+ end
2162
+ ```
2163
+
2164
+ For example, an instance of the previous `dff` system can be extended with an inverted output as follows:
2165
+ ```ruby
2166
+ system :some_system do
2167
+ ...
2168
+ dff :dff0
2169
+ dff0.open do
2170
+ output :qb
2171
+ qb <= ~q
2172
+ end
2173
+ ...
2174
+ end
2175
+ ```
2176
+
2177
+
2178
+
2179
+ ### Overloading of operators
2180
+
2181
+ Operators can be overloaded for specific types. This allows for instance to support seamlessly fixed-point computations without requiring explicit readjustment of the position of the decimal point.
2182
+
2183
+ An operator is redefined as follows:
2184
+
2185
+ ```ruby
2186
+ <type>.define_operaot(:<op>) do |<args>|
2187
+ <operation description>
2188
+ end
2189
+ ```
2190
+
2191
+ Where:
2192
+
2193
+ - `type` is the type from which the operation is overloaded.
2194
+ - `op` is the operator that is overloaded (e.g., `+`)
2195
+ - `args` are the arguments of the operation.
2196
+ - `operation description` is an HDLRuby description of the new operation.
2197
+
2198
+ For example, for `fix32` a 32-bit (decimal point at 16-bit) fixed point type defined as follows:
2199
+
2200
+ ```ruby
2201
+ signed[31..0].typedef(:fix32)
2202
+ ```
2203
+
2204
+ The multiplication operator can be overloaded as follows to ensure the decimal point have always the right position:
2205
+
2206
+ ```ruby
2207
+ fix32.define_operator(:*) do |left,right|
2208
+ (left.as(signed[31..0]) * right) >> 16
2209
+ end
2210
+ ```
2211
+
2212
+ 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
+
2214
+ 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 point type of variable width (and whose decimal point is set at the half of its bit range):
2216
+
2217
+ ```ruby
2218
+ typedef(:fixed) do |width|
2219
+ signed[(width-1)..0]
2220
+ end
2221
+ ```
2222
+
2223
+ The multiplication operator would be overloaded as follows:
2224
+
2225
+ ```ruby
2226
+ fixed.define_operator do |width,left,right|
2227
+ (left.as(signed[(width-1)..0]) * right) >> width/2
2228
+ end
2229
+ ```
2230
+
2231
+ ### Predicate and access methods
2232
+
2233
+ In order to get information about the current state of the hardware description HDLRuby provides the following predicates:
2234
+
2235
+ | predicate name | predicate type | predicate meaning |
2236
+ | :--- | :--- | :--- |
2237
+ | `is_block?` | bit | tells if in execution block |
2238
+ | `is_par?` | bit | tells if current parallel block is parallel|
2239
+ | `is_seq?` | bit | tells if current parallel block is sequential|
2240
+ | `is_clocked?` | bit | tells if current behavior is clocked (activated on a sole rising or falling edge of a signal) |
2241
+ | `cur_block` | block | gets the current block |
2242
+ | `cur_behavior` | behavior | gets the current behavior |
2243
+ | `cur_systemT` | system | gets the current system |
2244
+ | `one_up` | block/system | gets the upper construct (block or system) |
2245
+ | `last_one` | any | last declared construct |
2246
+
2247
+ Several enumerators are also provided for accessing the internals of the current construct (in the current state):
2248
+
2249
+ | enumerator name | accessed elements |
2250
+ | :--- | :--- |
2251
+ | `each_input` | input signals of the current system |
2252
+ | `each_output` | output signals of the current system |
2253
+ | `each_inout` | inout signals of the current system |
2254
+ | `each_behavior` | behaviors of the current system |
2255
+ | `each_event` | events of the current behavior |
2256
+ | `each_block` | blocks of the current behavior |
2257
+ | `each_statement` | statements of the current block |
2258
+ | `each_inner` | inner signals of the current block (or system if not within a block) |
2259
+
2260
+ ### Global signals
2261
+
2262
+ HDLRuby allows to declare 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.
2263
+
2264
+ In order to ease the design of standardized libraries, the following global signals are defined by default:
2265
+
2266
+ | signal name | signal type | signal function |
2267
+ | :--- | :--- | :--- |
2268
+ | `$reset` | bit | global reset |
2269
+ | `$resetb` | bit | global reset complement |
2270
+ | `$clk` | bit | global clock |
2271
+
2272
+ __Note__:
2273
+
2274
+ - When not used, the global signals are discarded.
2275
+
2276
+
2277
+
2278
+ ### Defining and executing Ruby methods within HDLRuby constructs
2279
+ <a name="method"></a>
2280
+
2281
+ 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
+
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`.
2284
+
2285
+ ```ruby
2286
+ def some_arrow
2287
+ sig1 <= sig0
2288
+ end
2289
+
2290
+ system :sys0 do
2291
+ input :sig0
2292
+ output :sig1
2293
+
2294
+ some_arrow
2295
+ end
2296
+
2297
+ system :sys1 do
2298
+ input :sig0, :clk
2299
+ output :sig1
2300
+
2301
+ par(clk.posedge) do
2302
+ some_arrow
2303
+ end
2304
+ end
2305
+ ```
2306
+
2307
+ __Warning__:
2308
+
2309
+ - 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
+
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 problems 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
+
2313
+ ```ruby
2314
+ def in_decl
2315
+ input :in0
2316
+ end
2317
+
2318
+ system :sys0 do
2319
+ in_decl
2320
+ end
2321
+
2322
+ system :sys1 do
2323
+ input :in0
2324
+ in_decl
2325
+ end
2326
+
2327
+ system :sys2 do
2328
+ par do
2329
+ in_decl
2330
+ end
2331
+ end
2332
+ ```
2333
+
2334
+ Like any other Ruby method, methods defined in HDLRuby support variadic arguments, named arguments and block arguments. For example, the following method can be used to connects a driver to multiple signals:
2335
+
2336
+ ```ruby
2337
+ def mconnect(driver, *signals)
2338
+ signals.each do |signal|
2339
+ signal <= driver
2340
+ end
2341
+ end
2342
+
2343
+ system :sys0 do
2344
+ input :i0
2345
+ input :o0, :o1, :o2, :o3
2346
+
2347
+ mconnect(i0,o0,o1,o2,o3)
2348
+ end
2349
+ ```
2350
+
2351
+
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:
2353
+
2354
+ ```ruby
2355
+ def after(cycles,rst = $rst, &code)
2356
+ sub do
2357
+ inner :count
2358
+ hif rst == 1 do
2359
+ count <= 0
2360
+ end
2361
+ helse do
2362
+ hif count < cycles do
2363
+ count <= count + 1
2364
+ end
2365
+ helse do
2366
+ instance_eval(&code)
2367
+ end
2368
+ end
2369
+ end
2370
+ end
2371
+ ```
2372
+
2373
+ In the code above:
2374
+
2375
+ - the default initialization of `rst` to `$rst` allows to reset the counter even if no such signal it provided as argument.
2376
+
2377
+ - `sub` ensures that the `count` signal do not conflict with another signal with the same name.
2378
+
2379
+ - the `instance_eval` keyword is a standard Ruby method that executes the block passed as argument in context.
2380
+
2381
+ The following is an example that switches a LED on after 1000000 clock cycles using the previously defined `after` ruby method:
2382
+
2383
+ ```ruby
2384
+ system :led_after do
2385
+ output :led
2386
+ input :clk
2387
+
2388
+ par(clk.posedge) do
2389
+ (led <= 0).hif($rst)
2390
+ after(100000) { led <= 1 }
2391
+ end
2392
+ end
2393
+ ```
2394
+
2395
+ __Note__:
2396
+
2397
+ - 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 signal declared in this method will not collide with them.
2398
+
2399
+
2400
+ ### Dynamic description
2401
+
2402
+ When describing a system, it is possible to disconnect or to completely undefine a signal or an instance.
2403
+
2404
+
2405
+ ## Extending HDLRuby
2406
+ <a name="extend"></a>
2407
+
2408
+ Like any Ruby classes, the constructs of HDLRuby can be dynamically extended. If it is not recommended to change their internal structure, it is possible to add methods to them for extension.
2409
+
2410
+ ### Extending HDLRuby constructs globally
2411
+
2412
+ By gobal extension of hardware constructs we actually mean the classical extension of Ruby classes by monkey patching the corresponding class. For example, it is possible to add a methods giving the number of signals in the interface of a system instance as follows:
2413
+
2414
+ ```ruby
2415
+ class SystemI
2416
+ def interface_size
2417
+ return each_input.size + each_output.size + each_inout.size
2418
+ end
2419
+ end
2420
+ ```
2421
+
2422
+ From there, the method `interface_size` can be used on any system instance as follows: `<system instance>.interface_size`.
2423
+
2424
+ The following table gives the class of each construct of HDLRuby.
2425
+
2426
+ | construct | class |
2427
+ | :--- | :--- |
2428
+ | data type | Type |
2429
+ | system | SystemT |
2430
+ | scope | Scope |
2431
+ | system instance | SystemI |
2432
+ | signal | Signal |
2433
+ | connection | Connection |
2434
+ | par/seq | Behavior |
2435
+ | timed | TimeBehavior |
2436
+ | event | Event |
2437
+ | par/seq/sub | Block |
2438
+ | transmit | Transmit |
2439
+ | hif | If |
2440
+ | hcase | Case |
2441
+
2442
+
2443
+ ### Extending HDLRuby constructs locally
2444
+
2445
+ 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 in 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`:
2446
+
2447
+ ```ruby
2448
+ dff.singleton_class.class_eval do
2449
+ def interface_size
2450
+ return each_input.size + each_output.size + each_inout.size
2451
+ end
2452
+ end
2453
+ ```
2454
+
2455
+ It is also possible to extend locally an instance using the same methods.
2456
+ For example, with the following code, only instance `dff0` will respond to method `interface_size`:
2457
+
2458
+ ```ruby
2459
+ dff :dff0
2460
+
2461
+ dff0.singleton_class.class_eval do
2462
+ def interface_size
2463
+ return each_input.size + each_output.size + each_inout.size
2464
+ end
2465
+ end
2466
+ ```
2467
+
2468
+ Finally, it is possible to extend locally all the instances of a system using method `singleton_instance` in place of method `singleton_class`.
2469
+ For example, with the following code, all the instances of system `dff` will respond to method `interface_size`:
2470
+
2471
+ ```ruby
2472
+ dff.singleton_instance.class_eval do
2473
+ def interface_size
2474
+ return each_input.size + each_output.size + each_inout.size
2475
+ end
2476
+ end
2477
+ ```
2478
+
2479
+ ### Modifying the generation behavior
2480
+
2481
+ The main purpose of allowing global and local extensions for hardware constructs is to give the user the possibility implements its own synthesis methods. For example, one may want to implement some algorithm for a given kind of system. For that purpose, the user can define an abstract system (without any hardware content), that holds the specific algorithm as follows:
2482
+
2483
+ ```ruby
2484
+ system(:my_base) {}
2485
+
2486
+ my_base.singleton_instance.class_eval do
2487
+ def my_generation
2488
+ <some code>
2489
+ end
2490
+ end
2491
+ ```
2492
+
2493
+ Then, when this system named `my_base` is included into another system, this latter will inherit from the algorithms implemented inside method `my_generation` as shown in the following code:
2494
+
2495
+ ```ruby
2496
+ system :some_system, my_base do
2497
+ <some system description>
2498
+ end
2499
+ ```
2500
+
2501
+ However, when generation the low-level description of this system, code similar to the following will have to be written for applying `my_generation`:
2502
+
2503
+ ```ruby
2504
+ some_system :instance0
2505
+ instance0.my_generation
2506
+ low = instance0.to_low
2507
+ ```
2508
+
2509
+ This can be avoided by redefining the `to_low` method as follows:
2510
+
2511
+ ```ruby
2512
+ system(:my_base) {}
2513
+
2514
+ my_base.singleton_instance.class_eval do
2515
+ def my_generation
2516
+ <some code>
2517
+ end
2518
+
2519
+ alias :_to_low :to_low
2520
+ def to_low
2521
+ my_generation
2522
+ _to_low
2523
+ end
2524
+ end
2525
+ ```
2526
+
2527
+ This way, calling directly `to_low` will automatically use `my_generation`.
2528
+
2529
+
2530
+
2531
+
2532
+
2533
+
2534
+ # Standard library
2535
+ <a name="library"></a>
2536
+
2537
+ The standard libraries are included into the module `Std`.
2538
+ They can be loaded as follows, where `<library name>` is the name of the
2539
+ library:
2540
+
2541
+ ```ruby
2542
+ require 'std/<library name>'
2543
+ ```
2544
+
2545
+ After the libraries are loaded, the module `Std` must be included as follows:
2546
+
2547
+ ```ruby
2548
+ include HDLRuby::High::Std
2549
+ ```
2550
+
2551
+
2552
+
2553
+ ## Clocks
2554
+ <a name="clocks"></a>
2555
+
2556
+ The `clocks` library provides utilities for an easier handling of clock synchronizations.
2557
+
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.
2559
+
2560
+ ```ruby
2561
+ require 'std/clocks'
2562
+ include HDLRuby::High::Std
2563
+
2564
+ system :dff_slow do
2565
+ input :clk, :rst
2566
+ input :d
2567
+ output :q
2568
+
2569
+ ( q <= d & ~rst ).at(clk.posedge * 3)
2570
+ end
2571
+ ```
2572
+
2573
+ __Note__: this library does generate all the RTL code for the circuit handling the division of the frequency.
2574
+
2575
+ ## Counters
2576
+ <a name="counters"></a>
2577
+
2578
+ This library provides two new constructs for implementing synthesizable wait statements.
2579
+
2580
+ The first construct is the `after` statement that activates a block after a given number of clocks cycles is passed. Its syntax is the following:
2581
+
2582
+ ```ruby
2583
+ after(<number>,<clock>,<reset>)
2584
+ ```
2585
+
2586
+ Where:
2587
+ * `<number>` is the number of cycles to wait.
2588
+ * `<clock>` is the clock to use, this argument can be omitted.
2589
+ * `<reset>` is the signal used to reset the counter used for waiting, this argument can be omitted.
2590
+
2591
+ This statement can be used both 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
+
2593
+ 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
+
2595
+
2596
+ ## Decoder
2597
+ <a name="decoder"></a>
2598
+
2599
+ This library provides a new set of control statements for easily describing an instruction decoder.
2600
+
2601
+ A decoder can be declared anywhere in the code describing a system using the `decoder` keyword as follows:
2602
+
2603
+ ```ruby
2604
+ decoder(<signal>) <block>
2605
+ ```
2606
+
2607
+ Where `signal` is the signal to decode and `block` is a procedure block (i.e., Ruby `proc`) describing the decoding procedure. This procedure block can contain any code supported by a standard behavior, but also supports the `entry` statement that describes a pattern of a bit vector to decode and the corresponding action to perform when the signal matches this pattern. The syntax of the `entry` statement is the following:
2608
+
2609
+ ```ruby
2610
+ entry(<pattern>) <block>
2611
+ ```
2612
+
2613
+ Where `pattern` is a string describing the pattern to match for the entry, and `block` is a procedure block describing the actions (some HDLRuby code) that are performed when the entry matches. The string describing the pattern can include `0` and `1` characters for specifying a specific value for the corresponding bit, or any alphabetical character for specifying a field in the pattern. The fields in the pattern can then be used by name in the block describing the action. When a letter is used several times within a pattern, the corresponding bits are concatenated, and are used as a signal multi-bit signal in the block.
2614
+
2615
+ For example, the following code describes a decoder for signal `ir` with two entries, the first one computing the sum of fields `x` and `y` and assigning the result to signal `s` and the second one computing the sum of fields `x` `y` and `z` and assigning the result to signal `s`:
2616
+
2617
+ ```ruby
2618
+ decoder(ir) do
2619
+ entry("000xx0yy") { s <= x + y }
2620
+ entry("10zxxzyy") { s <= x + y + z }
2621
+ end
2622
+ ```
2623
+
2624
+ In can be noticed for field `z` in the example above that the bits of are not required to be contiguous.
2625
+
2626
+ ## FSM
2627
+ <a name="fsm"></a>
2628
+
2629
+ This library provides a new set of control statements for easily describing a finite state machine (FSM).
2630
+
2631
+ A finite state machine can be declared anywhere provided it is outside a behavior using the `fsm` keyword as follows:
2632
+
2633
+ ```ruby
2634
+ fsm(<event>,<reset>,<mode>) <block>
2635
+ ```
2636
+
2637
+ Where `event` is the event (rising falling edge of a signal) activating the state transitions, `rst` is the reset signal, and `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).
2638
+
2639
+ The states of a FSM are described follows:
2640
+
2641
+ ```ruby
2642
+ <kind>(<name>) <block>
2643
+ ```
2644
+
2645
+ 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 followings:
2646
+
2647
+ * 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.
2648
+ * state: the default kind of state, it will be synchronous if the FSM is synchronous or asynchronous otherwise.
2649
+ * sync: the synchronous kind of state, it will be synchronous whatever the kind of FSM is used.
2650
+ * async: the asynchronous kind of state, it will be asynchronous whatever the kind of FSM is used.
2651
+
2652
+ In addition, it is possible to define a default action that will be executed whatever the state is using the following statement:
2653
+
2654
+ ```ruby
2655
+ default <block>
2656
+ ```
2657
+
2658
+ Where `block` is the action to execute.
2659
+
2660
+ State transitions are by default set to be from one state to the following in the description order. If no more transition is declared the next one is the first declared transition. A specific transition is defined using the `goto` statement as last statement of the action block as follows:
2661
+
2662
+ ```ruby
2663
+ goto(<condition>,<names>)
2664
+ ```
2665
+
2666
+ 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
+
2668
+ ```ruby
2669
+ goto(cond,:st_a,:st_b,:st_c)
2670
+ ```
2671
+
2672
+ 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
+
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`):
2675
+
2676
+ ```ruby
2677
+ fsm(clk.posedge,rst,:sync) do
2678
+ default { ok <= 0 }
2679
+ reset do
2680
+ goto(but_a, :reset, but_a_on)
2681
+ end
2682
+ state(:but_a_on) do
2683
+ goto(but_a, :but_a_off, :but_a_on)
2684
+ end
2685
+ state(:but_a_off) do
2686
+ goto(but_b, :but_a_off, :but_b_on)
2687
+ end
2688
+ state(:but_b_on) do
2689
+ goto(but_b, :but_b_off, :but_b_on)
2690
+ end
2691
+ state(:but_b_off) do
2692
+ ok <= 1
2693
+ goto(:but_b_off)
2694
+ end
2695
+ end
2696
+ ```
2697
+
2698
+ ## Channel
2699
+ <a name="channel"></a>
2700
+
2701
+ This library provides a unified interface to complex communication protocols. It provides a new kind of component called the channel that abstracts the details of a communication protocol. 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
+
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 synchronisation 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
+
2705
+ * `writer_ports`: generate ports in the system for writing to the channel. This method is used without any argument.
2706
+
2707
+ * `reader_ports`: generate ports in the system for reading from the channel. This method is used without any argument.
2708
+
2709
+ * `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
+ * `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
+
2713
+ For example a system sending successive 8 bit values through a channel can be described as follows:
2714
+
2715
+ ```ruby
2716
+ system :producer8 do |channel|
2717
+ # Inputs of the producer: clock and reset.
2718
+ input :clk, :rst
2719
+ # Instantiate the channel ports
2720
+ channel.writer_ports
2721
+ # Inner 8-bit counter for generating values.
2722
+ [8].inner :counter
2723
+
2724
+ # The value production process
2725
+ par(clk.posedge) do
2726
+ hif(rst) { counter <= 0 }
2727
+ helse do
2728
+ channel.write(counter) { counter <= counter + 1 }
2729
+ end
2730
+ end
2731
+ end
2732
+ ```
2733
+
2734
+ __Note__: In the code above, the channel is passed as generic argument of the system.
2735
+
2736
+ A new channel is declared like using the keyword `channel` as follows:
2737
+
2738
+ ```ruby
2739
+ channel <name> <block>
2740
+ ```
2741
+
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 actually similar 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:
2743
+
2744
+ * srgg
2745
+
2746
+ ## Reconf
2747
+ <a name="reconf"></a>
2748
+
2749
+ This library provides a unified interface to partially (or dynamically)
2750
+ reconfigurable devices.
2751
+
2752
+ ## Pipeline
2753
+ <a name="pipeline"></a>
2754
+
2755
+ This library provides a construct for an easy description of pipeline architectures.
2756
+
2757
+
2758
+
2759
+
2760
+ # Development
2761
+
2762
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
2763
+
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
+
2766
+ # Contributing
2767
+
2768
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Lovic Gauthier/HDLRuby.
2769
+
2770
+
2771
+ # License
2772
+
2773
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
2774
+