Merge branch 'dev' into stable

This commit is contained in:
mrg 2021-04-21 13:45:47 -07:00
commit 9d438d9181
11 changed files with 411 additions and 45 deletions

View File

@ -1,12 +1,9 @@
![](./images/OpenRAM_logo_yellow_transparent.svg)
# OpenRAM # OpenRAM
[![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/) [![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/)
[![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) [![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE)
[![Download](./images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/stable.zip)
Master:
[![Download](./images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/master.zip)
Dev:
[![Download](./images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) [![Download](./images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip)
An open-source static random access memory (SRAM) compiler. An open-source static random access memory (SRAM) compiler.
@ -34,8 +31,7 @@ things that need to be fixed.
The OpenRAM compiler has very few dependencies: The OpenRAM compiler has very few dependencies:
+ [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) + [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
+ Python 3.5 or higher + Python 3.5 or higher
+ Python numpy (pip3 install numpy to install) + Various Python packages (pip install -r requirements.txt)
+ Python scipy (pip3 install scipy to install)
If you want to perform DRC and LVS, you will need either: If you want to perform DRC and LVS, you will need either:
+ Calibre (for [FreePDK45]) + Calibre (for [FreePDK45])

View File

@ -123,6 +123,14 @@ class _wordline_driver:
self.vertical_supply = vertical_supply self.vertical_supply = vertical_supply
class _bitcell_array:
def __init__(self,
wordline_layer,
wordline_pitch_factor=2):
self.wordline_layer = wordline_layer
self.wordline_pitch_factor = wordline_pitch_factor
class layer_properties(): class layer_properties():
""" """
This contains meta information about the module routing layers. These This contains meta information about the module routing layers. These
@ -159,6 +167,10 @@ class layer_properties():
self._wordline_driver = _wordline_driver(vertical_supply=False) self._wordline_driver = _wordline_driver(vertical_supply=False)
self._local_bitcell_array = _bitcell_array(wordline_layer="m2")
self._global_bitcell_array = _bitcell_array(wordline_layer="m3")
@property @property
def bank(self): def bank(self):
return self._bank return self._bank
@ -191,3 +203,11 @@ class layer_properties():
def wordline_driver(self): def wordline_driver(self):
return self._wordline_driver return self._wordline_driver
@property
def global_bitcell_array(self):
return self._global_bitcell_array
@property
def local_bitcell_array(self):
return self._local_bitcell_array

View File

@ -674,7 +674,8 @@ class layout():
directions=None, directions=None,
size=[1, 1], size=[1, 1],
implant_type=None, implant_type=None,
well_type=None): well_type=None,
min_area=False):
""" """
Punch a stack of vias from a start layer to a target layer by the center. Punch a stack of vias from a start layer to a target layer by the center.
""" """
@ -708,7 +709,7 @@ class layout():
implant_type=implant_type, implant_type=implant_type,
well_type=well_type) well_type=well_type)
if cur_layer != from_layer: if cur_layer != from_layer or min_area:
self.add_min_area_rect_center(cur_layer, self.add_min_area_rect_center(cur_layer,
offset, offset,
via.mod.first_layer_width, via.mod.first_layer_width,

View File

@ -10,6 +10,8 @@ from tech import layer_names
import os import os
import shutil import shutil
from globals import OPTS from globals import OPTS
from vector import vector
from pin_layout import pin_layout
class lef: class lef:
@ -68,13 +70,63 @@ class lef:
def lef_write(self, lef_name): def lef_write(self, lef_name):
""" Write the entire lef of the object to the file. """ """ Write the entire lef of the object to the file. """
if OPTS.drc_exe and OPTS.drc_exe[0] == "magic": if OPTS.detailed_lef:
self.magic_lef_write(lef_name)
return
debug.info(3, "Writing detailed LEF to {0}".format(lef_name)) debug.info(3, "Writing detailed LEF to {0}".format(lef_name))
self.detailed_lef_write(lef_name)
else:
debug.info(3, "Writing abstract LEF to {0}".format(lef_name))
# Can possibly use magic lef write to create the LEF
# if OPTS.drc_exe and OPTS.drc_exe[0] == "magic":
# self.magic_lef_write(lef_name)
# return
self.abstract_lef_write(lef_name)
self.indent = "" # To maintain the indent level easily def abstract_lef_write(self, lef_name):
# To maintain the indent level easily
self.indent = ""
self.lef = open(lef_name, "w")
self.lef_write_header()
# Start with blockages on all layers the size of the block
# minus the pin escape margin (hard coded to 4 x m3 pitch)
# These are a pin_layout to use their geometric functions
perimeter_margin = self.m3_pitch
self.blockages = {}
for layer_name in self.lef_layers:
self.blockages[layer_name]=[]
for layer_name in self.lef_layers:
ll = vector(perimeter_margin, perimeter_margin)
ur = vector(self.width - perimeter_margin, self.height - perimeter_margin)
self.blockages[layer_name].append(pin_layout("",
[ll, ur],
layer_name))
# For each pin, remove the blockage and add the pin
for pin_name in self.pins:
pin = self.get_pin(pin_name)
inflated_pin = pin.inflated_pin(multiple=1)
for blockage in self.blockages[pin.layer]:
if blockage.overlaps(inflated_pin):
intersection_shape = blockage.intersection(inflated_pin)
# If it is zero area, don't add the pin
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
continue
# Remove the old blockage and add the new ones
self.blockages[pin.layer].remove(blockage)
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages)
self.lef_write_pin(pin_name)
self.lef_write_obstructions(abstracted=True)
self.lef_write_footer()
self.lef.close()
def detailed_lef_write(self, lef_name):
# To maintain the indent level easily
self.indent = ""
self.lef = open(lef_name, "w") self.lef = open(lef_name, "w")
self.lef_write_header() self.lef_write_header()
@ -136,24 +188,29 @@ class lef:
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("{0}END {1}\n".format(self.indent, name)) self.lef.write("{0}END {1}\n".format(self.indent, name))
def lef_write_obstructions(self): def lef_write_obstructions(self, abstracted=False):
""" Write all the obstructions on each layer """ """ Write all the obstructions on each layer """
self.lef.write("{0}OBS\n".format(self.indent)) self.lef.write("{0}OBS\n".format(self.indent))
for layer in self.lef_layers: for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer])) self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
self.indent += " " self.indent += " "
if abstracted:
blockages = self.blockages[layer]
for b in blockages:
self.lef_write_shape(b.rect)
else:
blockages = self.get_blockages(layer, True) blockages = self.get_blockages(layer, True)
for b in blockages: for b in blockages:
self.lef_write_shape(b) self.lef_write_shape(b)
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent)) self.lef.write("{0}END\n".format(self.indent))
def lef_write_shape(self, rect): def lef_write_shape(self, obj):
if len(rect) == 2: if len(obj) == 2:
""" Write a LEF rectangle """ """ Write a LEF rectangle """
self.lef.write("{0}RECT ".format(self.indent)) self.lef.write("{0}RECT ".format(self.indent))
for item in rect: for item in obj:
# print(rect) # print(obj)
self.lef.write(" {0} {1}".format(round(item[0], self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid), self.round_grid),
round(item[1], round(item[1],
@ -162,12 +219,10 @@ class lef:
else: else:
""" Write a LEF polygon """ """ Write a LEF polygon """
self.lef.write("{0}POLYGON ".format(self.indent)) self.lef.write("{0}POLYGON ".format(self.indent))
for item in rect: for item in obj:
self.lef.write(" {0} {1}".format(round(item[0], self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid), self.round_grid),
round(item[1], round(item[1],
self.round_grid))) self.round_grid)))
# for i in range(0,len(rect)):
# self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")

View File

@ -139,13 +139,13 @@ class pin_layout:
min_area = drc("{}_minarea".format(self.layer)) min_area = drc("{}_minarea".format(self.layer))
pass pass
def inflate(self, spacing=None): def inflate(self, spacing=None, multiple=0.5):
""" """
Inflate the rectangle by the spacing (or other rule) Inflate the rectangle by the spacing (or other rule)
and return the new rectangle. and return the new rectangle.
""" """
if not spacing: if not spacing:
spacing = 0.5*drc("{0}_to_{0}".format(self.layer)) spacing = multiple*drc("{0}_to_{0}".format(self.layer))
(ll, ur) = self.rect (ll, ur) = self.rect
spacing = vector(spacing, spacing) spacing = vector(spacing, spacing)
@ -154,15 +154,23 @@ class pin_layout:
return (newll, newur) return (newll, newur)
def inflated_pin(self, spacing=None, multiple=0.5):
"""
Inflate the rectangle by the spacing (or other rule)
and return the new rectangle.
"""
inflated_area = self.inflate(spacing, multiple)
return pin_layout(self.name, inflated_area, self.layer)
def intersection(self, other): def intersection(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
(ll, ur) = self.rect (ll, ur) = self.rect
(oll, our) = other.rect (oll, our) = other.rect
min_x = max(ll.x, oll.x) min_x = max(ll.x, oll.x)
max_x = min(ll.x, oll.x) max_x = min(ur.x, our.x)
min_y = max(ll.y, oll.y) min_y = max(ll.y, oll.y)
max_y = min(ll.y, oll.y) max_y = min(ur.y, our.y)
return [vector(min_x, min_y), vector(max_x, max_y)] return [vector(min_x, min_y), vector(max_x, max_y)]
@ -578,6 +586,30 @@ class pin_layout:
return None return None
def cut(self, shape):
"""
Return a set of shapes that are this shape minus the argument shape.
"""
# Make the unique coordinates in X and Y directions
x_offsets = sorted([self.lx(), self.rx(), shape.lx(), shape.rx()])
y_offsets = sorted([self.by(), self.uy(), shape.by(), shape.uy()])
new_shapes = []
# Create all of the shapes
for x1, x2 in zip(x_offsets[0:], x_offsets[1:]):
if x1==x2:
continue
for y1, y2 in zip(y_offsets[0:], y_offsets[1:]):
if y1==y2:
continue
new_shape = pin_layout("", [vector(x1, y1), vector(x2, y2)], self.lpp)
# Don't add the existing shape in if it overlaps the pin shape
if new_shape.contains(shape):
continue
new_shapes.append(new_shape)
return new_shapes
def same_lpp(self, lpp1, lpp2): def same_lpp(self, lpp1, lpp2):
""" """
Check if the layers and purposes are the same. Check if the layers and purposes are the same.

View File

@ -11,6 +11,7 @@ from sram_factory import factory
from vector import vector from vector import vector
import debug import debug
from numpy import cumsum from numpy import cumsum
from tech import layer_properties as layer_props
class global_bitcell_array(bitcell_base_array.bitcell_base_array): class global_bitcell_array(bitcell_base_array.bitcell_base_array):
@ -223,11 +224,20 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
new_name = "{0}_{1}".format(base_name, col + col_value) new_name = "{0}_{1}".format(base_name, col + col_value)
self.copy_layout_pin(inst, pin_name, new_name) self.copy_layout_pin(inst, pin_name, new_name)
# Add the global word lines
wl_layer = layer_props.global_bitcell_array.wordline_layer
for wl_name in self.local_mods[0].get_inputs(): for wl_name in self.local_mods[0].get_inputs():
for local_inst in self.local_insts:
wl_pin = local_inst.get_pin(wl_name)
self.add_via_stack_center(from_layer=wl_pin.layer,
to_layer=wl_layer,
offset=wl_pin.center())
left_pin = self.local_insts[0].get_pin(wl_name) left_pin = self.local_insts[0].get_pin(wl_name)
right_pin = self.local_insts[-1].get_pin(wl_name) right_pin = self.local_insts[-1].get_pin(wl_name)
self.add_layout_pin_segment_center(text=wl_name, self.add_layout_pin_segment_center(text=wl_name,
layer=left_pin.layer, layer=wl_layer,
start=left_pin.lc(), start=left_pin.lc(),
end=right_pin.rc()) end=right_pin.rc())

View File

@ -10,6 +10,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
import debug import debug
from tech import layer_properties as layer_props
class local_bitcell_array(bitcell_base_array.bitcell_base_array): class local_bitcell_array(bitcell_base_array.bitcell_base_array):
@ -190,6 +191,11 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
def route(self): def route(self):
global_wl_layer = layer_props.global_bitcell_array.wordline_layer
global_wl_pitch = getattr(self, "{}_pitch".format(global_wl_layer))
global_wl_pitch_factor = layer_props.global_bitcell_array.wordline_pitch_factor
local_wl_layer = layer_props.local_bitcell_array.wordline_layer
# Route the global wordlines # Route the global wordlines
for port in self.all_ports: for port in self.all_ports:
if port == 0: if port == 0:
@ -204,25 +210,27 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
in_pin = self.wl_insts[port].get_pin(in_pin_name) in_pin = self.wl_insts[port].get_pin(in_pin_name)
y_offset = in_pin.cy() y_offset = in_pin.cy()
if port == 0: if port == 0:
y_offset -= 2 * self.m3_pitch y_offset -= global_wl_pitch_factor * global_wl_pitch
else: else:
y_offset += 2 * self.m3_pitch y_offset += global_wl_pitch_factor * global_wl_pitch
self.add_layout_pin_segment_center(text=wl_name,
layer="m3",
start=vector(self.wl_insts[port].lx(), y_offset),
end=vector(self.wl_insts[port].lx() + self.wl_array.width, y_offset))
mid = vector(in_pin.cx(), y_offset) mid = vector(in_pin.cx(), y_offset)
self.add_path("m2", [in_pin.center(), mid])
# A short jog to the global line
self.add_via_stack_center(from_layer=in_pin.layer, self.add_via_stack_center(from_layer=in_pin.layer,
to_layer="m2", to_layer=local_wl_layer,
offset=in_pin.center()) offset=in_pin.center(),
self.add_via_center(self.m2_stack, min_area=True)
self.add_path(local_wl_layer, [in_pin.center(), mid])
self.add_via_stack_center(from_layer=local_wl_layer,
to_layer=global_wl_layer,
offset=mid,
min_area=True)
# Add the global WL pin
self.add_layout_pin_rect_center(text=wl_name,
layer=global_wl_layer,
offset=mid) offset=mid)
# Route the buffers # Route the buffers
for port in self.all_ports: for port in self.all_ports:
driver_outputs = self.driver_wordline_outputs[port] driver_outputs = self.driver_wordline_outputs[port]

View File

@ -153,6 +153,9 @@ class options(optparse.Values):
# Route the input/output pins to the perimeter # Route the input/output pins to the perimeter
perimeter_pins = True perimeter_pins = True
# Detailed or abstract LEF view
detailed_lef = False
keep_temp = False keep_temp = False

View File

@ -263,13 +263,18 @@ class sram_base(design, verilog, lef):
# Add it as an IO pin to the perimeter # Add it as an IO pin to the perimeter
lowest_coord = self.find_lowest_coords() lowest_coord = self.find_lowest_coords()
pin_width = pin.rx() - lowest_coord.x route_width = pin.rx() - lowest_coord.x
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
pin_offset = vector(lowest_coord.x, pin.by()) pin_offset = vector(lowest_coord.x, pin.by())
self.add_layout_pin(pin_name, self.add_layout_pin(pin_name,
pin.layer, pin.layer,
pin_offset, pin_offset,
pin_width, pin_width,
pin.height()) pin.height())
self.add_rect(pin.layer,
pin_offset,
route_width,
pin.height())
def route_escape_pins(self): def route_escape_pins(self):
""" """

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="605.40302"
height="165.26472"
viewBox="0 0 605.40301 165.26473"
id="svg2"
version="1.1"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="OpenRAM_logo_yellow_transparent.svg"
inkscape:export-filename="/home/mrg/openram/images/OpenRAM_logo_yellow_transparent.png"
inkscape:export-xdpi="150"
inkscape:export-ydpi="150">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2634"
inkscape:window-height="1333"
id="namedview3551"
showgrid="false"
inkscape:zoom="2.8592481"
inkscape:cx="232.75305"
inkscape:cy="82.632362"
inkscape:window-x="208"
inkscape:window-y="96"
inkscape:window-maximized="0"
inkscape:current-layer="svg2"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<text
id="text3336"
y="113.18625"
x="173.17645"
style="font-style:normal;font-weight:normal;font-size:22.5px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#003c6c;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4140"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:80px;font-family:Futura;-inkscape-font-specification:'Futura Bold';fill:#003c6c;fill-opacity:1"
y="113.18625"
x="173.17645">OpenRAM</tspan></text>
<rect
y="39.336884"
x="36.581963"
height="87.463478"
width="89.973282"
id="rect4144"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:8.3992691;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path8080"
d="m 53.960768,13.421563 v 21.96078"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 81.568617,13.421563 v 21.96078"
id="path8112"
inkscape:connector-curvature="0" />
<path
id="path8118"
d="m 109.17646,13.421563 v 21.96078"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 53.960768,151.84317 V 129.88239"
id="path8137"
inkscape:connector-curvature="0" />
<path
id="path8143"
d="M 81.568617,151.84317 V 129.88239"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 109.17646,151.84317 V 129.88239"
id="path8149"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 151.21568,56.715693 H 129.2549"
id="path8157"
inkscape:connector-curvature="0" />
<path
id="path8163"
d="M 151.21568,84.323543 H 129.2549"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 151.21568,111.93138 H 129.2549"
id="path8169"
inkscape:connector-curvature="0" />
<path
id="path8177"
d="m 13.421548,56.715693 h 21.96078"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.421548,84.323543 h 21.96078"
id="path8183"
inkscape:connector-curvature="0" />
<path
id="path8189"
d="m 13.421548,111.93138 h 21.96078"
style="fill:none;fill-rule:evenodd;stroke:#003c6c;stroke-width:3.69754982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<ellipse
ry="5.9607844"
rx="5.647059"
cy="7.4607844"
cx="53.96077"
id="path8078"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8110"
cx="81.568619"
cy="7.4607844"
rx="5.647059"
ry="5.9607844" />
<ellipse
ry="5.9607844"
rx="5.647059"
cy="7.4607844"
cx="109.17645"
id="ellipse8116"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="scale(1,-1)"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8135"
cx="53.96077"
cy="-157.80394"
rx="5.647059"
ry="5.9607844" />
<ellipse
transform="scale(1,-1)"
ry="5.9607844"
rx="5.647059"
cy="-157.80394"
cx="81.568619"
id="ellipse8141"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="scale(1,-1)"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8147"
cx="109.17645"
cy="-157.80394"
rx="5.647059"
ry="5.9607844" />
<ellipse
transform="rotate(90)"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8155"
cx="56.715668"
cy="-157.17644"
rx="5.647059"
ry="5.9607844" />
<ellipse
transform="rotate(90)"
ry="5.9607844"
rx="5.647059"
cy="-157.17644"
cx="84.323517"
id="ellipse8161"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="rotate(90)"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8167"
cx="111.93137"
cy="-157.17644"
rx="5.647059"
ry="5.9607844" />
<ellipse
transform="matrix(0,1,1,0,0,0)"
ry="5.9607844"
rx="5.647059"
cy="7.4607844"
cx="56.715668"
id="ellipse8175"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="matrix(0,1,1,0,0,0)"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8181"
cx="84.323517"
cy="7.4607844"
rx="5.647059"
ry="5.9607844" />
<ellipse
transform="matrix(0,1,1,0,0,0)"
ry="5.9607844"
rx="5.647059"
cy="7.4607844"
cx="111.93137"
id="ellipse8187"
style="fill:#003c6c;fill-opacity:1;stroke:#003c6c;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="fill:#fdc700;fill-opacity:1;stroke:none;stroke-width:4.87900019;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3553"
width="88.83606"
height="86.559578"
x="37.165073"
y="39.245544"
ry="4.3552427" />
</svg>

After

Width:  |  Height:  |  Size: 9.7 KiB