HDLRuby 3.9.0 → 3.9.3

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.
@@ -1,4 +1,4 @@
1
- # An IC netlist mrdel and SVG-based vizualizer for HDLRuby
1
+ # An IC netlist model and SVG-based vizualizer for HDLRuby
2
2
 
3
3
  # require 'stackprof'
4
4
 
@@ -12,6 +12,21 @@ module HDLRuby::Viz
12
12
  DOWN = 8
13
13
  BLOCKED = 16
14
14
 
15
+ # Get the base name of the port.
16
+ def self.port_base_name(name)
17
+ return name.sub(/\[.*\]\z/,"")
18
+ end
19
+
20
+ # Get the bit part of the port name if any.
21
+ def self.port_bit_name(name)
22
+ return name.match(/\[.*\]\z/)[0]
23
+ end
24
+
25
+ # Tell if a port name is for a sub port.
26
+ def self.port_bit_name?(name)
27
+ return name =~ /\[.*\]\z/
28
+ end
29
+
15
30
 
16
31
  # An IC Port
17
32
  class Port
@@ -110,6 +125,9 @@ module HDLRuby::Viz
110
125
 
111
126
  # Give the size of the IC in number of statements.
112
127
  def number_statements
128
+ if self.type == :instance then
129
+ return self.system.number_statements
130
+ end
113
131
  # Get the number from the branches.
114
132
  snum = @branches.reduce(0) do |sum,branch|
115
133
  sum + branch.number_statements
@@ -118,6 +136,7 @@ module HDLRuby::Viz
118
136
  snum += @children.reduce(0) do |sum,child|
119
137
  sum + child.number_statements
120
138
  end
139
+ return snum
121
140
  end
122
141
 
123
142
 
@@ -269,43 +288,54 @@ module HDLRuby::Viz
269
288
  @uports.clear
270
289
  @rports.clear
271
290
  @dports.clear
291
+ # Ports sides by direction and base name.
292
+ @port_base_dir = {}
293
+ # Process the ports.
272
294
  @ports.each do |port|
273
- if port.targets.empty? then
274
- puts "Dangling port: #{port.name} (of #{port.ic.name})"
275
- # Not connected port, put it on the side with the less ports.
276
- if port.direction == :input then
277
- if lports.size <= uports.size then
278
- port.side = LEFT
279
- else
280
- port.side = UP
281
- end
282
- else
283
- if rports.size <= dports.size then
284
- port.side = RIGHT
285
- else
286
- port.side = DOWN
287
- end
288
- end
295
+ # Maybe there is a port with the same direction.
296
+ side = @port_base_dir[[HDLRuby::Viz.port_base_name(port.name),
297
+ port.direction]]
298
+ if side then
299
+ port.side = side
289
300
  else
290
- # The port is connected.
291
- if port.direction == :input then
292
- # For now, use the first target only for deciding.
293
- d_left = port.targets[0].ic.xpos - @box[0]
294
- d_up = @box[3] -
295
- port.targets[0].ic.ypos + port.targets[0].ic.height
296
- if d_left <= d_up then
297
- port.side = LEFT
301
+ # No, process to port.
302
+ if port.targets.empty? then
303
+ puts "Dangling port: #{port.name} (of #{port.ic.name})"
304
+ # Not connected port, put it on the side with the less ports.
305
+ if port.direction == :input then
306
+ if lports.size <= uports.size then
307
+ port.side = LEFT
308
+ else
309
+ port.side = UP
310
+ end
298
311
  else
299
- port.side = UP
312
+ if rports.size <= dports.size then
313
+ port.side = RIGHT
314
+ else
315
+ port.side = DOWN
316
+ end
300
317
  end
301
318
  else
302
- d_right = @box[2] -
303
- port.targets[0].ic.xpos + port.targets[0].ic.width
304
- d_down = port.targets[0].ic.ypos - @box[1]
305
- if d_right <= d_down then
306
- port.side = RIGHT
319
+ # The port is connected.
320
+ if port.direction == :input then
321
+ # For now, use the first target only for deciding.
322
+ d_left = port.targets[0].ic.xpos - @box[0]
323
+ d_up = @box[3] -
324
+ port.targets[0].ic.ypos + port.targets[0].ic.height
325
+ if d_left <= d_up then
326
+ port.side = LEFT
327
+ else
328
+ port.side = UP
329
+ end
307
330
  else
308
- port.side = DOWN
331
+ d_right = @box[2] -
332
+ port.targets[0].ic.xpos + port.targets[0].ic.width
333
+ d_down = port.targets[0].ic.ypos - @box[1]
334
+ if d_right <= d_down then
335
+ port.side = RIGHT
336
+ else
337
+ port.side = DOWN
338
+ end
309
339
  end
310
340
  end
311
341
  end
@@ -321,6 +351,9 @@ module HDLRuby::Viz
321
351
  when DOWN
322
352
  @dports << port
323
353
  end
354
+ # Also for the handling of bits.
355
+ @port_base_dir[[HDLRuby::Viz.port_base_name(port.name),
356
+ port.direction]] = port.side
324
357
  end
325
358
  end
326
359
 
@@ -675,6 +708,7 @@ module HDLRuby::Viz
675
708
  nd = child.dports.size * @port_width
676
709
  child.height = nl > nr ? nl : nr
677
710
  child.width = nu > nd ? nu : nd
711
+ puts "For assign" if child.type == :assign
678
712
  puts "First width=#{child.width} height=#{child.height} [#{child.lports.size},#{child.uports.size},#{child.rports.size},#{child.dports.size}]"
