HDLRuby 3.5.1 → 3.6.1

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: ddf985a2c95d278dd5267350cb09cf3310d29a21ede26b0dea69381ae0cd8ed8
4
- data.tar.gz: 0b38f0e98fdc47a7a0ba692777957a76cc239fc22d5ae4eb9c4b979df88fa186
3
+ metadata.gz: 86a98906417747050937e8547246ff7ac1cb06e78da82ae4c63385b26dbaa97e
4
+ data.tar.gz: 1096ee8f5bf5ec44409420e6fa60969bf9798f93cec7fa3dd862abc5ac18527f
5
5
  SHA512:
6
- metadata.gz: fbe2f1ecba2cbd9fe06e1707479b5024a4b21a839f857a357b2ea4880ecb90dd1a48a91c8e32b45ea5f1b670d52b1e3fdb6297f71cd2dd05cc013447fd0151ad
7
- data.tar.gz: 16cde53ba9e257f76c60f7ce1b75fda7b416433668d07fe0f696fcdeff000e921777e142cb09140930ccf65de48dea8f4565d0831c896bc7304d59d0bc64f5d2
6
+ metadata.gz: 824c3bf0f96d889913175fccef2d8b854c5da86221e2c70f633f91d104374c6456a1a4958eef0d68da1e3437da8b96b67558b7d563c0cf3c29a6681c8fa8fb1c
7
+ data.tar.gz: 05adeeaa6c1e7a3872d045ad876a295a58548abd610302a94d84f4ac317d84b3bc907adca05daa093cb0d9fa79163836b0d6c5269c9fbcfd83f9cca3dcc42635
data/README.md CHANGED
@@ -17,6 +17,12 @@ hdrcc --get-tuto
17
17
 
18
18
  __What's new__
19
19
 
20
+ For HDLRuby version 3.6.x:
21
+
22
+ * Added a new element for the GUI board that allows to assign an expression to a signal on the fly while simulating.
23
+
24
+ * Added a new slider element for the GUI board (from 3.6.1).
25
+
20
26
  For HDLRuby version 3.5.0:
21
27
 
22
28
  * Added direct support for Verilog HDL files as input to 'hdrcc'.
@@ -2220,6 +2226,12 @@ The list of possible elements is as follows:
2220
2226
 
2221
2227
  * `bt`: represents a set of push buttons, their number is set to match the bit-width of the attached signal.
2222
2228
 
2229
+ * `slider`: represents an horizontal slider.
2230
+
2231
+ * `text`: represents a text input box whose content is interpreted as an expression. The syntax of the expression follows Ruby, and the available variables include the board's display objects. For example, if a set of LEDs is named `leds`, it will be accessible as a variable.
2232
+
2233
+ * `hook`: attaches a signal to the board without displaying. It can be used as a variable in `text` expressions, similar to display objects.
2234
+
2223
2235
  * `led`: represents a set of LEDs, their number is set to match the bit-width of the attached signal.
2224
2236
 
2225
2237
  * `hexa`: represents a hexadecimal number display, its character width is set to match the width of the largest possible value of the attached signal.
@@ -10,20 +10,36 @@ system :with_board do
10
10
  inner rst: 0
11
11
  [8].inner :sw_a, :sw_b
12
12
  [9].inner :led_z
13
+ [8].inner :expr, :show
13
14
  [16].inner counter: 0
14
15
  [8].inner :counter8
15
16
  signed[8].inner :scounter8
16
17
 
18
+ bit[8][-256].inner :mem
19
+ [8].inner :addr, :din, :dout
20
+
21
+ mem[addr] <= din
22
+ dout <= mem[addr]
23
+
17
24
  # Description of the board.
18
25
  # It is updated at each rising edge of +clk2+.
19
26
  board(:some_board) do
20
27
  actport clk2.posedge
21
28
  bt reset: rst
29
+ hook sw_ai: sw_a
30
+ hook sw_bi: sw_b
22
31
  row
23
32
  sw sw_a: sw_a
24
- sw sw_b: sw_b
33
+ slider sw_b: sw_b
25
34
  led led_z: led_z
26
35
  row
36
+ text expr: expr
37
+ digit show: show
38
+ row
39
+ text addr: addr
40
+ hexa dout: dout
41
+ text din: din
42
+ row
27
43
  digit cnt_d: counter
28
44
  hexa cnt_h: counter
