Возможно, какие-то задержки роль играют. Я чисто визуально подбирал количество тактов, при котором частота появления нулей при прогоне теста в эмуляторе совпадает с прогоном на реальном таймере.
Вид для печати
Я видел эти 5 тактов по результатам Ваших исследований ранее, поэтому этот момент на модели тщательно проверял и обдумывал где там может лишний такт набежать. В самой схеме таймера - никак, это изолированный тактовый домен CLC/4, может где-то снаружи в схеме сопряжения с шиной, но ей все равно, другие значения тоже на такт "дрожали" бы. В итоге я надеюсь мы Ваш тест прогоним полностью на получившейся реплике и увидим, будет расхождение с реальным ВМ1 или нет.
Update: кстати работу счетчика легко проверить и без программы на реальном ВМ1. Запускаем ВМ1, он запускает таймер, забираем у ВМ1 шину через DMR, запускаем цикл чтения из регистра таймера внешним агентом, цикл не заканчиваем и на nAD0 осциллографом наблюдаем поведение младшего разряда счетчика таймера. Будет у меня рабочий стенд ВМ1 + FPGA - проверю.
Матрица приоритетного шифратора прерываний основное время отключена от питания, все линии разряжены. При исполнении команды, в фазе проверки наличия запроса на прерывание от основной ПЛМ формируется строб, по этому стробу матрица шифратора "просыпается", фиксирует входные запросы, прогоняет их через себя, фиксирует результаты в выходном латче, возвращает ответный строб готовности и снова отключается. "Зеленые" технологии :). Основная ПЛМ тоже с каким-то хитрым отключением о питания, пока не разобрался.
Входные запросы прерываний ACLO, IRQ1, IRQ2, IRQ3, VIRQ фиксируются на входе шифратора с использованием не нормального триггера, а динамической логики, через емкость затвора транзистора. Фиксация происходит по ниспадающему фронту CLC, поэтому, если "не повезет" и в этот момент будет изменятся уровень входных линий, то транзистор может оказаться в промежуточном состоянии, получим пороговые и переходные процессы на шифраторе и непредсказуемый результат на выходе. В связи с этим рекомендуется все внешние входы IRQ1-3, VIRQ синхронизировать на внешней микросхеме по фронту CLC. В БК все засинхронизировано, на MC1201.01 - не все, по IRQ1 (HALT), IRQ3 и ACLO могут быть проблемы. События редкие, вероятность очень невысокая, но тем не менее.
Update: ответный строб формируется сразу оказывается. Картинка со схемой:
http://s017.radikal.ru/i414/1412/fb/5f5847efb36bt.jpg
RESET - сброс процессорного модуля
REQ - запрос на работу шифратора
ACK - ответный строб
ENA - высокий - постоянная трансляция во входном латче запросов на прерывание, матрица выключена, низкий - латч фиксирует входы, матрица частично разрешается
STB - высокий - матрица полностью разрешена, выходной латч разрешен, низкий - латч фиксирует выходы
Разобрал генератор векторов прерываний, долго искал что такое 270 вектор, оказывается в книжке "МикроЭВМ, Том 2" опечатка, и IRQ3 прерывается по 270 вектору (а написано 274). Ниже фрагмент всех векторов, которые вообще есть у процессора в таблице и по которым он может "ходить".
Дальше буду разбирать генератор констант.
Прерывание по нарастающему фронту nACLO никак не влияет на обработку. Если два отдельных детектора ниспадающего среза (и он используется) и нарастающего фронта. Влияние запроса от детектора фронт возможно только в краткий момент в первом цикле после сброса, тогда поведение непредсказуемо (вероятно зависание шифратора).Код:always
begin
case(vsel)
4'b0000: vmux = 16'o160006; // double error
4'b0001: vmux = 16'o000020; // IOT instruction
4'b0010: vmux = 16'o000010; // reserved opcode
4'b0011: vmux = 16'o000014; // T-bit trap
4'b0100: vmux = 16'o000004; // invalid opcode
4'b0101: //
case (pa[1:0]) // initial start
2'b00: vmux = 16'o177716; // register base
2'b01: vmux = 16'o177736; // depends on
2'b10: vmux = 16'o177756; // processor number
2'b10: vmux = 16'o177776; //
endcase //
4'b0110: vmux = 16'o000030; // EMT instruction
4'b0111: vmux = 16'o160012; // int ack timeout
4'b1000: vmux = 16'o000270; // IRQ3 falling edge
4'b1001: vmux = 16'o000024; // ACLO falling edge
4'b1010: vmux = 16'o000100; // IRQ2 falling edge
4'b1011: vmux = 16'o160002; // IRQ1 low level/HALT
4'b1100: vmux = 16'o000034; // TRAP instruction
4'b1101: vmux = vreg; // vector register
4'b1110: vmux = svec; // start @177704*
4'b1111: vmux = 16'o000000; // unused vector
default: vmux = 16'o000000; //
endcase
end
Тогда отметить цепь к которой он подключен, ПКМ->Properties->Net и там ввести нужное имя. Но порт отображает имя всей цеи, если подключите к ней еще порты - то будет то же самое имя. Более того, все фрагменты цепей с одинаковым именем считаются электрически единой цепью.
Если такая функциональность не нужна, то лучше нарисовать компонент с прямоугольником и одним пином без имени и менять у всего компонента аттрибут Value, я так на схемах с ВП1/ВМ1 делаю для внешних пинов, потому что цепи с такими именами могут быть внутри схемы, обзывать коротенький фрагмент от пина до буфера осмысленным полезным именем жалко.
Это я все понимаю. И имя Net у меня есть, оно отображается на самом ромбике порта. А мне нужно еще ВТОРОЕ имя, которое будет над ромбиком отображаться. (т.е., например, порт P41 (41 ножка микросхемы значит), а над ней выше пояснение Y1 (т.е. первая линия шины для клавиатуры)).
Порт имеет только аттрибут Net Name и все.
Для Ваших целей можно
- использовать только имя порта/цепи
- поставить компонент и использовать его аттрибут value
- просто написать дополнительный текст (не будет привязан, отдельный объект)
Я для обозначения пина ставил компонент вместо порта и использовал Value. На схемах ВП1 этот компонент заменял всю ячейку ввода-вывода, на ВМ1/ВМ80 представлял только пин.
Красиво разложился приоритетный шифратор прерываний, это вот там маленькая матричка в правом нижнем углу на нашей фотографии кристалла.
На его работу существенно влияет бит 2 регистра режима (177700), я этот бит назвал ncpu, вот так работает шифратор штатно, при ncpu=0:
Строчки я расписал от наивысшего приоритета к низшему:Код://______________________________________________________________________________
//
// ncpu = 0, simplified matrix to demostrate priority encoding
//
// iato & qbto;
// & ~iato & qbto & dble;
// psw[11] & ~iato & qbto & ~dble ;
// psw[10] & ~iato & qbto & ~dble;
// ~psw[11] & ~psw[10] & ~iato & qbto & ~dble;
//
// ~qbto & uerr;
// ~psw[10] & psw[4] & ~qbto & ~uerr;
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & aclo;
// ~psw[11] & ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & irq[1];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & irq[2];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & ~irq[2] & irq[3];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & ~irq[2] & ~irq[3] & ~virq;
//
- тайм-аут по извлечению вектора прерывания (немаскируемое)
- двойное зависание (немаскируемое)
- зависание шины, (psw[11] и psw[10] как-то управляют реакцией на прерывание)
- недопустимый код инструкции (немаскируемое)
- T-бит (psw[4]) (маскируется psw[10])
- понижение питания nACLO (маскируется psw[10])
- irq[1] (маскируется psw[10] или psw[11])
- irq[2] (маскируется psw[10] или psw[7])
- irq[3] (маскируется psw[10] или psw[7])
- virq (маскируется psw[10] или psw[7]) (низкий уровень активный)
С детектором фронта ACLO тоже понятно, это перезапуск процессора после снятия DCLO. То есть ACLO должен сниматься строго после DCLO, иначе никакого старта не будет.
А вот при ncpu = 1 модифицируется поведение T-бита, он перестает работать как бит ловушки, вместо этого он как-то начинает влиять на внешние прерывания, пока ясности нет. (Позже выяснилось что это бит режима wait)
Вот полная матрица, может у кого мысли будут:
Такое в Сети нашел:Код://______________________________________________________________________________
//
// Interrupt matrix rewritten (for clarity and readability)
//
module vm1_pli
(
input [19:0] rq,
output [10:0] sp
);
wire [20:0] p;
wire [10:0] pl;
wire [3:1] irq;
wire [11:0] psw;
wire virq;
wire plir, uerr;
wire ncpu, dble;
wire acok, aclo; // ACLO detector requests
wire iato, qbto; // qbus timeouts and odd address
assign psw[10] = rq[0];
assign plir = rq[1];
assign psw[11] = rq[2];
assign uerr = rq[3];
assign psw[7] = rq[4];
assign virq = rq[8]; // low active level
assign qbto = rq[9];
assign dble = rq[10];
assign aclo = rq[11];
assign ncpu = rq[12]; // low active level
assign acok = rq[13];
assign irq[1] = rq[14];
assign psw[4] = rq[15];
assign irq[2] = rq[16];
assign iato = rq[17];
assign irq[3] = rq[18];
function cmp
(
input [19:0] i,
input [19:0] c,
input [19:0] m
);
cmp = &(~(i ^ c) | m);
endfunction
//______________________________________________________________________________
//
// ncpu = 0, simplified matrix to demostrate priority encoding
//
// iato & qbto;
// & ~iato & qbto & dble;
// psw[11] & ~iato & qbto & ~dble ;
// & psw[10] & ~iato & qbto & ~dble;
// ~psw[11] & ~psw[10] & ~iato & qbto & ~dble;
//
// ~qbto & uerr;
// ~psw[10] & psw[4] & ~qbto & ~uerr;
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & aclo;
// ~psw[11] & ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & irq[1];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & irq[2];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & ~irq[2] & irq[3];
// ~psw[10] & ~psw[4] & ~qbto & ~uerr & ~aclo & ~psw[7] & ~irq[1] & ~irq[2] & ~irq[3] & ~virq;
//
assign p[0] = plir & ~qbto & ~aclo & ~uerr & ncpu & ~irq[1] & ~irq[2] & ~irq[3] & virq;
assign p[10] = plir & ~psw[10] & ~qbto & ~aclo & ~uerr & ncpu & ~irq[1];
assign p[3] = plir & ~psw[11] & ~psw[10] & psw[4] & ~qbto & ~aclo & ~uerr & ncpu & irq[1];
assign p[2] = plir & ~psw[11] & ~psw[10] & ~psw[4] & ~qbto & ~aclo & ~uerr & irq[1];
assign p[1] = plir & ~psw[10] & ~qbto & ~aclo & ~uerr & ncpu & ~psw[7] & ~irq[1] & irq[2];
assign p[7] = plir & ~psw[10] & ~psw[4] & ~qbto & ~aclo & ~uerr & ~psw[7] & ~irq[1] & irq[2];
assign p[6] = plir & ~psw[10] & psw[4] & ~qbto & ~aclo & ~uerr & ncpu & ~psw[7] & ~irq[1] & ~irq[2] & irq[3];
assign p[9] = plir & ~psw[10] & ~psw[4] & ~qbto & ~aclo & ~uerr & ~psw[7] & ~irq[1] & ~irq[2] & irq[3];
assign p[4] = plir & ~psw[10] & psw[4] & ~qbto & ~aclo & ~uerr & ncpu & ~psw[7] & ~irq[1] & ~irq[2] & ~irq[3] & ~virq;
assign p[5] = plir & ~psw[10] & ~psw[4] & ~qbto & ~aclo & ~uerr & ~psw[7] & ~irq[1] & ~irq[2] & ~irq[3] & ~virq;
assign p[11] = plir & ~psw[10] & ~psw[4] & ~qbto & aclo & ~uerr;
assign p[12] = plir & ~psw[10] & psw[4] & ~qbto & ~uerr & ~ncpu ;
assign p[13] = plir & ~psw[10] & psw[4] & ~qbto & aclo & ~uerr & ncpu ;
assign p[20] = plir & ~psw[11] & ~psw[10] & ~iato & qbto & ~dble;
assign p[14] = plir & psw[11] & ~iato & qbto & ~dble ;
assign p[18] = plir & psw[10] & ~iato & qbto & ~dble;
assign p[19] = plir & ~iato & qbto & dble;
assign p[16] = plir & iato & qbto;
assign p[15] = plir & uerr & ~qbto;
assign p[8] = ~plir & ~acok;
assign p[17] = ~plir & acok;
assign sp = ~pl;
assign pl[0] = p[20] | p[19] | p[15] | p[9] | p[7] | p[6] | p[1]; // 20, 19, 17, 16, 15, 13,
assign pl[1] = p[20] | p[19] | p[17] | p[13] | p[11] | p[9] | p[6]; // 12, 11, 9, 7, 6, 5, 4, 1
assign pl[2] = p[20] | p[17] | p[16] | p[5] | p[4];
assign pl[3] = p[20] | p[19] | p[17] | p[16] | p[15] | p[12];
assign pl[4] = p[8];
assign pl[5] = p[20] | p[17] | p[15] | p[13] | p[12] | p[11] | p[9] | p[7] | p[6] | p[5] | p[4] | p[1];
assign pl[6] = p[20] | p[19] | p[18] | p[16] | p[15] | p[14] | p[12] | p[10] | p[9] | p[7] | p[5];
assign pl[7] = p[19] | p[18] | p[17] | p[16] | p[14] | p[3] | p[2];
assign pl[8] = p[20] | p[19] | p[18] | p[17] | p[16] | p[15] | p[14] | p[13] | p[11] | p[9] | p[6];
assign pl[9] = p[14] | p[13] | p[12] | p[11] | p[10] | p[9] | p[8] | p[7] | p[5] | p[3] | p[2] | p[0];
assign pl[10] = p[20] | p[19] | p[18] | p[17] | p[16] | p[15] | p[14] | p[13] | p[12] | p[11] | p[5] | p[4];
endmodule
Добавлю от себя что в битах 4 и 3 читается номер процессора (00 для главного, 01/10/11 для ведомого). Да, этот ncpu очень даже на wait похож. Может устанавливаться по сигналу из ядра, надо будет проследить его связь с исполнением инструкции wait. Значит бит T после wait не генерирует исключение, прерывания, если они были замаскированы T-битом, в состоянии wait разрешаются, все логично.Цитата:
177700
Чтение всегда 177740
Запись
биты 0,1 - "1" в любой разряд - останов процессора
бит 2 - запись "1" приостанавливает процессор в ожидании любого прерывания (аналогично команде wait)