В прошлой статье мы установили все программы, а в этой части, мы наконец приступим к практической части. Готовьтесь, эта часть будет очень большой. Для тех кто пропустил прошлые части — ссылки ниже.
![](https://habrastorage.org/r/w1560/webt/cb/nu/pa/cbnupar8ezcii7thxuzr91ye3oy.png)
В этой части мы:
Предполагается, что вы уже прочитали предыдущие материалы. Если мне удалось вас заинтересовать, прошу под кат!
Откроем xschem:
Типичная ошибка, если вы не выполнили
Если вы сделали всё правильно, откроется следующее окно XSCHEM:
![xschem_opened.png](https://habrastorage.org/r/w1560/webt/3o/r_/ah/3or_ahkt98wboor-dykv2p-cgc8.png)
Если вам открылось что-то иное, то скорее всего — вы не в папке xschem, либо у вас не установлен PDK, либо вы НЕ клонировали мой репозиторий, который содержит Caravel и изменённый файл xschemrc. Вам не нужно менять этот файл, если вы используете проект из моего репозитория. Мой файл xschemrc можно найти тут.
Затем я собрал схему простого NAND.
![](https://habrastorage.org/r/w1560/webt/e2/ut/bo/e2utbo1brpaaxsaqibhdrz6xemg.png)
Затем нажал на Insert и создал 4 транзистора:
![](https://habrastorage.org/r/w1560/webt/gn/et/ud/gnetuday0wtgcz-9zkcwfts05zs.png)
В окне я выбрал компонент, который мне нужен. Для этого в списке я выбрал sky130A/libs.tech из левого списка (отмечено красным).
Затем из списка, я открыл папку
![](https://habrastorage.org/r/w1560/webt/b1/dj/sw/b1djsw7ncmo_kdh2galdbpjp4pw.png)
Затем я добавил
![](https://habrastorage.org/r/w1560/webt/ru/y8/uk/ruy8uk5_da94hoxenkggv9y5g-o.png)
Повторяем те же действия для
Затем я добавил
![](https://habrastorage.org/r/w1560/webt/nu/re/yt/nureytwp8hijmtcskxb-mdk0ofy.png)
Затем я выбрал OPIN:
![](https://habrastorage.org/r/w1560/webt/jc/-e/iu/jc-eiunnyocz4brtcozkoqhz7bs.png)
Левый клик для того, чтобы открыть меню параметров. Чтобы назвать его, поменяйте параметр lab на
![laby.png](https://habrastorage.org/r/w1560/webt/jk/lr/ca/jklrcajirvbobvlbh5rd8dgvvnu.png)
Затем я создал
Также я поменял параметр W nfet транзисторов на 0.65мкм. А W транзисторов PFET я поменял на 1:
![](https://habrastorage.org/r/w1560/webt/au/3t/nz/au3tnz7kwstmi_amnhbh1mc0uae.png)
Затем я использовал Shift + W и W, чтобы подключить транзисторы. Чтобы выбрать объекты зажмите левый клик и выберите регион внутри, которого будут выбраны все объекты.
Используйте M, чтобы двигать выбранные объекты. Нажмите U для отмены последнего действия:
![nand_xschem.png](https://habrastorage.org/r/w1560/webt/9n/xw/a9/9nxwa9-03tdbbqzatjqwb6m6_iw.png)
Давайте поймём, как выглядит SPICE netlist. Документацию можно взять из NGSPICE manual.
SPICE netlist это список соединения компонентов (nets), декларация компонентов (subckt, resistor, capacitor, etc) и их определений (.subckt/.ends).
Симуляторы SPICE поддерживают 3 (основных) режима работы.
![inverter_waveform.png](https://habrastorage.org/r/w1560/webt/iy/eo/du/iyeodu34xruv9r5odx-rzorbyfi.png)
AC симуляция позволяет построить график зависимости напряжения, усиления и тока от частоты источника. DC позволяет построить график зависимости напряжения и тока от напряжения и тока. Во всех режимах поддерживаются скрипты измерения значений (
Для генерации SPICE netlist нажмём на кнопку netlist.
![](https://habrastorage.org/r/w1560/webt/o4/s3/nf/o4s3nfkq8adwzzcfwyqljjymora.png)
SPICE netlist имеет следующий вид:
Но этот netlist не содержит источников напряжения либо тока. Поэтому, если вы попробуете просимулировать эту схему, у вас будет ошибка о том, что схему нельзя просимулировать. Также netlist компонента не содержит ․lib/.include которые подскажут симулятору, где искать объявленные модели транзисторов и других компонентов PDK.
Теперь сгенерируем symbol:
Затем создадим новую схему. Для этого нажмём на
![nand_tb.PNG](https://habrastorage.org/r/w1560/webt/hb/jt/zg/hbjtzgutpqm2vvn8nclbclwfduu.png)
И code для code S1 и S2. Первый кусок кода подключает необходимые библиотеки. Второй кусок кода говорит симулятору NGSPICE просимулировать по 0.1ns до достижения 30ns. Конкретно блок ․control работает только в NGSPICE, в других симуляторах нужно поменять под конкретный симулятор.
Параметр
Схему можно найти в файле
Затем я нажал на кнопку «netlist», для того чтобы сгенерировать
После этого сгенерируется файл netlist:
Чтобы произвести симуляцию выполним эту команду:
Хотя ․spiceinit содержит настройки, которые ускорят запуск симуляции в несколько раз, тем не менее симуляция занимает очень длительное время. Все библиотеки и симуляторы, которые я использовал, производили симуляцию за пару секунд. Тим Митро утверждает, что причина в том, что мы загружаем все три corner case и абсолютно все определения, для всех компонентов, вне зависимости от того, какие варианты нам нужны.
Если у вас git status показывает, что ․spiceinit изменился, значит вы случайно запустили симуляцию пятой командой из списка конфигурации XSCHEM. Верните его в исходное положение. Либо страдайте симуляциями по 10 лет.
После симуляции в терминале должна быть следующая консоль։
![ngspice console.png](https://habrastorage.org/r/w1560/webt/_d/hf/fp/_dhffpyxgptmscv-tiaohzimdtw.png)
И следующее окно:
![](https://habrastorage.org/r/w1560/webt/zo/tn/z2/zotnz2gwqv8aygkcmkiwysgvflg.png)
Really cool!
Сделаем plot по отдельности. Введите в консоль NGSPICE:
Должно получиться так:
![nand_tb.raw.plotted.png](https://habrastorage.org/r/w1560/webt/ou/pj/22/oupj22tttuenv_40pon1voucnka.png)
Чтобы выйти из NGSPICE введите:
Мы научились делать схему и получать из неё SPICE netlist. Иногда выгодно писать SPICE netlist самому, но я не буду вас мучать симуляциями и SPICE netlist-ами ։D. Приступим, наконец, к так называемому layout.
Для рисования layout будем использовать Klayout, но для DRC и LVS будем использовать Magic VLSI.
PS: Я решил не переводить layout ибо не нашёл хорошего слова.
Очевидно, что для того, чтобы сделать Layout, нам нужно понять значение каждого слоя в нашей layout, которую мы должны нарисовать. Рассмотрим процесс производства микросхемы.
Для начала делают подложку из кремния.
![](https://habrastorage.org/r/w1560/webt/nd/tb/tn/ndtbtnpokjh8xv3pwtjnkimie6c.png)
Затем вся пластина покрывается в фоторезист.
![](https://habrastorage.org/r/w1560/webt/fo/bl/oc/fobloccewjogkvad5qvz7npysay.png)
После чего, светом фоторезист убирается.
![](https://habrastorage.org/r/w1560/webt/ec/ml/k7/ecmlk7rcvqvnnn6_z_lntnwtsfc.png)
Во все места микросхемы, которые нужно покрыть N полупроводником (слой NWELL нашей микросхемы) вводятся ионные импланты мышьяка.
![](https://habrastorage.org/r/w1560/webt/et/xn/5q/etxn5qinlwgzy2ncacs1swogcrc.png)
После чего фоторезист убирается. Затем эти шаги повторяются, для создания PWELL, но вместо мышьяка используется бор.
Мы получили наш NWELL/PWELL, теперь мы вставляем диффузии типа P и типа N. Там, где диффузия (diff) соприкасается с PSDM вставляется P полупроводник. Там, где диффузия (diff) соприкасается с NSDM вставляется N полупроводник:
Используя термическую обработку, образуется диэлектрик из диоксида кремния SiO2. Чтобы изготовить эту маску, берётся слой, в котором поликремний находится над диффузией (слой poly).
![](https://habrastorage.org/r/w1560/webt/ju/tv/sr/jutvsryvrrsgsfqm_yf1hzux7ho.png)
После чего вставляется слой поликремния. Для этого поликремний испаряется, и микрочастицы вставляются в области, где фоторезист отсутствует:
![](https://habrastorage.org/r/w1560/webt/hd/xy/fx/hdxyfx8qza9hvtdifqc4r3ftofs.png)
Затем, аналогичным образом, вставляется контакт (licon1) и первый слой тонкого металла li1.
![](https://habrastorage.org/r/w1560/webt/rd/ub/xq/rdubxqo4lat91xrxqyk3pqeu5i0.png)
Эти два шага повторяются для каждого слоя via и Mx.
![](https://habrastorage.org/r/w1560/webt/jr/j_/yg/jrj_yg2suwydhurdl9badznuzn8.png)
Откроем уже существующую ячейку и скопируем из неё все необходимую базу: содержимое слоёв, стиль и т.д. и т.п.
Это запустит Klayout с файлом технологии (lyt), настройками для конкретной технологии (lyp), в режиме редактирования (-e) и откроет файл
Если у вас segfault, значит вы случайно запустили Klayout из репозитория Убунту. Если сверху у вас не видно большой T и надписи sky130A, значит у вас не установлен PDK, либо вы не сделали
Если вы всё сделали правильно, откроется окно Klayout:
![klayout_opened.png](https://habrastorage.org/r/w1560/webt/bn/-l/n1/bn-ln1clpngarvd30utrfcrseps.png)
В левой панели нужно найти ячейку
![SaveLayoutOptions.png](https://habrastorage.org/r/w1560/webt/hs/lx/li/hslxlizrg3lq_8hsdceitclbfpk.png)
Затем откроем этот файл. Выйдите из Klayout и введите след. команду։
Должно открыться следующее окно.
Причина, почему мы копируем существующий элемент в том, что нам нужен слой OUTLINE, а точнее её высота. Без неё наша ячейка не поместится внутри линий питания библиотеки sky130_fd_sc_hd, ибо инструмент Place and route не будет знать, как именно поставить эту ячейку относительно линий питания (Power Rails).
Ещё стоит сказать, про то, что эта библиотека использует транзисторы с повышенным уровнем Vth для уменьшения энергопотребления. Для этого над всеми PFET транзисторами проведён слой hvtp. Мы удалим его, ибо наша схема построена на обычных транзисторах.
Для этого выберем этот слой, кликнув несколько раз, пока надпись внизу не укажет полигон, который находится на слое HVTP. Затем нажмите Delete:
![delete_hvtp.png](https://habrastorage.org/r/w1560/webt/fv/of/94/fvof94hoqfkaoyatau1cuot3s7o.png)
В правой верхней панели HVTP должно стать серым. Это означает, что данный слой не содержит полигонов.
![hvtp_gray.png](https://habrastorage.org/r/w1560/webt/zc/yk/mv/zcykmvxefebdgnwveqpxzcjfgh0.png)
Скроем слои, которые не содержат полигонов. Нажмите правой кнопкой на любой слой и выберете Hide Empty Layers.
![hide_empty_layers.png](https://habrastorage.org/r/w1560/webt/9m/2e/df/9m2edf24daqgcduvkb5hwhplr_s.png)
Должно получиться вот так:
![after_hidden_layers.png](https://habrastorage.org/r/w1560/webt/zk/lm/g_/zklmg_ycz4clvae1m4gr_j60ssm.png)
Красота! А теперь поменяем стиль отрисовки некоторых слоёв. Для этого поставим галочки в панели Layer Toolbox.
![layer_toolbox.png](https://habrastorage.org/r/w1560/webt/zx/6s/4j/zx6s4jgilkz3hrdfozcm92jcp0u.png)
Для этого в верхней панели выбираем слой, а в нижней можем менять цвет и паттерн конкретного слоя.
Должно выйти вот так:
![inverter_layers_colored.png](https://habrastorage.org/r/w1560/webt/01/6d/ee/016deek8tg3tkgxohrzyqsl9y1m.png)
Чтобы спрятать слой, выберете слой и нажмите на него левой кнопкой мыши, должно открыться следующее подменю. В нём вы можете либо спрятать один слой, показать слой, либо спрятать и показать все слои.
![](https://habrastorage.org/r/w1560/webt/a9/kb/se/a9kbselldp4gg2-qsjd-xurwjee.png)
Теперь наконец-то, поменяем эту схему на схему NAND. Скроем слои, которые мы не будем пока менять. Оставим только poly, licon и diff. Нажимаем на любой слой и «Hide all». Затем нажимаем на poly, diff, licon и нажимаем на Show. Должно быть так:
![inverter_after_hidden_layers.png](https://habrastorage.org/r/w1560/webt/5s/s6/ru/5ss6rurg0lck2zuildgofxx5rvo.png)
Настроим рулетку. Откройте меню
![Ruler menu.png](https://habrastorage.org/r/w1560/webt/ui/ve/js/uivejspwgplp41f-zky3aam9kew.png)
Поменяйте рулетку в ортогональный режим и включите
![Rules and annotation.png](https://habrastorage.org/r/w1560/webt/4m/p6/mq/4mp6mqylhpvdfodxsm-k-ar0qpy.png)
Закройте это окно и нажмите F3. И поменяйте шаг на 0.01.
![grid step.png](https://habrastorage.org/r/w1560/webt/n0/lr/zn/n0lrznzdqv2ganumf52eirofx4i.png)
Теперь продлим diff. Двойной клик по diff откроет меню редактирования полигона. Поменяйте Upper right X: 0.34 + 1.09.
![diff upper right x.png](https://habrastorage.org/r/w1560/webt/sx/rl/aa/sxrlaaf_wrezlntodpb6xce2e-m.png)
Откуда взялся 1.09? Я добавил длину каждого элемента. Прочитаем правила DRC для нашей технологи вот тут. Нас интересуют следующие правила.
Расстояние licon от поликремния должно быть более чем 0.05мкм:
![licon.11a.PNG](https://habrastorage.org/r/w1560/webt/mn/hn/84/mnhn84uht-gh36gj0myjiupceqi.png)
Расстояние между двумя полигонами должно быть ровно 150нм:
![poly.1a.png](https://habrastorage.org/r/w1560/webt/rj/bg/vm/rjbgvmrlghdiownosb6fc_yfzcm.png)
Licon должен быть окружён диффузией минимум на 40нм:
![licon.5a.png](https://habrastorage.org/r/w1560/webt/0a/7f/bg/0a7fbgs-xfz3yzvfkebrf7iofn4.png)
Licon позволяют подключать металлический слой li1 к поликремнию, либо к диффузии. Вот слои в разрезе:
![layers.png](https://habrastorage.org/r/w1560/webt/kn/in/v3/kninv3_u3cl9z93onjsmdbxtxsk.png)
Из документации мы узнаём, что расстояние между licon должно быть 170нм, а сами licon должны быть размером 0.17мкм на 0.17мкм:
![licon2.png](https://habrastorage.org/r/w1560/webt/hc/c9/jh/hcc9jh2j_k-bcu0uzp_nlq_cxwg.png)
![licon1.png](https://habrastorage.org/r/w1560/webt/fw/j7/ft/fwj7ftl4rmdsgqfq8mwk4vb0bh8.png)
Итоговая структура. Видим все наши правила в деле:
![diff_len.png](https://habrastorage.org/r/w1560/webt/1m/hb/9w/1mhb9wm5bvv4munjknqduzkh94k.png)
Чувствуйте обман? Вроде технология называется 130нм, а поликремний 150нм? Всё просто 130нм можно применять только в специальных компонентах SRAM ячеек.
Теперь нарисуем второй поликремний, который в скором времени станет gate-ом для двух транзисторов. Для этого я создал Box из поликремния и установил координаты. Чтобы понять какие координаты поставить, я просто взял координаты первого поликремния и добавил к ним 0.05мкм + 0.17мкм + 0.05мкм + 0.150мкм = 0.27 + 0.15 мкм по горизонтали.
![second_poly.png](https://habrastorage.org/r/w1560/webt/p7/ur/69/p7ur69usm74pthprqq4dqm2jdbu.png)
Затем повторил те же действия для нижней диффузии. Теперь сделаем контакты (licon).
Скопировал три верхние и два нижние licon и переместил их центр так, чтобы между ними было расстояние 0.25мкм от второго licon. 0.25 мкм взято не из воздуха. Поликремний должен быть от левого licon на 50нм правее. Затем, сам поликремний имеет длину 0.150мкм, и в конце концов 50нм от поликремния находится сам licon. В итоге должно быть вот так:
![0.25 licon](https://habrastorage.org/r/w1560/webt/_c/5o/ov/_c5oovxrj6benxpvigdjzvic79y.png)
Добавим второе соединение к поликремнию. Из документации мы узнаем, что поликремний должен окружать licon с двух сторон по 80нм, а по всем остальным сторонам хотя бы 50нм.
![licon8.png](https://habrastorage.org/r/w1560/webt/cf/ii/hk/cfiihk3fhho772imezniasejsoe.png)
Для этого создадим Box 0.34мкм на 0.34мкм. Минимум нужен 0.33 на 0.33. Затем скопируем licon1 и поместим его посередине поликремния. Получится как-то так:
![second_licon1.PNG](https://habrastorage.org/r/w1560/webt/ts/mo/sg/tsmosgrxh4ptwvdky1zfub1gj-g.png)
Удалим средние нижние два контакта ибо мы не хотим подключать ничего извне к drain левого NMOS транзистора, который по совместительству является source-ом правого NMOS.
![licon_done.png](https://habrastorage.org/r/w1560/webt/cj/2g/dx/cj2gdxiiya_h7stkkn8na_qlxds.png)
Сделаем металлический слой li1. Включаем отображение li1. Заглянем в документацию и поймём, каким размером должен быть li1 по правилам DRC.
![li.5.png](https://habrastorage.org/r/w1560/webt/vx/pm/6h/vxpm6hf4vljmvl1o7lb21imx5fa.png)
Здесь мы найдём правила касательно минимального li1 от li1 расстояния, и минимальной ширины LI1.
![li.1.png](https://habrastorage.org/r/w1560/webt/lp/4d/jy/lp4djyjrw7k7ym2apzfb2m9uzdi.png)
![li.3.png](https://habrastorage.org/r/w1560/webt/hy/f5/as/hyf5asyefna8058hdyp9b9bf8mk.png)
Я удалил весь LI1, кроме верхнего и нижнего Box-а, которые я удлинил так, чтобы он выступал из диффузии на 0.34. Затем я заново нарисовал остальные LI1:
![li1_done.png](https://habrastorage.org/r/w1560/webt/9a/yw/nw/9aywnwr1ojb157-w_t4jrqdhhvw.png)
Затем я удлинил OUTLINE на 0.05 + 0.34 так, чтобы он включал нарисованный LI1.
![outline1.png](https://habrastorage.org/r/w1560/webt/0q/og/a2/0qoga2pkd8vcvnbf-ahuob9zs_4.png)
Повторим те же действия для слоёв nwell.drawing, psdm.drawin, nsdm.drawing, areaid.standardc. А ещё я поменял слой text.drawing, поменяв text слева снизу из inv_1 в my_nand:
![before_npc_met_li1_label_changes.PNG](https://habrastorage.org/r/w1560/webt/lu/vv/tl/luvvtlh5x4gkp03c0p-d-dp2uua.png)
Затем я включил отображение NPC.drawing и поменял паттерн на что-то видное. И пошёл читать, что это такое. В документации видим:
![licon15.png](https://habrastorage.org/r/w1560/webt/b5/nc/5q/b5nc5q-lhy9vwtblrr_whigibum.png)
Так что удлиняем его на 0.34+0.05. Затем я взял Ruler и измерил насколько licon1 окружён npc. Упс 0.08мкм:
![npc_1.png](https://habrastorage.org/r/w1560/webt/cw/34/x7/cw34x7hydwa67jsftv16jvjomiw.png)
Давайте это исправим. Я переместил горку правого поликремния на 0.02мкм вниз. Затем я скопировал правый вертикальный Box поликремния и переместил его, используя Move на 0.42 влево. Потом я удалил старый полигон поликремния.
![npc_2.PNG](https://habrastorage.org/r/w1560/webt/tl/1z/ca/tl1zcawwnhfvh1ezza-fj-pb6gm.png)
После чего я скопировал горку правого поликремния и поместил его под licon-ом левого поликремния. Затем я удалил старый полигон.
![npc_3.PNG](https://habrastorage.org/r/w1560/webt/lv/x0/h-/lvx0h-6xpuuk5gobofgo7n42xaw.png)
Теперь к слою металла. Включаем отображение met1.drawing, met1.label, met1.pin и также удлиняем металл VPWR/VGND power rail. Для этого двойным нажатием по met1 открываем меню редактирования Path и удлиняем его на 0.05+0.34мкм. Меняем значение 1.38 на 1.77. Должно получиться вот так.
![met1_vgnd.png](https://habrastorage.org/r/w1560/webt/qu/v0/8w/quv08wnotxbjltsxcbxb4ww391e.png)
Это нужно, чтобы когда инструмент Place and route поместит ячейки рядом с друг другом, эти ячейки автоматическим образом поместились на уже нарисованные power rail-и.
Логичный вопрос: почему бы не использовать LI1 для линий питания?
Ответ прост: LI1 тонкий слой металла. На короткие расстояния, сопротивление LI1 можно игнорировать. Для бОльших расстояний LI1 не годится для подачи питания ибо имеет значительное сопротивление.
Решение: Используйте met1 для подачи питания, поскольку met1 имеет в 4 раза меньше сопротивления чем li1.
Теперь повторяем это же действие для VPWR.
![met1_vpwr.png](https://habrastorage.org/r/w1560/webt/ir/oo/am/irooammcf2qr5wm9pfke73ftp_k.png)
Теперь остановимся и поймём, что такое met1.pin и met1.label. Слои .pin показывают, где находится точка соединения, а .label содержит текст с именем этого .pin-а. Давайте скроем все наши слои и взглянем на met1.pin и met1.label. Если мы не поставим текст с названием пина в слое .label, то инструменты place and route не будут знать, какие пины данного компонента соответствуют одноимённым названиям пинов в SPICE netlist.
![pin_label_1.png](https://habrastorage.org/r/w1560/webt/md/do/yr/mddoyry1aiqqtv4u7dsemr-zno8.png)
На данной картинке плохо видно, но в слое met1.label содержится элемент text с текстом VGND и VPWR. Вот они вблизи.
![pin_label_2.png](https://habrastorage.org/r/w1560/webt/xl/ph/nu/xlphnu-lu4w7lk7manwwxcoyzci.png)
Если пины не будут соответствовать названиям пинов в нашей схеме, то во время LVS netgen пожалуется нам, что имена наших пинов схемы не соответствуют именам в layout.
Также стоит рассмотреть NWELL.pin, NWELL.label, PWELL.label. PWELL как мы уже рассмотрели, это по сути вся микросхема. Части PWELL можно изолировать, а поскольку он является полупроводником и является Bulk-ом транзистора, он должен быть подключен к источнику напряжения. Чтобы Place and route знал куда подключать VPWR/VGND, чтобы подать напряжение на Bulk, нам нужно поставить text в слое PWELL.label и Box в слое PWELL.pin. По аналогии, это нужно проделать и с NWELL.label и NWELL.pin, но в отличие от PWELL — NWELL нужно явно указать, нарисовав Box в NWELL.drawing.
Иногда разработчики Standard Cell Library требуют подать напряжение к Bulk, чтобы уменьшить Vth, подняв производительность, либо повышают Vth, чтобы уменьшить энергопотребление см. Body effect. Поскольку мы скопировали слои из inv_1 ячейки, то у нас уже есть нарисованные NWELL, PWELL слои. Вот посмотрите!
![pwell_nwell.PNG](https://habrastorage.org/r/w1560/webt/ew/hn/cc/ewhncc5-jnxmzujtu0haxjhviy0.png)
Теперь разберёмся с mcon. Этот слой используется для подключения металлического слоя met1 и слоя li1. Включим отображение этого слоя:
![mcon_stage.png](https://habrastorage.org/r/w1560/webt/io/az/xq/ioazxqvzzsdidzzmyb6xazisd5k.png)
Как видим, MCON используется для подачи VPWR/VGND в слой LI1. MCON должен находиться от другого MCON на 0.19мкм, а сам MCON должен иметь размер 0.17 на 0.17мкм. Я не стал добавлять больше MCON.
Включаем LI1.pin:
![li1_pin.png](https://habrastorage.org/r/w1560/webt/m_/uh/qh/m_uhqhud8-mfkwv1vjmmneanusc.png)
Сначала поменяем цвет на лаймовый, затем переместим li1.pin, туда где будут подключаться наши входы и выходы.
![li1_pin_lime.png](https://habrastorage.org/r/w1560/webt/ye/0m/-e/ye0m-eoldeikhuot76mnsii9wx8.png)
Теперь сделаем li1.label. Смотрим на схему и видим, что в схеме к VGND подключён NFET с гейтом, который подключён к входу A. Почему это важно? Если мы подключим вход B к гейту этой NFET, то LVS пожалуется на то, что схема не соответствует нашей layout:
![nand_xschem.png](https://habrastorage.org/r/w1560/webt/9n/xw/a9/9nxwa9-03tdbbqzatjqwb6m6_iw.png)
Включаем слой li1.label. И перемещаем текст Y на почти центр li1, который проходит посередине. Перемещаем A на левый li1.
Затем переименовываем оставшийся текст Y в B и перемещаем на правый LI1. Для этого двойным нажатием открываем меню редактирования текста.
![Text_edit.png](https://habrastorage.org/r/w1560/webt/7f/vm/re/7fvmreyzjdmiyuhyq4lt9c_lpbw.png)
Сохраняем файл через File -> Save all и НЕ закрываем Klayout. Он нам понадобится в следующей части.
![](https://habrastorage.org/r/w780q1/webt/kg/hq/9z/kghq9za934md5ceo14bxovinlgy.jpeg)
![](https://habrastorage.org/webt/cb/nu/pa/cbnupar8ezcii7thxuzr91ye3oy.png)
Как разработать микросхему, от идеи до результата. Ссылки на все статьи։
В этой части мы:
- Будем рисовать схему, используя XSCHEM
- Произведём симуляцию нашей схемы, используя NGSPICE
- Поймём цикл производства микросхемы
- Нарисуем Layout, используя KLayout
Предполагается, что вы уже прочитали предыдущие материалы. Если мне удалось вас заинтересовать, прошу под кат!
Откроем xschem:
cd xschem
xschem
Типичная ошибка, если вы не выполнили
source sourceme.sh
։Tcl_AppInit() error: can not execute /home/armleo/Desktop/habr_nand_sky130/xschem/xschemrc, please fix:
can't read "env(PDK_ROOT)": no such variable
Если вы сделали всё правильно, откроется следующее окно XSCHEM:
![xschem_opened.png](https://habrastorage.org/webt/3o/r_/ah/3or_ahkt98wboor-dykv2p-cgc8.png)
Если вам открылось что-то иное, то скорее всего — вы не в папке xschem, либо у вас не установлен PDK, либо вы НЕ клонировали мой репозиторий, который содержит Caravel и изменённый файл xschemrc. Вам не нужно менять этот файл, если вы используете проект из моего репозитория. Мой файл xschemrc можно найти тут.
Затем я собрал схему простого NAND.
File -> New Schematic
:![](https://habrastorage.org/webt/e2/ut/bo/e2utbo1brpaaxsaqibhdrz6xemg.png)
Затем нажал на Insert и создал 4 транзистора:
![](https://habrastorage.org/webt/gn/et/ud/gnetuday0wtgcz-9zkcwfts05zs.png)
В окне я выбрал компонент, который мне нужен. Для этого в списке я выбрал sky130A/libs.tech из левого списка (отмечено красным).
Затем из списка, я открыл папку
sky130_fd_pr
, отмечено черным:![](https://habrastorage.org/webt/b1/dj/sw/b1djsw7ncmo_kdh2galdbpjp4pw.png)
Затем я добавил
nfet_01v8
из списка sky130_fd_pr
, затем я скопировал этот транзистор:![](https://habrastorage.org/webt/ru/y8/uk/ruy8uk5_da94hoxenkggv9y5g-o.png)
Повторяем те же действия для
pfet_01v8
из sky130_fd_pr
.Затем я добавил
OPIN
из devices
. Для этого я нажал Insert и выбрал из списка стандартной библиотеки (красная) папку devices (синий цвет):![](https://habrastorage.org/webt/nu/re/yt/nureytwp8hijmtcskxb-mdk0ofy.png)
Затем я выбрал OPIN:
![](https://habrastorage.org/webt/jc/-e/iu/jc-eiunnyocz4brtcozkoqhz7bs.png)
Левый клик для того, чтобы открыть меню параметров. Чтобы назвать его, поменяйте параметр lab на
Y
:![laby.png](https://habrastorage.org/webt/jk/lr/ca/jklrcajirvbobvlbh5rd8dgvvnu.png)
Затем я создал
IOPIN
с названиями VPWR
, VGND
, иIPIN
с названием A
и B
. Эти типы используются, чтобы сказать XSCHEM, чтобы он создал пины для этой схемы с соответствующим типом и названием.Также я поменял параметр W nfet транзисторов на 0.65мкм. А W транзисторов PFET я поменял на 1:
![](https://habrastorage.org/webt/au/3t/nz/au3tnz7kwstmi_amnhbh1mc0uae.png)
Затем я использовал Shift + W и W, чтобы подключить транзисторы. Чтобы выбрать объекты зажмите левый клик и выберите регион внутри, которого будут выбраны все объекты.
Используйте M, чтобы двигать выбранные объекты. Нажмите U для отмены последнего действия:
![nand_xschem.png](https://habrastorage.org/webt/9n/xw/a9/9nxwa9-03tdbbqzatjqwb6m6_iw.png)
Давайте поймём, как выглядит SPICE netlist. Документацию можно взять из NGSPICE manual.
Первая строка всегда комментарий. Будьте осторожны.
* это комментарий
* .lib, чтобы включить библиотеку.
* После пути к библиотеке должен стоять corner case (tt/ss/ff)
* .lib не может содержать enviornment variables,
* так что нам нужно использовать абсолютный путь
.lib "/home/armleo/Desktop/pdk_root/sky130A/libs.tech/ngspice/sky130.lib.spice" tt
* Включить файлы с объявлениями разных компонентов
.include "/home/armleo/Desktop/pdk_root/sky130A/libs.ref/sky130_fd_io/spice/sky130_fd_io.spice"
.include "/home/armleo/Desktop/pdk_root/sky130A/libs.ref/sky130_fd_sc_hvl/spice/sky130_fd_sc_hvl.spice"
.include "/home/armleo/Desktop/pdk_root/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice"
* Создать компонент типа subckt с именем X123
* Первая буква означает։
* R - Resistor
* C - Capacitors
* X - subckt
* sky130 объявляет транзисторы в виде subckt
* Подключить a, b, c, vdd, vss линии к пинам subckt
* последний идентификатор показывает тип subckt: subckt_example
X123 a b c vdd vss subckt_example
* Декларация самой subckt example
.subckt subckt_example pin_a pin_b pin_c vdd vss
* Объявить резистор R1
* Между a и b
* И имеющая 1k (тысяча) сопротивления
R1 a b 1k
* Декларация конденсатора C1
* между b и vss
* И имеющая 10 pico Farad
C1 b vss 10p
* конец subckt
.ends
* Провести анализ transient
* 1ns шаг, 10ns до конца
.tran 1ns 10ns
* Конец декларации SPICE
.end
SPICE netlist это список соединения компонентов (nets), декларация компонентов (subckt, resistor, capacitor, etc) и их определений (.subckt/.ends).
Симуляторы SPICE поддерживают 3 (основных) режима работы.
.TRAN
анализ, используется для того, чтобы составить графики время-значения напряжения, либо время-значение тока. Вот результат .TRAN
анализа инвертора.![inverter_waveform.png](https://habrastorage.org/webt/iy/eo/du/iyeodu34xruv9r5odx-rzorbyfi.png)
AC симуляция позволяет построить график зависимости напряжения, усиления и тока от частоты источника. DC позволяет построить график зависимости напряжения и тока от напряжения и тока. Во всех режимах поддерживаются скрипты измерения значений (
.meas
). Про анализы написано много статей, стоит обратиться именно к ним. В этой статье мы не будем рассматривать ничего кроме .TRAN
.Для генерации SPICE netlist нажмём на кнопку netlist.
![](https://habrastorage.org/webt/o4/s3/nf/o4s3nfkq8adwzzcfwyqljjymora.png)
SPICE netlist имеет следующий вид:
**.subckt my_nand Y A VPWR B VGND VPB VNB
*.opin Y
*.ipin A
*.iopin VPWR
*.ipin B
*.iopin VGND
*.iopin VPB
*.iopin VNB
XM1 Y B net1 VNB sky130_fd_pr__nfet_01v8 L=0.15 W=0.65 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM2 net1 A VGND VNB sky130_fd_pr__nfet_01v8 L=0.15 W=0.65 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM3 Y A VPWR VPB sky130_fd_pr__pfet_01v8 L=0.15 W=1 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM4 Y B VPWR VPB sky130_fd_pr__pfet_01v8 L=0.15 W=1 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
**.ends
** flattened .save nodes
.end
Но этот netlist не содержит источников напряжения либо тока. Поэтому, если вы попробуете просимулировать эту схему, у вас будет ошибка о том, что схему нельзя просимулировать. Также netlist компонента не содержит ․lib/.include которые подскажут симулятору, где искать объявленные модели транзисторов и других компонентов PDK.
Теперь сгенерируем symbol:
Symbol -> Make symbol from schematic
.Затем создадим новую схему. Для этого нажмём на
File -> New Schematic
и назовём её my_nand_tb.sch
. Файл следует сохранить в той же папке, где и другие ․sch в папке xschem нашего проекта.![nand_tb.PNG](https://habrastorage.org/webt/hb/jt/zg/hbjtzgutpqm2vvn8nclbclwfduu.png)
И code для code S1 и S2. Первый кусок кода подключает необходимые библиотеки. Второй кусок кода говорит симулятору NGSPICE просимулировать по 0.1ns до достижения 30ns. Конкретно блок ․control работает только в NGSPICE, в других симуляторах нужно поменять под конкретный симулятор.
vsource
для источников напряжения. И этот же компонент в режиме пульса для входов. Для этого я прочитал в мануале NGSPICE, как создать пульс. Все напряжения я взял 1.65 вольт.Параметр
mc_mm_switch
поставлен в значение 0, поскольку в древних версиях был баг, из-за чего этот параметр нужно было определять вручную.Схему можно найти в файле
my_nand_tb.sch
, в моём репозитории.Затем я нажал на кнопку «netlist», для того чтобы сгенерировать
my_nand_tb.spice
, который содержит источники напряжения, а значит, если вы всё сделали правильно, симуляция должна пройти удачно.После этого сгенерируется файл netlist:
my_nand_tb.spice
. Вот его содержимое:**.subckt my_nand_tb input0_net vdd1v8 output_net input1_net
*.opin input0_net
*.opin vdd1v8
*.opin output_net
*.opin input1_net
V2 input0_net GND PULSE(0 1.65 5ns 1ns 1ns 4ns 10ns)
V3 vdd1v8 GND 1.65
V4 input1_net GND PULSE(0 1.65 15ns 1ns 1ns 9ns 20ns)
C1 output_net GND 20ff m=1
x1 vdd1v8 vdd1v8 input0_net output_net input1_net GND GND my_nand
**** begin user architecture code
.param mc_mm_switch=0
.lib /opt/pdk_root/sky130A/libs.tech/ngspice/sky130.lib.spice ss
.temp 125
.control
tran 0.1n 30n
plot V(input0_net) V(input1_net) V(output_net)
write
.endc
**** end user architecture code
**.ends
* expanding symbol: my_nand.sym # of pins=7
* sym_path: /home/armleo/Desktop/habr_nand_sky130/xschem/my_nand.sym
* sch_path: /home/armleo/Desktop/habr_nand_sky130/xschem/my_nand.sch
.subckt my_nand VPWR VPB A Y B VNB VGND
*.opin Y
*.ipin A
*.iopin VPWR
*.ipin B
*.iopin VGND
*.iopin VPB
*.iopin VNB
XM1 Y B net1 VNB sky130_fd_pr__nfet_01v8 L=0.15 W=0.65 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM2 net1 A VGND VNB sky130_fd_pr__nfet_01v8 L=0.15 W=0.65 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM3 Y A VPWR VPB sky130_fd_pr__pfet_01v8 L=0.15 W=1 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
XM4 Y B VPWR VPB sky130_fd_pr__pfet_01v8 L=0.15 W=1 nf=1 ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
+ sa=0 sb=0 sd=0 mult=1 m=1
.ends
.GLOBAL GND
** flattened .save nodes
.end
Симуляция testbench
Чтобы произвести симуляцию выполним эту команду:
ngspice -r "my_nand_tb.raw" "my_nand_tb.spice"
Хотя ․spiceinit содержит настройки, которые ускорят запуск симуляции в несколько раз, тем не менее симуляция занимает очень длительное время. Все библиотеки и симуляторы, которые я использовал, производили симуляцию за пару секунд. Тим Митро утверждает, что причина в том, что мы загружаем все три corner case и абсолютно все определения, для всех компонентов, вне зависимости от того, какие варианты нам нужны.
Если у вас git status показывает, что ․spiceinit изменился, значит вы случайно запустили симуляцию пятой командой из списка конфигурации XSCHEM. Верните его в исходное положение. Либо страдайте симуляциями по 10 лет.
После симуляции в терминале должна быть следующая консоль։
![ngspice console.png](https://habrastorage.org/webt/_d/hf/fp/_dhffpyxgptmscv-tiaohzimdtw.png)
И следующее окно:
![](https://habrastorage.org/webt/zo/tn/z2/zotnz2gwqv8aygkcmkiwysgvflg.png)
Really cool!
Сделаем plot по отдельности. Введите в консоль NGSPICE:
plot v(output_net)
plot v(input0_net)
plot v(input1_net)
Должно получиться так:
![nand_tb.raw.plotted.png](https://habrastorage.org/webt/ou/pj/22/oupj22tttuenv_40pon1voucnka.png)
Чтобы выйти из NGSPICE введите:
exit
Разработка Layout
Мы научились делать схему и получать из неё SPICE netlist. Иногда выгодно писать SPICE netlist самому, но я не буду вас мучать симуляциями и SPICE netlist-ами ։D. Приступим, наконец, к так называемому layout.
Для рисования layout будем использовать Klayout, но для DRC и LVS будем использовать Magic VLSI.
PS: Я решил не переводить layout ибо не нашёл хорошего слова.
▍Разбираемся в слоях
Очевидно, что для того, чтобы сделать Layout, нам нужно понять значение каждого слоя в нашей layout, которую мы должны нарисовать. Рассмотрим процесс производства микросхемы.
Для начала делают подложку из кремния.
![](https://habrastorage.org/webt/nd/tb/tn/ndtbtnpokjh8xv3pwtjnkimie6c.png)
Затем вся пластина покрывается в фоторезист.
![](https://habrastorage.org/webt/fo/bl/oc/fobloccewjogkvad5qvz7npysay.png)
После чего, светом фоторезист убирается.
![](https://habrastorage.org/webt/ec/ml/k7/ecmlk7rcvqvnnn6_z_lntnwtsfc.png)
Во все места микросхемы, которые нужно покрыть N полупроводником (слой NWELL нашей микросхемы) вводятся ионные импланты мышьяка.
![](https://habrastorage.org/webt/et/xn/5q/etxn5qinlwgzy2ncacs1swogcrc.png)
После чего фоторезист убирается. Затем эти шаги повторяются, для создания PWELL, но вместо мышьяка используется бор.
Мы получили наш NWELL/PWELL, теперь мы вставляем диффузии типа P и типа N. Там, где диффузия (diff) соприкасается с PSDM вставляется P полупроводник. Там, где диффузия (diff) соприкасается с NSDM вставляется N полупроводник:
![](https://habrastorage.org/getpro/habr/post_images/cdb/bcd/c2f/cdbbcdc2ff96bd76b4e74ae026817d64.png)
Используя термическую обработку, образуется диэлектрик из диоксида кремния SiO2. Чтобы изготовить эту маску, берётся слой, в котором поликремний находится над диффузией (слой poly).
![](https://habrastorage.org/webt/ju/tv/sr/jutvsryvrrsgsfqm_yf1hzux7ho.png)
После чего вставляется слой поликремния. Для этого поликремний испаряется, и микрочастицы вставляются в области, где фоторезист отсутствует:
![](https://habrastorage.org/webt/hd/xy/fx/hdxyfx8qza9hvtdifqc4r3ftofs.png)
Затем, аналогичным образом, вставляется контакт (licon1) и первый слой тонкого металла li1.
![](https://habrastorage.org/webt/rd/ub/xq/rdubxqo4lat91xrxqyk3pqeu5i0.png)
Эти два шага повторяются для каждого слоя via и Mx.
![](https://habrastorage.org/webt/jr/j_/yg/jrj_yg2suwydhurdl9badznuzn8.png)
▍Разработка Layout (практическая часть)
Откроем уже существующую ячейку и скопируем из неё все необходимую базу: содержимое слоёв, стиль и т.д. и т.п.
LD_LIBRARY_PATH=/opt/klayout-v0.27.4/bin-release /opt/klayout-v0.27.4/bin-release/klayout -e -nn $PDK_ROOT/sky130A/libs.tech/klayout/sky130A.lyt \
-l $PDK_ROOT/sky130A/libs.tech/klayout/sky130A.lyp \
$PDK_ROOT/sky130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds
Это запустит Klayout с файлом технологии (lyt), настройками для конкретной технологии (lyp), в режиме редактирования (-e) и откроет файл
sky130_fd_sc_hd.gds
. Документацию можно найти вот тут.Если у вас segfault, значит вы случайно запустили Klayout из репозитория Убунту. Если сверху у вас не видно большой T и надписи sky130A, значит у вас не установлен PDK, либо вы не сделали
source sourcme.sh
до того как запустить Klayout. Я на этом уже сто раз попадался.Если вы всё сделали правильно, откроется окно Klayout:
![klayout_opened.png](https://habrastorage.org/webt/bn/-l/n1/bn-ln1clpngarvd30utrfcrseps.png)
В левой панели нужно найти ячейку
sky130_fd_sc_hd_inv_1
. Затем нажать правую кнопку мыши и выбрать Save Selected Cells As
, и сохранить его, как my_nand.gds
в папке gds нашего проекта. И в открывшемся окне нажмите ОК.![SaveLayoutOptions.png](https://habrastorage.org/webt/hs/lx/li/hslxlizrg3lq_8hsdceitclbfpk.png)
Затем откроем этот файл. Выйдите из Klayout и введите след. команду։
LD_LIBRARY_PATH=/opt/klayout-v0.27.4/bin-release /opt/klayout-v0.27.4/bin-release/klayout -e -nn $PDK_ROOT/sky130A/libs.tech/klayout/sky130A.lyt -l $PDK_ROOT/sky130A/libs.tech/klayout/sky130A.lyp gds/my_nand.GDS
Должно открыться следующее окно.
![klayout_my_nand_start.png](https://habrastorage.org/webt/eg/kw/qy/egkwqyfgnvhucqdxl3ksvt3y8cw.png)
Причина, почему мы копируем существующий элемент в том, что нам нужен слой OUTLINE, а точнее её высота. Без неё наша ячейка не поместится внутри линий питания библиотеки sky130_fd_sc_hd, ибо инструмент Place and route не будет знать, как именно поставить эту ячейку относительно линий питания (Power Rails).
Ещё стоит сказать, про то, что эта библиотека использует транзисторы с повышенным уровнем Vth для уменьшения энергопотребления. Для этого над всеми PFET транзисторами проведён слой hvtp. Мы удалим его, ибо наша схема построена на обычных транзисторах.
Для этого выберем этот слой, кликнув несколько раз, пока надпись внизу не укажет полигон, который находится на слое HVTP. Затем нажмите Delete:
![delete_hvtp.png](https://habrastorage.org/webt/fv/of/94/fvof94hoqfkaoyatau1cuot3s7o.png)
В правой верхней панели HVTP должно стать серым. Это означает, что данный слой не содержит полигонов.
![hvtp_gray.png](https://habrastorage.org/webt/zc/yk/mv/zcykmvxefebdgnwveqpxzcjfgh0.png)
Скроем слои, которые не содержат полигонов. Нажмите правой кнопкой на любой слой и выберете Hide Empty Layers.
![hide_empty_layers.png](https://habrastorage.org/webt/9m/2e/df/9m2edf24daqgcduvkb5hwhplr_s.png)
Должно получиться вот так:
![after_hidden_layers.png](https://habrastorage.org/webt/zk/lm/g_/zklmg_ycz4clvae1m4gr_j60ssm.png)
Красота! А теперь поменяем стиль отрисовки некоторых слоёв. Для этого поставим галочки в панели Layer Toolbox.
![layer_toolbox.png](https://habrastorage.org/webt/zx/6s/4j/zx6s4jgilkz3hrdfozcm92jcp0u.png)
Для этого в верхней панели выбираем слой, а в нижней можем менять цвет и паттерн конкретного слоя.
- Poly -> Первый паттерн
- Licon1 -> Purple, 4ая линия, 3ий паттерн
- Diff -> Orange, whole pattern (первый)
- Li1 -> Orange, netted pattern (последний)
Должно выйти вот так:
![inverter_layers_colored.png](https://habrastorage.org/webt/01/6d/ee/016deek8tg3tkgxohrzyqsl9y1m.png)
Чтобы спрятать слой, выберете слой и нажмите на него левой кнопкой мыши, должно открыться следующее подменю. В нём вы можете либо спрятать один слой, показать слой, либо спрятать и показать все слои.
![](https://habrastorage.org/webt/a9/kb/se/a9kbselldp4gg2-qsjd-xurwjee.png)
Теперь наконец-то, поменяем эту схему на схему NAND. Скроем слои, которые мы не будем пока менять. Оставим только poly, licon и diff. Нажимаем на любой слой и «Hide all». Затем нажимаем на poly, diff, licon и нажимаем на Show. Должно быть так:
![inverter_after_hidden_layers.png](https://habrastorage.org/webt/5s/s6/ru/5ss6rurg0lck2zuildgofxx5rvo.png)
Настроим рулетку. Откройте меню
Edit
и нажмите Ruler And Annotation Setup
.![Ruler menu.png](https://habrastorage.org/webt/ui/ve/js/uivejspwgplp41f-zky3aam9kew.png)
Поменяйте рулетку в ортогональный режим и включите
Snap To Grid
.![Rules and annotation.png](https://habrastorage.org/webt/4m/p6/mq/4mp6mqylhpvdfodxsm-k-ar0qpy.png)
Закройте это окно и нажмите F3. И поменяйте шаг на 0.01.
![grid step.png](https://habrastorage.org/webt/n0/lr/zn/n0lrznzdqv2ganumf52eirofx4i.png)
Теперь продлим diff. Двойной клик по diff откроет меню редактирования полигона. Поменяйте Upper right X: 0.34 + 1.09.
![diff upper right x.png](https://habrastorage.org/webt/sx/rl/aa/sxrlaaf_wrezlntodpb6xce2e-m.png)
Откуда взялся 1.09? Я добавил длину каждого элемента. Прочитаем правила DRC для нашей технологи вот тут. Нас интересуют следующие правила.
Расстояние licon от поликремния должно быть более чем 0.05мкм:
![licon.11a.PNG](https://habrastorage.org/webt/mn/hn/84/mnhn84uht-gh36gj0myjiupceqi.png)
Расстояние между двумя полигонами должно быть ровно 150нм:
![poly.1a.png](https://habrastorage.org/webt/rj/bg/vm/rjbgvmrlghdiownosb6fc_yfzcm.png)
Licon должен быть окружён диффузией минимум на 40нм:
![licon.5a.png](https://habrastorage.org/webt/0a/7f/bg/0a7fbgs-xfz3yzvfkebrf7iofn4.png)
Licon позволяют подключать металлический слой li1 к поликремнию, либо к диффузии. Вот слои в разрезе:
![layers.png](https://habrastorage.org/webt/kn/in/v3/kninv3_u3cl9z93onjsmdbxtxsk.png)
Из документации мы узнаём, что расстояние между licon должно быть 170нм, а сами licon должны быть размером 0.17мкм на 0.17мкм:
![licon2.png](https://habrastorage.org/webt/hc/c9/jh/hcc9jh2j_k-bcu0uzp_nlq_cxwg.png)
![licon1.png](https://habrastorage.org/webt/fw/j7/ft/fwj7ftl4rmdsgqfq8mwk4vb0bh8.png)
Итоговая структура. Видим все наши правила в деле:
![diff_len.png](https://habrastorage.org/webt/1m/hb/9w/1mhb9wm5bvv4munjknqduzkh94k.png)
Чувствуйте обман? Вроде технология называется 130нм, а поликремний 150нм? Всё просто 130нм можно применять только в специальных компонентах SRAM ячеек.
Теперь нарисуем второй поликремний, который в скором времени станет gate-ом для двух транзисторов. Для этого я создал Box из поликремния и установил координаты. Чтобы понять какие координаты поставить, я просто взял координаты первого поликремния и добавил к ним 0.05мкм + 0.17мкм + 0.05мкм + 0.150мкм = 0.27 + 0.15 мкм по горизонтали.
![second_poly.png](https://habrastorage.org/webt/p7/ur/69/p7ur69usm74pthprqq4dqm2jdbu.png)
Затем повторил те же действия для нижней диффузии. Теперь сделаем контакты (licon).
Скопировал три верхние и два нижние licon и переместил их центр так, чтобы между ними было расстояние 0.25мкм от второго licon. 0.25 мкм взято не из воздуха. Поликремний должен быть от левого licon на 50нм правее. Затем, сам поликремний имеет длину 0.150мкм, и в конце концов 50нм от поликремния находится сам licon. В итоге должно быть вот так:
![0.25 licon](https://habrastorage.org/webt/_c/5o/ov/_c5oovxrj6benxpvigdjzvic79y.png)
Добавим второе соединение к поликремнию. Из документации мы узнаем, что поликремний должен окружать licon с двух сторон по 80нм, а по всем остальным сторонам хотя бы 50нм.
![licon8.png](https://habrastorage.org/webt/cf/ii/hk/cfiihk3fhho772imezniasejsoe.png)
Для этого создадим Box 0.34мкм на 0.34мкм. Минимум нужен 0.33 на 0.33. Затем скопируем licon1 и поместим его посередине поликремния. Получится как-то так:
![second_licon1.PNG](https://habrastorage.org/webt/ts/mo/sg/tsmosgrxh4ptwvdky1zfub1gj-g.png)
Удалим средние нижние два контакта ибо мы не хотим подключать ничего извне к drain левого NMOS транзистора, который по совместительству является source-ом правого NMOS.
![licon_done.png](https://habrastorage.org/webt/cj/2g/dx/cj2gdxiiya_h7stkkn8na_qlxds.png)
Сделаем металлический слой li1. Включаем отображение li1. Заглянем в документацию и поймём, каким размером должен быть li1 по правилам DRC.
![li.5.png](https://habrastorage.org/webt/vx/pm/6h/vxpm6hf4vljmvl1o7lb21imx5fa.png)
Здесь мы найдём правила касательно минимального li1 от li1 расстояния, и минимальной ширины LI1.
![li.1.png](https://habrastorage.org/webt/lp/4d/jy/lp4djyjrw7k7ym2apzfb2m9uzdi.png)
![li.3.png](https://habrastorage.org/webt/hy/f5/as/hyf5asyefna8058hdyp9b9bf8mk.png)
Я удалил весь LI1, кроме верхнего и нижнего Box-а, которые я удлинил так, чтобы он выступал из диффузии на 0.34. Затем я заново нарисовал остальные LI1:
![li1_done.png](https://habrastorage.org/webt/9a/yw/nw/9aywnwr1ojb157-w_t4jrqdhhvw.png)
Затем я удлинил OUTLINE на 0.05 + 0.34 так, чтобы он включал нарисованный LI1.
![outline1.png](https://habrastorage.org/webt/0q/og/a2/0qoga2pkd8vcvnbf-ahuob9zs_4.png)
Повторим те же действия для слоёв nwell.drawing, psdm.drawin, nsdm.drawing, areaid.standardc. А ещё я поменял слой text.drawing, поменяв text слева снизу из inv_1 в my_nand:
![before_npc_met_li1_label_changes.PNG](https://habrastorage.org/webt/lu/vv/tl/luvvtlh5x4gkp03c0p-d-dp2uua.png)
Затем я включил отображение NPC.drawing и поменял паттерн на что-то видное. И пошёл читать, что это такое. В документации видим:
![licon15.png](https://habrastorage.org/webt/b5/nc/5q/b5nc5q-lhy9vwtblrr_whigibum.png)
Так что удлиняем его на 0.34+0.05. Затем я взял Ruler и измерил насколько licon1 окружён npc. Упс 0.08мкм:
![npc_1.png](https://habrastorage.org/webt/cw/34/x7/cw34x7hydwa67jsftv16jvjomiw.png)
Давайте это исправим. Я переместил горку правого поликремния на 0.02мкм вниз. Затем я скопировал правый вертикальный Box поликремния и переместил его, используя Move на 0.42 влево. Потом я удалил старый полигон поликремния.
![npc_2.PNG](https://habrastorage.org/webt/tl/1z/ca/tl1zcawwnhfvh1ezza-fj-pb6gm.png)
После чего я скопировал горку правого поликремния и поместил его под licon-ом левого поликремния. Затем я удалил старый полигон.
![npc_3.PNG](https://habrastorage.org/webt/lv/x0/h-/lvx0h-6xpuuk5gobofgo7n42xaw.png)
Теперь к слою металла. Включаем отображение met1.drawing, met1.label, met1.pin и также удлиняем металл VPWR/VGND power rail. Для этого двойным нажатием по met1 открываем меню редактирования Path и удлиняем его на 0.05+0.34мкм. Меняем значение 1.38 на 1.77. Должно получиться вот так.
![met1_vgnd.png](https://habrastorage.org/webt/qu/v0/8w/quv08wnotxbjltsxcbxb4ww391e.png)
Это нужно, чтобы когда инструмент Place and route поместит ячейки рядом с друг другом, эти ячейки автоматическим образом поместились на уже нарисованные power rail-и.
Логичный вопрос: почему бы не использовать LI1 для линий питания?
Ответ прост: LI1 тонкий слой металла. На короткие расстояния, сопротивление LI1 можно игнорировать. Для бОльших расстояний LI1 не годится для подачи питания ибо имеет значительное сопротивление.
Решение: Используйте met1 для подачи питания, поскольку met1 имеет в 4 раза меньше сопротивления чем li1.
Теперь повторяем это же действие для VPWR.
![met1_vpwr.png](https://habrastorage.org/webt/ir/oo/am/irooammcf2qr5wm9pfke73ftp_k.png)
▍met1.pin/met1.label и другие .pin/.label
Теперь остановимся и поймём, что такое met1.pin и met1.label. Слои .pin показывают, где находится точка соединения, а .label содержит текст с именем этого .pin-а. Давайте скроем все наши слои и взглянем на met1.pin и met1.label. Если мы не поставим текст с названием пина в слое .label, то инструменты place and route не будут знать, какие пины данного компонента соответствуют одноимённым названиям пинов в SPICE netlist.
![pin_label_1.png](https://habrastorage.org/webt/md/do/yr/mddoyry1aiqqtv4u7dsemr-zno8.png)
На данной картинке плохо видно, но в слое met1.label содержится элемент text с текстом VGND и VPWR. Вот они вблизи.
![pin_label_2.png](https://habrastorage.org/webt/xl/ph/nu/xlphnu-lu4w7lk7manwwxcoyzci.png)
Если пины не будут соответствовать названиям пинов в нашей схеме, то во время LVS netgen пожалуется нам, что имена наших пинов схемы не соответствуют именам в layout.
Также стоит рассмотреть NWELL.pin, NWELL.label, PWELL.label. PWELL как мы уже рассмотрели, это по сути вся микросхема. Части PWELL можно изолировать, а поскольку он является полупроводником и является Bulk-ом транзистора, он должен быть подключен к источнику напряжения. Чтобы Place and route знал куда подключать VPWR/VGND, чтобы подать напряжение на Bulk, нам нужно поставить text в слое PWELL.label и Box в слое PWELL.pin. По аналогии, это нужно проделать и с NWELL.label и NWELL.pin, но в отличие от PWELL — NWELL нужно явно указать, нарисовав Box в NWELL.drawing.
Иногда разработчики Standard Cell Library требуют подать напряжение к Bulk, чтобы уменьшить Vth, подняв производительность, либо повышают Vth, чтобы уменьшить энергопотребление см. Body effect. Поскольку мы скопировали слои из inv_1 ячейки, то у нас уже есть нарисованные NWELL, PWELL слои. Вот посмотрите!
![pwell_nwell.PNG](https://habrastorage.org/webt/ew/hn/cc/ewhncc5-jnxmzujtu0haxjhviy0.png)
Теперь разберёмся с mcon. Этот слой используется для подключения металлического слоя met1 и слоя li1. Включим отображение этого слоя:
![mcon_stage.png](https://habrastorage.org/webt/io/az/xq/ioazxqvzzsdidzzmyb6xazisd5k.png)
Как видим, MCON используется для подачи VPWR/VGND в слой LI1. MCON должен находиться от другого MCON на 0.19мкм, а сам MCON должен иметь размер 0.17 на 0.17мкм. Я не стал добавлять больше MCON.
Включаем LI1.pin:
![li1_pin.png](https://habrastorage.org/webt/m_/uh/qh/m_uhqhud8-mfkwv1vjmmneanusc.png)
Сначала поменяем цвет на лаймовый, затем переместим li1.pin, туда где будут подключаться наши входы и выходы.
![li1_pin_lime.png](https://habrastorage.org/webt/ye/0m/-e/ye0m-eoldeikhuot76mnsii9wx8.png)
Теперь сделаем li1.label. Смотрим на схему и видим, что в схеме к VGND подключён NFET с гейтом, который подключён к входу A. Почему это важно? Если мы подключим вход B к гейту этой NFET, то LVS пожалуется на то, что схема не соответствует нашей layout:
![nand_xschem.png](https://habrastorage.org/webt/9n/xw/a9/9nxwa9-03tdbbqzatjqwb6m6_iw.png)
Включаем слой li1.label. И перемещаем текст Y на почти центр li1, который проходит посередине. Перемещаем A на левый li1.
Затем переименовываем оставшийся текст Y в B и перемещаем на правый LI1. Для этого двойным нажатием открываем меню редактирования текста.
![Text_edit.png](https://habrastorage.org/webt/7f/vm/re/7fvmreyzjdmiyuhyq4lt9c_lpbw.png)
Сохраняем файл через File -> Save all и НЕ закрываем Klayout. Он нам понадобится в следующей части.
Об автореМеня зовут Арман и я окончил институт Synopsys по профилю VLSI разработки микросхем. В основном я занимаюсь разработкой цифровых компонентов для микросхем и IP для ПЛИС. В прошлом я был программистом, писал бэкенд на Node.js и разрабатывал под микроконтроллеры, но решил пересесть на что-то сложнее, попробовать себя, так сказать.
Я открыт к найму, поэтому, если вас интересует найм разработчика цифровых микросхем с тремя годами опыта и очень интересными проектами (Радиомодемы, преобразователи интерфейсов, процессоры и очень многое), напишите мне в личку.
Как разработать микросхему, от идеи до результата. Ссылки на все статьи։
![](https://habrastorage.org/webt/kg/hq/9z/kghq9za934md5ceo14bxovinlgy.jpeg)