29
45
  digit cnt_s: scounter8
@@ -35,6 +51,9 @@ system :with_board do
35
51
  # The adder.
36
52
  led_z <= sw_a.as(bit[9]) + sw_b
37
53
 
54
+ # The text input and result.
55
+ show <= expr
56
+
38
57
  # The counters and the generation of +clk2+.
39
58
  counter8 <= counter[7..0]
40
59
  scounter8 <= counter[7..0]
@@ -52,7 +71,7 @@ system :with_board do
52
71
  clk <= 0
53
72
  clk2 <= 0
54
73
  !10.ns
55
- repeat(1000) do
74
+ repeat(10000) do
56
75
  clk <= 1
57
76
  !10.ns
58
77
  clk <= 0
@@ -20,6 +20,9 @@ module HDLRuby::High::Std
20
20
  include Hmissing
21
21
 
22
22
  attr_reader :namespace
23
+
24
+ ## Suffix telling a text is an expression to compute.
25
+ TO_COMPUTE = "="
23
26
 
24
27
  ## Class describing a row of slide switches.
25
28
  SW = Struct.new(:id, :size, :hwrite) do
@@ -31,7 +34,7 @@ module HDLRuby::High::Std
31
34
  '<label class="sw"><input type="checkbox" data-bit="' +
32
35
  (self.size-i-1).to_s + '" ' +
33
36
  'onchange="sw_change(this)">' +
34
- '<span class="slider"></span></label>\n'
37
+ '<span class="sw_slider"></span></label>\n'
35
38
  end.join + "</div>\\n"
36
39
  end
37
40
  end
@@ -49,6 +52,43 @@ module HDLRuby::High::Std
49
52
  end.join + "</div>\\n"
50
53
  end
51
54
  end
55
+
56
+ ## Class describing an "analog" slide switch.
57
+ SLIDER = Struct.new(:id, :min, :max, :hwrite) do
58
+ def to_html
59
+ # Prepare the min, max and blank strings.
60
+ min = self.min.to_s
61
+ max = self.max.to_s
62
+ return "<div class=\"sliderset\" id=\"#{self.id}\" data-value=\"0\">\\n" +
63
+ '<span class="name">' + self.hwrite.to_s.chop + '</span>' +
64
+ '<span>&nbsp;&nbsp;</span>' +
65
+ '<input type="range" min="' + min + '" max="' + max +
66
+ '" value="' + min + '" ' +
67
+ 'class="slider" oninput="slider_change(this)">' +
68
+ "</div>\\n"
69
+ end
70
+ end
71
+
72
+ ## Class describing a text-based input.
73
+ TEXT = Struct.new(:id, :size, :hwrite) do
74
+ def to_html
75
+ return "<div class=\"textset\" id=\"#{self.id}\" data-value=\"0\">\\n" +
76
+ '<form onSubmit="text_submit(this); return false">\\n' +
77
+ '<span class="name">' + self.hwrite.to_s.chop + '</span>' +
78
+ '<span>&nbsp;&nbsp;</span>' +
79
+ '<input class="matrix_in" type="text" name="text" ' +
80
+ 'placeholder="Enter an expression">' +
81
+ "</form>\\n" +
82
+ "</div>\\n"
83
+ end
84
+ end
85
+
86
+ ## Class describing a hook (invisible display element).
87
+ HOOK = Struct.new(:id, :size, :hread) do
88
+ def to_html
89
+ return "<div id=\"#{self.id}\" data-value=\"0\"/>\\n"
90
+ end
91
+ end
52
92
 
53
93
  ## Class describing a row of LEDs.
54
94
  LED = Struct.new(:id, :size, :hread) do
@@ -248,6 +288,16 @@ Content-Type: text/html
248
288
  height: 40px;
249
289
  }
250
290
 
291
+ .sliderset {
292
+ display: flex;
293
+ flex-direction: row;
294
+ justify-content: center;
295
+ align-items: center;
296
+ margin-left: 8px;
297
+ margin-right: 8px;
298
+ height: 40px;
299
+ }
300
+
251
301
  .ledset {
252
302
  display: flex;
253
303
  flex-direction: row;
@@ -430,7 +480,7 @@ Content-Type: text/html
430
480
  height: 0;
431
481
  }
432
482
 
