bat 1.0.0

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.
data/lib/Inv.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the Inverter part
2
+ class Inv < TwoPorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, TwoPorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p1 = !#{@p0};\n"
8
+ end
9
+ end
data/lib/Mux2.rb ADDED
@@ -0,0 +1,25 @@
1
+ # This class defines the 2-to-1 Multiplexer part
2
+ class Mux2 < Inst
3
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
4
+ # It is responsible for defining applicable nodes, then calling its superclass, Inst, to complete other tasks.
5
+ def initialize(name)
6
+ super(name,[0,1,2,3],[10])
7
+ end
8
+
9
+ # This method defines the connections held by the ports of this object and returns the specific ABEL code to be output for this
10
+ # object based on the connections on its input ports.
11
+ def abelout
12
+ # make these class variables just for consistency's sake
13
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
14
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
15
+ @p2 = self.get_port("p2").connections.collect{|p| p.name}.to_s
16
+ @p3 = self.get_port("p3").connections.collect{|p| p.name}.to_s
17
+
18
+ s = ""
19
+ s << "\n\"active low enabled MUX2\nWHEN (#{@p0} == 1) THEN\n\t#{self.name}p10 = 0;\n"
20
+ s << "else WHEN (!#{@p0} & !#{@p1}) THEN\n\t#{self.name}p10 = #{@p2};\n"
21
+ s << "else WHEN (!#{@p0} & #{@p1}) THEN\n\t#{self.name}p10 = #{@p3};\n"
22
+ end
23
+ end
24
+
25
+ # TODO - need to handle empty nets!!
data/lib/Nand2.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 2-Input NAND part
2
+ class Nand2 < ThreePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, ThreePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p2 = !(#{@p0} & #{@p1});\n"
8
+ end
9
+ end
data/lib/Nand2c.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 2-Input AND part
2
+ class Nand2c < ThreePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, ThreePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p2 = (#{@p0} & #{@p1});\n"
8
+ end
9
+ end
data/lib/Nand3.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 3-Input NAND part
2
+ class Nand3 < FourPorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, FourPorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p3 = !(#{@p0} & #{@p1} & #{@p2});\n"
8
+ end
9
+ end
data/lib/Nand3c.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 3-Input AND part
2
+ class Nand3c < FourPorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, FourPorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p3 = (#{@p0} & #{@p1} & #{@p2});\n"
8
+ end
9
+ end
data/lib/Nand4.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 4-Input NAND part
2
+ class Nand4 < FivePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, FivePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p4 = !(#{@p0} & #{@p1} & #{@p2} & #{@p3});\n"
8
+ end
9
+ end
data/lib/Nand4c.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 4-Input AND part
2
+ class Nand4c < FivePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, FivePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p4 = (#{@p0} & #{@p1} & #{@p2} & #{@p3});\n"
8
+ end
9
+ end
data/lib/Nor2.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 2-Input NOR part
2
+ class Nor2 < ThreePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, ThreePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p2 = !(#{@p0} # #{@p1});\n"
8
+ end
9
+ end
data/lib/Nor2c.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 2-Input OR part
2
+ class Nor2c < ThreePorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, ThreePorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p2 = (#{@p0} # #{@p1});\n"
8
+ end
9
+ end
data/lib/Nor3.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the 3-Input NOR part
2
+ class Nor3 < FourPorts
3
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
4
+ # These connections are defined in the abelout method of this object's superclass, FourPorts.
5
+ def abelout
6
+ super
7
+ "#{self.name}p3 = !(#{@p0} # #{@p1} # #{@p2});\n"
8
+ end
9
+ end
data/lib/OnePort.rb ADDED
@@ -0,0 +1,11 @@
1
+ # This class is the superclass for all one port Inst objects.
2
+ # Vdd, Input, Gnd, and Output inherit from this class.
3
+
4
+ class OnePort < Inst
5
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
6
+ # It is responsible for calling its superclass Inst and passing to it the correct number of input ports and output ports to
7
+ # be created, it also instructs Inst to not designate nodes for output ports of objects which inherit from this class.
8
+ def initialize(name,inputs = [],outputs = [0])
9
+ super(name,inputs,outputs,false)
10
+ end
11
+ end
data/lib/Output.rb ADDED
@@ -0,0 +1,17 @@
1
+ # This class defines the Output port instance.
2
+ class Output < OnePort
3
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
4
+ # It is responsible for defining applicable output pins, then calling its superclass, OnePort, to complete other tasks.
5
+ def initialize(name)
6
+ super(name,[0],[])
7
+ self.outputs = "#{self.name}p0\tpin;\n"
8
+ end
9
+
10
+ # This method defines the connections held by the ports of this object and returns the specific ABEL code to be output for this
11
+ # object based on the connections on its input port.
12
+ def abelout
13
+ # make this a class variable just for consistency's sake
14
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
15
+ "#{self.name}p0 = #{@p0};\n"
16
+ end
17
+ end
@@ -0,0 +1,80 @@
1
+ # This module defines a number of helper methods that assist the Parser class in completing its task.
2
+ module ParseHelper
3
+ # Takes a string (str) as input and returns true if the given string has matching sets of parentheses, otherwise it returns false.
4
+ def self.parens_check(str)
5
+ str.count("(") == str.count(")")
6
+ end
7
+
8
+ # Takes an integer (numports) and the name of an Inst (instname) and returns an array of Inst names properly formatted
9
+ # to take into account the fact that the Inst has multiple bits.
10
+ def self.member_inst_names(numports,instname)
11
+ p = 0
12
+ a = []
13
+ # while we have not reached the number of ports
14
+ while p < numports
15
+ # add a port name to the array
16
+ addstr = "#{instname}m#{p}"
17
+ a << addstr
18
+ p+=1
19
+ end
20
+ # return the array
21
+ a
22
+ end
23
+
24
+ # Takes a string (str) that defines a netlist and a hash of all existing Inst objects (insts) as input and produces an array of unique port
25
+ # names that are defined as connections in that netlist.
26
+ def self.get_port_names(str,insts)
27
+ a = []
28
+ i = 0
29
+ s=""
30
+ # while we are not at the end of the line
31
+ while i < str.length
32
+ # append current character to a new string
33
+ s << str[i].chr
34
+ # if the parens match append it to an array
35
+ if parens_check(s)
36
+ a << self.parse_port_names(s,insts)
37
+ s = ""
38
+ end
39
+ # keep checking
40
+ i+=1
41
+ end
42
+ # return the array (use uniq to get rid of duplicate bufz ports)
43
+ a.uniq
44
+ end
45
+
46
+ # Takes a string of a portname (str) as input and returns an array where the first element is the name of the Inst object
47
+ # to which the port belongs, and the second element is the port it represents on the given Inst.
48
+ def self.portname_split(str)
49
+ a = []
50
+ if str =~ /(\w+)((p\d+\z|out\z))/
51
+ a[0] = $1
52
+ a[1] = $2
53
+ else
54
+ raise "Invalid EDF"
55
+ end
56
+ a
57
+ end
58
+
59
+ private
60
+
61
+ def self.parse_port_names(str,insts)
62
+ # if we are dealing with an instance (as defined in the EDF)
63
+ if str =~ /(\(portRef\s)(\w+)(\s\(instanceRef\s)(\w+)/
64
+ # if it is a bufz fake out portname to match output pin name
65
+ if insts["#{$4.downcase}"].class.to_s.downcase == "bufz" && !%w[p0 p1 p2 p3 p4 p5 p6].find {|d| d == $2.downcase}
66
+ "#{$4.downcase}out"
67
+ else
68
+ "#{$4.downcase}#{$2.downcase}"
69
+ end
70
+ # if we are dealing with a port (as defined in the EDF) of a multi-membered Inst
71
+ elsif str =~ /(\(portRef\s\(member\s)(\w+)(\s)(\d+)/
72
+ "#{$2.downcase}m#{$4}p0"
73
+ # if we are dealing with a port (as defined in the EDF) of a standard Inst
74
+ elsif str =~ /(\(portRef\s)(\w+)/
75
+ "#{$2.downcase}p0"
76
+ else
77
+ raise "Invalid EDF"
78
+ end
79
+ end
80
+ end
data/lib/Parser.rb ADDED
@@ -0,0 +1,137 @@
1
+ # This class handles all parsing operations for this application. It makes extensive use of the ParseHelper module to accomplish this.
2
+ class Parser
3
+ # Takes an array of lines (filearray) - presumably from an EDF file - and parses them, dynamically creating a data structure
4
+ # by defining the connections between Inst objects as they are created.
5
+ def parse(filearray)
6
+ # read through our array to find and store the start and end points
7
+ filearray.each_with_index do |line,index|
8
+ line.strip!
9
+ # store linecounts as indexes into the array (zero based)
10
+ @startline = index if line =~ /interface/
11
+ if line =~ /design root/
12
+ @endline = index - 2
13
+ break
14
+ end
15
+ end
16
+
17
+ # chop invalid parts off of array
18
+ filearray = filearray.slice(@startline..@endline)
19
+
20
+ arrplace = 0
21
+ arrlength = filearray.length - 1
22
+ valid_edf = []
23
+ tmpstr = ""
24
+ @insts = {}
25
+ while arrplace <= arrlength
26
+ # see if we have a keyword on the current line
27
+ if filearray[arrplace] =~ /\A\(port\s+|\A\(instance|\A\(net/
28
+ # we do, see if its parens are matched
29
+ if ParseHelper.parens_check(filearray[arrplace])
30
+ # they are, so put the string into the array
31
+ valid_edf << filearray[arrplace]
32
+ else
33
+ # they are not, so write the array location to a temp string
34
+ tmpstr << filearray[arrplace]
35
+ # see if we are at the end of the array
36
+ break if arrplace + 1 >= arrlength
37
+ # if not keep trying to match parens
38
+ arrplace += 1
39
+ tmpstr << filearray[arrplace]
40
+ # replace this with paren check
41
+ while !ParseHelper.parens_check(tmpstr)
42
+ break if arrplace + 1 >= arrlength
43
+ arrplace += 1
44
+ tmpstr << filearray[arrplace]
45
+ end
46
+ valid_edf << tmpstr
47
+ tmpstr = ""
48
+ end
49
+ # look at next place
50
+ arrplace += 1
51
+ else
52
+ arrplace += 1
53
+ end
54
+ end
55
+
56
+ valid_edf.each do |l|
57
+ # for the first keyword port
58
+ if l =~ /\A\(port\s+/
59
+ # if there are multiple members
60
+ if l =~ /(\w+)(\s+)(\d+)(\(direction)(\s)(input|output)/
61
+ instnum = $3.to_i
62
+ insttype = $6.capitalize
63
+ instname = $1.downcase
64
+ # generate names for each member
65
+ inames = ParseHelper.member_inst_names(instnum,instname)
66
+ # puts "Creating #{instnum} Insts of type #{insttype} named #{inames.join(", ")}"
67
+ # create the inst objects of the proper type and store in insts hash
68
+ inames.each do |i|
69
+ @insts[i] = Object.const_get(insttype).new(i)
70
+ end
71
+ # if there are no members
72
+ elsif l =~ /(\w+)(\s)(\(direction)(\s)(input|output)/
73
+ insttype = $5.capitalize
74
+ instname = $1.downcase
75
+ # puts "Creating an Inst of type #{insttype} named #{instname}"
76
+ # create the inst objects of the proper type and store in insts hash
77
+ @insts["#{instname}"] = Object.const_get(insttype).new(instname)
78
+ else
79
+ throw "Error Parsing Ports"
80
+ end
81
+ # for the second keyword, "instance"
82
+ elsif l =~ /(\A\(instance\s+)(\w+)(\(viewRef)(\s)(viewnamedefault\(cellRef)(\s)(\w+)/
83
+ insttype = $7.capitalize
84
+ instname = $2.downcase
85
+ # create the inst objects of the proper type and store them in the hash
86
+ # puts "Creating an Inst of type #{insttype} named #{instname}"
87
+ @insts["#{instname}"] = Object.const_get(insttype).new(instname)
88
+ elsif l =~ /(\A\(net\sNet\d+\(joined)(.*)/
89
+ # get the names for the joined ports in individual arrays
90
+ # make this get_port_names method modify names for bufz ports on the fly
91
+ ports = ParseHelper.get_port_names($2,@insts)
92
+ # look for output ports to find the master
93
+ # if inst type is bufz then automatically set it as a masterport
94
+ # I have the inst name and the port name availible to me separately
95
+ outputports = []
96
+ inputports = []
97
+ unless ports.length <= 1
98
+ ports.each do |p|
99
+ # split portnames into inst name and port name
100
+ splitport = ParseHelper.portname_split(p)
101
+ # if the portname is out we have a bufz output port
102
+ if splitport[1] == "out"
103
+ # we know this is an output so add it to output
104
+ outputports << p
105
+ # otherwise check to see if this might be a output port of another type
106
+ elsif @insts[splitport[0]].get_port(splitport[1]).type == "out"
107
+ # we know this is an output so add it to output
108
+ outputports << p
109
+ else
110
+ # otherwise it is an input
111
+ inputports << p
112
+ end
113
+ end
114
+
115
+ # this assumes there is only one input port
116
+ # since bufz is treated as a unit this should be true
117
+ # if it is not there will be errors - but they will be the fault
118
+ # of the circuit designer
119
+ op = ParseHelper.portname_split(outputports.first)
120
+ inputports.each do |p|
121
+ # puts "Cross-Connecting #{op} to #{p}"
122
+ # convert port names to separate inst names and port names
123
+ ip = ParseHelper.portname_split(p)
124
+ # cross connect ports
125
+ # puts "connecting #{ip[0]} on #{ip[1]} to #{op[0]} on #{op[1]}"
126
+ @insts[ip[0]].get_port(ip[1]).add_connection(@insts[op[0]].get_port(op[1]))
127
+ # puts "connecting #{op[0]} on #{op[1]} to #{ip[0]} on #{ip[1]}"
128
+ @insts[op[0]].get_port(op[1]).add_connection(@insts[ip[0]].get_port(ip[1]))
129
+ end
130
+ end
131
+ else
132
+ throw "Error Parsing Nets/Instances"
133
+ end
134
+ end
135
+ @insts
136
+ end
137
+ end
data/lib/Port.rb ADDED
@@ -0,0 +1,24 @@
1
+ # This class defines the Port object. Ports are instantiated each time an Inst object is created and they correspond to
2
+ # the conecptual "ports" found on each Inst. They are connected to other ports via a connection list, these connections
3
+ # are built by the Parser component and in sum form the data structure which models the digital circuit described by the
4
+ # input EDF file.
5
+
6
+ class Port
7
+ attr_accessor :inst, :type, :name, :connections
8
+
9
+ # This method is called each time a new Port object is instantiated. It takes a string argument for the Inst it
10
+ # belongs to (inst); the type of port it is, either input or output, (type); and its name (name), a concatenation
11
+ # of the name of the Inst to which it belongs and the port which it is representing.
12
+ def initialize(inst, type, name)
13
+ self.inst = inst
14
+ self.connections = []
15
+ self.type = type
16
+ self.name = name
17
+ end
18
+
19
+ # This method takes the name of another port as a string (port) and appends it to an array which holds the connection
20
+ # list attribute (connections) for the given port.
21
+ def add_connection(port)
22
+ self.connections << port
23
+ end
24
+ end
data/lib/ThreePorts.rb ADDED
@@ -0,0 +1,17 @@
1
+ # This class is the superclass for all three port Inst objects
2
+ # Nor2, Nand2c, Xor2, Nand2, and Nor2c inherit from this class
3
+
4
+ class ThreePorts < Inst
5
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
6
+ # It is responsible for calling its superclass Inst and passing to it the correct number of input ports and output ports to
7
+ # be created.
8
+ def initialize(name)
9
+ super(name,[0,1],[2])
10
+ end
11
+
12
+ # This method defines the connections held by the ports for this object's subclasses.
13
+ def abelout
14
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
15
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
16
+ end
17
+ end
data/lib/TwoPorts.rb ADDED
@@ -0,0 +1,16 @@
1
+ # This class is the superclass for all two port Inst objects
2
+ # Inv and Buf1 inherit from this class
3
+
4
+ class TwoPorts < Inst
5
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
6
+ # It is responsible for calling its superclass Inst and passing to it the correct number of input ports and output ports to
7
+ # be created.
8
+ def initialize(name)
9
+ super(name,[0],[1])
10
+ end
11
+
12
+ # This method defines the connections held by the ports for this object's subclasses.
13
+ def abelout
14
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
15
+ end
16
+ end