verilog_gen 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/README.md +22 -1
  4. data/Rakefile +20 -0
  5. data/bin/hdl_equal +82 -0
  6. data/bin/vgen +57 -1
  7. data/bin/vscan +354 -0
  8. data/demos/router/Makefile +11 -0
  9. data/demos/router/build/chip1_router.rb +50 -0
  10. data/demos/router/build/chip2_router.rb +33 -0
  11. data/demos/router/build/generic_router.rb +96 -0
  12. data/demos/router/rtl/fifo_ctrl.v +93 -0
  13. data/demos/router/rtl/flop_delay.v +37 -0
  14. data/demos/router/rtl/generic_mem.v +38 -0
  15. data/demos/router/rtl/router_ctrl.v +73 -0
  16. data/demos/router/rtl/rr_arb.v +55 -0
  17. data/demos/router/vendors/vendor1/mem_16nm_bist_ctrl.v +56 -0
  18. data/demos/router/vendors/vendor1/mem_16nm_ram4x64.v +50 -0
  19. data/demos/router/vendors/vendor1/mem_16nm_ram8x64.v +50 -0
  20. data/demos/router/vendors/vendor2/mem_16nm_bist_ctrl.v +56 -0
  21. data/demos/router/vendors/vendor2/mem_16nm_ram12x73.v +50 -0
  22. data/demos/router/vendors/vendor2/mem_16nm_ram4x73.v +50 -0
  23. data/docs/demo.md +142 -0
  24. data/docs/sst.md +76 -0
  25. data/features/cucumber.yml +1 -0
  26. data/features/hdl_equal/hello.feature +9 -0
  27. data/features/hdl_equal/leaf_compare.feature +11 -0
  28. data/features/hdl_equal/neg_compare.feature +17 -0
  29. data/features/hdl_equal/port_width_compare.feature +17 -0
  30. data/features/sprint1/hello.feature +9 -0
  31. data/features/sprint1/hier_connect_1.feature +81 -0
  32. data/features/sprint1/hier_connect_2.feature +91 -0
  33. data/features/sprint1/hier_connect_3.feature +90 -0
  34. data/features/sprint1/inhibit_port.feature +41 -0
  35. data/features/sprint1/input_connect.feature +79 -0
  36. data/features/sprint1/leaf_rename.feature +41 -0
  37. data/features/sprint1/new_leaf_design.erb +52 -0
  38. data/features/sprint1/output_connect.feature +79 -0
  39. data/features/sprint1/regex_port_rewrites.feature +43 -0
  40. data/features/sprint1/subrange_port.feature +43 -0
  41. data/features/sprint1/swap_leaf.feature +122 -0
  42. data/features/sprint1/tie_port.feature +40 -0
  43. data/features/sprint1/unused_port.feature +41 -0
  44. data/features/sprint1/vector_split.feature +41 -0
  45. data/features/sprint1/wire_connect.feature +46 -0
  46. data/features/sprint2/expression_net.feature +41 -0
  47. data/features/sprint2/fifo.feature +61 -0
  48. data/features/sprint2/wire_expression.feature +48 -0
  49. data/features/step_definitions/vgen_steps.rb +3 -0
  50. data/features/support/env.rb +3 -1
  51. data/features/vgen/add_child.feature +60 -0
  52. data/features/vgen/fifo_ctrl.feature +24 -0
  53. data/features/vgen/hello.feature +9 -0
  54. data/features/vgen/leaf_node.feature +15 -0
  55. data/features/vgen/output_dir.feature +19 -0
  56. data/features/vgen/simple_node.feature +24 -0
  57. data/features/vgen/thin_hookup.feature +22 -0
  58. data/features/vscan/bad_path.feature +9 -0
  59. data/features/vscan/class_override.feature +23 -0
  60. data/features/vscan/class_override_path.feature +23 -0
  61. data/features/vscan/complex_expressions.feature +47 -0
  62. data/features/vscan/data_types_2001.feature +36 -0
  63. data/features/vscan/data_types_sv.feature +53 -0
  64. data/features/vscan/hello.feature +9 -0
  65. data/features/vscan/hiearchy_path.feature +23 -0
  66. data/features/vscan/illegal_argument.feature +9 -0
  67. data/features/vscan/inout.feature +23 -0
  68. data/features/vscan/interface_nested.feature +53 -0
  69. data/features/vscan/interface_nested_no_out.feature +48 -0
  70. data/features/vscan/interface_param_default.feature +41 -0
  71. data/features/vscan/interface_param_override.feature +27 -0
  72. data/features/vscan/interface_port.feature +41 -0
  73. data/features/vscan/interface_sv.feature +35 -0
  74. data/features/vscan/leaf_1995.feature +27 -0
  75. data/features/vscan/leaf_2001.feature +25 -0
  76. data/features/vscan/leaf_negative_1995.feature +24 -0
  77. data/features/vscan/leaf_sv.feature +25 -0
  78. data/features/vscan/localparam_2001.feature +38 -0
  79. data/features/vscan/missing_parameter.feature +24 -0
  80. data/features/vscan/multiple_class.feature +9 -0
  81. data/features/vscan/multiple_flavors.feature +64 -0
  82. data/features/vscan/multiple_modules.feature +60 -0
  83. data/features/vscan/name_mismatch.feature +24 -0
  84. data/features/vscan/net_type.feature +67 -0
  85. data/features/vscan/parameter_override.feature +43 -0
  86. data/features/vscan/parameters_1995.feature +43 -0
  87. data/features/vscan/parameters_2001.feature +38 -0
  88. data/features/vscan/read_only.feature +19 -0
  89. data/features/vscan/reverse_vectors_1995.feature +33 -0
  90. data/features/vscan/single_line_1995.feature +24 -0
  91. data/features/vscan/vectors_1995.feature +33 -0
  92. data/features/vscan/vectors_2001.feature +29 -0
  93. data/features/vscan/vectors_sv.feature +31 -0
  94. data/lib/templates/helpers.rb +85 -0
  95. data/lib/templates/v2k_template.erb +6 -0
  96. data/lib/verilog_gen.rb +8 -3
  97. data/lib/verilog_gen/hdl_module.rb +274 -0
  98. data/lib/verilog_gen/hookup.rb +153 -0
  99. data/lib/verilog_gen/pin.rb +39 -0
  100. data/lib/verilog_gen/port.rb +109 -0
  101. data/lib/verilog_gen/proxy.rb +33 -0
  102. data/lib/verilog_gen/string.rb +38 -0
  103. data/lib/verilog_gen/version.rb +1 -1
  104. data/spec/fixture/generic_mem.v +38 -0
  105. data/spec/hdl_child_array_spec.rb +29 -0
  106. data/spec/hdl_hier_spec.rb +45 -0
  107. data/spec/hdl_hookup.spec +37 -0
  108. data/spec/hdl_module_spec.rb +117 -0
  109. data/spec/hdl_output_spec.rb +88 -0
  110. data/spec/hdl_port_spec.rb +35 -0
  111. data/spec/hdl_remove_child.spec +37 -0
  112. data/spec/pin_spec.rb +37 -0
  113. data/spec/port_spec.rb +90 -0
  114. data/spec/proxy_spec.rb +41 -0
  115. data/spec/spec_helper.rb +2 -0
  116. data/verilog_gen.gemspec +1 -1
  117. metadata +194 -8
  118. data/features/hello.feature +0 -8
  119. data/features/support/aruba.rb +0 -1
@@ -0,0 +1,153 @@
1
+ module VerilogGen
2
+
3
+ # Check if all the ports in the list are inputs.
4
+ # @param [Array] port_lst is the list of ports
5
+ # @return [Boolean] True if all are inputs.
6
+ def self.unconnected_input_ports?(port_lst)
7
+ return false if port_lst.empty?
8
+ port_lst.each do |port|
9
+ return false unless port.direction == "input"
10
+ end
11
+ return true
12
+ end
13
+
14
+ # Check if all the ports in the list are outputs.
15
+ # @param [Array] port_lst is the list of ports
16
+ # @return [Boolean] True if all are outputs.
17
+ def self.unconnected_output_ports?(port_lst)
18
+ return false if port_lst.empty?
19
+ port_lst.each do |port|
20
+ return false unless port.direction == "output"
21
+ end
22
+ return true
23
+ end
24
+
25
+ # Find the super width from a list of ports.
26
+ # @param [Array] list of ports
27
+ # @return [Array] lhs, rhs
28
+ # @note:
29
+ # Assumes that all ports in the list are of same endiannes..
30
+ # FIXME: For this it looks at the port in the middle.
31
+ # Should scan all the ports to detect it.
32
+ def self.super_port_width(port_lst)
33
+ sample_port = port_lst[port_lst.size/2]
34
+ lhs_values = []
35
+ rhs_values = []
36
+ port_lst.each do |port|
37
+ lhs_values << port.lhs
38
+ rhs_values << port.rhs
39
+ end
40
+ if sample_port.lhs > sample_port.rhs
41
+ return lhs_values.max, rhs_values.min
42
+ else
43
+ return lhs_values.min, rhs_values.max
44
+ end
45
+ end
46
+
47
+ # Adds a connect port to the hdl module class.
48
+ # @return nil
49
+ # @note The name of the connect port is the name of the pin
50
+ # and the width of the port is the super width.
51
+ def self.add_new_connect_port(klass, pin_name, port_lst)
52
+ lhs, rhs = super_port_width(port_lst)
53
+ p = port_lst[0].create_connect_port(pin_name, lhs, rhs)
54
+ klass.ports[pin_name] = p
55
+ end
56
+
57
+ # Create pins for unconnected ports in current instance.
58
+ # @param [Object] instance of hdl module
59
+ # @return [Fixnum] Number of pins added
60
+ # @note Ports with existing pins are skippped.
61
+ def self.create_missing_pins(instance)
62
+ num_pins_created = 0
63
+ instance.class.ports.each do |port_name, port|
64
+ unless instance.pins.key? port_name
65
+ instance.pins[port_name] = Pin.new(port)
66
+ num_pins_created += 1
67
+ end
68
+ end
69
+ num_pins_created
70
+ end
71
+
72
+ # Create missing pins for all children below the instance.
73
+ # Use depth first to build all the leaf and then the rest of the
74
+ # modules.
75
+ # @param [Object] instance of the design.
76
+ # @return [nil]
77
+ # @note Idempotent since port that have pins are skipped.
78
+ def self.create_missing_pins_depth_first(instance)
79
+ if instance.class.proxy
80
+ # Leaf do not change the ports. hence we don't need to do it again.
81
+ # But it is harmless if all ports are already connected.
82
+ create_missing_pins instance
83
+ else
84
+ instance.class.child_instances.each do |child_name, child|
85
+ create_missing_pins_depth_first child
86
+ end
87
+ # If new pins are created then we would need to create the connect ports
88
+ # in the current class.
89
+ num_new_ports = create_connect_ports(instance.class)
90
+
91
+ # Run custom user connect
92
+ instance.class.connect
93
+
94
+ # If we added new ports to the class then all instantiaton must get new pins.
95
+ create_missing_pins instance if num_new_ports > 0
96
+ end
97
+ end
98
+
99
+ # Create connectivity map for children of a hdl module.
100
+ # @param [Object] klass of the hdl module.
101
+ # @return [Hash] hash of array. PinName => [Port0, Port 10.....]
102
+ #
103
+ def self.get_child_pins_connectivity(klass)
104
+ pin_connections = Hash.new {|hash, key| hash[key] = Array.new }
105
+ klass.child_instances.each do |child_name, child|
106
+ child.pins.each do |port_name, pin|
107
+ pin_connections[pin.name].push pin.port
108
+ end
109
+ end
110
+ pin_connections
111
+ end
112
+
113
+ # Create ports to provide connectivity to the child instances.
114
+ # @param [Object] klass HdlModule
115
+ # @return [Fixnum] number of ports created in the class.
116
+ # @note
117
+ # An input port is created if the children pins are inputs.
118
+ # A output port is created if the children pins are output.
119
+ # If mixture of input and output pins, then no ports are created.
120
+ # The width of the port is the superset of the width.
121
+ def self.create_connect_ports(klass)
122
+ num_connect_ports = 0
123
+ pin_connections = get_child_pins_connectivity(klass)
124
+ pin_connections.each do |pin_name, port_lst|
125
+ if unconnected_input_ports?(port_lst)
126
+ add_new_connect_port(klass, pin_name, port_lst)
127
+ num_connect_ports += 1
128
+ elsif unconnected_output_ports?(port_lst)
129
+ add_new_connect_port(klass, pin_name, port_lst)
130
+ num_connect_ports += 1
131
+ end
132
+ end
133
+ num_connect_ports
134
+ end
135
+
136
+ # Connect child instances and create hookup ports.
137
+ # @param [Object] top_level_class of the design.
138
+ # @note
139
+ # Start with each child instance.
140
+ #
141
+ def self.hookup(top_level_class)
142
+ top_level_class.child_instances.each do |instance_name, instance|
143
+ create_missing_pins_depth_first(instance)
144
+ end
145
+ # Run custom user connect
146
+ top_level_class.connect
147
+
148
+ # Create the primary connect ports
149
+ create_connect_ports(top_level_class)
150
+
151
+ end
152
+
153
+ end
@@ -0,0 +1,39 @@
1
+ module VerilogGen
2
+ # Model of a pin connected to a port
3
+ class Pin
4
+
5
+ attr_reader :port, :name, :type, :lhs, :rhs, :direction
6
+
7
+ # A pin connects to a port.
8
+ # @note By default the pin name, type and width is the same as port.
9
+ def initialize(port)
10
+ @port = port
11
+ @name = port.name
12
+ @type = port.type
13
+ @lhs = port.lhs
14
+ @rhs = port.rhs
15
+ @direction = port.direction
16
+ end
17
+
18
+ # Update a pin attributes.
19
+ # @param [String] name of the pin
20
+ # @param [Hash] params properties of pin
21
+ # @option params [String] :name of the pin
22
+ # @option params [String] :type of the pin
23
+ # @option params [Fixnum] :lhs left hand width of the pin
24
+ # @option params [Fixnum] :rhs right hand width of the pin
25
+ # @option params [String] :direction of the pin
26
+ def connect(pin_name, params = {})
27
+ @name = pin_name
28
+ params.each do |key, value|
29
+ raise ArgumentError, "Unknown attribute '#{key}' specified for pin" \
30
+ unless instance_variables.include?("@#{key}".to_sym)
31
+ instance_variable_set("@#{key}", value)
32
+ end
33
+ end
34
+
35
+ def width
36
+ (@lhs - @rhs + 1).abs
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,109 @@
1
+ module VerilogGen
2
+ # Model of a verilog port.
3
+ class Port
4
+
5
+ @@DEFAULT_PARAMS = {
6
+ :name => "",
7
+ :direction => "input",
8
+ :lhs => 0,
9
+ :rhs => 0,
10
+ :type => "wire",
11
+ :packed => "",
12
+ :unpacked => ""
13
+ }
14
+
15
+ # Construct a port.
16
+ # @param [Hash] params properties of the port
17
+ # @option params [String] :name name of the port
18
+ # @option params [String] :direction By default input
19
+ # @option params [Integer]:left By default 0
20
+ # @option params [Integer] right hand digit. By default 0.
21
+ # @note If lhs and rhs are 0 then it is a scalar port else vector type.
22
+ def initialize(name, params = {})
23
+ @@DEFAULT_PARAMS.each do |key, value|
24
+ instance_variable_set("@#{key}", value)
25
+ self.class.send(:attr_reader, key.to_s)
26
+ end
27
+
28
+ @name = name
29
+
30
+ params.each do |key, value|
31
+ raise ArgumentError,
32
+ "invalid value of port field '#{key}' with '#{value}'" \
33
+ unless @@DEFAULT_PARAMS.has_key? key
34
+ instance_variable_set("@#{key}", value)
35
+ end
36
+
37
+ #Enumeration checking.
38
+ raise ArgumentError, "direction '#{direction}' is not valid value" \
39
+ unless @direction == "input" or @direction == "output"\
40
+ or @direction == "inout"
41
+
42
+ # FIXME: Hack lhs and rhs
43
+ unless @packed == ""
44
+ m = /\[\s*(-*\d+)\s*:\s*(-*\d+)\s*\]/.match @packed
45
+ @lhs = m.captures[0].to_i
46
+ @rhs = m.captures[1].to_i
47
+ end
48
+ end
49
+
50
+ # Equaltiy of port
51
+ # @param [Object] other port instance
52
+ # @return [Boolean] comparion result
53
+ def ==(other)
54
+ return false unless other.instance_of?(self.class)
55
+ name == other.name && direction == other.direction \
56
+ && lhs == other.lhs && rhs == other.rhs
57
+ end
58
+
59
+ # Well behaved hash keys
60
+ # @param [Object] other port instance
61
+ # @return [Boolean] true/false
62
+ # @note if a.eql?(b) then a.hash = b.hash
63
+ def eql?(other)
64
+ return self == other
65
+ end
66
+
67
+ # Compute the hash key.
68
+ def hash
69
+ return name.hash ^ direction.hash ^ lhs.hash ^ rhs.hash
70
+ end
71
+
72
+ # Utility function to detect scalar vector port.
73
+ # @return [Boolean] true if this is a scalar port else vector.
74
+ # @note A port is scalar if lhs and rhs are both 0.
75
+ def scalar?
76
+ lhs == 0 and rhs == 0
77
+ end
78
+
79
+ # Utility function to return the width of the port
80
+ # @return [Integer] Width of the port
81
+ def width
82
+ (lhs > rhs) ? lhs - rhs + 1 : rhs - lhs + 1
83
+ end
84
+
85
+ # Utility routine to return the port declaration
86
+ # @return [String]
87
+ def type
88
+ if direction == "output" and width == 1
89
+ return "logic"
90
+ elsif direction == "output"
91
+ return "logic [#{lhs}:#{rhs}]"
92
+ elsif direction == "input" and not scalar?
93
+ return "[#{lhs}:#{rhs}]"
94
+ else
95
+ return ""
96
+ end
97
+ end
98
+
99
+ # HACK for creating a connect port.
100
+ # Want to create a port that is identical to the current port but
101
+ # has a different name and width.
102
+ # @note : This is a hack for getting the demo to work.
103
+ def create_connect_port(new_name, new_lhs, new_rhs)
104
+ p = Port.new(new_name, direction: direction,
105
+ lhs: new_lhs , rhs: new_rhs, type: type,
106
+ packed: "", unpacked: "")
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,33 @@
1
+ # Wrapper routines to import design into ruby.
2
+
3
+ module VerilogGen
4
+ # Return the created class for subsequent access.
5
+ @@verilog_leaf_created = {}
6
+
7
+ # Invoke vscan to create the leaf proxy.
8
+ # @param [String] Class name of hdl leaf.
9
+ # @param [Hash] parameter to pass to vscan.
10
+ # @param file_name [Hash] name of the rtl file.
11
+ # @return Hdl module class.
12
+ # @note
13
+ # Once a class is created then subsequent access will return prev value.
14
+ def self.leaf(klass, params = {})
15
+ options = { parameter: "", file_name: klass.snakecase + ".v" }
16
+ params.each do |key, value|
17
+ raise ArgumentError, "invalid valid value of leaf '#{key}'" \
18
+ unless options.key? key
19
+ options[key] = params[key]
20
+ end
21
+
22
+ key = klass + options[:parameter]
23
+ unless @@verilog_leaf_created.key?(key)
24
+ puts "Running vscan #{options[:parameter]} -class #{klass} #{options[:file_name]}"
25
+ output = `vscan #{options[:parameter]} -class #{klass} \
26
+ #{options[:file_name]}`
27
+ eval output, binding, __FILE__, __LINE__
28
+ @@verilog_leaf_created[key] = Object.const_get("VerilogGen::#{klass}")
29
+ end
30
+ @@verilog_leaf_created[key]
31
+ end
32
+ end
33
+
@@ -0,0 +1,38 @@
1
+ class String
2
+ def camelize
3
+ self.split("_").each {|s| s.capitalize! }.join("")
4
+ end
5
+
6
+ def snakecase
7
+ #gsub(/::/, '/').
8
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
9
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
10
+ tr('-', '_').
11
+ gsub(/\s/, '_').
12
+ gsub(/__+/, '_').
13
+ downcase
14
+ end
15
+
16
+ def constantize
17
+ names = self.split('::')
18
+ names.shift if names.empty? || names.first.empty?
19
+ names.inject(Object) do |constant, name|
20
+ if constant == Object
21
+ constant.const_get(name)
22
+ else
23
+ candidate = constant.const_get(name)
24
+ next candidate if constant.const_defined?(name, false)
25
+ next candidate unless Object.const_defined?(name)
26
+ # Go down the ancestors to check it it's owned
27
+ # directly before we reach Object or the end of ancestors.
28
+ constant = constant.ancestors.inject do |const, ancestor|
29
+ break const if ancestor == Object
30
+ break ancestor if ancestor.const_defined?(name, false)
31
+ const
32
+ end
33
+ # owner is in Object, so raise
34
+ constant.const_get(name, false)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module VerilogGen
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,38 @@
1
+ // --------------------------------------------------
2
+ //
3
+ // Generic memory
4
+ //
5
+ // This module is a generic memory with write/read enables and
6
+ // read data is available registered (next clock cycle). The
7
+ // Width and Depth of the memory are parameterizeable.
8
+ //
9
+ // --------------------------------------------------
10
+
11
+ module generic_mem
12
+ #( parameter DEPTH=8,
13
+ parameter WIDTH=32,
14
+ localparam AWIDTH=$clog2(DEPTH) )
15
+ (
16
+ input wire clk,
17
+ input wire mem_wr_en,
18
+ input wire [AWIDTH-1:0] mem_wr_addr,
19
+ input wire [WIDTH-1:0] mem_wr_data,
20
+ input wire mem_rd_en,
21
+ input wire [AWIDTH-1:0] mem_rd_addr,
22
+ input wire [WIDTH-1:0] mem_rd_data
23
+ );
24
+
25
+ // The memory declaration
26
+ reg [WIDTH-1:0] generic_memory [DEPTH-1:0];
27
+
28
+ always @ (posedge clk) begin
29
+ if( mem_wr_en ) begin
30
+ generic_memory[mem_wr_addr] <= #0 mem_wr_data;
31
+ end
32
+
33
+ if( mem_rd_en ) begin
34
+ mem_rd_data <= #0 generic_memory[mem_rd_addr];
35
+ end
36
+ end
37
+
38
+ endmodule
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ # Check the syntax for accessing child instances in array.
4
+ #
5
+ describe VerilogGen::HdlModule do
6
+ before(:all) do
7
+ class Leaf < VerilogGen::HdlModule
8
+ end
9
+
10
+ class Node < VerilogGen::HdlModule;
11
+ 10.times do |i|
12
+ add_child_instance "leaf#{i}", Leaf
13
+ end
14
+ end
15
+
16
+ end
17
+ it "should have the correct number of chilren" do
18
+ expect(Node.child_instances.size).to eq(10)
19
+ end
20
+ it "should support dot notation" do
21
+ expect(Node.leaf0.instance_name).to eq("leaf0")
22
+ end
23
+ it "should support loop in dot notation" do
24
+ 10.times do |i|
25
+ expect(Node.child_instances["leaf#{i}"].instance_name).to eq("leaf#{i}")
26
+ end
27
+ end
28
+
29
+ end