433
- .slider {
483
+ .sw_slider {
434
484
  position: absolute;
435
485
  cursor: pointer;
436
486
  top: 0;
@@ -443,7 +493,7 @@ Content-Type: text/html
443
493
  border: solid 2px #505050;
444
494
  }
445
495
 
446
- .slider:before {
496
+ .sw_slider:before {
447
497
  position: absolute;
448
498
  content: "";
449
499
  height: 16px;
@@ -455,16 +505,48 @@ Content-Type: text/html
455
505
  transition: .2s;
456
506
  }
457
507
 
458
- input:checked + .slider {
508
+ input:checked + .sw_slider {
459
509
  background-color: yellow;
460
510
  }
461
511
 
462
- input:checked + .slider:before {
512
+ input:checked + .sw_slider:before {
463
513
  -webkit-transform: translateY(-16px);
464
514
  -ms-transform: translateY(-16px);
465
515
  transform: translateY(-16px);
466
516
  }
467
517
 
518
+ .slider {
519
+ -webkit-appearance: none;
520
+ width: 100%;
521
+ height: 25px;
522
+ background-color: #ccc;
523
+ -webkit-transition: .2s;
524
+ transition: .2s;
525
+ border: solid 2px #505050;
526
+ margin: 2px;
527
+ box-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
528
+ -moz-box-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
529
+ -webkit-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
530
+ }
531
+
532
+ .slider::-webkit-slider-thumb {
533
+ -webkit-appearance: none;
534
+ appearance: none;
535
+ width: 25px;
536
+ height: 25px;
537
+ background: black;
538
+ border: solid 2px #505050;
539
+ cursor: pointer;
540
+ }
541
+
542
+ .slider::-moz-range-thumb {
543
+ width: 25px;
544
+ height: 25px;
545
+ background: black;
546
+ border: solid 2px #505050;
547
+ cursor: pointer;
548
+ }
549
+
468
550
  .matrix {
469
551
  font-size: 26px;
470
552
  font-family: "Lucida Console", "Courier New", monospace;
@@ -476,6 +558,17 @@ Content-Type: text/html
476
558
  -webkit-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
477
559
  }
478
560
 
561
+ .matrix_in {
562
+ font-size: 26px;
563
+ font-family: "Lucida Console", "Courier New", monospace;
564
+ color: #0B190B;
565
+ background-color: #9BBC0F;
566
+ border: solid 2px #505050;
567
+ box-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
568
+ -moz-box-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
569
+ -webkit-shadow: -1px -1px 1px white, 1px 1px 1px #101010;
570
+ }
571
+
479
572
  .bt {
480
573
  background-color: #ccc;
481
574
  border: solid 2px #505050;
@@ -586,7 +679,9 @@ Content-Type: text/html
586
679
  const element = prow.lastElementChild;
587
680
  // Depending of the kind of element.
588
681
  if (element.classList.contains('swset') ||
589
- element.classList.contains('btset')) {
682
+ element.classList.contains('btset') ||
683
+ element.classList.contains('sliderset') ||
684
+ element.classList.contains('textset') ) {
590
685
  // Input element.
591
686
  input_ids.push(element.id);
592
687
  } else {
@@ -628,6 +723,14 @@ Content-Type: text/html
628
723
  // console.log("sw value=" + swset.dataset.value);
629
724
  }
630
725
 
726
+ // Handler of slider change.
727
+ function slider_change(slider) {
728
+ // Get the set holding slider.
729
+ const sliderset = slider.parentElement;
730
+ sliderset.dataset.value = slider.value;
731
+ // console.log("slider value=" + sliderset.dataset.value);
732
+ }
733
+
631
734
  // Set the aspect of a button to clicked.
632
735
  function bt_on(bt) {
633
736
  bt.innerHTML = '<i class="bt_on"></i>';
@@ -660,6 +763,16 @@ Content-Type: text/html
660
763
  btset.dataset.value = btset.dataset.value & ~(1 << bit);
661
764
  }
662
765
 
766
+
767
+ // Handler of the text submit
768
+ function text_submit(form) {
769
+ // Get the et holding the form.
770
+ const textset = form.parentElement;
771
+ // Update the value, suffixed with #{TO_COMPUTE} for telling it is a
772
+ // text expression to compute.
773
+ textset.dataset.value = form.elements.text.value + "#{TO_COMPUTE}"
774
+ }
775
+
663
776
 
664
777
  // Switch a led on.
665
778
  function led_on(led) {
@@ -916,7 +1029,7 @@ HTMLRESPONSE
916
1029
  end
917
1030
  # Create the HDLRuby program port.
918
1031
  @program.outport(hport)
919
- # Create the ui component.
1032
+ # Create the UI component.
920
1033
  hport = hport.first
921
1034
  @elements << SW.new(@elements.size,hport[1].type.width,:"#{hport[0]}=")
922
1035
  end
@@ -929,10 +1042,58 @@ HTMLRESPONSE
929
1042
  # Create the HDLRuby program port.
930
1043
  @program.outport(hport)
931
1044
  hport = hport.first
932
- # Create the ui component.
1045
+ # Create the UI component.
933
1046
  @elements << BT.new(@elements.size,hport[1].type.width,:"#{hport[0]}=")
934
1047
  end
935
1048
 
1049
+ # Add a new slider element attached to HDLRuby port +hport+
1050
+ def slider(hport)
1051
+ if !hport.is_a?(Hash) or hport.size != 1 then
1052
+ raise UIError.new("Malformed HDLRuby port declaration: #{hport}")
1053
+ end
1054
+ # Create the HDLRuby program port.
1055
+ @program.outport(hport)
1056
+ hport = hport.first
1057
+ # Compute the min and max values.
1058
+ width = hport[1].type.width
1059
+ if hport[1].type.signed? then
1060
+ min = -2**(width-1)
1061
+ max = 2**(width-1) - 1
1062
+ else
1063
+ min = 0
1064
+ max = 2**width - 1
1065
+ end
1066
+ # Create the UI component.
1067
+ @elements << SLIDER.new(@elements.size,min,max,:"#{hport[0]}=")
1068
+ end
1069
+
1070
+ # Add a new text input element attached to HDLRuby port +hport+
1071
+ def text(hport)
1072
+ if !hport.is_a?(Hash) or hport.size != 1 then
1073
+ raise UIError.new("Malformed HDLRuby port declaration: #{hport}")
1074
+ end
1075
+ # Create the HDLRuby program port.
1076
+ @program.outport(hport)
1077
+ hport = hport.first
1078
+ # Create the UI component.
1079
+ @elements << TEXT.new(@elements.size,hport[1].type.width,:"#{hport[0]}=")
1080
+ end
1081
+
1082
+ # Add a new hook element attached to HDLRuby port +hport+.
1083
+ # NOTE: a hook element is not displayed on the board but can be used
1084
+ # in the `text` expression.
1085
+ def hook(hport)
1086
+ if !hport.is_a?(Hash) or hport.size != 1 then
1087
+ raise UIError.new("Malformed HDLRuby port declaration: #{hport}")
1088
+ end
1089
+ # Create the HDLRuby program port.
1090
+ @program.inport(hport)
1091
+ hport = hport.first
1092
+ # Createthe UI component (invisible)
1093
+ @elements << HOOK.new(@elements.size,hport[1].type.width,hport[0])
1094
+ @out_elements << @elements[-1]
1095
+ end
1096
+
936
1097
  # Add a new LED element attached to HDLRuby port +hport+.
937
1098
  def led(hport)
938
1099
  if !hport.is_a?(Hash) or hport.size != 1 then
@@ -941,7 +1102,7 @@ HTMLRESPONSE
941
1102
  # Create the HDLRuby program port.
942
1103
  @program.inport(hport)
943
1104
  hport = hport.first
944
- # Createthe ui component.
1105
+ # Createthe UI component.
945
1106
  @elements << LED.new(@elements.size,hport[1].type.width,hport[0])
946
1107
  @out_elements << @elements[-1]
947
1108
  end
@@ -1032,6 +1193,33 @@ HTMLRESPONSE
1032
1193
  end
1033
1194
 
1034
1195
 
1196
+ # Compute a value.
1197
+ def compute(val)
1198
+ # Preprocess val to match Ruby syntax.
1199
+ val = "0" unless val
1200
+ val = val.gsub("%20"," ")
1201
+ # Replace the names by the corresponding ports read result.
1202
+ val = val.gsub(/([\._a-zA-Z0-9]+)/) do |str|
1203
+ if str[0] >= "a" && str[0] <= "z" then
1204
+ # Variable identifier, process it if recognized.
1205
+ RubyHDL.send(Regexp.last_match[1]).to_s rescue str
1206
+ else
1207
+ # Other token leave it as is.
1208
+ str
1209
+ end
1210
+ end
1211
+ # Compute.
1212
+ res = 0
1213
+ safe = $SAFE
1214
+ begin
1215
+ $SAFE = 2
1216
+ res = eval(val).to_i
1217
+ rescue SyntaxError => se
1218
+ rescue StandardError => se
1219
+ end
1220
+ $SAFE = safe
1221
+ return res
1222
+ end
1035
1223
 
1036
1224
  # Update port number +id+ with value +val+.
1037
1225
  def update_port(id,val)
@@ -1057,8 +1245,17 @@ HTMLRESPONSE
1057
1245
  # This should be an AJAX request, process it.
1058
1246
  commands = request.split(";")
1059
1247
  commands.each do |command|
1060
- next unless command.include?(":")
1061
- id, val = command.split(":").map {|t| t.to_i}
1248
+ # next unless command.include?(":")
1249
+ # id, val = command.split(":").map {|t| t.to_i}
1250
+ id, val = command.split(":",2)
1251
+ next unless val
1252
+ id = id.to_i
1253
+ if val[-1] == "=" then
1254
+ # This is an expression to compute.
1255
+ val = self.compute(val.chop)
1256
+ else
1257
+ val = val.to_i
1258
+ end
1062
1259
  self.update_port(id,val)
1063
1260
  end
1064
1261
  # And generate the response: an update of each board output element.
@@ -1,3 +1,3 @@
1
1
  module HDLRuby
2
- VERSION = "3.5.1"
2
+ VERSION = "3.6.1"
3
3
  end
@@ -3047,6 +3047,12 @@ end
3047
3047
  </li>
3048
3048
  <li><p><code>led</code>: represents a set of LEDs, their number is set to match the bit-width of the attached signal.</p>
3049
3049
  </li>
3050
+ <li><p><code>slider</code>: represents an horizontal slider.</p>
3051
+ </li>
3052
+ <li><p><code>text</code>: represents a text input box whose content is interpreted as an expression. The syntax of the expression follows Ruby, and the available variables include the board's display objects. For example, if a set of LEDs is named <code>leds</code>, it will be accessible as a variable.</p>
3053
+ </li>
3054
+ <li><p><code>hook</code>: attaches a signal to the board without displaying. It can be used as a variable in <code>text</code> expressions, similar to display objects.</p>
3055
+ </li>
3050
3056
  <li><p><code>hexa</code>: represents a hexadecimal number display, its character width is set to match the width of the largest possible value of the attached signal.</p>
3051
3057
  </li>
3052
3058
  <li><p><code>digit</code>: represents a decimal number display, its character width is set to match the width of the largest possible positive or the smallest possible negative value of the attached signal.</p>
data/tuto/tutorial_sw.md CHANGED
@@ -3750,6 +3750,12 @@ And the comprise the following:
3750
3750
 
3751
3751
  * `led`: represents a set of LEDs, their number is set to match the bit-width of the attached signal.
3752
3752
 
3753
+ * `slider`: represents an horizontal slider.
3754
+
3755
+ * `text`: represents a text input box whose content is interpreted as an expression. The syntax of the expression follows Ruby, and the available variables include the board's display objects. For example, if a set of LEDs is named `leds`, it will be accessible as a variable.
3756
+
3757
+ * `hook`: attaches a signal to the board without displaying. It can be used as a variable in `text` expressions, similar to display objects.
3758
+
3753
3759
  * `hexa`: represents a hexadecimal number display, its character width is set to match the width of the largest possible value of the attached signal.
3754
3760
 
3755
3761
  * `digit`: represents a decimal number display, its character width is set to match the width of the largest possible positive or the smallest possible negative value of the attached signal.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: HDLRuby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.1
4
+ version: 3.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lovic Gauthier
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2024-12-25 00:00:00.000000000 Z
10
+ date: 2025-01-09 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler
@@ -488,7 +488,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
488
488
  - !ruby/object:Gem::Version
489
489
  version: '0'
490
490
  requirements: []
491
- rubygems_version: 3.6.0
491
+ rubygems_version: 3.6.2
492
492
  specification_version: 4
493
493
  summary: HDLRuby is a library for describing and simulating digital electronic systems.
494
494
  test_files: []