ruby-gdsii 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.
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
+