[Перевод] Реверс-инжиниринг чипа компьютера Commodore

Предыстория и первые пробы


В своём старом посте я писал, что работал над реверс-инжинирингом чипа PLA компьютера Commodore 128. Теперь я почти завершил этот процесс, поэтому настало время поделиться своими открытиями.

Это был очень интересный проект, потому что я не особо много знал о проектировании и изготовлении полупроводников. Мои знания ограничивались рассматриванием снимков кристаллов и восхищением этими красивыми фотографиями.

Для меня исследование началось с покупки дешёвого микроскопа для пайки компонентов, устанавливаемых поверхностным монтажом (SMD).

8769f786f8e3fe7cc66b99e9c769a0d6.jpg


Дешёвый микроскоп
Спустя какое-то время я нашёл на Youtube видео, демонстрирующее более простой способ извлечения кремниевых кристаллов из корпуса.


Способ выглядел достаточно простым для реализации дома, ведь у меня уже имелось всё необходимое оборудование. Для извлечения интегральной схемы из корпуса обычно требуется нагретая серная кислота или другие опасные химикаты, с которыми я не очень хотел экспериментировать дома. Поэтому я раскопал в своих запасах пару сломанных чипов MOS (никогда ничего не выбрасывайте, вдруг пригодится). Немного потрудившись, я получил два кристалла 8521R0 и один 8721 PLA. В предыдущем посте я показывал первое реальное фото.

0391fd63b8adcfa882790e721cafae4f.png


Полная фотография чипа 8721 PLA

Микроскоп получше


Хоть эксперимент и был удачным, я сразу понял, что микроскопу не хватает разрешения, чтобы делать снимки с достаточным для меня качеством. При использовании линзы Барлоу 2x максимальное увеличение составляет 90x. Кроме того, у микроскопа нет предметного столика, поэтому мне приходилось класть кристалл на стол, а затем перемещать микроскоп целиком; такая конструкция очень неустойчива и с её помощью сложно снять нужные части.

Поэтому я нашёл и купил микроскоп получше, тоже за разумные деньги.

25a17770d7e95a8683554ccf044c13b0.jpg


Микроскоп AmScope ME580-T

Он гораздо лучше справлялся со съёмкой фотографий в достойном качестве, но я был недоволен камерой, которую купил с ним. Это дешёвая камера без возможности удалённого управления, за исключением приложения AmScope. В то время Raspberry Pi foundation выпустила новую высококачественную камеру для Raspberry Pi. Эта камера имеет совместимое с микроскопом C-крепление, поэтому я сразу купил её и установил на микроскоп. Она потрясающе справляется со своей задачей, обеспечивая полный контроль из комфортного Linux.

f3e50be140ccb42ef5ff5d1eb74bd57e.jpg


Часть кремниевого кристалла 8521R0

По сравнению с предыдущей системой это стало огромным прогрессом. Из-за увеличившегося разрешения мне пришлось сшивать фотографии, чтобы получать изображения большего размера. Поначалу это кажется простым, но оказалось (как вы уже могли догадаться) совсем нелёгкой задачей. Я по-прежнему испытываю трудности со склейкой фотографий, но постепенно повышаю навык. Одним из ключевых факторов для успешного панорамного объединения снимков является равномерность фотографий в фокусировке, балансе белого и т.п. Чем более однородны фотографии, тем проще и лучше становится их склейка.

Механизация


Всё это заставило меня заняться механизацией столика. Меня начало очень утомлять перемещения столика вручную, при котором фотографии смещались по нескольким осям и возникали другие искажения.

Проведя большую работу по проектированию, 3D-печати и исследованиям прошивок CNC, я пришёл к следующей конструкции:

eb5e347fcdd1493b5896ff00982d4c5c.jpg


Модифицированный микроскоп AmScope ME580-T

Сверху установлен 7-дюймовый дисплей Raspberry, сзади которого закреплён Raspberry Pi4. На фото не видно камеру RPi HiQ, установленную на микроскопе. RPi делает фотографии, отображает их на дисплее, а также выполняет код на Python, управляющий платой CNC.

Предметный столик и выравнивающий столик перемещаются шаговыми двигателями 28BYJ-48, которые управляются небольшой платой с ESP32, на которой выполняется Grbl_Esp32, а также четырьмя контроллерами шаговых двигателей AD4498.

Схема обладает определёнными программными и аппаратными проблемами, но работает для моих целей достаточно хорошо.


Разобравшись с логистикой, я вернулся к реверс-инжинирингу самого чипа. Изначально я хотел заняться чипом PLA, потому что разобраться в нём будет проще всего. PLA расшифровывается как Programmable Logic Array; подобные структуры очень часто использовались в эпоху Commodore.