679
713
  # Ensure IC have some thickness.
680
714
  if child.type != :register then
@@ -684,15 +718,17 @@ module HDLRuby::Viz
684
718
  child.width = @port_width if child.width < @port_width
685
719
  # But enlarge if more than one port horizontally or
686
720
  # vertically for easier routing and readability.
687
- if child.lports.size + child.rports.size > 1 and
688
- child.height == @port_width and
689
- child.width == @port_width then
690
- child.width *= 2
691
- end
692
- if child.uports.size + child.dports.size > 1 and
693
- child.width == @port_width and
694
- child.height == @port_width then
695
- child.height *= 2
721
+ if child.type != :assign then # However assign are treated appart
722
+ if child.lports.size + child.rports.size > 1 and
723
+ child.height == @port_width and
724
+ child.width == @port_width then
725
+ child.width *= 2
726
+ end
727
+ if child.uports.size + child.dports.size > 1 and
728
+ child.width == @port_width and
729
+ child.height == @port_width then
730
+ child.height *= 2
731
+ end
696
732
  end
697
733
  # Also ensure the chip is wide enough.
698
734
  if child.type == :assign then
@@ -728,8 +764,9 @@ module HDLRuby::Viz
728
764
  child.height = 3 if child.height < @port_width
729
765
  child.width = 3 if child.width < @port_width
730
766
  end
731
- puts "for register: #{child.name} ports.size=#{child.ports.size}, width=#{child.width} height=#{child.height}"
767
+ # puts "for register: #{child.name} ports.size=#{child.ports.size}, width=#{child.width} height=#{child.height}"
732
768
  end
769
+ puts "Then width=#{child.width} height=#{child.height} [#{child.lports.size},#{child.uports.size},#{child.rports.size},#{child.dports.size}]"
733
770
 
734
771
  end
735
772
  end
@@ -759,6 +796,7 @@ module HDLRuby::Viz
759
796
  puts "With number of statements: #{num} are base area=#{area}"
760
797
  # First compute the target area, and width and height of each type.
761
798
  ics.each do |ic|
799
+ puts "For ic=#{ic.name}"
762
800
  # Update the target area.
763
801
  n_area = ic.width * ic.height
764
802
  area = n_area if n_area > area
@@ -782,11 +820,13 @@ module HDLRuby::Viz
782
820
  pH = ic.height if ic.height > pH
783
821
  # Ensure the target area is reached.
784
822
  if ic.branches[0].type == :par then
785
- # For par processes, increase squarely.
786
- if pW <= pH then
787
- pW += 1
788
- else
789
- pH += 1
823
+ while pW*pW < area do
824
+ # For par processes, increase squarely.
825
+ if pW <= pH then
826
+ pW += 1
827
+ else
828
+ pH += 1
829
+ end
790
830
  end
791
831
  else
792
832
  # For non par processes, increase vertically.
@@ -804,7 +844,7 @@ module HDLRuby::Viz
804
844
  if ic.type == :instance then
805
845
  ic.width = iW
806
846
  ic.height = iH
807
- else
847
+ elsif [:process, :clocked_process, :timed_process]. include?(ic.type) then
808
848
  puts "For process #{ic.name} setting size from #{ic.width},#{ic.height} to #{pW},#{pH}"
809
849
  ic.width = pW
810
850
  ic.height = pH
@@ -1278,6 +1318,7 @@ module HDLRuby::Viz
1278
1318
  # Also place the ports of the current IC.
1279
1319
  poses = []
1280
1320
  @lports.each do |lport|
1321
+ next unless lport.targets[0] # Skip dangling port.
1281
1322
  lport.ypos = lport.targets[0].ypos
1282
1323
  lport.ypos += 1 if lport.targets[0].side == UP
1283
1324
  lport.ypos -= 1 if lport.targets[0].side == DOWN
@@ -1290,10 +1331,10 @@ module HDLRuby::Viz
1290
1331
  end
1291
1332
  poses = []
1292
1333
  @uports.each do |uport|
1334
+ next unless uport.targets[0] # Skip dangling port.
1293
1335
  uport.xpos = uport.targets[0].xpos
1294
1336
  uport.xpos -= 1 if uport.targets[0].side == LEFT
1295
1337
  uport.xpos += 1 if uport.targets[0].side == RIGHT
1296
- puts "Now uport.xpos=#{uport.xpos}"
1297
1338
  # Ensure ports do not overlap.
1298
1339
  while poses[uport.xpos] do
1299
1340
  uport.xpos += 1
@@ -1303,6 +1344,7 @@ module HDLRuby::Viz
1303
1344
  end
1304
1345
  poses = []
1305
1346
  @rports.each do |rport|
1347
+ next unless rport.targets[0] # Skip dangling port.
1306
1348
  rport.ypos = rport.targets[0].ypos
1307
1349
  rport.ypos += 1 if rport.targets[0].side == UP
1308
1350
  rport.ypos -= 1 if rport.targets[0].side == DOWN
@@ -1315,6 +1357,7 @@ module HDLRuby::Viz
1315
1357
  end
1316
1358
  poses = []
1317
1359
  @dports.each do |dport|
1360
+ next unless dport.targets[0] # Skip dangling port.
1318
1361
  dport.xpos = dport.targets[0].xpos
1319
1362
  dport.xpos -= 1 if dport.targets[0].side == LEFT
1320
1363
  dport.xpos += 1 if dport.targets[0].side == RIGHT
@@ -1531,41 +1574,127 @@ module HDLRuby::Viz
1531
1574
  end
