HDLRuby 2.2.16 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f752aaab90bc0318eadca1d00745607d477bf742a568de5e0c17a64e399327f1
4
- data.tar.gz: 0d3dc8821a51afa9cbae15a60611beb3b3b3671add3728a5843ad51f42013534
3
+ metadata.gz: 6548ba8f8c1572f8aa254b168eab065bc5d0a06ac996d792b4082a9243a2dfc9
4
+ data.tar.gz: 97891dad52f2454d37755af82cf6d23b2665cccd39a44caff81701921f233931
5
5
  SHA512:
6
- metadata.gz: 0116cacdf784719837ede586042b07903ad54540b797549e7731c0a35e7fb9be9ffad241d237c454d6d47dcf94346004a73913610e2dfecb1e3b58b4984ea75c
7
- data.tar.gz: 233ff279a0c056998ae3b88017d08f2a69986919b4b148058c30e3da8573d96792e103b938a50654b96b75ce17a46ec1d45ec1069e27f56847538e095d4fb00b
6
+ metadata.gz: 6df258eebc8a3448824aca9bf39d24ad98c9302728c2584bb34880b8160b42a00f6b7e0fed68a4097403046e0621bf16c8048c43ce95090254f4e9e6e1ebc079
7
+ data.tar.gz: 73cc373d53e91a756922c8539f15283f793db0ce6e1b3e7c2ae566ae6e2c19691ee62d7dd3ac5ca1f1e19c61a809ab234aba3c790ae207327f8cd2609c76816f
data/README.md CHANGED
@@ -1301,14 +1301,7 @@ __The vector operator__ `[]` is used for building types representing vectors of
1301
1301
  <type>[<range>]
1302
1302
  ```
1303
1303
 
1304
- 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
1305
- 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
1306
- bellow:
1307
-
1308
- ```ruby
1309
- bit[7..-4]
1310
- ```
1311
-
1304
+ The `<range>` of a vector type indicates the position of the starting and ending bits.
1312
1305
  A `n..0` range can also be abbreviated to `n+1`. For instance, the two following types are identical:
1313
1306
 
1314
1307
  ```ruby
@@ -2801,6 +2794,19 @@ bit[4,4].inner :sig
2801
2794
 
2802
2795
  When performing computation with fixed point types, HDLRuby ensures that the result's decimal point position is correct.
2803
2796
 
2797
+ In addition to the fixed point data type, a method is added to the literal objects (Numeric) to convert them to fixed point representation:
2798
+
2799
+ ```ruby
2800
+ <litteral>.to_fix(<number of bits after the decimal point>)
2801
+ ```
2802
+
2803
+ For example the following code converts a floating point value to a fixed point value with 16 bits after the decimal point:
2804
+
2805
+ ```
2806
+ 3.178.to_fix(16)
2807
+ ```
2808
+
2809
+
2804
2810
  ## Channel
2805
2811
  <a name="channel"></a>
2806
2812
 
@@ -2809,27 +2815,17 @@ This library provides a unified interface to complex communication protocols thr
2809
2815
  ### Using a channel
2810
2816
 
2811
2817
  A channel is used similarly to a pipe: it has an input where data can be written and an output where data can be read. The ordering of the data and the synchronization depend on the internals of the channel, e.g., a channel can be FIFO or LIFO. The interaction with the channel is done using the following methods:
2812
-
2813
- * `input <name>`: generate ports in the system for reading from the channel amd associate them to `name`
2814
- * `output <name>`: generate ports in the system for writing to the channel and associate them to `name`
2815
- * `inout <name>`: generate ports in the system for reading and writing to the channel and associate them to `name`
2816
- * `inner <name>`: generates inner signals for accessing directly the channel
2817
-
2818
- __Note__: `input`, `output`, `inout` and `inner` for channels work similarly to the ones of data types for declaring signals. In particular, `input`, `output` and `inout` are to be used in systems that do not include the channel and `inner` is to be used in the system that include the channel.
2819
-
2820
- When the channel ports are declared, they can be accessed using the following methods depending on whether they are writing or reading ports:
2821
2818
 
2822
2819
  * `write(<args>) <block>`: write to the channel and execute `block` when `write` completes. `args` is a list of arguments required for performing the write that depend on the channel.
