HDLRuby 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/tuto/tutorial_sw.md CHANGED
@@ -273,30 +273,30 @@ If everything was OK, a file named `my_circuit.v` should have appeared in the `w
273
273
  ```verilog
274
274
  `timescale 1ps/1ps
275
275
 
276
- module _v0_1( _v1_clk, _v2_rst, _v3_addr, _v4_data_in, _v5_data_out );
277
- input _v1_clk;
278
- input _v2_rst;
279
- input [15:0] _v3_addr;
280
- input _v4_ce;
281
- input [7:0] _v5_data_in;
282
- output [7:0] _v6_data_out;
276
+ module _v0_1( clk, rst, addr, data_in, data_out );
277
+ input clk;
278
+ input rst;
279
+ input [15:0] addr;
280
+ input ce;
281
+ input [7:0] data_in;
282
+ output [7:0] data_out;
283
283
 
284
284
 
285
285
  endmodule
286
286
  ```
287
287
 
288
- The syntax looks indeed a little bit different from HDLRuby, but you should be able to recognize the description of the circuit. The name of the ports is different though, this is because HDLRuby supports any Unicode character for names and to avoid compatibility problems, it recreates the names when generating Verilog. Still, an effort is made to keep the original name, e.g., `clk` became `_v1_clk`. But, just for the fun, please replace `:addr` in the HDLRuby file with `:☺` and regenerate Verilog HDL from it... It works! And the result is:
288
+ The syntax looks indeed a little bit different from HDLRuby, but you should be able to recognize the description of the circuit. The name of the module is different though, this is because HDLRuby supports any Unicode character for names and to avoid compatibility problems, it recreates the names when generating Verilog. But, just for the fun, please replace `:addr` in the HDLRuby file with `:☺` and regenerate Verilog HDL from it... It works! And the result is:
289
289
 
290
290
  ```verilog
291
291
  `timescale 1ps/1ps
292
292
 
293
- module _v0_1( _v1_clk, _v2_rst, _v3_, _v4_data_in, _v5_data_out );
294
- input _v1_clk;
295
- input _v2_rst;
296
- input [15:0] _v3_;
297
- input _v4_ce;
298
- input [7:0] _v5_data_in;
299
- output [7:0] _v6_data_out;
293
+ module _v0_1( clk, rst, _v1_, data_in, data_out );
294
+ input clk;
295
+ input rst;
296
+ input [15:0] _v1_;
297
+ input ce;
298
+ input [7:0] data_in;
299
+ output [7:0] data_out;
300
300
 
301
301
 
302
302
  endmodule
@@ -357,17 +357,17 @@ Three new files should have appeared in the `work` directory: `_v10_5.v`, `_v8_4
357
357
  ```verilog
358
358
  `timescale 1ps/1ps
359
359
 
360
- module _v0_3( _v1_clk, _v2_rst, _v3_addr, _v4_ce0, _v5_ce1, _v6_data_in, _v7_data_out );
361
- input _v1_clk;
362
- input _v2_rst;
363
- input [15:0] _v3_addr;
364
- input _v4_ce0;
365
- input _v5_ce1;
366
- input [7:0] _v6_data_in;
367
- output [7:0] _v7_data_out;
360
+ module _v0_3( clk, rst, addr, ce0, ce1, data_in, data_out );
361
+ input clk;
362
+ input rst;
363
+ input [15:0] addr;
364
+ input ce0;
365
+ input ce1;
366
+ input [7:0] data_in;
367
+ output [7:0] data_out;
368
368
 
369
- _v8_4 _v9_my_circuit0();
370
- _v10_5 _v11_my_circuit1();
369
+ _v8_4 my_circuit0();
370
+ _v10_5 my_circuit1();
371
371
 
372
372
  endmodule
373
373
  ```
@@ -497,14 +497,14 @@ When the compile succeeds (no error message), two new files appear in `work`, na
497
497
  ```verilog
498
498
  `timescale 1ps/1ps
499
499
 
500
- module _v0_3( _v1_clk, _v2_rst, _v3_addr, _v4_ce0, _v5_ce1, _v6_data_in, _v7_data_out );
500
+ module _v0_3( clk, rst, addr, ce0, ce1, data_in, data_out );
501
501
  input _v1_clk;
