http://my-files.ru/6exwbt
Собсна, вот. Внутри схема минимальной обвязки в DipTrace + проект под квартус.
О схеме
Не надо это собирать

Схема более эскиз, нежели принципиальная - просто чтобы было понятно, какой сигнал чем рулит.
RAM нет, она для запуска не нужна. ROM 2 штуки по 32к, на младший и старший байт ШД. Можно обойтись одной 16-битной.
Разъем ISA условен, опять же, чтобы было понятно, что туда выводится.
Генератор OSC - KXO-97 на 30 МГц.
Нет ни защитных буферов, ни согласования 3.3V <-> 5V, ни блокирующих кондеров. Короче, голая логика.
О проекте
В качестве тэзэ я принял 8086-1 в максимальном режиме с возможностью обмена с 8-битной внешней шиной.
"Чипсет" сначала планировал на MAX V (CPLD), но отсутствие встроенной RAM хотя бы байт на 100-200 убило. Регистры DMA превратились в монстрообразную кашу из D-триггеров и коммутаторов, сожрав порядка 300 LE из 1500 доступных в топовом MAX V.
Поэтому переехал на циклон 4, меньшие последний квартус выбрать не дает. Да, из пушки по воробьям. Но это решаемо, я думаю.
Блок 8284 состоит из счетчика, который формирует CLK из OSC, двойной синхронизации READY и синхронизации RESET.
Входов READY три штуки - IORDY (сигнал с шины), DMARDY, его может ронять DMA, когда занимается своими делами, и STEER_RDY, который роняет перестановщик байтов, удлинняя цикл для обмена двумя байтами вместо одного. На вход синхронизатора в 8284 это все заведено через AND.
Вход RESET также является AND 2 входов - от кнопки и PWRGOOD от ATX БП.
Блок 8288.
Главной проблемой, как ни странно, стал момент определения начала цикла. Согласно спецификациям, S0-S2 могут упасть как до начала Т1, так и после. Соотв., ALE начинается от момента "кто позже упадет" - S или CLK. Вроде просто, но объяснить это квартусу я толком не сумел. Надо будет переделать, то, что есть, мне не нравится, хотя и работает.
Для DT_R фактически делается 2 одинаковых по длительности сигнала - один сам DT_R (т.е. падающий в 0 при чтении), второй - DT_R_POS, всегда =1, для формирования сигналов чтения-записи. Есть соблазн получать DT_R из DT_R_POS и сэкономить регистр, но не выйдет, пробовал.
DEN я сразу делаю инверсным (DEN_INV), так как для чтения и записи у него разная длительность, соотв. реально формируются 2 сигнала DEN_R и DEN_W, а результат суммируем по AND.
Отдельная тема INTA. Проц генерит их 2 штуки подряд, выставляя LOCK, дабы чего не вышло. Согласно спекам, DT_R/DEN нужно формировать только для второго INTA, поэтому введен счетчик таковых и учтен.
AEN_INV разрешает работу регистров адреса проца (которые по АЛЕ), встает в 1 только при захвате шины DMA. Для простоты будем считать, что AEN_INV всегда =0, т.е. DMA никогда не получит шину.
Перестановщик (bus steering, далее ПС). Собственно, зачем он нужен - примерно понятно, у проца ШД 16 бит, а на внешней шине - только 8.
Первоначальной идеей было просто генерить 2 полноценных цикла, т.е. ПС перехватывает S0-S2 между процом и 8288, после чего в "T3" на некоторое время подпирает их единицей и через такт снимает, имитируя начало нового цикла. Одновременно с подпиранием меняем A0 шине 0->1 и подсовываем ей старшую половину шины проца.
Сделал так, потом сунул нос в ISA bus architecture, а в 286 чипсете, оказывается, попросту дергают MRD/MWR/IORD/IOWR. Поэтому переделал именно в такой вид, экономия - аж 1 такт.
Попутно наткнулся на проблему: шина проца физически сводится к 8-битной двумя коммутаторами, переключаются которые по SELH. При записи все в порядке - источник (проц) предоставляет данные для обеих половин шины. Однако, при чтении, у нас так или иначе будет источник только для какой-то одной половины шины. Т.е. мы-то прочитаем с шины младший байт, но после переключения коммутаторов на старшую половину, он потеряется. Поэтому просто запоминаем его в FPGA, после чего подсовываем процу во 2 "цикле".
Работа перестановщика основана на счетчике тактов, он считает фронты CLK, как только упали S0-S2, доходит до 11b и более не меняется, обрано в 0 - по фронту S0-S2 либо если отработал "подпиратель" командных сигналов, т.е. мы начали 2 "цикл".
По этому счетчику ориентируется STEER_RDY, пока у нас первый такт, надо что-то быстро предпринять, иначе двойная синхра в 8284 растянет цикл. Поэтому, пока счетчик в 00b, по спаду CLK роняем этот сигнал в первом цикле (SELH = 0) или поднимаем в 1 во втором (SELH = 1). Далее, по следующему спаду, принимаем решение - формировать второй цикл или нет. Почему не сразу? Потому что только здесь A0 и BHE валидны, т.е., проц выставил их на ноги, и они по ALE попали в фиксаторы.
В остальном все просто. Так как адресный декодер работает только с командными сигналами, а не с сырыми S0-S2, он к моменту принятия решения еще не знает, адресуется внешнее устройство (т.е. 8-битное) или нет. Поэтому он исключительно по адресам формирует 2 предположения - EXT_MEM и EXT_IO (пока прибито в 1). Ну а ПС уже учитывает MEM_OP и IO_OP от 8288, т.е. если адрес является внешним для ИО, но не является таковым для памяти, а операция именно с памятью, то ничего не делаем. Результатом всех этих комбинаций является сигнал EXT_DEV, который и пишется с инверсией в STEER_RDY при принятии решения.
Мелочь, а важно. Если проц выполняет 8-битный цикл по старшему байту, нам тоже нужно переключить коммутаторы, что учтено в конечной формуле для SELH.
Разумеется, это все черновик. Но это то, что есть на данный момент, может кому будет интересно.
Как-то так. Извините, если невнятно изъясняюсь, комментарии в коде есть. Если чего - спрашивайте.
