HDLRuby 3.5.1 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []