.
Возникло сомнение в правильности фазы выдачи сигналов SEL1 и SEL2 в модели Qsync ( и её CPP-варианте ).
Async :
http://pic.pdp-11.ru/images/msim11.png
Qsync
http://pic.pdp-11.ru/images/msim12.png
Вид для печати
.
Возникло сомнение в правильности фазы выдачи сигналов SEL1 и SEL2 в модели Qsync ( и её CPP-варианте ).
Async :
http://pic.pdp-11.ru/images/msim11.png
Qsync
http://pic.pdp-11.ru/images/msim12.png
.
Аналогично для начального изменения сигнала INIT :
Async
http://pic.pdp-11.ru/images/msim13.png
Qsync
http://pic.pdp-11.ru/images/msim14.png
- - - Добавлено - - -
Если модель Async верна - в модели Qsync все сигналы должны изменяться точно так же, как и в модели Async.
При текущем алгоритме изменения SEL1 - при входе в HALT_TRAP он остаётся установленным при уже выданном на шину адресе 177676 :
Код:################
HALT Trap to 160002 = HALT
################
; 000010 -> 177716:000000
-------------------------------------------------
C B S D D W R B I I D D S I H E A D I S S
L AD S Y I O T P S R A M M A N A V C C R L L
C Y N N U B L 7 Q K R G C I L N L L 3 1 2
-------------------------------------------------
1 177716 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 177716 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 160001 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 160001 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 000000 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 000000 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 160011 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 160011 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 000000 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
; PSW :000344 -> 177676:177777
-------------------------------------------------
C B S D D W R B I I D D S I H E A D I S S
L AD S Y I O T P S R A M M A N A V C C R L L
C Y N N U B L 7 Q K R G C I L N L L 3 1 2
-------------------------------------------------
1 177676 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
1 177676 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 000344 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 000344 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 000344 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 000344 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 000000 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Проверил ~SELx, там нет ошибки в Async, все соответствует схеме, видимо, сигнал через два регистра и дешифратор долго проходит.
По INIT фаза в моделях будет отличаться, так выполнен переход на синхронную модель, триггер был нужен. Сигнал длительный, практически никогда в работе не используется, поэтому разницу в такта в момент сброса не считаю принципиальной.
В том и проблема модели Qsync, что адрес там выставляется без задержки ( как в модели Async ), а SEL1 изменяется с задержкой ( не как в модели Async )
Но в CPP-модели такая неадекватность явно лишняя - надо ( наверное ) особо подчеркнуть в комментариях к коду модели Qsync, каким должно быть правильное поведение сигнала INIT в данном случае.
Я второстепенные сигналы (BSY, INIT, SEL, входы прерываний) не очень точно переносил, там может быть фазовое отличие на полтакта/такт.
Я уже не помню как оно было, там относительно запутанный сдвиговый регистр с обратной связью, как я понимаю, оно сделано для того чтобы обеспечить минимальную длительность сигнала сброса периферии процессора, если сигнал приходит извне. Ну и сброс всего провессора по INIT если есть ACLO. Проще на реальном процессоре посмотреть как ведет себя INIT при старте.
Сигнал SEL должен выставляться синхронно с адресом, а сниматься синхронно с SYNC - иначе на шине возникает куча-мала.
В текущей CPP-модели сигнал INIT ведёт себя не как в реальном процессоре, а как в модели Qsync - и это не радует.
- - - Добавлено - - -
Если в модели Qsync при вычислении pin_init_out заменить reset на reset_rc - сигнал INIT начинает изменяться синхронно с DCLO :
Есть ли у такого решения какие-то недостатки ?Код:assign pin_init_out = init_out[0] | reset_rc;
По схеме процессора - nSELx это защелка (латч) равенства состояния шины AD адресу 1777xx, фиксируется по nSYNC. То есть - пока nSYNC высокий, состояние nSEL изменяется согласно состоянию AD, когда nSYNC активируется (спад в низкий уровень, начало цикла) - nSEL замораживается. То есть, это не какой-то сакральный внутрений сигнал, который как-то влияет на исполнение кода или внутренности процессора, это просто тупой дешифратор адреса.
С установкой nSELx при высоком nSYNC в обоих моделях все в порядке, Async ставит строго согласно схемы, в реальном процессоре сигнал физически запаздывает (там на картинке видно что по срезу CLC на шину наконец вылазит достоверный адрес и почти сразу за его установлением активируется nSEL1). То есть - Async строго кошерный, но из-за своей идеальности дает немного отличную картинку от реального процессора. Qsync дешифрацию и защелкивание nSELx выполняет по фронту CLC. Это реальное отличие, да. Связано с тем, что у нас в схемотехнике не допускаются латчи, а на полтакта ранее по срезу CLC дешифрацию выполнить нельзя - потому что еще нет адреса и не разрешена работа шины. Но, главное, nSELx все равно активирован до среза nSYNC, то есть логика шины никак не нарушается. Со снятием непонятно что смущает, в любом случае на шине имеется минимум длительностью один такт высокого nSYNC, nSELx при этом в Async/Qsync вполне корректно снимается:
http://pic.pdp-11.ru/images/sel1mym.png
Итого - Async идеальный, строго по схеме, из-за этого сигнал nSEL выглядит как пришедший на полтакта раньше. Qsync задерживает nSEL на полтакта (не по схеме), но так же выглядит и реальный процессор. Принципиальных проблем для работы шины тут нет - взаимный порядок событий с nSYNC соблюден. Еще надо не забывать что nSYNC и AD - это комбинации внутренних и внешних сигналов, от внутреннего и внешнего агентов, процессор же может читаться-писаться внешним агентом, и тут уже фазу защелкивания во флип-флопе подкручивать бесполезно. Теоретически, для того чтобы ставить nSEL в Qsync на полтакта ранее, для внутреннего обращения можно было бы куда-то залезть глубого внутрь, вытащить адрес для дешифрации прямо с ALU, предсказать запись в регистр адреса areg, предсказать разрешение шины (если она опоздает то надо дешифровать позже, то есть уже с выхода регистра areg, а не с АЛУ - появится мультиплексор адреса, замечательно), и выполнять фиксацию дешифрации одновременно с этими всеми событиями. А для внешнего обращения это все вообще не работает, надо строить еще один параллельный дешифратор. В итоге получим достаточно сложную и нечитаемую схему. Для сохранения фазы многих внутренних управляющих сигналов это было оправдано и делалось (теперь иногда приходится вникать, потому что оно совсем уж дико выглядит местами), для второстепенного сигнала дешифратора, с незначительным непринципиальным отставанием фазы - нет.
Впрочем, для CPP-модели внести изменение проблем нет, можно защелки sel_xx
обрабатывать по обоим фронтам. Верилог такого не пропустит, а на C++ это запросто. Тогда и будет счастье, всем и даром :)Код:always @(posedge pin_clk_p)
begin
if (~pin_sync_in)
begin
sel_xx <= sel177x;
sel_00 <= sel177x & (pin_ad_in[3:1] == 3'b000);
sel_02 <= sel177x & (pin_ad_in[3:1] == 3'b001);
sel_04 <= sel177x & (pin_ad_in[3:1] == 3'b010);
sel_06 <= sel177x & (pin_ad_in[3:1] == 3'b011);
sel_10 <= sel177x & (pin_ad_in[3:1] == 3'b100);
sel_12 <= sel177x & (pin_ad_in[3:1] == 3'b101);
sel_14 <= sel177x & (pin_ad_in[3:1] == 3'b110);
sel_16 <= sel177x & (pin_ad_in[3:1] == 3'b111);
end
end
Этот кусок инициализации при переносе в синхронную модель некоторое время не хотел работать и требовал отладки, поэтому немного отличается от реальной схемы. Qsync строится на совсем других принципах, отличных от Async и реального процессора, в ней не допускается применение латчей. Чисто теоретически в Qsync можно добиться точно такой же картинки как в Async, но в некоторых местах это требует неоправданного усложнения и изменения логики (становится менее понятной и читаемой). Поэтому незначительные фазовые отличия для редких событий на второстепенных сигналах, скорее всего, в Qsync останутся.
- - - Добавлено - - -
Чисто теоретические - сбросы пытаются не делать сложными комбинационными схемами. Выход станет зависеть напрямую от DCLO, несинхронизировано. pin_init_out снаружи соединен с pin_init_in, который используется для сброса таймера и детекторов спада прерывания, поэтому его желательно для реальной ПЛИС таки синхронизировать - разветвленные комбинационные схемы иногда дают ложные короткие пики и асинхронные сбросы их успевают поймать. По pin_init_in предполагается внешняя синхронизация при реальном использовании. Но если практически - то, думаю, можно так поступить, особенно для CPP модели (мне в Qsync стабильность и нежелание потенциальных проблем все-таки важнее, но ОК, тоже внесу коррекцию).
PS. DCLO в реальных схемах (БК/1201.01) по срезу CLC синхронизировано вне процессора, поэтому такой ситуации как на диаграмме не будет.
Потому в tbench.v более актуален такой код :
Код://
// CPU start
//
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
dclo = 1;
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
@ (negedge clk);
aclo = 1;
$display("Processor ACLO and DCLO deasserted");
Да, можно и так сделать, внесу изменения.
- - - Добавлено - - -
Кстати, начальная цель при переходе на Qsync была оставить только одну тактовую частоту и только одно событие по фронту тактовой частоты (это бы и ускорило CPP-модель, только eval_p остался бы). Две фазы достаточно сильно усложняют логику и забирают избыточные ресурсы, это я просто не осилил за один проход такое упрощение сделать. Поэтому все фазы соблюдались бы с точностью максимум до полутакта. Теперь есть модель Wsync, если и будет модификация до единой частоты, то уже на ней, Qsync в этом плане меняться не будет.