1532
1575
 
1533
1576
  # Get the neighbor free positions for port.
1534
- # def free_neighbors(port,cpos)
1535
1577
  def free_neighbors(port0,port1,cpos)
1536
1578
  res = []
1537
- # Left neighbor.
1538
- lpos = [cpos[0]-1,cpos[1]]
1539
- if lpos[0] >= 0 then
1540
- elem = @route_matrix[lpos[1]][lpos[0]]
1541
- # res << lpos if elem.free_from_right?(port)
1542
- res << lpos if elem.free_from_right?(port0,port1) and
1543
- !ic_port_conflict(port0,port1,[lpos[0]-1,lpos[1]],RIGHT)
1544
- end
1545
- # Up neighbor.
1546
- upos = [cpos[0],cpos[1]+1]
1547
- if upos[1] < @route_height then
1548
- elem = @route_matrix[upos[1]][upos[0]]
1549
- # res << upos if elem.free_from_down?(port)
1550
- res << upos if elem.free_from_down?(port0,port1) and
1551
- !ic_port_conflict(port0,port1,[upos[0],upos[1]+1],DOWN)
1552
- end
1553
- # Right neighbor.
1554
- rpos = [cpos[0]+1,cpos[1]]
1555
- if rpos[0] < @route_width then
1556
- elem = @route_matrix[rpos[1]][rpos[0]]
1557
- # res << rpos if elem.free_from_left?(port)
1558
- res << rpos if elem.free_from_left?(port0,port1) and
1559
- !ic_port_conflict(port0,port1,[rpos[0]+1,rpos[1]],LEFT)
1560
- end
1561
- # Down neighbor.
1562
- dpos = [cpos[0],cpos[1]-1]
1563
- if dpos[1] >= 0 then
1564
- elem = @route_matrix[dpos[1]][dpos[0]]
1565
- # res << dpos if elem.free_from_up?(port)
1566
- res << dpos if elem.free_from_up?(port0,port1) and
1567
- !ic_port_conflict(port0,port1,[dpos[0],dpos[1]-1],UP)
1568
- end
1579
+ # For cosmetic reasons of the wires, the order of processing depends
1580
+ # on the relative position of the ports.
1581
+ if port0.xpos < port1.xpos and port0.ypos < port1.ypos then
1582
+ # Left neighbor.
1583
+ lpos = [cpos[0]-1,cpos[1]]
1584
+ if lpos[0] >= 0 then
1585
+ elem = @route_matrix[lpos[1]][lpos[0]]
1586
+ res << lpos if elem.free_from_right?(port0,port1) and
1587
+ !ic_port_conflict(port0,port1,[lpos[0]-1,lpos[1]],RIGHT)
1588
+ end
1589
+ # Up neighbor.
1590
+ upos = [cpos[0],cpos[1]+1]
1591
+ if upos[1] < @route_height then
1592
+ elem = @route_matrix[upos[1]][upos[0]]
1593
+ res << upos if elem.free_from_down?(port0,port1) and
1594
+ !ic_port_conflict(port0,port1,[upos[0],upos[1]+1],DOWN)
1595
+ end
1596
+ # Right neighbor.
1597
+ rpos = [cpos[0]+1,cpos[1]]
1598
+ if rpos[0] < @route_width then
1599
+ elem = @route_matrix[rpos[1]][rpos[0]]
1600
+ res << rpos if elem.free_from_left?(port0,port1) and
1601
+ !ic_port_conflict(port0,port1,[rpos[0]+1,rpos[1]],LEFT)
1602
+ end
1603
+ # Down neighbor.
1604
+ dpos = [cpos[0],cpos[1]-1]
1605
+ if dpos[1] >= 0 then
1606
+ elem = @route_matrix[dpos[1]][dpos[0]]
1607
+ res << dpos if elem.free_from_up?(port0,port1) and
1608
+ !ic_port_conflict(port0,port1,[dpos[0],dpos[1]-1],UP)
1609
+ end
1610
+ elsif port0.xpos < port1.xpos and port0.ypos > port1.ypos then
1611
+ # Left neighbor.
1612
+ lpos = [cpos[0]-1,cpos[1]]
1613
+ if lpos[0] >= 0 then
1614
+ elem = @route_matrix[lpos[1]][lpos[0]]
1615
+ res << lpos if elem.free_from_right?(port0,port1) and
1616
+ !ic_port_conflict(port0,port1,[lpos[0]-1,lpos[1]],RIGHT)
1617
+ end
1618
+ # Down neighbor.
1619
+ dpos = [cpos[0],cpos[1]-1]
1620
+ if dpos[1] >= 0 then
1621
+ elem = @route_matrix[dpos[1]][dpos[0]]
1622
+ res << dpos if elem.free_from_up?(port0,port1) and
1623
+ !ic_port_conflict(port0,port1,[dpos[0],dpos[1]-1],UP)
1624
+ end
1625
+ # Right neighbor.
1626
+ rpos = [cpos[0]+1,cpos[1]]
1627
+ if rpos[0] < @route_width then
1628
+ elem = @route_matrix[rpos[1]][rpos[0]]
1629
+ res << rpos if elem.free_from_left?(port0,port1) and
1630
+ !ic_port_conflict(port0,port1,[rpos[0]+1,rpos[1]],LEFT)
1631
+ end
1632
+ # Up neighbor.
1633
+ upos = [cpos[0],cpos[1]+1]
1634
+ if upos[1] < @route_height then
1635
+ elem = @route_matrix[upos[1]][upos[0]]
1636
+ res << upos if elem.free_from_down?(port0,port1) and
1637
+ !ic_port_conflict(port0,port1,[upos[0],upos[1]+1],DOWN)
1638
+ end
1639
+ elsif port0.xpos > port1.xpos and port0.ypos > port1.ypos then
1640
+ # Right neighbor.
1641
+ rpos = [cpos[0]+1,cpos[1]]
1642
+ if rpos[0] < @route_width then
1643
+ elem = @route_matrix[rpos[1]][rpos[0]]
1644
+ res << rpos if elem.free_from_left?(port0,port1) and
1645
+ !ic_port_conflict(port0,port1,[rpos[0]+1,rpos[1]],LEFT)
1646
+ end
1647
+ # Down neighbor.
1648
+ dpos = [cpos[0],cpos[1]-1]
1649
+ if dpos[1] >= 0 then
1650
+ elem = @route_matrix[dpos[1]][dpos[0]]
1651
+ res << dpos if elem.free_from_up?(port0,port1) and
1652
+ !ic_port_conflict(port0,port1,[dpos[0],dpos[1]-1],UP)
1653
+ end
1654
+ # Left neighbor.
1655
+ lpos = [cpos[0]-1,cpos[1]]
1656
+ if lpos[0] >= 0 then
1657
+ elem = @route_matrix[lpos[1]][lpos[0]]
1658
+ res << lpos if elem.free_from_right?(port0,port1) and
1659
+ !ic_port_conflict(port0,port1,[lpos[0]-1,lpos[1]],RIGHT)
1660
+ end
1661
+ # Up neighbor.
1662
+ upos = [cpos[0],cpos[1]+1]
1663
+ if upos[1] < @route_height then
1664
+ elem = @route_matrix[upos[1]][upos[0]]
1665
+ res << upos if elem.free_from_down?(port0,port1) and
1666
+ !ic_port_conflict(port0,port1,[upos[0],upos[1]+1],DOWN)
1667
+ end
1668
+ else
1669
+ # Right neighbor.
1670
+ rpos = [cpos[0]+1,cpos[1]]
1671
+ if rpos[0] < @route_width then
1672
+ elem = @route_matrix[rpos[1]][rpos[0]]
1673
+ res << rpos if elem.free_from_left?(port0,port1) and
1674
+ !ic_port_conflict(port0,port1,[rpos[0]+1,rpos[1]],LEFT)
1675
+ end
1676
+ # Up neighbor.
1677
+ upos = [cpos[0],cpos[1]+1]
1678
+ if upos[1] < @route_height then
1679
+ elem = @route_matrix[upos[1]][upos[0]]
1680
+ res << upos if elem.free_from_down?(port0,port1) and
1681
+ !ic_port_conflict(port0,port1,[upos[0],upos[1]+1],DOWN)
1682
+ end
1683
+ # Left neighbor.
1684
+ lpos = [cpos[0]-1,cpos[1]]
1685
+ if lpos[0] >= 0 then
1686
+ elem = @route_matrix[lpos[1]][lpos[0]]
1687
+ res << lpos if elem.free_from_right?(port0,port1) and
1688
+ !ic_port_conflict(port0,port1,[lpos[0]-1,lpos[1]],RIGHT)
1689
+ end
1690
+ # Down neighbor.
1691
+ dpos = [cpos[0],cpos[1]-1]
1692
+ if dpos[1] >= 0 then
1693
+ elem = @route_matrix[dpos[1]][dpos[0]]
1694
+ res << dpos if elem.free_from_up?(port0,port1) and
1695
+ !ic_port_conflict(port0,port1,[dpos[0],dpos[1]-1],UP)
1696
+ end
1697
+ end
1569
1698
  # Return the free neigbor positions.
1570
1699
  return res
1571
1700
  end
@@ -1651,29 +1780,16 @@ module HDLRuby::Viz
1651
1780
  pos0 = [port0.xpos,port0.ypos]
1652
1781
  pos1 = [port1.xpos,port1.ypos]
1653
1782
  oset = [pos0]
1654
- # oset = Set.new
1655
1783
  oset << pos0
1656
1784
  from = { }
1657
- # gscore = Hash.new(1/0.0)
1658
- # gscore[pos0] = 0
1659
1785
  gscore = Array.new(@route_matrix.size) { Array.new(@route_matrix[0].size) { 1/0.0 } }
1660
1786
  gscore[pos0[1]][pos0[0]] = 0
1661
- # fscore = Hash.new(1/0.0)
1662
- # fscore[pos0] = taxi_distance(pos0,pos1)
1663
1787
  fscore = Array.new(@route_matrix.size) { [] }
1664
1788
  fscore[pos0[1]][pos0[0]] = taxi_distance(pos0,pos1)
1665
1789
  while oset.any? do
1666
1790
  # Pick the position from oset with the minimum fscore.
1667
1791
  cpos = nil # Current position
1668
1792
  mscore = 1/0.0 # Minimum score
1669
- # oset.each do |pos|
1670
- # # score = fscore[pos]
1671
- # score = fscore[pos[1]][pos[0]]
1672
- # if score < mscore then
1673
- # mscore = score
1674
- # cpos = pos
1675
- # end
1676
- # end
1677
1793
  # The best score is necessily at the end of oset.
1678
1794
  cpos = oset.pop
1679
1795
  # puts "cpos=#{cpos}"
@@ -1682,23 +1798,16 @@ module HDLRuby::Viz
1682
1798
  from[pos1] = cpos
1683
1799
  return reconstruct_path(port0,port1,from,pos1)
1684
1800
  end
