Coverage for tests/rcx25/device_capacitor_plates_test.py: 100%

34 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-02 23:32 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024-2026 Martin Jan Köhler and Harald Pretl 

4# Johannes Kepler University, Institute for Integrated Circuits. 

5# 

6# This file is part of KPEX 

7# (see https://github.com/iic-jku/klayout-pex). 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21# SPDX-License-Identifier: GPL-3.0-or-later 

22# -------------------------------------------------------------------------------- 

23# 

24 

25import allure 

26import unittest 

27 

28import klayout.db as kdb 

29 

30from klayout_pex.klayout.lvsdb_extractor import DEVICE_CAPACITOR_PLATE_PROPERTY 

31from klayout_pex.rcx25.c.device_capacitor_plates import DeviceCapacitorPlates 

32 

33 

34def netlist() -> kdb.Netlist: 

35 """ 

36 A MOM cap between the nets A and B, and an nmos between A and C 

37 """ 

38 netlist = kdb.Netlist() 

39 circuit = kdb.Circuit() 

40 circuit.name = 'chip' 

41 netlist.add(circuit) 

42 nets = {name: circuit.create_net(name) for name in ('A', 'B', 'C')} 

43 for device_class, class_name, device_name, terminal_nets in ( 

44 (kdb.DeviceClassCapacitor(), 'mom', 'C1', {'A': 'A', 'B': 'B'}), 

45 (kdb.DeviceClassMOS4Transistor(), 'nmos', 'M1', {'D': 'A', 'S': 'C'})): 

46 device_class.name = class_name 

47 netlist.add(device_class) 

48 device = circuit.create_device(device_class, device_name) 

49 for terminal, net_name in terminal_nets.items(): 

50 device.connect_terminal(terminal, nets[net_name]) 

51 return netlist 

52 

53 

54def shape(net: str, plate: bool) -> kdb.PolygonWithProperties: 

55 properties = {'net': net, DEVICE_CAPACITOR_PLATE_PROPERTY: True} if plate else {'net': net} 

56 return kdb.PolygonWithProperties(kdb.Polygon(kdb.Box(0, 0, 100, 100)), properties) 

57 

58 

59@allure.parent_suite("Unit Tests") 

60@allure.tag("RCX25", "Capacitance", "Device Capacitor Plates") 

61class Test(unittest.TestCase): 

62 def test_terminal_nets_of_the_capacitor_devices(self): 

63 chip = netlist() 

64 plates = DeviceCapacitorPlates.from_circuit(chip.circuit_by_name('chip'), device_class_names={'mom'}) 

65 self.assertEqual({frozenset(('A', 'B'))}, plates.terminal_net_pairs) 

66 

67 def test_plates_of_a_device(self): 

68 chip = netlist() 

69 plates = DeviceCapacitorPlates.from_circuit(chip.circuit_by_name('chip'), device_class_names={'mom'}) 

70 self.assertTrue(plates.are_plates_of_a_device(shape('A', plate=True), 'A', shape('B', plate=True), 'B')) 

71 # e.g. a wire of the net B, outside of the device 

72 self.assertFalse(plates.are_plates_of_a_device(shape('A', plate=True), 'A', shape('B', plate=False), 'B')) 

73 # e.g. a wire of the net C across the device, on its plate layers too 

74 self.assertFalse(plates.are_plates_of_a_device(shape('A', plate=True), 'A', shape('C', plate=True), 'C'))