502
502
  input _v2_rst;
503
- input [15:0] _v3_addr;
504
- input _v4_ce0;
505
- input _v5_ce1;
506
- input [7:0] _v6_data_in;
507
- output [7:0] _v7_data_out;
503
+ input [15:0] addr;
504
+ input ce0;
505
+ input ce1;
506
+ input [7:0] data_in;
507
+ output [7:0] data_out;
508
508
  wire _v8_0;
509
509
  wire _v9_1;
510
510
  wire [15:0] _v10_2;
@@ -518,29 +518,29 @@ module _v0_3( _v1_clk, _v2_rst, _v3_addr, _v4_ce0, _v5_ce1, _v6_data_in, _v7_dat
518
518
  wire [7:0] _v18_10;
519
519
  wire [7:0] _v19_11;
520
520
 
521
- _v20_4 _v21_my_circuit0(._v1_clk(_v8_0),._v2_rst(_v9_1),._v3_addr(_v10_2),._v22_ce(_v11_3),._v6_data_in(_v12_4),._v7_data_out(_v18_10));
522
- _v23_5 _v24_my_circuit1(._v1_clk(_v13_5),._v2_rst(_v14_6),._v3_addr(_v15_7),._v22_ce(_v16_8),._v6_data_in(_v17_9),._v7_data_out(_v19_11));
523
- assign _v8_0 = _v1_clk;
521
+ _v20_4 my_circuit0(.clk(_v8_0),.rst(_v9_1),.addr(_v10_2),.ce(_v11_3),.data_in(_v12_4),.data_out(_v18_10));
522
+ _v23_5 my_circuit1(.clk(_v13_5),.rst(_v14_6),.addr(_v15_7),.ce(_v16_8),.data_in(_v17_9),.data_out(_v19_11));
523
+ assign _v8_0 = clk;
524
524
 
525
- assign _v9_1 = _v2_rst;
525
+ assign _v9_1 = rst;
526
526
 
527
- assign _v10_2 = _v3_addr;
527
+ assign _v10_2 = addr;
528
528
 
529
- assign _v11_3 = _v4_ce0;
529
+ assign _v11_3 = ce0;
530
530
 
531
- assign _v12_4 = _v6_data_in;
531
+ assign _v12_4 = data_in;
532
532
 
533
- assign _v13_5 = _v1_clk;
533
+ assign _v13_5 = clk;
534
534
 
535
- assign _v14_6 = _v2_rst;
535
+ assign _v14_6 = rst;
536
536
 
537
- assign _v15_7 = _v3_addr;
537
+ assign _v15_7 = addr;
538
538
 
539
- assign _v16_8 = _v5_ce1;
539
+ assign _v16_8 = ce1;
540
540
 
541
- assign _v17_9 = _v6_data_in;
541
+ assign _v17_9 = data_in;
542
542
 
543
- assign _v7_data_out = (_v18_10 + _v19_11);
543
+ assign data_out = (_v18_10 + _v19_11);
544
544
 
545
545
 
546
546
  endmodule
@@ -599,7 +599,7 @@ With HDL like Verilog HDL, there is a real distinction between wires and storage
599
599
 
600
600
  __Note__: one may ask what about the `variable` construct in VHDL: those are syntactic intermediates used for simplifying the descriptions. HDLRuby also supports such a `variable` construct, but those are simply the variables of the Ruby language. Therefore, these variables can hold not only values but any Ruby or HDLRuby constructs.
601
601
 
602
- In HDLRuby, there are three kinds of signals: the input ports, the output ports, the inout ports, and the inner signals. The first three kinds of signals have already been described in the section about declaring a [circuit](#circuit-declare). At that time they were called ports because it is what such constructs are called in common HDL. However, in HDLRuby there is no distinction at all between ports and signals, hence from now on, we will use the term `signal` in general, and the term `port` when we only want to refer to the interface of a circuit. The inner signals can be used inside a circuit and are usually used as an intermediate for internal computations. They are declared like the ports, but using `inner` instead of `input`, `output`, or `inout`. For example, the following code declares a module named `a_circuit` with two 1-bit inputs, one 8-bit output, and one 4-bit inner signal.
602
+ In HDLRuby, there are four kinds of signals: the input ports, the output ports, the inout ports, and the inner signals. The first three kinds of signals have already been described in the section about declaring a [circuit](#circuit-declare). At that time they were called ports because it is what such constructs are called in common HDL. However, in HDLRuby there is no distinction at all between ports and signals, hence from now on, we will use the term `signal` in general, and the term `port` when we only want to refer to the interface of a circuit. The inner signals can be used inside a circuit and are usually used as an intermediate for internal computations. They are declared like the ports, but using `inner` instead of `input`, `output`, or `inout`. For example, the following code declares a module named `a_circuit` with two 1-bit inputs, one 8-bit output, and one 4-bit inner signal.
603
603
 
604
604
  ```ruby
605
605
  system(:a_circuit) do
@@ -737,9 +737,11 @@ This section will explain the following about sequencers:
737
737
 
738
738
  * [How to write a structured programming algorithm in a sequencer.](#322-how-to-write-a-structured-programming-algorithm-in-a-sequencer)
739
739
 
740
- * [How to use enumerators in a sequencer.](#323-how-to-use-enumerators-in-a-sequencer)
740
+ * [How to write and use a sequencer function.](#323-how-to-write-and-use-a-sequencer-function)
741
+
742
+ * [How to use enumerators in a sequencer.](#324-how-to-use-enumerators-in-a-sequencer)
741
743
 
742
- * [What happens when there are several sequencers?](#324-what-happens-when-there-are-several-sequencers)
744
+ * [What happens when there are several sequencers?](#325-what-happens-when-there-are-several-sequencers)
743
745
 
744
746
 
745
747
  #### 3.2.1 How to declare and control a sequencer
@@ -952,7 +954,7 @@ In detail here is a list of the control statements you can use within a sequence
952
954
 
953
955
  * `sif(<condition>) <block>`: executes `block` if `condition` is true (i.e., different from 0).
954
956
 
955
- - `selsif(<condition>) <block>`: executes `block` if the previous `sif` and `selsif` conditions are false and if the current `condition` is true.
957
+ * `selsif(<condition>) <block>`: executes `block` if the previous `sif` and `selsif` conditions are false and if the current `condition` is true.
956
958
 
957
959
  * `selse <block>`: executes `block` if the conditions of the previous `sif` and `selsif` are false (i.e., equals 0). It is also used for giving the default block for the `scase` statements (see below).
958
960
 
@@ -970,6 +972,8 @@ In detail here is a list of the control statements you can use within a sequence
970
972
 
971
973
  * `scontinue`: ends the current iteration.
972
974
 
975
+ * `steps(<num>)`: performs `num` times `step` (`num` can be any expression). Useful for waiting a certain number of cycles.
976
+
973
977
  > __IMPORTANT__: each control statement requires one clock cycle for each branch they perform, independently of what their block contains. For example, in the following code, the value of `y` will be set one cycle after `x` is set to 0, and one cycle before `z` is set to 1.
974
978
 
975
979
  ```ruby
@@ -1096,7 +1100,7 @@ clk <= 1
1096
1100
  ```
1097
1101
 
1098
1102
  > __IMPORTANT__: as said when presenting HDLRuby, this language is implemented on top of the Ruby language, and is fully compatible with it. For instance, you can write any Ruby code within HDLRuby constructs (e.g., `def`), and you can write HDLRuby code within Ruby constructs. However, there is an important difference: Ruby code is executed at compile time (i.e., when hdrcc runs) and does not produce any hardware, whereas HDLRuby code is the description of the hardware that will be produced and will be then executed either through simulation or after production physically.
1099
- Then, what calling `clk!` do is paste the HDLRuby code in place. Here it is used to shorten the code: instead of setting each time the clock to 0, advancing time, then setting it to 1, writing `clk!` is enough to obtain the same result.
1103
+ Then, what calling `clk!` do is paste the HDLRuby code in place. Here it is used to shorten the code: instead of each time setting the clock to 0, advancing time, then setting it to 1 again, writing `clk!` is enough to obtain the same result.
1100
1104
  It is from this capability to mix Ruby and HDLRuby that comes the *meta programmability* of HDLRuby.
1101
1105
 
1102
1106
  Finally, when you simulate with the following command:
@@ -1110,6 +1114,38 @@ You should obtain the following kind of resulting VCD file:
1110
1114
  ![hruby_simulator.vcd](fact_vcd.png)
1111
1115
 
1112
1116
 
1117
+ #### But in structured programming, it is better to use local variables!
1118
+
1119
+ Indeed, in the factorial program, signals `val` and `res` are only used within the sequencer, so why declare them outside it? The code would be more clear if they were declared more locally, i.e., *inside* it, and even better, inside its main loop. So let us modify it as follows:
1120
+
1121
+ ```ruby
1122
+ system :fact do
1123
+ input :clk, :start, :req
1124
+ [5].input :data_in
1125
+ output :ack
1126
+ [32].output :data_out
1127
+
1128
+ sequencer(clk,start) do
1129
+ sloop do
1130
+ [4].inner :val
1131
+ [24].inner :res
1132
+
1133
+ ack <= 0
1134
+ swhile(req != 1)
1135
+ val <= data_in
1136
+ res <= 1
1137
+ swhile(val>1) do
1138
+ res <= res*val
1139
+ val <= val - 1
1140
+ end
1141
+ data_out <= res
1142
+ ack <= 1
1143
+ end
1144
+ end
1145
+ end
1146
+ ```
1147
+
1148
+ You can simulate it again, and you should obtain exactly the same result. However, if you try to access `res` or `val` outside the main loop, then an error will be raised.
1113
1149
 
1114
1150
 
1115
1151
  #### Now about `sfor`
@@ -1208,16 +1244,128 @@ You should obtain the following time chart:
1208
1244
 
1209
1245
 
1210
1246
 
1247
+ #### 3.2.3. How to write and use a sequencer function.
1248
+
1249
+ Why not necessarily associated with algorithmic, it is common in software to define functions for code reuse and implementation of recursive algorithms. HDLRuby also provided such kinds of functions, with all the software features, including recursion, using the construct `sdef`. Such a function is defined as follows:
1250
+
1251
+ ```ruby
1252
+ sdef :<name> do |<arguments>|
1253
+ <body>
1254
+ end
1255
+ ```
1256
+
1257
+ In the code above, `name` is the name of the function, `arguments` is a list of arguments and `body` is the code of the function that can be any kind of HDLRuby sequencer code. For returning a value from a function, the `sreturn(<value>)` command is used. For example, the following describes a function computing the factorial of its argument `n`:
1258
+
1259
+ ```ruby
1260
+ sdef :fact do |n|
1261
+ sif(n>1) { sreturn(n*fact(n-1) }
1262
+ selse { sreturn(1) }
1263
+ end
1264
+ ```
1265
+
1266
+ There is a lot to unpack from this small example:
1267
+
1268
+ 1. Such a function can be defined outside or inside a module, but can only be called within a sequencer.
1269
+
1270
+ 2. The arguments of a function, here `n`, do not have any defined type: their type, and consequently the final implementation of the function, is determined by the data type of the actual arguments when the function is called. For example, in the following code, the data type of the actual argument `val` is 16-bit unsigned, hence that will be the data type of `n`.
1271
+
1272
+ ```ruby
1273
+ [16].inner :val, :res
1274
+
1275
+ sequencer do
1276
+ val <= 5
1277
+ res <= fact(val)
1278
+ end
1279
+ ```
1280
+
1281
+ 3. When a function is recursive, a stack is created to store the arguments and the sequencer states for returning at each recursion. The size of this stack is by default set to the bit width of the largest argument, e.g., for `fact` it is set for supporting 16 recursions. In case of stack overflow, i.e., there were too many recursive calls, the recursion is stopped, and the execution of the sequencer proceeds from just after the last call.
1282
+
1283
+ 4. The behavior of the stack can be controlled in two ways when defining a function as follows:
1284
+
1285
+ ```ruby
1286
+ sdef(:<name>,<size>, proc <error_handler>) do |<arguments>|
1287
+ <body>
1288
+ end
1289
+ ```
1290
+
1291
+ In the code above, `size` is the forced size of the stack, and `error_handler` is a block of code that will be executed when a stack overflow occurs. Both arguments are optional, but if the error handler is provided, then the size must also be provided. For example, the code of the factorial can be rewritten as follows for forcing the stack to support 64 recursions:
1292
+
1293
+ ```ruby
1294
+ sdef(:fact,64) do |n|
1295
+ sif(n>1) { sreturn(n*fact(n-1) }
1296
+ selse { sreturn(1) }
1297
+ end
1298
+ ```
1299
+
1300
+ It can also be defined as follows to support only 8 recursions but to set a signal named `stack_overflow` to 1 when a stack overflow happens:
1301
+
1302
+ ```ruby
1303
+ sdef(:fact, 8, proc { stack_overflow <= 1 }) do |n|
1304
+ sif(n>1) { sreturn(n*fact(n-1) }
1305
+ selse { sreturn(1) }
1306
+ end
1307
+ ```
1308
+
1309
+ Here is a full example using the factorial:
1310
+
1311
+ ```ruby
1312
+ sdef(:fact,8,proc { stack_overflow_error <= 1 }) do |n|
1313
+ sif(n > 1) { sreturn(n*fact(n-1)) }
1314
+ selse { sreturn(1) }
1315
+ end
1316
+
1317
+
1318
+ # Checking the fact function.
1319
+ system :module_with_fact do
1320
+
1321
+ inner :clk,:rst
1322
+
1323
+ [16].inner :val
1324
+ [16].inner :res
1325
+ inner stack_overflow_error: 0
1326
+
1327
+ sequencer(clk.posedge,rst) do
1328
+ 5.stimes do |i|
1329
+ val <= i
1330
+ res <= fact(val)
1331
+ end
1332
+ hprint("stack_overflow_error=",stack_overflow_error,"\n")
1333
+ end
1334
+
1335
+ timed do
1336
+ clk <= 0
1337
+ rst <= 0
1338
+ !10.ns
1339
+ clk <= 1
1340
+ !10.ns
1341
+ clk <= 0
1342
+ rst <= 1
1343
+ !10.ns
1344
+ clk <= 1
1345
+ !10.ns
1346
+ clk <= 0
1347
+ rst <= 0
1348
+ !10.ns
1349
+ clk <= 1
1350
+ repeat(500) do
1351
+ !10.ns
1352
+ clk <= ~clk
1353
+ end
1354
+ end
1355
+ end
1356
+ ```
1357
+
1358
+
1211
1359
  ---
1212
1360
 
1213
1361
  So now, you know:
1214
1362
 
1215
- * How to describe fully fledged algorithms with sequencers.
1363
+ * How to describe fully-fledged algorithms with sequencers using conditional and control statements as well as functions, including recursive ones.
1216
1364
 
1217
1365
  Also, if you are not familiar with languages like Ruby or Python, the `sfor` may look great compared to what C can provide. But this is just the beginning, HDLRuby can do better than that.
1218
1366
 
1219
1367
 
1220
- #### 3.2.3. How to use enumerators in a sequencer
1368
+ #### 3.2.4. How to use enumerators in a sequencer
1221
1369
 
1222
1370
  If sometimes you program with Ruby, you may know about enumerators: they are objects used for processing iteratively several elements of objects. The HDLRuby's sequencer provides the same concept: it is possible to build hardware enumerators for any enumerable objects and they will run like Ruby's.
1223
1371
 
@@ -1284,12 +1432,12 @@ That's all that we will explain here, the remaining is exactly like Ruby. Moreov
1284
1432
 
1285
1433
  sequencer(clk,start) do
1286
1434
  16.stimes {|i| ar[i] <= sin }
1287
- ar.ssort
1288
- 16.stimes {|i| sout <= ar[i] }
1435
+ res = ar.ssort
1436
+ 16.stimes {|i| sout <= res[i] }
1289
1437
  end
1290
1438
  ```
1291
1439
 
1292
- In this example, `16.stimes` generates an enumerator over the `0..7` range, and is a way to build an enumerator from an integer value.
1440
+ In this example, `16.stimes` generates an enumerator over the `0..7` range, and is a way to build an enumerator from an integer value. In addition, please notice the use of the Ruby variable `res` for accessign the signal containing the sort result.
1293
1441
 
1294
1442
  * Apply a 4-point FIR filter over an array obtained from input signal `sin` with 0-padding at the beginning and output the result to `sout`
1295
1443
 
@@ -1309,7 +1457,29 @@ That's all that we will explain here, the remaining is exactly like Ruby. Moreov
1309
1457
  end
1310
1458
  ```
1311
1459
 
1312
- In this example, `[_h00]*3` builds an array of three 8-bit zeros for the padding, `seach` creates the iterators over this padding. This iterator is added to one over `ar` which creates a global iterator over them all. `seach_slice` and `sreduce` work the same way their Ruby equivalent `each_slice` and `reduce` do.
1460
+ In this example, `[_h00]*3` builds an array of three 8-bit zeros for the padding, `seach` creates the iterators over this padding. This iterator is added to one over `ar` which creates a global iterator over them all. `seach_slice` and `sreduce` work the same way their Ruby equivalent `each_slice` and `reduce` do. Here, since the result is a single byte, it is directly assigned to the output `sout`, but the following could also have been possible:
1461
+
1462
+ ```ruby
1463
+ input :clk,:start
1464
+ [8].input :sin
1465
+ [8].output :sout
1466
+
1467
+ bit[8][-4].inner coefs: [_h01,_h05,_h0A,_hFE]
1468
+ bit[8][-16].inner : ar
1469
+
1470
+ res = nil
1471
+
1472
+ sequencer(clk,start) do
1473
+ 16.stime {|i| ar[i] <= sin }
1474
+ res = ([_h00]*3).seach + ar.seach).seach_slice(4).sreduce(_h00) do |a,b,c,d|
1475
+ a*coefs[0] + b * coefs[1] + c * coefs[2] + d * coefs[3]
1476
+ end
1477
+ end
1478
+
1479
+ sout <= res
1480
+ ```
1481
+
1482
+ Please notice that since the Ruby variable `res` is used outside the sequencer, it must also be declared outside (`res = nil`).
1313
1483
 
1314
1484
 
1315
1485
 
@@ -1354,7 +1524,7 @@ But this is not all: contrary to software, hardware is inherently parallel, a pr
1354
1524
 
1355
1525
 
1356
1526
 
1357
- #### 3.2.4. What happens when there are several sequencers?
1527
+ #### 3.2.5. What happens when there are several sequencers?
1358
1528
 
1359
1529
 
1360
1530
  #### General considerations
@@ -1698,7 +1868,7 @@ In software, when you want to do parallelism you usually need specific libraries
1698
1868
 
1699
1869
  * [A sequencer is not a program](#41-a-sequencer-is-not-a-program)
1700
1870
 
1701
- * [Adding parallelism is genuine](#42-parallel-control-statements-and-enumerators)
1871
+ * [Adding parallelism is genuine](#42-parallel-control-statements-functions-and-enumerators)
1702
1872
 
1703
1873
  ### 4.1. A sequencer is not a program
1704
1874
 
@@ -1736,7 +1906,7 @@ sequencer(clk,start) do
1736
1906
  > __WARNING__: in hardware design with HDLRuby (and with all similar languages like Verilog VHDL or VHDL,) it is assumed that a clock is slow enough for the relevant combinatorial circuits to complete computation before the next cycle. If this is not the case, the resulting circuits will not function properly. Fortunately, the synthesis frameworks usually provide tools for verifying these timings.
1737
1907
 
1738
1908
 
1739
- ### 4.2. Parallel control statements and enumerators
1909
+ ### 4.2. Parallel control statements, functions, and enumerators
1740
1910
 
1741
1911
  Sequencers provide many constructs for easy control and enumeration. However, those constructs are sequential by construction. What if you would like to do the same in parallel? This is possible, but there is an important restriction:
1742
1912
 
@@ -1840,14 +2010,46 @@ Yes, this is becoming confusing because it is hard to know what Ruby does when e
1840
2010
  * `zip`
1841
2011
 
1842
2012
 
2013
+ #### 4.2.3. Can functions be parallel too?
2014
+
2015
+ As explained before, the body of a `sdef` function can contain any kind of sequencer code, hence parallel code is also possible. Yet, calling and returning from such a function are themselves sequential procedures that require several cycles to be performed. Hence, there exists a parallel version of `sdef` whose call and return as well as its body execution is fully combinatorial. It is declared as follows:
2016
+
2017
+ ```ruby
2018
+ hdef :<name> do |<arguments>|
2019
+ <body>
2020
+ end
2021
+ ```
2022
+
2023
+ As you can see, the declaration is identical to the `sdef` one. However the behavior is different, and this new kind of function has the following limitations:
2024
+
2025
+ 1. It cannot contain any sequential code, i.e., constructs like `step`, `sif` or `sloop`.
2026
+
2027
+ 2. It does not support the `sreturn` constructs either, instead, it is the last value computed by the function that is returned.
2028
+
2029
+ 3. It cannot be recursive.
2030
+
2031
+ Here is an example of a parallel-compatible function counting the number of ones in the input argument:
2032
+
2033
+ ```ruby
2034
+ hdef :popcount do |n|
2035
+ n.each.reduce(_b0.as(n.type),&:+)
2036
+ end
2037
+ ```
2038
+
2039
+ In the code above, it can be seen that no return is provided but instead, it will be the result of the parallel sum result that will be returned since it is the last computation of the function. Also, the data type of the sum is obtained from the argument `n` (`as(n.type)`).
2040
+
1843
2041
  ---
1844
2042
 
1845
2043
  Now you know:
1846
2044
 
1847
- * How to use Ruby code for concisely describing parallel HDLRuby code.
2045
+ * How to introduce parallelism within a sequencer.
1848
2046
 
2047
+ * How to define a parallel-compatible function using `hdef`
1849
2048
 
1850
- #### 4.2.3. Parallel is faster, so why do sequential computations?
2049
+ But, by the way, why bother with sequential code if parallel one is faster?
2050
+
2051
+
2052
+ #### 4.2.4. Parallel is faster, so why do sequential computations?
1851
2053
 
1852
2054
  Why parallel dataflow computations are indeed faster than sequential ones, in theory, they also have some drawbacks.
1853
2055
 
@@ -1898,7 +2100,11 @@ First, we must make things clear:
1898
2100
 
1899
2101
  > Processes in hardware has very little (nothing?) to do with any kind of software process.
1900
2102
 
1901
- In hardware, a process is a list of data flow statements that are activated (we would say *executed* if they were software instructions) on a common condition. Depending on the activation condition, there are three kinds of processes:
2103
+ In hardware, a process is a list of data flow statements that are activated (we would say *executed* if they were software instructions) on a common condition.
2104
+
2105
+ > By data flow statements, we mean all the assignment statements, the `hif`, `helse`, `hcase` and `hwhen` statements, and the calls to `hdef` functions.
2106
+
2107
+ Depending on the activation condition, there are three kinds of processes:
1902
2108
 
1903
2109
  * The connection processes (in HDLRuby they are considered to be processes)
1904
2110
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: HDLRuby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lovic Gauthier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-10 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -195,11 +195,12 @@ files:
195
195
  - lib/HDLRuby/hdr_samples/with_reconf.rb
196
196
  - lib/HDLRuby/hdr_samples/with_reduce.rb
197
197
  - lib/HDLRuby/hdr_samples/with_ref_array.rb
198
- - lib/HDLRuby/hdr_samples/with_register_stack.rb
198
+ - lib/HDLRuby/hdr_samples/with_ref_expr.rb
199
199
  - lib/HDLRuby/hdr_samples/with_sequencer.rb
200
200
  - lib/HDLRuby/hdr_samples/with_sequencer_deep.rb
201
201
  - lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb
202
202
  - lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb
203
+ - lib/HDLRuby/hdr_samples/with_sequencer_func.rb
203
204
  - lib/HDLRuby/hdr_samples/with_sequencer_sync.rb
204
205
  - lib/HDLRuby/hdr_samples/with_str2value.rb
205
206
  - lib/HDLRuby/hdr_samples/with_subsums.rb
@@ -370,6 +371,7 @@ files:
370
371
  - lib/HDLRuby/std/pipeline.rb
371
372
  - lib/HDLRuby/std/reconf.rb
372
373
  - lib/HDLRuby/std/sequencer.rb
374
+ - lib/HDLRuby/std/sequencer_func.rb
373
375
  - lib/HDLRuby/std/sequencer_sync.rb
374
376
  - lib/HDLRuby/std/std.rb
375
377
  - lib/HDLRuby/std/task.rb
@@ -1,150 +0,0 @@
1
- require 'soft/stacks.rb'
2
-
3
- include HDLRuby::High::Soft
4
-
5
-
6
- # A system testing the bram-based stack.
7
- system :register_stack_test do
8
-
9
- widthA = 3
10
- size = 2**widthA
11
- widthD = 8
12
-
13
-
14
- input :clk,:rst,:ce
15
- [2].inner :cmd
16
- [widthD].inner :din,:dout
17
- inner :empty, :full
18
- douts = size.times.map { |i| [widthD].inner :"dout#{i}" }
19
-
20
- register_stack(widthA,widthD,size).(:stackI).(clk,rst,ce,cmd,din,dout,empty,full,*douts)
21
-
22
- [widthD].inner :count # Additional counter for the test.
23
-
24
- timed do
25
- clk <= 0
26
- ce <= 0
27
- rst <= 0
28
- cmd <= READ
29
- din <= 0
30
- !10.ns
31
- clk <= 1
32
- !10.ns
33
- clk <= 0
34
- rst <= 1
35
- !10.ns
36
- clk <= 1
37
- !10.ns
38
- clk <= 0
39
- rst <= 0
40
- ce <= 1
41
- din <= 1
42
- !10.ns
43
- clk <= 1
44
- repeat(9) do
45
- !10.ns
46
- clk <= 0
47
- cmd <= PUSH
48
- din <= din + 1
49
- !10.ns
50
- clk <= 1
51
- end
52
- !10.ns
53
- clk <= 0
54
- !10.ns
55
- clk <= 1
56
- din <= -1
57
- repeat(8) do
58
- !10.ns
59
- clk <= 0
60
- cmd <= READ
61
- din <= din + 1
62
- !10.ns
63
- clk <= 1
64
- end
65
- !10.ns
66
- clk <= 0
67
- !10.ns
68
- clk <= 1
69
- count <= 0
70
- repeat(4) do
71
- !10.ns
72
- clk <= 0
73
- din <= 1
74
- cmd <= POP
75
- !10.ns
76
- clk <= 1
77
- !10.ns
78
- clk <= 0
79
- count <= count + 1
80
- din <= count
81
- cmd <= PUSH
82
- !10.ns
83
- clk <= 1
84
- end
85
- !10.ns
86
- clk <= 0
87
- !10.ns
88
- clk <= 1
89
- repeat(9) do
90
- !10.ns
91
- clk <= 0
92
- din <= 1
93
- cmd <= POP
94
- !10.ns
95
- clk <= 1
96
- end
97
- !10.ns
98
- clk <= 0
99
- din <= _b8hAA
100
- cmd <= PUSH
101
- !10.ns
102
- clk <= 1
103
- !10.ns
104
- clk <= 0
105
- din <= 7
106
- cmd <= WRITE
107
- !10.ns
108
- clk <= 1
109
- din <= -1
110
- repeat(8) do
111
- !10.ns
112
- clk <= 0
113
- cmd <= WRITE
114
- din <= din + 1
115
- !10.ns
116
- clk <= 1
117
- end
118
- !10.ns
119
- clk <= 0
120
- din <= size-1
121
- cmd <= READ
122
- !10.ns
123
- clk <= 1
124
- !10.ns
125
- clk <= 0
126
- din <= -3
127
- cmd <= POP
128
- !10.ns
129
- clk <= 1
130
- !10.ns
131
- clk <= 0
132
- din <= 31
133
- cmd <= PUSH
134
- !10.ns
135
- clk <= 1
136
- !10.ns
137
- clk <= 0
138
- din <= 3
139
- cmd <= POP
140
- !10.ns
141
- clk <= 1
142
- !10.ns
143
- clk <= 0
144
- din <= size-1
145
- cmd <= READ
146
- !10.ns
147
- clk <= 1
148
- end
149
-
150
- end