1685
- # oset.delete(cpos) # No need anymore since pop
1686
1801
  # Get the neighbor positions for port.
1687
- # poses = free_neighbors(port0,cpos)
1688
1802
  poses = free_neighbors(port0,port1,cpos)
1689
1803
  poses.each do |pos|
1690
1804
  # Try it.
1691
- # tscore = gscore[cpos] + cost_position(port0,pos)
1692
1805
  tscore = gscore[cpos[1]][cpos[0]] + cost_position(port0,pos)
1693
- # if tscore < gscore[pos] then
1694
1806
  if tscore < gscore[pos[1]][pos[0]] then
1695
1807
  # This path to neigbor is better than any previous one, keep it.
1696
1808
  from[pos] = cpos
1697
- # gscore[pos] = tscore
1698
1809
  gscore[pos[1]][pos[0]] = tscore
1699
- # fscore[pos] = tscore + taxi_distance(pos,pos1)
1700
1810
  fscore[pos[1]][pos[0]] = tscore + taxi_distance(pos,pos1)
1701
- # oset << pos unless oset.include?(pos)
1702
1811
  idx = oset.bsearch_index {|p| fscore[p[1]][p[0]] <= fscore[pos[1]][pos[0]] }
1703
1812
  if idx then
1704
1813
  oset.insert(idx,pos)
@@ -2377,14 +2486,26 @@ module HDLRuby::Viz
2377
2486
  id = Viz.to_svg_id(ic.name)
2378
2487
  # Determine the side of the inputs (and consequently of the outputs),
2379
2488
  # and the number of inputs.
2380
- iside = LEFT # Default side: left
2489
+ iside = nil
2381
2490
  inum = 0
2382
2491
  ic.ports.each do |port|
2383
2492
  if port.direction == :input then
2384
2493
  iside = port.side
2385
2494
  inum += 1
2495
+ elsif port.direction == :output then
2496
+ case port.side
2497
+ when LEFT
2498
+ iside = RIGHT
2499
+ when RIGHT
2500
+ iside = LEFT
2501
+ when UP
2502
+ iside = DOWN
2503
+ when DOWN
2504
+ iside = UP
2505
+ end
2386
2506
  end
2387
2507
  end
2508
+ raise "Connection with no port for #{ic.name}" unless iside
2388
2509
  # NOTE: inum is zero in case of a constant, force at least 1.
2389
2510
  inum = 1 if inum < 1
2390
2511
  # The length of a leg
@@ -2498,6 +2619,8 @@ module HDLRuby::Viz
2498
2619
  res = "<rect fill=\"#88f\" stroke=\"#000\" "
2499
2620
  when :negedge
2500
2621
  res = "<rect fill=\"#f88\" stroke=\"#000\" "
2622
+ when :anyedge
2623
+ res = "<rect fill=\"#888\" stroke=\"#000\" "
2501
2624
  else
2502
2625
  res = "<rect fill=\"#ff0\" stroke=\"#000\" "
2503
2626
  end
@@ -2517,6 +2640,8 @@ module HDLRuby::Viz
2517
2640
  res = "<rect fill=\"#88f\" stroke=\"#000\" "
2518
2641
  when :negedge
2519
2642
  res = "<rect fill=\"#f88\" stroke=\"#000\" "
2643
+ when :anyedge
2644
+ res = "<rect fill=\"#888\" stroke=\"#000\" "
2520
2645
  else
2521
2646
  res = "<rect fill=\"#ff0\" stroke=\"#000\" "
2522
2647
  end
@@ -2551,6 +2676,8 @@ module HDLRuby::Viz
2551
2676
  res = "<rect fill=\"#88f\" stroke=\"#000\" "
2552
2677
  when :negedge
2553
2678
  res = "<rect fill=\"#f88\" stroke=\"#000\" "
2679
+ when :anyedge
2680
+ res = "<rect fill=\"#888\" stroke=\"#000\" "
2554
2681
  else
2555
2682
  res = "<rect fill=\"#ff0\" stroke=\"#000\" "
2556
2683
  end
@@ -2570,6 +2697,8 @@ module HDLRuby::Viz
2570
2697
  res = "<rect fill=\"#88f\" stroke=\"#000\" "
2571
2698
  when :negedge
2572
2699
  res = "<rect fill=\"#f88\" stroke=\"#000\" "
2700
+ when :anyedge
2701
+ res = "<rect fill=\"#888\" stroke=\"#000\" "
2573
2702
  else
2574
2703
  res = "<rect fill=\"#ff0\" stroke=\"#000\" "
2575
2704
  end
@@ -2605,15 +2734,22 @@ module HDLRuby::Viz
2605
2734
  # Generate the string representing a port for display in the SVG
2606
2735
  def port_str(port)
2607
2736
  # Generate the port name (strip everything before the last ".")
2608
- name = port.name.sub(/^.*\./,"")
2737
+ # name = port.name.sub(/^.*\./,"")
2738
+ name = port.name.split(/(?<!\.)\.(?!\.)/).last
2609
2739
  # Strip the suffix $I and $O
2610
2740
  name = name.sub(/\$(I|O)$/,"")
2741
+ # For registers' bit ports, only keep the bit number.
2742
+ if port.ic.type==:register and HDLRuby::Viz.port_bit_name?(name) then
2743
+ name = HDLRuby::Viz.port_bit_name(name)
2744
+ end
2611
2745
  # Add a suffix for edge properties.
2612
2746
  case port.type
2613
2747
  when :posedge
2614
2748
  return name + " \u2197"
2615
2749
  when :negedge
2616
2750
  return name + " \u2198"
2751
+ when :anyedge
2752
+ return name + " \u2195"
2617
2753
  else
2618
2754
  return name
2619
2755
  end
@@ -2660,7 +2796,10 @@ module HDLRuby::Viz
2660
2796
  # Sets the styles.
2661
2797
  res += "<style>\n"
2662
2798
  # Fonts
2663
- res += ".small#{self.idC} { font: #{sF}px sans-serif; }\n"
2799
+ res += ".small#{self.idC} { font: #{sF}px sans-serif; " # }\n" # +
2800
+ res += "stroke=\"yellow\"; stroke-width=\"6\"; paint-order=\"stroke fill;\" }\n"
2801
+ # "border: 2px solid black; padding: 10px; display: inline-block; " +
2802
+ # " background-color: rgba(0, 128, 255, 0.2); }\n"
2664
2803
  res += ".medium#{self.idC} { font: #{mF}px sans-serif; }\n"
2665
2804
  res += ".large#{self.idC} { font: #{lF}px sans-serif; }\n"
2666
2805
  res += "</style>\n"
@@ -2818,11 +2957,19 @@ module HDLRuby::Viz
2818
2957
  if child == self then
2819
2958
  res += "<text class=\"small#{self.idC}\" style=\"text-anchor: end\" " +
2820
2959
  "x=\"#{(port.xpos)*@scale-pT}\" "+
2821
- "y=\"#{(port.ypos+0.5)*@scale+sF/2.5}\">" + # port.name +
2960
+ "y=\"#{(port.ypos+0.5)*@scale+sF/2.5}\">" +
2961
+ self.port_str(port) + "</text>\n"
2962
+ elsif (child.type == :assign and port.direction == :input and
2963
+ child.ports.size.even? and child.ports.index(port) == child.ports.size/2) then
2964
+ # Middle input of an alu, slide it bellow to avoid collision
2965
+ # with the output port.
2966
+ res += "<text class=\"small#{self.idC}\" x=\"#{(port.xpos)*@scale+pT}\" "+
2967
+ "y=\"#{(port.ypos+0.8)*@scale+sF/2.5}\">" +
2822
2968
  self.port_str(port) + "</text>\n"
2823
2969
  else
2970
+ # General case.
2824
2971
  res += "<text class=\"small#{self.idC}\" x=\"#{(port.xpos)*@scale+pT}\" "+
2825
- "y=\"#{(port.ypos+0.5)*@scale+sF/2.5}\">" + # port.name +
2972
+ "y=\"#{(port.ypos+0.45)*@scale+sF/2.5}\">" +
2826
2973
  self.port_str(port) + "</text>\n"
2827
2974
  end
2828
2975
  end
@@ -2886,10 +3033,18 @@ module HDLRuby::Viz
2886
3033
  "x=\"#{(port.xpos+1)*@scale+pT}\" " +
2887
3034
  "y=\"#{(port.ypos+0.5)*@scale+sF/2.5}\">" + # port.name +
2888
3035
  self.port_str(port) + "</text>\n"
3036
+ elsif (child.type == :assign and port.direction == :input and
3037
+ child.ports.size.even? and child.ports.index(port) == child.ports.size/2) then
3038
+ # Middle input of an alu, slide it bellow to avoid collision
3039
+ # with the output port.
3040
+ res += "<text class=\"small#{self.idC}\" style=\"text-anchor: end\" " +
3041
+ "x=\"#{(port.xpos+1)*@scale-pT}\" "+
3042
+ "y=\"#{(port.ypos+0.8)*@scale+sF/2.5}\">" + # port.name +
3043
+ self.port_str(port) + "</text>\n"
2889
3044
  else
2890
3045
  res += "<text class=\"small#{self.idC}\" style=\"text-anchor: end\" " +
2891
3046
  "x=\"#{(port.xpos+1)*@scale-pT}\" "+
2892
- "y=\"#{(port.ypos+0.5)*@scale+sF/2.5}\">" + # port.name +
3047
+ "y=\"#{(port.ypos+0.45)*@scale+sF/2.5}\">" + # port.name +
2893
3048
  self.port_str(port) + "</text>\n"
2894
3049
  end
2895
3050
  end
@@ -2973,14 +3128,15 @@ module HDLRuby::Viz
2973
3128
  cty += 1
2974
3129
  end
2975
3130
  end
2976
- # Leave a space for left or right ports if any.
2977
- sl = child.ports.any? {|p| p.side == LEFT } ? 1.0 : 0.0
2978
- sr = child.ports.any? {|p| p.side == RIGHT } ? 1.0 : 0.0
3131
+ # # Leave a space for left or right ports if any.
3132
+ # sl = (child.ports.any? {|p| p.side == LEFT }) ? 1.0 : 0.0
3133
+ # sr = (child.ports.any? {|p| p.side == RIGHT }) ? 1.0 : 0.0
2979
3134
  # Recompute the scale.
2980
3135
  fit = [
2981
- (target.width+sl+sr+(bT/@scale)) / (cwidth),
2982
- (target.height+(bT/@scale)) / (cheight),
2983
- 3.0
3136
+ # (target.width+sl+sr+(bT/@scale/2.0)) / (cwidth),
3137
+ (target.width+(bT/@scale/2.0)) / (cwidth),
3138
+ (target.height+(bT/@scale/2.0)) / (cheight),
3139
+ 1.0# 3.0
2984
3140
  ].max
2985
3141
  target.scale = @scale / fit
2986
3142
  puts "fit=#{fit} target.scale=#{target.scale}"
