blob: e9df15f559c2a56c8ab298eead89ae751aaf7bb5 [file] [log] [blame]
################################################################################################
# Copyright 2023 GlobalFoundries PDK Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################################
#================================================
# --------------- CUSTOM CLASSES ----------------
#================================================
#=========== CUSTOM READER ===========
class SubcircuitModelsReader < RBA::NetlistSpiceReaderDelegate
def parse_element(sup, element)
begin
super
rescue
case element
when 'C'
super("#{sup} C=2e-16", element)
when 'R'
super("#{sup} R=0", element)
else
super
end
end
end
# implements the delegate interface:
# take and translate the element
def element(circuit, ele, name, model, value, nets, params)
case ele
when 'C'
error('Capacitor needs two nodes') if nets.size != 2
# provide a device class
cls = circuit.netlist.device_class_by_name(model)
unless cls
cls = RBA::DeviceClassCapacitor.new
cls.name = model
circuit.netlist.add(cls)
end
# create a device
device = circuit.create_device(cls, name)
# and configure the device
%w[A B].each_with_index do |t, index|
device.connect_terminal(t, nets[index])
end
# parameters in the model are given in micrometer units, so
# we need to translate the parameter values from SI to um values:
device.set_parameter('A', ((params['W'] || 0.0) * (params['L'] || 0.0)) * 1e12)
device.set_parameter('P', ((params['W'] || 0.0) + (params['L'] || 0.0)) * 2e6)
device.set_parameter('C', (params['C'] || 0.0))
when 'R'
case nets.size
when 3
# provide a device class
cls = circuit.netlist.device_class_by_name(model)
unless cls
cls = RBA::DeviceClassResistorWithBulk.new
cls.name = model
circuit.netlist.add(cls)
end
# create a device
device = circuit.create_device(cls, name)
# and configure the device
%w[A B W].each_with_index do |t, index|
device.connect_terminal(t, nets[index])
end
when 2
# provide a device class
cls = circuit.netlist.device_class_by_name(model)
unless cls
cls = RBA::DeviceClassResistor.new
cls.name = model
circuit.netlist.add(cls)
end
# create a device
device = circuit.create_device(cls, name)
# and configure the device
%w[A B].each_with_index do |t, index|
device.connect_terminal(t, nets[index])
end
else
error('Resistor needs two or three nodes')
end
# parameters in the model are given in micrometer units, so
# we need to translate the parameter values from SI to um values:
device.set_parameter('W', ((params['W'] || 0.0) * (params['PAR'] || 1.0)) * 1e6)
device.set_parameter('L', ((params['L'] || 0.0) * (params['S'] || 1.0)) * 1e6)
device.set_parameter('R', (params['R'] * (params['S'] || 1.0) / (params['PAR'] || 1.0)))
else
return super
end
true
end
end
# 4 terminals resistor device extractor
class BResistor < RBA::DeviceClassResistorWithBulk
def initialize
super
enable_parameter('R', false)
enable_parameter('W', true)
enable_parameter('L', true)
end
end
# 3 terminals resistor device extractor
class NResistor < RBA::DeviceClassResistor
def initialize
super
enable_parameter('R', false)
enable_parameter('W', true)
enable_parameter('L', true)
end
end
# MIMCAP device extractor
class MIMCap < RBA::DeviceClassCapacitor
def initialize
super
enable_parameter('C', true)
enable_parameter('A', true)
enable_parameter('P', true)
end
end
class VarCap < RBA::DeviceClassCapacitorWithBulk
def initialize
super
enable_parameter("C", false)
enable_parameter("A", true)
enable_parameter("P", true)
end
end