ruby-gdsii 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE.txt +20 -0
  2. data/README.txt +113 -0
  3. data/bin/rgds-debug +43 -0
  4. data/bin/rgds-dump +38 -0
  5. data/bin/rgds-join +98 -0
  6. data/bin/rgds-layers +53 -0
  7. data/bin/rgds-sremove +135 -0
  8. data/bin/rgds-ssplit +113 -0
  9. data/bin/rgds-stats +134 -0
  10. data/bin/rgds-structs +41 -0
  11. data/bin/rgds-tree +166 -0
  12. data/bin/rgds2rb +99 -0
  13. data/lib/gdsii.rb +137 -0
  14. data/lib/gdsii/aref.rb +243 -0
  15. data/lib/gdsii/bnf.rb +309 -0
  16. data/lib/gdsii/boundary.rb +53 -0
  17. data/lib/gdsii/box.rb +65 -0
  18. data/lib/gdsii/byte_order.rb +36 -0
  19. data/lib/gdsii/element.rb +172 -0
  20. data/lib/gdsii/group.rb +98 -0
  21. data/lib/gdsii/library.rb +518 -0
  22. data/lib/gdsii/mixins.rb +378 -0
  23. data/lib/gdsii/node.rb +65 -0
  24. data/lib/gdsii/path.rb +169 -0
  25. data/lib/gdsii/property.rb +108 -0
  26. data/lib/gdsii/record.rb +606 -0
  27. data/lib/gdsii/record/consts.rb +384 -0
  28. data/lib/gdsii/record/datatypes/ascii.rb +145 -0
  29. data/lib/gdsii/record/datatypes/bitarray.rb +101 -0
  30. data/lib/gdsii/record/datatypes/data.rb +111 -0
  31. data/lib/gdsii/record/datatypes/int2.rb +67 -0
  32. data/lib/gdsii/record/datatypes/int4.rb +65 -0
  33. data/lib/gdsii/record/datatypes/nodata.rb +60 -0
  34. data/lib/gdsii/record/datatypes/real4.rb +51 -0
  35. data/lib/gdsii/record/datatypes/real8.rb +120 -0
  36. data/lib/gdsii/sref.rb +61 -0
  37. data/lib/gdsii/strans.rb +133 -0
  38. data/lib/gdsii/structure.rb +352 -0
  39. data/lib/gdsii/text.rb +203 -0
  40. data/pkg/ruby-gdsii.gem +23 -0
  41. data/samples/hello.gds +0 -0
  42. data/samples/hello.out.rb +84 -0
  43. data/samples/hello.rb +94 -0
  44. data/test/baseline/dcp1.gds +0 -0
  45. data/test/baseline/h_write.gds +0 -0
  46. data/test/h_pthru.rb +22 -0
  47. data/test/h_write.rb +117 -0
  48. data/test/hs_pthru.rb +31 -0
  49. data/test/l_pthru.rb +23 -0
  50. data/test/test_gds_group.rb +379 -0
  51. data/test/test_gds_record.rb +99 -0
  52. metadata +118 -0
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ ##############################################################################
3
+ #
4
+ # == gds2rb.rb
5
+ #
6
+ # Reads a GDSII file and then generates the corresponding Ruby code necessary
7
+ # to recreate the GDSII.
8
+ #
9
+ # === Author
10
+ #
11
+ # James D. Masters (james.d.masters@gmail.com)
12
+ #
13
+ # === History
14
+ #
15
+ # * 03/26/2007 (jdm): Initial version
16
+ #
17
+ ##############################################################################
18
+
19
+ require 'getoptlong'
20
+ require 'gdsii/record.rb'
21
+ include Gdsii
22
+
23
+ usage = "
24
+ Reads a GDSII file and then generates the corresponding Ruby code necessary
25
+ to recreate the GDSII.
26
+
27
+ Usage: gds2rb.rb [options] <gds-file> <rb-file> <gds-out-file>
28
+
29
+ Options:
30
+
31
+ -s, --structs Specify structure(s) in a space separated list to process.
32
+ The default behavior is to process all structures.
33
+ -f, --force Force existing Ruby file if it exists.
34
+ -h, --help Displays this usage message.
35
+
36
+ "
37
+
38
+ # Get command-line arguments
39
+ structs = []
40
+ force = false
41
+
42
+ opts = GetoptLong.new(
43
+ ['--structs', '-s', GetoptLong::OPTIONAL_ARGUMENT],
44
+ ['--force', '-f', GetoptLong::OPTIONAL_ARGUMENT|GetoptLong::NO_ARGUMENT],
45
+ ['--help', '-h', GetoptLong::OPTIONAL_ARGUMENT|GetoptLong::NO_ARGUMENT]
46
+ )
47
+
48
+ opts.each do |option, argument|
49
+ case option
50
+ when '--help' : abort usage
51
+ when '--structs' : structs = argument.split(/\s+/)
52
+ when '--force' : force = true
53
+ end
54
+ end
55
+
56
+ # Get GDSII file directory from command line
57
+ gds_file, rb_file, gds_out_file = ARGV
58
+ unless (gds_file and rb_file and gds_out_file)
59
+ abort usage
60
+ end
61
+
62
+ # Fail if the Ruby file exists and force isn't enabled
63
+ if File.exists? rb_file and not force
64
+ abort "\nRuby file exists: #{rb_file} (use -f or --force to ignore)"
65
+ end
66
+
67
+ space_before = [GRT_BOUNDARY, GRT_PATH, GRT_TEXT, GRT_NODE,
68
+ GRT_BOX, GRT_ENDSTR, GRT_ENDLIB]
69
+
70
+ # Open Ruby file for write
71
+ File.open(rb_file, 'w') do |rbf|
72
+ # Write the header information
73
+ rbf.puts "require 'gdsii'"
74
+ rbf.puts
75
+ rbf.puts "File.open('#{gds_out_file}', 'wb') do |outf|"
76
+ rbf.puts
77
+
78
+ # Read the GDSII file and write out resulting GDSII files
79
+ File.open(gds_file, 'rb') do |inf|
80
+ # Read each record in the GDSII file
81
+ Record.read_each(inf) do |record|
82
+ rbf.puts if space_before.member?(record.type)
83
+ if record.type == GRT_BGNSTR
84
+ strname = Record.peek(inf).data_value
85
+ rbf.puts
86
+ rbf.puts ' ' + '#' * 76
87
+ rbf.puts ' # STRUCTURE: ' + strname.to_s
88
+ rbf.puts ' ' + '#' * 76
89
+ rbf.puts
90
+ end
91
+ rbf.puts " Gdsii::Record.new(Gdsii::GRT_#{record.name}, #{record.data_value.inspect}).write(outf)"
92
+ end
93
+ end
94
+
95
+ rbf.puts
96
+ rbf.puts "end"
97
+ end
98
+
99
+
@@ -0,0 +1,137 @@
1
+ #
2
+ # There are two approaches to interacting with a GDSII file using this module:
3
+ #
4
+ # 1. At the record level (low-level)
5
+ # 2. At the record group level (high-level)
6
+ #
7
+ #
8
+ # = Approach #1
9
+ #
10
+ # (See Record class for details)
11
+ #
12
+ # Interaction at the record level is intended for streamlined file processing
13
+ # where the author has a good knowledge of the GDSII structure. A typical
14
+ # usage might be to streamline changes to a GDSII file such as changing
15
+ # bus bit characters on a node name from <> to [] format (see the samples
16
+ # directory of this library installation for an example). Here is a simple
17
+ # way to dump the all strings in a GDSII file using the Record class:
18
+ #
19
+ # require 'gdsii'
20
+ #
21
+ # # Note: 'rb' is required for DOS/Windows compatibility
22
+ # File.open('mydesign.gds', 'rb') do |file|
23
+ # Gds::Record.read_each(file) do |record|
24
+ # puts record.data[0] if record.is_string?
25
+ # end
26
+ # end
27
+ #
28
+ #
29
+ # = Approach #2
30
+ #
31
+ # (See Group, Library, Structure, Element, Boundary, Path, Text, SRef, ARef,
32
+ # Node, and Box classes for details)
33
+ #
34
+ # The second approach offers a high-level interface to the GDSII format which
35
+ # might be ideal in cases where the author may not be familiar with the details
36
+ # of the GDSII format. This example will write a small transistor cell:
37
+ #
38
+ # require 'gdsii'
39
+ #
40
+ # Gdsii::Library.new('MYLIB.DB') do |lib|
41
+ #
42
+ # Gdsii::Structure.new('trans') do |struct|
43
+ #
44
+ # # Diffusion layer
45
+ # struct.add Gdsii::Boundary.new(1, 0, [-2000,0, -2000,4000, 2000,4000, 2000,0, -2000,0])
46
+ #
47
+ # # Gate layer... add a property labling as "gate"
48
+ # Gdsii::Path.new(2, 0, 0, 800, [0,-600, 0,4600]) do |path|
49
+ # path.add Gdsii::Property.new(1, 'gate')
50
+ # struct.add path
51
+ # end
52
+ #
53
+ # # Add this structure to the library
54
+ # lib.add struct
55
+ #
56
+ # end
57
+ #
58
+ # # Write the library to a file
59
+ # lib.write('trans.gds')
60
+ #
61
+ # end
62
+ #
63
+ #
64
+ # = Important notes
65
+ #
66
+ # == Look at inherited and mixed-in methods
67
+ #
68
+ # The high-level classes in this GDSII library rely heavily upon inheritance
69
+ # and mixed-in modules to reduce code. When reviewing documentation, be sure
70
+ # to be aware of methods defined implicitly through class inheritance and
71
+ # through Module#include and Module#extend.
72
+ #
73
+ # == Use 'b' during R/W of files
74
+ #
75
+ # Be sure to always use the 'b' read/write attribute when reading and writing
76
+ # GDSII files to ensure that read/write happens properly on DOS/Windows
77
+ # systems. For example (see IO#open for more details):
78
+ #
79
+ # inf = File.open('mydesign.gds', 'rb')
80
+ # outf = File.open('mydesign.gds', 'wb')
81
+ #
82
+ # == Improving performance
83
+ #
84
+ # The low-level GDSII methods will offer significantly better GDSII read/write
85
+ # performance as compared to the high-level methods. For most streamlined
86
+ # manipulations of GDSII files, the low-level methods are probably the best
87
+ # option. For smaller GDSII files or when code re-use/readability is
88
+ # important, then the performance hit with the high-level methods may not be
89
+ # a concern.
90
+ #
91
+ # Here are some benchmarks using both low and high level methods to read and
92
+ # immediately write a GDSII file:
93
+ #
94
+ # * GDSII file size: 7 MB
95
+ # * WinXP machine: Intel(R) Pentium(R) M (Centrino) 1.6 Ghz @ 1 GB RAM
96
+ # * Linux machine (SuSE): 2x Intel(R) Pentium(R) 4 3.4 Ghz @ 1 GB RAM
97
+ #
98
+ # Linux WinXP
99
+ # ------- -------
100
+ # High-level methods: 8m 45s 11m 23s
101
+ # Low-level methods: 0m 45s 1m 29s
102
+ #
103
+ module Gdsii
104
+ # Empty module here as a placeholder for rdoc
105
+ end
106
+
107
+ # Require byte order, constants, and mixins
108
+ require 'gdsii/byte_order.rb'
109
+ require 'gdsii/record/consts.rb'
110
+ require 'gdsii/mixins.rb'
111
+
112
+ # Require low-level files (data types and records)
113
+ require 'gdsii/record/datatypes/bitarray.rb'
114
+ require 'gdsii/record/datatypes/int4.rb'
115
+ require 'gdsii/record/datatypes/nodata.rb'
116
+ require 'gdsii/record/datatypes/real4.rb'
117
+ require 'gdsii/record/datatypes/ascii.rb'
118
+ require 'gdsii/record/datatypes/data.rb'
119
+ require 'gdsii/record/datatypes/real8.rb'
120
+ require 'gdsii/record/datatypes/int2.rb'
121
+ require 'gdsii/record.rb'
122
+
123
+ # Require high-level files
124
+ require 'gdsii/bnf.rb'
125
+ require 'gdsii/group.rb'
126
+ require 'gdsii/element.rb'
127
+ require 'gdsii/property.rb'
128
+ require 'gdsii/strans.rb'
129
+ require 'gdsii/boundary.rb'
130
+ require 'gdsii/path.rb'
131
+ require 'gdsii/text.rb'
132
+ require 'gdsii/box.rb'
133
+ require 'gdsii/node.rb'
134
+ require 'gdsii/sref.rb'
135
+ require 'gdsii/aref.rb'
136
+ require 'gdsii/structure.rb'
137
+ require 'gdsii/library.rb'
@@ -0,0 +1,243 @@
1
+ require 'gdsii/element'
2
+ require 'gdsii/group'
3
+ require 'gdsii/strans'
4
+
5
+ module Gdsii
6
+
7
+ #
8
+ # Represents a GDSII structure array reference (ARef) element. Most
9
+ # methods are from Element or from the various included Access module
10
+ # methods.
11
+ #
12
+ class ARef < Element
13
+
14
+ # Include various record accessors
15
+ include Access::ELFlags
16
+ include Access::Plex
17
+ include Access::StransGroup
18
+ include Access::Sname
19
+
20
+ #
21
+ # ARef BNF description:
22
+ #
23
+ # <aref> ::= AREF [ELFLAGS] [PLEX] SNAME [<strans>] COLROW XY
24
+ #
25
+ self.bnf_spec = BnfSpec.new(
26
+ BnfItem.new(GRT_AREF),
27
+ BnfItem.new(GRT_ELFLAGS, true),
28
+ BnfItem.new(GRT_PLEX, true),
29
+ BnfItem.new(GRT_SNAME),
30
+ BnfItem.new(Strans, true),
31
+ BnfItem.new(GRT_COLROW),
32
+ BnfItem.new(GRT_XY),
33
+ BnfItem.new(Properties, true),
34
+ BnfItem.new(GRT_ENDEL)
35
+ )
36
+
37
+ #
38
+ # Create a new structure array reference (ARef) to be used within a
39
+ # Structure object. The structure name is a String or anything that has
40
+ # a #to_s method. The ref_xy is a *single* set of x/y coordinates
41
+ # that the placement of the ARef (note this is _NOT_ the same as the
42
+ # XY record for ARef - see #xy_record for more details). The colrow is an
43
+ # array of a number of columns and rows respectively. The colrow_spc is
44
+ # an array of spacing values for columns and rows respectively.
45
+ #
46
+ # # Create an ARef at coordinates (0,0) with 2 columns and 8 rows. The
47
+ # # spacing between columns is 200 units and between rows is 300 units.
48
+ # aref = ARef.new('array', [0,0], [2,8], [200, 300])
49
+ #
50
+ # Note, the #ref_xy, #column_space, and #row_space are required.
51
+ # See #xy_record for details.
52
+ #
53
+ def initialize(sname=nil, ref_xy=nil, colrow=nil, colrow_spc=nil)
54
+ super()
55
+ @records[GRT_AREF] = Record.new(GRT_AREF)
56
+ self.sname = sname unless sname.nil?
57
+ self.colrow = colrow unless colrow.nil?
58
+ self.ref_xy = ref_xy unless ref_xy.nil?
59
+ self.column_space = colrow_spc[0] if colrow_spc.class == Array
60
+ self.row_space = colrow_spc[1] if colrow_spc.class == Array
61
+ yield self if block_given?
62
+ end
63
+
64
+ #
65
+ # Get the colrow record (returns Record)
66
+ #
67
+ def colrow_record() @records.get(GRT_COLROW); end
68
+
69
+ #
70
+ # Get the colrow array of numbers (returns 2-element Array of Fixnum)
71
+ # where the first number is columns and the second is rows [col, row].
72
+ # Alternatively, the #rows and #columns method may also be used.
73
+ #
74
+ # aref.colrow #=> [2, 8]
75
+ #
76
+ def colrow() @records.get_data(GRT_COLROW); end
77
+
78
+ #
79
+ # Set the colrow number (see #colrow for format details). Alternatively,
80
+ # the #rows= and #columns= methods may be used.
81
+ #
82
+ # aref.colrow = [2, 8]
83
+ #
84
+ def colrow=(val) @records.set(GRT_COLROW, val); end
85
+
86
+ #
87
+ # Set the columns number in the COLROW record (Fixnum)
88
+ #
89
+ # aref.columns = 2
90
+ #
91
+ def columns=(val)
92
+ if (cr=colrow)
93
+ @records.set(GRT_COLROW, [val, cr[1]])
94
+ else
95
+ @records.set(GRT_COLROW, [val, nil])
96
+ end
97
+ end
98
+
99
+ #
100
+ # Get the columns number in the COLROW record (returns Fixnum)
101
+ #
102
+ # aref.columns #=> 2
103
+ #
104
+ def columns()
105
+ (cr=@records.get(GRT_COLROW)) ? cr[0] : nil
106
+ end
107
+
108
+ #
109
+ # Set the rows number in the COLROW record
110
+ #
111
+ # aref.rows = 8
112
+ #
113
+ def rows=(val)
114
+ if (cr=colrow)
115
+ @records.set(GRT_COLROW, [cr[0], val])
116
+ else
117
+ @records.set(GRT_COLROW, [nil, val])
118
+ end
119
+ end
120
+
121
+ #
122
+ # Get the rows number in the COLROW record (returns Fixnum)
123
+ #
124
+ # aref.rows #=> 8
125
+ #
126
+ def rows()
127
+ (cr=@records.get(GRT_COLROW)) ? cr[1] : nil
128
+ end
129
+
130
+ #
131
+ # Defines the placement XY coordinate for this ARef. See #xy_record for
132
+ # details on how the XY record is used in ARef.
133
+ #
134
+ # aref.ref_xy = [10, 20]
135
+ #
136
+ def ref_xy=(val)
137
+ if val.class == Array and val.length == 2
138
+ @ref_xy = val
139
+ update_xy
140
+ else
141
+ raise TypeError, "Expected Array of length 2"
142
+ end
143
+ end
144
+
145
+ #
146
+ # Returns the placement XY coordinate for this ARef. See #xy_record for
147
+ # details on how the XY record is used in ARef.
148
+ #
149
+ # aref.ref_xy #=> [10, 20]
150
+ #
151
+ def ref_xy(); @ref_xy; end
152
+
153
+ #
154
+ # Defines the column spacing (in units) for this ARef. Internally this
155
+ # value is stored in the XY record. See #xy_record for details on how the
156
+ # XY record is used in ARef.
157
+ #
158
+ # aref.column_space = 200
159
+ #
160
+ def column_space=(val)
161
+ @column_space = val
162
+ update_xy
163
+ end
164
+
165
+ #
166
+ # Returns the placement XY coordinate for this ARef. See #xy_record for
167
+ # details on how the XY record is used in ARef.
168
+ #
169
+ # aref.column_space #=> 200
170
+ #
171
+ def column_space(); @column_space; end
172
+
173
+ #
174
+ # Defines the row spacing (in units) for this ARef. Internally this
175
+ # value is stored in the XY record. See #xy_record for details on how the
176
+ # XY record is used in ARef.
177
+ #
178
+ # aref.row_space = 300
179
+ #
180
+ def row_space=(val)
181
+ @row_space = val
182
+ update_xy
183
+ end
184
+
185
+ #
186
+ # Returns the placement XY coordinate for this ARef. See #xy_record for
187
+ # details on how the XY record is used in ARef.
188
+ #
189
+ # aref.row_space #=> 300
190
+ #
191
+ def row_space(); @row_space; end
192
+
193
+ #
194
+ # Gets the ARef record for XY.
195
+ #
196
+ # Important note on the XY record (i.e. #xy, #xy_record): the GDSII
197
+ # specification calls for exactly 3 XY records for ARef. Because of this
198
+ # specification, there is no #xy= method available for the ARef class.
199
+ # Instead, the XY record is created dynamically when all three of these
200
+ # components are set. Otherwise, the XY record will not exist.
201
+ #
202
+ # The XY record data specification is as follows:
203
+ #
204
+ # * 1: ARef reference point (#ref_xy)
205
+ # * 2: column_space*columns+reference_x (#ref_xy, #columns, and #column_space)
206
+ # * 3: row_space*rows+reference_y (#ref_xy, #rows, and #row_space)
207
+ #
208
+ def xy_record() @records.get(GRT_XY); end
209
+
210
+ #
211
+ # Gets an xy point record (returns an Array). Note, it is probably easier
212
+ # to use #ref_xy, #column_space, or #row_space instead; see #xy_record for
213
+ # details on how the XY record is used for ARef.
214
+ #
215
+ def xy() @records.get_data(GRT_XY); end
216
+
217
+
218
+ #####################
219
+ ## PRIVATE METHODS ##
220
+ #####################
221
+
222
+ private
223
+
224
+ #
225
+ # Update the GRT_XY record if all prerequisites are met (#ref_xy,
226
+ # #column_space, and #row_space).
227
+ #
228
+ def update_xy()
229
+ if ((pxy=ref_xy) and (cs=column_space) and (rs=row_space) and (cr=colrow).length == 2)
230
+ # see #xy_record for an explanation of this formula
231
+ array = pxy + [pxy[0]+cs*cr[0], pxy[1]] + [pxy[0], pxy[1]+rs*cr[1]]
232
+ @records.set(GRT_XY, array)
233
+ else
234
+ @records.set(GRT_XY, nil)
235
+ end
236
+ end
237
+
238
+ end
239
+ end
240
+
241
+
242
+
243
+