2823
2820
  * `read(<args>) <block>`: read the channel and execute `block` when the read completes. `args` is a list of arguments required for performing the write that depend on the channel.
2824
2821
 
2822
+
2825
2823
  For example, a system sending successive 8-bit values through a channel can be described as follows:
2826
2824
 
2827
2825
  ```ruby
2828
2826
  system :producer8 do |channel|
2829
2827
  # Inputs of the producer: clock and reset.
2830
2828
  input :clk, :rst
2831
- # Instantiate the channel ports
2832
- channel.output :chi
2833
2829
  # Inner 8-bit counter for generating values.
2834
2830
  [8].inner :counter
2835
2831
 
@@ -2837,7 +2833,7 @@ system :producer8 do |channel|
2837
2833
  par(clk.posedge) do
2838
2834
  hif(rst) { counter <= 0 }
2839
2835
  helse do
2840
- chi.write(counter) { counter <= counter + 1 }
2836
+ channel.write(counter) { counter <= counter + 1 }
2841
2837
  end
2842
2838
  end
2843
2839
  end
@@ -2845,6 +2841,22 @@ end
2845
2841
 
2846
2842
  __Note__: In the code above, the channel is passed as generic argument of the system.
2847
2843
 
2844
+ The access points to a channel can also be handled individually by declaring ports using the following methods:
2845
+
2846
+ * `input <name>`: declares a port for reading from the channel and associate them to `name` if any
2847
+ * `output <name>`: declares a port for writing to the channel and associate them to `name` if any
2848
+ * `inout <name>`: declares a port for reading and writing to the channel and associate them to `name` if any
2849
+
2850
+ Such port can then be accessed using the same `read` and `write` method of a channel, the difference being that they can also be configured for new access procedure using the `wrap` method:
2851
+
2852
+ * `wrap(<args>) <code>`: creates a new port whose read or write procedure has the elements of `<args>` and the ones produced by `<code>` assign to the arguments of the read or write procedure.
2853
+
2854
+ For example, assuming `mem` is a channel whose read and write access have as argument the target address and data signals, the following code creates a port for always accessing at address 0:
2855
+
2856
+ ```ruby
2857
+ addr0 = channel.input.wrap(0)
2858
+ ```
2859
+
2848
2860
  ### Channel branches
2849
2861
 
2850
2862
  Some channel may include several branches, they are accessed by name using the following method:
@@ -2888,7 +2900,7 @@ Where `name` is the name of the channel and `block` is a procedure block describ
2888
2900
  The first argument of the block must be the following:
2889
2901
  - `blk`: the block to execute when the write completes.
2890
2902
  Other arguments can be freely defined, and will be required by the `write` command.
2891
- * `brancher(name) <block>`: defines branch named +name+ described in `block`. The content of block can be any content valid for a channel, with the additional possiblity to access the internals of the upper channel.
2903
+ * `brancher(name) <block>`: defines branch named +name+ described in `block`. The content of block can be any content valid for a channel, with the additional possibility to access the internals of the upper channel.
2892
2904
 
2893
2905
  For example, a channel implemented by a simple register of generic type `typ`, that can be set to 0 using the `reset` command can be described as follows:
2894
2906
 
@@ -4,8 +4,8 @@ system :rom4_8 do
4
4
  [2..0].input :addr
5
5
  [7..0].output :data0,:data1,:data2
6
6
 
7
- bit[7..0][0..7].constant content0: [1,2,3,4,5,6,7]
8
- bit[7..0][-8].constant content1: [1,2,3,4,5,6,7]
7
+ bit[7..0][0..7].constant content0: [0,1,2,3,4,5,6,7]
8
+ bit[7..0][-8].constant content1: [0,1,2,3,4,5,6,7]
9
9
  bit[7..0][-8].constant content2: (8).times.to_a
10
10
 
11
11
  data0 <= content0[addr]
@@ -0,0 +1,96 @@
1
+ require 'std/memory.rb'
2
+ require 'std/linear.rb'
3
+ # require 'std/timing.rb'
4
+
5
+ include HDLRuby::High::Std
6
+
7
+
8
+ system :fir do |typ,iChannel,oChannel,coefs|
9
+ input :clk, :rst, :req
10
+ output :ack
11
+ # Declare the input port.
12
+ iChannel.input :iPort
13
+ # Declare the output port.
14
+ oChannel.output :oPort
15
+
16
+ # Declares the data registers.
17
+ datas = coefs.map.with_index do |coef,id|
18
+ coef.type.inner :"data_#{id}"
19
+ end
20
+
21
+ inner :req2
22
+
23
+
24
+ # Generate the mac pipeline.
25
+ mac_np(typ,clk.posedge,req2,ack,
26
+ datas.map{|data| channel_port(data) },
27
+ coefs.map{|coef| channel_port(coef) }, oPort)
28
+
29
+ # Generate the data transfer through the pipeline.
30
+ par(clk.posedge) do
31
+ req2 <= 0
32
+ hif(rst) { datas.each { |d| d <= 0 } }
33
+ hif(req) do
34
+ iPort.read(datas[0]) do
35
+ # datas.each_cons(2) { |d0,d1| d1 <= d0 }
36
+ datas[1..-1] <= datas[0..-2]
37
+ end
38
+ req2 <= 1
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+
45
+
46
+
47
+ system :work do
48
+
49
+ inner :clk,:rst,:req,:ack
50
+
51
+ # The input memory.
52
+ mem_rom([8],8,clk,rst,
53
+ [_00000001,_00000010,_00000011,_00000100,
54
+ _00000101,_00000110,_00000111,_00001000]).(:iMem)
55
+ # The output memory.
56
+ mem_dual([8],8,clk,rst).(:oMem)
57
+ # The coefficients.
58
+ coefs = [_11001100,_00110011,_10101010,_01010101,
59
+ _11110000,_00001111,_11100011,_00011100]
60
+
61
+ # The filter
62
+ fir([8],iMem.branch(:rinc),oMem.branch(:winc),coefs).(:my_fir).(clk,rst,req,ack)
63
+
64
+ # iMem.branch(:rinc).inner :port
65
+ # [8].inner :a
66
+ # par(clk.posedge) do
67
+ # hif(req) { port.read(a) }
68
+ # end
69
+
70
+ timed do
71
+ req <= 0
72
+ clk <= 0
73
+ rst <= 0
74
+ !10.ns
75
+ clk <= 1
76
+ !10.ns
77
+ clk <= 0
78
+ rst <= 1
79
+ !10.ns
80
+ clk <= 1
81
+ !10.ns
82
+ clk <= 0
83
+ rst <= 0
84
+ !10.ns
85
+ clk <= 1
86
+ !10.ns
87
+ req <= 1
88
+ clk <= 0
89
+ 64.times do
90
+ !10.ns
91
+ clk <= 1
92
+ !10.ns
93
+ clk <= 0
94
+ end
95
+ end
96
+ end
@@ -63,12 +63,13 @@ end
63
63
 
64
64
 
65
65
  # A system writing indefinitely to a channel.
66
+ # Checking usage of channel without declaring a port.
66
67
  system :producer8 do |channel|
67
- # puts "channel=#{channel}"
68
+ # puts "channel=#{channel}, channel methods=#{channel.methods}"
68
69
  # Inputs of the producer: clock and reset.
69
70
  input :clk, :rst
70
- # Instantiate the channel ports
71
- channel.output :ch
71
+ # # Instantiate the channel ports
72
+ # channel.output :ch
72
73
  # Inner 8-bit counter for generating values.
73
74
  [8].inner :counter
74
75
 
@@ -76,7 +77,8 @@ system :producer8 do |channel|
76
77
  par(clk.posedge) do
77
78
  hif(rst) { counter <= 0 }
78
79
  helse do
79
- ch.write(counter) { counter <= counter + 1 }
80
+ # ch.write(counter) { counter <= counter + 1 }
81
+ channel.write(counter) { counter <= counter + 1 }
80
82
  end
81
83
  end
82
84
  end
@@ -96,20 +98,59 @@ system :consummer8 do |channel|
96
98
  end
97
99
  end
98
100
 
101
+ # A system reading indefinitely from a channel.
102
+ # Version without port declaration.
103
+ system :consummer16 do |channel|
104
+ # Input of the consummer: a clock is enough.
105
+ input :clk
106
+ # # Instantiate the channel ports
107
+ # channel.input :ch
108
+ # Inner buffer for storing the cunsummed value.
109
+ [16].inner :buf
110
+
111
+ # The value consumption process
112
+ par(clk.posedge) do
113
+ # ch.read(buf)
114
+ channel.read(buf)
115
+ end
116
+ end
117
+
99
118
 
100
119
  # A system testing the handshaker.
101
120
  system :hs_test do
102
121
  input :clk,:rst
103
122
 
104
- # Declares the handshaker
105
- handshaker([8]).(:hs)
123
+ # Declares two handshakers
124
+ handshaker([8]).(:hs0)
125
+ handshaker([16]).(:hs1)
106
126
 
107
127
  # # Sets the reset.
108
128
  # par(rst.posedge) { hs.reset }
129
+
130
+ # For the first handshake
109
131
 
110
132
  # Instantiate the producer.
111
- producer8(hs).(:producerI).(clk,rst)
133
+ producer8(hs0).(:producerI).(clk,rst)
112
134
 
113
135
  # Instantiate the consummer.
114
- consummer8(hs).(:consummerI).(clk)
136
+ consummer8(hs0).(:consummerI).(clk)
137
+
138
+ # For the second handshaker
139
+
140
+ # Instantiatethe consummer.
141
+ consummer16(hs1).(:consummer2I).(clk)
142
+
143
+ # Produce from within.
144
+ [16].inner :counter
145
+
146
+ # hs1.output :port
147
+
148
+ par(clk.posedge) do
149
+ hif(rst) { counter <= 0 }
150
+ helse do
151
+ # port.write(counter) { counter <= counter + 1 }
152
+ hs1.write(counter) { counter <= counter + 1 }
153
+ end
154
+ end
155
+
115
156
  end
@@ -12,8 +12,9 @@ system :fix_test do
12
12
 
13
13
  # Performs calculation between then
14
14
  timed do
15
- x <= _00110011
16
- y <= _01000000
15
+ # x <= _00110011 # 3.1875
16
+ x <= 3.1875.to_fix(4)
17
+ y <= _01000000 # 4
17
18
  !10.ns
18
19
  z <= x + y
19
20
  !10.ns
@@ -15,27 +15,36 @@ system :testmat do
15
15
  inner :clk,:rst, :req
16
16
 
17
17
  # Input memories
18
- mem_dual([8],256,clk,rst, rinc: :rst,winc: :rst).(:memL0)
18
+ # mem_dual([8],256,clk,rst, rinc: :rst,winc: :rst).(:memL0)
19
+ # The first memory is 4-bank for testing purpose.
20
+ mem_bank([8],4,256/4,clk,rst, rinc: :rst,winc: :rst).(:memL0)
21
+ # The others are standard dual-edge memories.
19
22
  mem_dual([8],256,clk,rst, rinc: :rst,winc: :rst).(:memL1)
20
23
  mem_dual([8],256,clk,rst, rinc: :rst,winc: :rst).(:memR)
21
24
  # Access ports.
22
- memL0.branch(:rinc).inner :readL0
23
- memL1.branch(:rinc).inner :readL1
24
- memR.branch(:rinc).inner :readR
25
+ # # memL0.branch(:rinc).inner :readL0
26
+ # # memL1.branch(:rinc).inner :readL1
27
+ # # memR.branch(:rinc).inner :readR
28
+ # memL0.branch(:rinc).input :readL0
29
+ # memL1.branch(:rinc).input :readL1
30
+ # memR.branch(:rinc).input :readR
25
31
 
26
32
  # Prepares the left and acc arrays.
27
- lefts = [readL0, readL1]
33
+ # lefts = [readL0, readL1]
34
+ lefts = [memL0.branch(:rinc), memL1.branch(:rinc)]
28
35
 
29
36
  # Accumulators memory.
30
37
  mem_file([8],2,clk,rst,rinc: :rst).(:memAcc)
31
- memAcc.branch(:anum).inner :accs
38
+ # # memAcc.branch(:anum).inner :accs
39
+ memAcc.branch(:anum).inout :accs
32
40
  accs_out = [accs.wrap(0), accs.wrap(1)]
33
41
 
34
42
  # Layer 0 ack.
35
43
  inner :ack0
36
44
 
37
45
  # Instantiate the matrix product.
38
- mac_n1([8],clk,req,ack0,lefts,readR,accs_out)
46
+ # mac_n1([8],clk,req,ack0,lefts,readR,accs_out)
47
+ mac_n1([8],clk,req,ack0,lefts,memR.branch(:rinc),accs_out)
39
48
 
40
49
  # Translation.
41
50
  # Translation memory.
@@ -43,10 +52,12 @@ system :testmat do
43
52
  # Tarnslation result
44
53
  mem_file([8],2,clk,rst,rinc: :rst).(:memF)
45
54
  # Access ports.
46
- memT.branch(:anum).inner :readT
47
- memF.branch(:anum).inner :writeF
55
+ # # memT.branch(:anum).inner :readT
56
+ # # memF.branch(:anum).inner :writeF
57
+ memT.branch(:anum).input :readT
58
+ memF.branch(:anum).output :writeF
48
59
  regRs = [ readT.wrap(0), readT.wrap(1) ]
49
- regLs = [ accs.wrap(0), accs.wrap(1) ]
60
+ regLs = accs_out
50
61
  regs = [ writeF.wrap(0), writeF.wrap(1) ]
51
62
 
52
63
  # Translater ack.
@@ -61,9 +72,10 @@ system :testmat do
61
72
  # Input memories.
62
73
  mem_dual([8],2,clk,rst, rinc: :rst,winc: :rst).(:mem2L0)
63
74
  # Access ports.
64
- mem2L0.branch(:rinc).inner :read2L0
65
- # memAcc.branch(:rinc).inner :accsR
66
- memF.branch(:rinc).inner :readF
75
+ # # mem2L0.branch(:rinc).inner :read2L0
76
+ # # memF.branch(:rinc).inner :readF
77
+ # mem2L0.branch(:rinc).input :read2L0
78
+ # memF.branch(:rinc).input :readF
67
79
 
68
80
  # Second layer ack.
69
81
  inner :ack1
@@ -73,29 +85,40 @@ system :testmat do
73
85
 
74
86
  sub do
75
87
  # Instantiate the second matrix product.
76
- # mac([8],clk,req,read2L0,accsR,res)
77
- mac([8],clk,ackT,ack1,read2L0,readF,channel_port(res))
88
+ # mac([8],clk,ackT,ack1,read2L0,readF,channel_port(res))
89
+ mac([8],clk,ackT,ack1,mem2L0.branch(:rinc),memF.branch(:rinc),
90
+ channel_port(res))
78
91
  end
79
92
 
80
93
 
81
94
 
82
95
  # The memory initializer.
83
- memL0.branch(:winc).inner :writeL0
84
- memL1.branch(:winc).inner :writeL1
85
- memR.branch(:winc).inner :writeR
86
- memT.branch(:winc).inner :writeT
87
- mem2L0.branch(:winc).inner :write2L0
96
+ # # memL0.branch(:winc).inner :writeL0
97
+ # # memL1.branch(:winc).inner :writeL1
98
+ # # memR.branch(:winc).inner :writeR
99
+ # # memT.branch(:winc).inner :writeT
100
+ # # mem2L0.branch(:winc).inner :write2L0
101
+ # memL0.branch(:winc).output :writeL0
102
+ # memL1.branch(:winc).output :writeL1
103
+ # memR.branch(:winc).output :writeR
104
+ # mem2L0.branch(:winc).output :write2L0
105
+ # memT.branch(:winc).output :writeT
88
106
  inner :fill, :fill2
89
107
  [8].inner :val
90
108
  par(clk.posedge) do
91
109
  hif(fill) do
92
- writeL0.write(val)
93
- writeL1.write(val+1)
94
- writeR.write(val+1)
110
+ # writeL0.write(val)
111
+ # writeL1.write(val+1)
112
+ # writeR.write(val+1)
113
+ memL0.branch(:winc).write(val)
114
+ memL1.branch(:winc).write(val+1)
115
+ memR.branch(:winc).write(val+1)
95
116
  end
96
117
  hif(fill2) do
97
- write2L0.write(val+2)
98
- writeT.write(val+2)
118
+ # write2L0.write(val+2)
119
+ # writeT.write(val+2)
120
+ mem2L0.branch(:winc).write(val+2)
121
+ memT.branch(:winc).write(val+2)
99
122
  end
100
123
  end
101
124