@@ -4382,7 +4538,7 @@ class HDLRuby::Low::SystemT
4382
4538
  # ports.each_value do |subs|
4383
4539
  ports.each do |name,subs|
4384
4540
  # Skip connection to registers, they are processed later.
4385
- next if regs[name]
4541
+ next if regs[HDLRuby::Viz.port_base_name(name)]
4386
4542
  # Not a register, can go on.
4387
4543
  subs.each do |p0|
4388
4544
  subs.each do |p1|
@@ -4400,15 +4556,17 @@ class HDLRuby::Low::SystemT
4400
4556
  # Check if there is a register corresponding to the port
4401
4557
  # (full port or sub port of the register).
4402
4558
  next if name.include?("$") # Skip register ports which are targets.
4403
- rname = name
4559
+ # rname = name
4560
+ rname = HDLRuby::Viz.port_base_name(name)
4404
4561
  while !regs.key?(rname) do
4405
4562
  break unless rname.include?(".")
4406
4563
  rname = rname.gsub(/\.[^.]*$/,"")
4407
4564
  end
4408
4565
  reg = regs[rname]
4409
4566
  next unless reg
4410
- # Connect the register, once per ic and direction.
4411
- subs.uniq {|p| [p.ic,p.direction] }.each do |p|
4567
+ # # Connect the register, once per ic and direction.
4568
+ # Connect the register, once per ic, direction and type.
4569
+ subs.uniq {|p| [p.ic,p.direction,p.type] }.each do |p|
4412
4570
  # puts "Connect to register port name #{name} in ic=#{world.name} with port=#{p.name}"
4413
4571
  if p.direction == :output then
4414
4572
  world.connect(p,ports[HDLRuby::Viz.reg2input_name(name)][0])
@@ -4444,16 +4602,48 @@ class HDLRuby::Low::SystemT
4444
4602
  # NOTE: p0 or p1 may be empty if outside current module.
4445
4603
  world.connect(p0,p1) unless (!p0 or !p1 or p0.targets.include?(p1))
4446
4604
  end
4447
- # Remove the dangling input ports in registers (they are ROMS).
4605
+ # # Remove the dangling input ports in registers (they are ROMS).
4606
+ # regs.each_value do |reg|
4607
+ # to_remove_input = reg.ports.select {|p| p.direction==:input }.all? do
4608
+ # |p|
4609
+ # p.targets.none?
4610
+ # end
4611
+ # if to_remove_input then
4612
+ # reg.ports.delete_if {|p| p.direction == :input }
4613
+ # end
4614
+ # end
4615
+ # Remove the dangling ports in registers (they are ROMS).
4448
4616
  regs.each_value do |reg|
4449
- to_remove_input = reg.ports.select {|p| p.direction==:input }.all? do
4450
- |p|
4451
- p.targets.none?
4617
+ reg.ports.delete_if {|p| p.targets.none? }
4618
+ end
4619
+
4620
+ # Gather the bit ports by owner port.
4621
+ port2bits = {}
4622
+ ports.each do |name,subs|
4623
+ subs.each do |port|
4624
+ port2bits[port.name] = []
4452
4625
  end
4453
- if to_remove_input then
4454
- reg.ports.delete_if {|p| p.direction == :input }
4626
+ end
4627
+ ports.each do |name,subs|
4628
+ subs.each do |port|
4629
+ if HDLRuby::Viz.port_bit_name?(port.name) then
4630
+ port2bits[HDLRuby::Viz.port_base_name(port.name)] << port
4631
+ end
4455
4632
  end
4456
4633
  end
4634
+ # Remove the dangling ports that are accessed by sub ports.
4635
+ ports.each do |name,subs|
4636
+ subs.each do |port|
4637
+ if port.targets.none? then
4638
+ # This is a dangling port, is it connected by bits.
4639
+ if port2bits[port.name].any? then
4640
+ # Yes, remove it.
4641
+ port.ic.ports.delete(port)
4642
+ end
4643
+ end
4644
+ end
4645
+ end
4646
+
4457
4647
  # Return the resulting visualization.
4458
4648
  return world
4459
4649
  end
@@ -4482,18 +4672,23 @@ class HDLRuby::Low::Scope
4482
4672
  # name = sname + inner.name.to_s
4483
4673
  # name = inner.name.to_s
4484
4674
  name = sname + inner.name.to_s
4485
- # Create the viz for the "register"
4486
- if typ.is_a?(HDLRuby::Low::TypeVector) and
4487
- typ.base.width > 1 then
4488
- puts "Adding scope register #{name} to #{world.name}"
4489
- # This is in fact a memory matrix.
4490
- reg = HDLRuby::Viz::IC.new(name,:memory,world)
4491
- else
4492
- puts "Adding plain register #{name} to #{world.name}"
4493
- # This is a plain register.
4494
- reg = HDLRuby::Viz::IC.new(name,:register,world)
4675
+ # But first cut of the index if any for the register.
4676
+ rname = HDLRuby::Viz.port_base_name(name)
4677
+ reg = regs[rname]
4678
+ unless reg then
4679
+ # Create the viz for the "register"
4680
+ if typ.is_a?(HDLRuby::Low::TypeVector) and
4681
+ typ.base.width > 1 then
4682
+ puts "Adding scope register #{rname} to #{world.name}"
4683
+ # This is in fact a memory matrix.
4684
+ reg = HDLRuby::Viz::IC.new(rname,:memory,world)
4685
+ else
4686
+ puts "Adding plain register #{rname} to #{world.name}"
4687
+ # This is a plain register.
4688
+ reg = HDLRuby::Viz::IC.new(rname,:register,world)
4689
+ end
4690
+ regs[reg.name] = reg
4495
4691
  end