Исходя из схемы с Википедии, нам следует ожидать, что на чипе есть два основных массива, AND и OR. Вводы подключены к AND, а выводы выходят из массива OR.

Вернувшись к предыдущему снимку кристалла, мы можем улучшить его, добавив аннотации контактов и областей чипа. Разобравшись с предназначением кристаллов, мы видим, что все вводы соединены с одним массивом, а все выводы — с другим, как и ожидалось. кроме того, это поможет нам понять, где какой массив.

fc118fe2501233c5efdd224bac1f0498.png


Снимок кристалла 8721 PLA с аннотациями

Здесь мы видим отмеченные контакты ввода-вывода и их подключение к выводной рамке и к контактам самого DIP. Также видны две основные области, составляющие структуру PLA, массив AND и массив OR. Кроме того, здесь внизу есть какая-то дополнительная логика, помеченная вопросительным знаком. Назначение её было для меня неизвестно, но поскольку все выходные контакты проходят через неё, я предполагал, что это некий выходной каскад.

Массив AND


Итак, если для начала мы начнём внимательнее исследовать матрицу AND, то увидим показанную ниже картину. Цвета немного искажены, потому что этот снимок делался ещё камерой AmScope и я не мог разобраться, как установить на ней баланс белого.

0d3d9ae2e415d8a240334378dafdb6e5.jpg


Матрица AND со слоем металла

Снимок не особо полезен для понимания происходящего, потому что все интересные части закрыты самым верхним слоем металла. Тогда я только начинал учиться, поэтому для удаления металла я воспользовался грубой силой. Я стёр металл сильным механическим воздействием; после изучения под микроскопом выяснилось, что удалилось вообще всё, кроме само подложки.

К счастью, необходимые мне подробности находились в диффузионном слое, расположенном в подложке:

6a8737c0ca87a6686dd0a2b5430e2ccc.jpg


Подложка матрицы AND

Внимательно присмотревшись к изображению, можно увидеть небольшие волнистые линии в тех местах, где расположен транзистор для создания соединения в матрице.

Массив OR


Перейдя к массиву OR, мы видим точно такой же формат. Сложно разбираться без устранения слоя металла, но проще по сравнению с матрицей AND. И гораздо проще, когда остались только подложка и диффузионный слой.

631e1d72a0030661a6543aed830fdeed.jpg


Матрица OR со слоем металла

9953c1f02009bc417da7220c8f15e92c.jpg


Подложка матрицы OR

Полное декодирование матрицы


Вооружённые этим знанием, мы можем приступать к восстановлению из изображений полной матрицы логики PLA.

Я отметил все транзисторы в каждой матрице точками и получил следующее изображение:

182802ea739d23864c0b24b7dd4b7fd7.jpg


Матрица AND со слоем металла

В матрице AND все входы горизонтальны, а на каждую линию подаётся обычный и инвертированный сигнал. В матрице OR все выводы горизонтальны и соединены с вертикальными линиями, называемыми минтермами.

Изучив точки, мы можем декодировать минтермы, выполняя логику «И» для всех вертикальных линий в матрице AND, например

p0 = CHAREN & HIRAM & BA & !MS3 & GAME & RW & AEC & A12 & !A13 & A14 & A15

Для выводов мы берём горизонтальную линию для каждого вывода и комбинируем её с «или», например

SDEN = p42 | p43 | p66 | p69

Так мы получили весь набор логических уравнений. Ура!

Выходной каскад


Вернёмся к полной фотографии кристалла — теперь у нас есть всё, кроме прямоугольника, отмеченного вопросительным знаком на выходном пути.

Изучая фотографии этого участка в более высоком разрешении, мы видим подобные структуры для каждого вывода. Во всех случаях, кроме двух, эта структура обходится и вывод из матрицы OR идёт напрямую на выходной контакт. Однако это не относится к двум контактам: DWE и CASENB.

DWE — это сигнал включения записи (Write Enable) подаваемый на чипы DRAM основной системы, а CASENB пропускает сигнал CAS к ОЗУ. Эти два сигнала каким то образом обрабатываются при помощи этих структур выходных вентилей, поэтому мне нужно было выполнить реверс-инжиниринг этого блока.

3cdf658fb6b62424f29e0cdfc455ce8c.jpg


Выходной блок со слоем металла

e478a26407848e4c170889fd76c5c5a5.jpg


Подложка выходного блока