4496
- regs[reg.name] = reg
4497
4692
  # Create the corresponding input and output ports.
4498
4693
  iname = HDLRuby::Viz.reg2input_name(name)
4499
4694
  puts "Adding input port #{iname} to reg #{reg.name}"
@@ -4546,21 +4741,11 @@ class HDLRuby::Low::Scope
4546
4741
  # Explicit port connect case.
4547
4742
  links << [ connection.left.to_viz_names[0],
4548
4743
  connection.right.to_viz_names[0] ]
4549
- # # Get the right refered name.
4550
- # rname = connection.right.to_viz_names[0]
4551
- # # If it is a register make the name its output.
4552
- # rname = HDLRuby::Viz.reg2output_name(rname) if regs[rname]
4553
- # # Get the left refered name.
4554
- # lname = connection.left.to_viz_names[0]
4555
- # # If it is a register make the name its input.
4556
- # lname = HDLRuby::Viz.reg2input_name(lname) if regs[lname]
4557
- # # Make the explicit port connect.
4558
- # links << [ lname, rname ]
4559
4744
  # Add the explicit port connection.
4560
4745
  puts "added link between #{links[-1][0]} and #{links[-1][1]}"
4561
4746
  next
4562
4747
  end
4563
- ic = HDLRuby::Viz::IC.new(HDLRuby.uniq_name("cxn"),:assign,world)
4748
+ ic = HDLRuby::Viz::IC.new(HDLRuby.uniq_name("cnx"),:assign,world)
4564
4749
  # Add its ports.
4565
4750
  # Output.
4566
4751
  name = connection.left.to_viz_names[0]
@@ -4595,14 +4780,15 @@ class HDLRuby::Low::Scope
4595
4780
  behavior.each_event do |ev|
4596
4781
  name = ev.ref.to_viz_names[0]
4597
4782
  next if ic.port?(name) # The port has already been added.
4598
- # Is it a clocked event?
4599
- if ev.on_edge? then
4600
- # Yes.
4601
- ports[name] << ic.add_port(name, :input, ev.type)
4602
- else
4603
- # No, use a standard port.
4604
- ports[name] << ic.add_port(name, :input)
4605
- end
4783
+ # # Is it a clocked event?
4784
+ # if ev.on_edge? then
4785
+ # # Yes.
4786
+ # ports[name] << ic.add_port(name, :input, ev.type)
4787
+ # else
4788
+ # # No, use a standard port.
4789
+ # ports[name] << ic.add_port(name, :input)
4790
+ # end
4791
+ ports[name] << ic.add_port(name, :input, ev.type)
4606
4792
  end
4607
4793
  # Recurse on its blocks.
4608
4794
  # behavior.block.to_viz(world,ic,ports)
@@ -4691,14 +4877,19 @@ class HDLRuby::Low::Block
4691
4877
  self.each_inner do |inner|
4692
4878
  name = bname + inner.name.to_s
4693
4879
  puts "Adding block register #{name} to #{world.name}"
4694
- # Create the viz for the "register"
4695
- if inner.type.base.width > 1 then
4696
- # This is in fact a memory matrix.
4697
- reg = HDLRuby::Viz::IC.new(name,:memory,world)
4698
- else
4699
- reg = HDLRuby::Viz::IC.new(name,:register,world)
4880
+ # But first cut of the index if any for the register.
4881
+ rname = HDLRuby::Viz.port_base_name(name)
4882
+ reg = regs[rname]
4883
+ unless reg then
4884
+ # Create the viz for the "register"
4885
+ if inner.type.base.width > 1 then
4886
+ # This is in fact a memory matrix.
4887
+ reg = HDLRuby::Viz::IC.new(rname,:memory,world)
4888
+ else
4889
+ reg = HDLRuby::Viz::IC.new(rname,:register,world)
4890
+ end
4891
+ regs[reg.name] = reg
4700
4892
  end
4701
- regs[reg.name] = reg
4702
4893
  # Create the corresponding input and output ports.
4703
4894
  iname = HDLRuby::Viz.reg2input_name(name)
4704
4895
  puts "Adding input port #{iname} to #{world.name}"
@@ -4767,20 +4958,22 @@ class HDLRuby::Low::Block
4767
4958
  end
4768
4959
 
4769
4960
  next unless stmnt.is_a?(HDLRuby::Low::Transmit)
4770
- name = stmnt.left.to_viz_names[0]
4961
+ lnames = stmnt.left.to_viz_names
4962
+ name = lnames[0]
4771
4963
  if iports.key?(name) then
4772
4964
  # Change to inout port.
4773
4965
  iports[name].direction = :inout
4774
- next
4775
- end
4966
+ # next
4967
+ # end
4776
4968
  # Add one port by output name.
4777
- unless oports.key?(name) then
4969
+ # unless oports.key?(name) then
4970
+ elsif !oports.key?(name) then
4778
4971
  puts "Adding output port #{name} to #{ic.name}"
4779
4972
  port = ic.add_port(name, :output)
4780
4973
  ports[name] << port
4781
4974
  oports[name] = port
4782
4975
  end
4783
- stmnt.right.to_viz_names.each do |name|
4976
+ (stmnt.right.to_viz_names+lnames[1..-1]).each do |name|
4784
4977
  if oports.key?(name) then
4785
4978
  # Change to inout port.
4786
4979
  oports[name].direction = :inout