Потратив довольно много времени на чтение информации о проектировании и производстве кремниевых чипов, а также сделав много попыток, я смог составить логично выглядящую схему. Я не буду подробно разбирать здесь весь процесс, а задокументирую и опубликую его позже. Здесь мне также хочется поблагодарить Фрэнка Вульфа за его помощь, по возможности поддержите его проект!

211a3953bf2051ddbeb7867a399cd319.png


Схема выходного блока

Заглядывая немного дальше, нужно сказать, что способ использования этой схемы с выводами DWE и CASENB превращает её в обычную D-защёлку. Позволяющая реализовать эта защёлка представлена в матрице PLA парой линий в матрице OR.

Результат


Итак, мы получили окончательный результат и теперь можем записать полный код HDL для чипа PLA компьютера C128. Для этого я буду использовать Verilog. Учтите. что это первый мой код на Verilog, поэтому он может быть неоптимальным. Использование D-защёлки для вывода обычно считается в Verilog плохой практикой, однако в данном случае я воспроизвожу логику и функциональность готового чипа.

По возможности я проверил его правильность, но если я что-то упустил, то сообщите об этом!

В отличие от PLA C64, чип PLA C128 нельзя заменить просто EPROM или чем-то подобным из-за наличия выходных защёлок.

module pla_8721(
    input rom_256,
    input va14,
    input charen,
    input hiram,
    input loram,
    input ba,
    input vma5,
    input vma4,
    input ms0,
    input ms1,
    input ms2,
    input ms3,
    input z80io,
    input z80en,
    input exrom,
    input game,
    input rw,
    input aec,
    input dmaack,
    input vicfix,
    input a10,
    input a11,
    input a12,
    input a13,
    input a14,
    input a15,
    input clk,

    output sden,
    output roml,
    output romh,
    output clrbnk,
    output from,
    output rom4,
    output rom3,
    output rom2,
    output rom1,
    output iocs,
    output dir,
    output reg dwe,
    output reg casenb,
    output vic,
    output ioacc,
    output gwe,
    output colram,
    output charom);

wire p0;
wire p1;
wire p2;
wire p3;
wire p4;
wire p5;
wire p6;
wire p7;
wire p8;
wire p9;
wire p10;
wire p11;
wire p12;
wire p13;
wire p14;
wire p15;
wire p16;
wire p17;
wire p18;
wire p19;
wire p20;
wire p21;
wire p22;
wire p23;
wire p24;
wire p25;
wire p26;
wire p27;
wire p28;
wire p29;
wire p30;
wire p31;
wire p32;
wire p33;
wire p34;
wire p35;
wire p36;
wire p37;
wire p38;
wire p39;
wire p40;
wire p41;
wire p42;
wire p43;
wire p44;
wire p45;
wire p46;
wire p47;
wire p48;
wire p49;
wire p50;
wire p51;
wire p52;
wire p53;
wire p54;
wire p55;
wire p56;
wire p57;
wire p58;
wire p59;
wire p60;
wire p61;
wire p62;
wire p63;
wire p64;
wire p65;
wire p66;
wire p67;
wire p68;
wire p69;
wire p70;
wire p71;
wire p72;
wire p73;
wire p74;
wire p75;
wire p76;
wire p77;
wire p78;
wire p79;
wire p80;
wire p81;
wire p82;
wire p83;
wire p84;
wire p85;
wire p86;
wire p87;
wire p88;
wire p89;

wire casenb_int;
wire casenb_latch;

/* Product terms */

assign p0 = charen & hiram & ba & !ms3 & game &  rw & aec & a12 & !a13 & a14 & a15;
assign p1 = charen & hiram &      !ms3 & game & !rw & aec & a12 & !a13 & a14 & a15;
assign p2 = charen & loram & ba & !ms3 & game &  rw & aec & a12 & !a13 & a14 & a15;
assign p3 = charen & loram &      !ms3 & game & !rw & aec & a12 & !a13 & a14 & a15;

assign p4 = charen & hiram & ba & !ms3 & !exrom & !game &  rw & aec & a12 & !a13 & a14 & a15;
assign p5 = charen & hiram &      !ms3 & !exrom & !game & !rw & aec & a12 & !a13 & a14 & a15;
assign p6 = charen & loram & ba & !ms3 & !exrom & !game &  rw & aec & a12 & !a13 & a14 & a15;
assign p7 = charen & loram &      !ms3 & !exrom & !game & !rw & aec & a12 & !a13 & a14 & a15;

assign p8 = ba & !ms3 & exrom & !game & rw & aec & a13 & !a13 & a14 & a15;
assign p9 =      !ms3 & exrom & !game & rw & aec & a12 & !a13 & a14 & a15;

assign p10 = ba & !ms2 & ms3 &  rw & aec & a12 & !a13 & a14 & a15;
assign p11 =      !ms2 & ms3 & !rw & aec & a12 & !a13 & a14 & a15;

assign p12 = charen & hiram & ba & !ms3 & game &  rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p13 = charen & hiram &      !ms3 & game & !rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p14 = charen & loram & ba & !ms3 & game &  rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p15 = charen & loram &      !ms3 & game & !rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;

assign p16 = charen & hiram & ba & !ms3 & !exrom & !game &  rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p17 = charen & hiram &      !ms3 & !exrom & !game & !rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p18 = charen & loram & ba & !ms3 & !exrom & !game &  rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p19 = charen & loram &      !ms3 & !exrom & !game & !rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;

assign p20 = ba & !ms3 & exrom & !game & rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p21 =      !ms3 & exrom & !game & rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;

assign p22 = ba & !ms2 & ms3 &  rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;
assign p23 =      !ms2 & ms3 & !rw & aec & !a10 & !a11 & a12 & !a13 & a14 & a15;

assign p24 = charen & hiram & ba & !ms3 & game &  rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p25 = charen & hiram &      !ms3 & game & !rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p26 = charen & loram & ba & !ms3 & game &  rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p27 = charen & loram &      !ms3 & game & !rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;

assign p28 = charen & hiram & ba & !ms3 & !exrom & !game &  rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p29 = charen & hiram &      !ms3 & !exrom & !game & !rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p30 = charen & loram & ba & !ms3 & !exrom & !game &  rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p31 = charen & loram &      !ms3 & !exrom & !game & !rw & aec & !a10 & a11 & a12 & !a13       & a15;

assign p32 = ba & !ms3 & exrom & !game & rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p33 =      !ms3 & exrom & !game & rw & aec & !a10 & a11 & a12 & !a13       & a15;

assign p34 = ba & !ms2 & ms3 &  rw & aec & !a10 & a11 & a12 & !a13 & a14 & a15;
assign p35 =      !ms2 & ms3 & !rw & aec & !a10 & a11 & a12 & !a13       & a15;

assign p36 = !aec;
assign p37 = !rw & aec & !a10 & a11 & a12 & !a13 & a15;

assign p39 = !charen & hiram & !ms3 &           game & rw & aec & a12 & !a13 & a14 & a15;
assign p40 = !charen & loram & !ms3 &           game & rw & aec & a12 & !a13 & a14 & a15;
assign p41 = !charen & hiram & !ms3 & !exrom & !game & rw & aec & a12 & !a13 & a14 & a15;

assign p42 = va14 & !vma5 & vma4 & !ms3          &  game & !aec;
assign p43 = va14 & !vma5 & vma4 & !ms3 & !exrom & !game & !aec;

assign p44 = !ms0 & !ms1 & ms2 &ms3 & z80en & rw & aec & a12 & !a13 & a14 & a15;
assign p45 = hiram & loram & !ms3 & !exrom & rw & aec & !a13 & !a14 & a15;

assign p46 = !ms3 & exrom & !game & aec & !a13 & !a14 & a15;
assign p47 = ms0 & !ms1 & ms3 & exrom & !game & aec & !a14 & a15;
assign p48 = !ms0 & ms1 & ms3                 & aec & !a14 & a15;

assign p49 = hiram & !ms3 & !exrom & !game & aec & a13 & !a14 & a15;
assign p50 = ms3 & exrom & !game & aec & a13 & !a14 & a15;

assign p51 = vma5 & vma4 & !ms3 & exrom & !game & !aec;
assign p52 =  ms0 & !ms1 & ms3 & rw & aec & !a12 & !a13 & a14 & a15;
assign p53 = !ms0 &  ms1 & ms3 & rw & aec & !a12 & !a13 & a14 & a15;
assign p54 = !ms0 & !ms1 & ms3 & rw & aec & !a12 & !a13 & a14 & a15;

assign p55 = !ms0 & !ms1 & z80io & !z80en & rw & aec & !a12 & !a13 & !a14 & !a15;
assign p56 = !ms0 & !ms1 & ms3 & rw & aec & !a14 &  a15;
assign p57 = !ms0 & !ms1 & ms3 & rw & aec &  a14 & !a15;

assign p58 = hiram         & !ms3          &  game & rw & aec & a13 &  a14 & a15;
assign p59 = hiram         & !ms3 & !exrom & !game & rw & aec & a13 &  a14 & a15;
assign p60 = hiram & loram & !ms3          &  game & rw & aec & a13 & !a14 & a15;

assign p61 = !z80io & !z80en & aec & !a10 & !a11        & !a13 & a14 & a15;
assign p62 = !z80io & !z80en & aec               &  a12 & !a13 & a14 & a15;
assign p63 = !z80io & !z80en & aec & !a10 &  a11 &  a12 & !a13 & a14 & a15;

assign p64 = !rw & aec;
assign p65 =  rw & aec;
assign p66 = !aec;

assign p67 = !ms2 & !z80en       & aec & !a10 & !a11 & a12 & !a13 & !a14 & !a15;
assign p68 = !ms2 & !z80en & !rw & aec & !a10 & !a11 & a12 & !a13 & !a14 & !a15;

assign p69 = !charen & !vma5 & vma4 & ms3 & aec;

assign p70 = !rom_256 & !ms0 & !ms1 & ms3 & rw & aec               & a14 & !a15;
assign p71 = !rom_256 & !ms0 & !ms1 & ms3 & rw & aec & !a12 & !a13 & a14 &  a15;
assign p72 = !rom_256 & !ms0 & !ms1 & z80io & !z80en & rw & aec & !a12 & !a13 & !a14 & !a15;

assign p73 = clk;
assign p74 = rw & !aec & vicfix;

assign p75 =            !ms0 & !ms1       & ms3 & rw & aec       &  a13 & a14 & a15;
assign p76 = !rom_256 & !ms0 & !ms1       & ms3 & rw & aec       &  a13 & a14 & a15;
assign p77 =            !ms0 &  ms1       & ms3 & rw & aec       &  a13 & a14 & a15;
assign p78 =            !ms0 &  ms1 & ms2 & ms3 & rw & aec & a12 & !a13 & a14 & a15;
assign p79 =             ms0 & !ms1       & ms3 & rw & aec       &  a13 & a14 & a15;
assign p80 =             ms0 & !ms1 & ms2 & ms3 & rw & aec & a12 & !a13 & a14 & a15;

assign p81 = !ms3 & exrom & !game & aec &  a12        & !a14 & !a15;
assign p82 = !ms3 & exrom & !game & aec        &  a13 & !a14;
assign p83 = !ms3 & exrom & !game & aec               &  a14;
assign p84 = !ms3 & exrom & !game & aec & !a12 & !a13 &  a14 &  a15;

assign p85 = !loram & ms3 &  aec;
assign p86 = !hiram & ms3 & !aec;

/* outputs */

assign sden = p42 || p43 || p66 || p69;
assign roml = p45 || p46 || p47;
assign romh = p49 || p50 || p51 || p52 || p79 || p80;
assign clrbnk = p85 || p86;
assign from = p48 || p53 || p77 || p78;
assign rom4 = p54 || p55 || p75;
assign rom3 = p56 || p70;
assign rom2 = p57;
assign rom1 = p58 || p59 || p60 || p71 || p71 || p76;
assign iocs = p0 || p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10 || p11 || p62;
assign dir = p12 || p14 || p16 || p18 || p20 || p22 || p24 || p26 || p28 || p30 || p32 || p34 || p39 || p40 || p41 || p44 || p65;
assign vic = p12 || p13 || p14 || p15 || p16 || p17 || p18 || p19 || p20 || p21 || p22 || p23 || p61;
assign ioacc = p0 || p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10 || p11 || 
               p12 || p13 || p14 || p15 || p16 || p17 || p18 || p19 || p20 || p21 || p22 || p61 || p62;
assign gwe = p37;
assign colram = p24 || p25 || p26 || p27 || p28 || p29 || p30 || p31 || p32 || p33 || p34 || p35 || p36 || p63 || p67;
assign charrom = p39 || p40 || p41 || p42 || p43 || p44 || p69;

assign casenb_latch = p73 || p74;

assign casenb_int = p0 || p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9
                || p10 || p11 || p12 || p13 || p14 || p15 || p16 || p17 || p18 || p19
                || p20 || p21 || p22 || p23 || p39 || p40 || p41 || p42 || p43 || p44
                || p45 || p46 || p47 || p48 || p49 || p50 || p51 || p52 || p53 || p54
                || p55 || p56 || p57 || p58 || p59 || p60 || p61 || p62 || p63 || p67
                || p69 || p70 || p71 || p72 || p75 || p76 || p77 || p78 || p79 || p80
                || p81 || p82 || p83 || p84;

/* Latched outputs */

always @ (clk or p64)
  if (clk)
    dwe <= p64;

always @ (casenb_latch or casenb_int)
  if (casenb_latch)
    casenb <= casenb_int;

endmodule


Что дальше


Следующим анализируемым чипом будет чип MMU компьютера C128, над которым придётся работать гораздо дольше, ведь это не просто обычный PLA.

© Habrahabr.ru