Вчера исправил еще ошибок в верилоге и успешно йопуну на 1801ВМ2 прошел, сегодня вечером буду продолжать, чегой-то АЛУ мне не нравится.
Вчера исправил еще ошибок в верилоге и успешно йопуну на 1801ВМ2 прошел, сегодня вечером буду продолжать, чегой-то АЛУ мне не нравится.
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
Сейчас такая последовательность микрокоманд формируется:
1 - это вход после аппаратного сбросаКод:1 plm[000076] op2 word ac ACC ACC ------ y --- ---- 2 plm[000056] op2 word ac ACC ACC ------ y --- runa 3 plm[000003] op1 word f1 *x PSW 000020 ------ ~y --- ---- 4 plm[000042] op1 byte f1 *x QREG 000000 ------ x&y --- ---- 5 plm[000037] op1 word f1 *x QREG vector 000000 x+y --- rdat 6 plm[000002] op2 word ac R7 QREG ------ y --- ----
2 - запуск безадресного чтения вектора начального пуска в буферный регистр данных Qreg
3 - сброс бита T (остальные биты по ходу устанавливаются)
4 - обнуление младшего байта вектора
5 - запуск чтения первого слова вектора
6 - копирование прочитанного в PC
Почему-то не проходит корректно запись в приемники данных.
Но видно что микрокоманды уже осмысленные идут, десятка два ошибок в верилоге поправил, думал уже совсем не взлетит.
PS. йопуна - это безадресное чтение, от сигнала IOP_UNA![]()
Я когда-то давно дизассемблировал 791402 в IDA. Только мне там всё равно ничего не понятно, поэтому я это просто забросил до лучших времён. Если надо, могу дать хоть идовский файл 791402.i64 (я использую IDA 5.0 x64, более новые смысла нету, там pdp-11 дизассемблируется нисколько не лучше), хоть сгенерированные листинг и асм.
Ещё, кстати, давно ещё, пытаясь разобраться с АЛУ ВМ1, путём всякого рода булевских преобразований, я получил более менее человекопонятный эквивалентный код АЛУ в верилоге.
код
Код://______________________________________________________________________________ // // Control and glue logic // assign wait_areg_free = ~plr[23] & (~plr[8] & ~plr[7]); //ожидать освобождения регистра A assign wait_write_complete = ~plr[23] & ( plr[8] | plr[7]); //ожидать завершения записи на шине МПИ //если qbus_adr и ожидать ожидать завершения записи на шине МПИ //или dout_req и ожидать освобождения регистра A //или ожидать чтение данных на шине МПИ и (TPLM == 2 или iak_flag) assign alu_qrdy = ~( (qbus_adr & wait_write_complete) // wait for write complete | (dout_req & wait_areg_free) // wait for areg free | (~plr[10] & (tplm[2] | iak_flag)) ); // wait for data or vector fetch ........ ........ ........ //______________________________________________________________________________ // // ALU function unit // // plr[17:13] cl alu_a alu_b alu_c alu_d alu_e alu_x oxy axy h alu // 00x00 0 ( 1 | 0 ) ( 1 | 0 ) 1 0 x&y x|y x^y x+y А // 00x01 # 0 ( 1 | 0 ) ( 1 | 0 ) 1 0 x&y x|y x^y x+y А # // 00x10 0 ( 1 | 0 ) ( 0 | 0 ) 0 0 x&y x x&~y x&~y Л // 00x11 * 0 ( 1 | 0 ) ( 1 | 0 ) 1 0 x&y x|y x^y x+y А + сдвиг // 01x00 1 ( 1 | 0 ) ( 1 | 0 ) 1 1 ~x&y ~x|y ~(x^y) y-x А // 01x01 # 1 ( 1 | 0 ) ( 1 | 0 ) 1 1 ~x&y ~x|y ~(x^y) y-x А # // 01x10 1 ( 1 | 0 ) ( 1 | 0 ) 0 0 x&y x|y x^y x^y Л // 01x11 * 1 ( 1 | 0 ) ( 1 | 0 ) 1 1 ~x&y ~x|y ~(x^y) y-x А + сдвиг // 10x00 0 ( 0 | 1 ) ( 1 | 0 ) 0 0 x&~y x|y y y Л // 10x01 # 0 ( 0 | 0 ) ( 0 | 0 ) 0 0 0 x x x Л # // 10x10 0 ( 0 | 0 ) ( 1 | 0 ) 0 0 0 x|y x|y x|y Л // 10x11 * 0 ( 0 | 0 ) ( 0 | 0 ) 0 0 0 x x x Л + сдвиг // 11x00 1 ( 0 | 1 ) ( 0 | 1 ) 1 0 x&~y x|~y ~(x^y) x-y А // 11x01 # 1 ( 0 | 1 ) ( 0 | 1 ) 1 0 x&~y x|~y ~(x^y) x-y А # // 11x10 0 ( 0 | 1 ) ( 0 | 0 ) 0 0 x&~y x x&y x&y Л // 11x11 * 1 ( 0 | 1 ) ( 0 | 1 ) 1 0 x&~y x|~y ~(x^y) x-y А + сдвиг //# - при этом ещё интерпретировать yreg как вектор или константу, а не номер регистра. // // ALU controls // assign cl_fc = plr[16] & ~(plr[17] & plr[14] & ~plr[13]); //флаг операции вычитания assign alu_a_fc = ~plr[17]; //флаг прямого y в oxy assign alu_b_fc = plr[17] & (plr[16] | ~(plr[14] | plr[13])); //флаг инверсного y в oxy assign alu_c_fc = (plr[17] ^ plr[16]) & ~plr[13] | (~plr[17] & alu_e_fc); //флаг прямого y в axy assign alu_d_fc = plr[17] & plr[16] & ~(plr[14] & ~plr[13]); //флаг инверсного y в axy assign alu_e_fc = ~(plr[17] & ~plr[16] | plr[14] & ~plr[13]); //флаг арифметической, а не логической операции assign alu_x_fc = ~plr[17] & plr[16] & ~(plr[14] & ~plr[13]); //флаг инверсного х // // ALU and/or products // assign nx = alu_x ? ~xreg : xreg; assign oxy = nx & ((alu_a ? yreg : 16'o000000) | (alu_b ? ~yreg : 16'o000000)); assign axy = nx | ((alu_c ? yreg : 16'o000000) | (alu_d ? ~yreg : 16'o000000)); // // ALU selectable function // assign h = oxy ^ axy; // в продукции c каждый бит означает: 1 - при арифметической операции в этом разряде будет перенос. 0 - не будет переноса assign c = cpred & axy | oxy; assign cpred = {c[14:0], cl}; // если арифметическая операция, то cpred ^ h - получается арифметическая операция, иначе остаётся h - логическая операция assign f = alu_e ? (cpred ^ h) : h; // Вот так это реализуется на Си // WORD tmp = ~((axy + oxy) + (cl ? 1 : 0)); // WORD c = (tmp & axy) | oxy; //определяем, будет ли перенос в данном разряде при сложении // тут каждый бит в с означает: 1 - при арифметической операции в этом бите будет перенос. 0 - не будет переноса // WORD cpred = (c << 1) | (cl ? 1 : 0); // если арифметическая операция, то cpred ^ h - получается арифметическая операция, иначе остаётся h - логическая операция // WORD f = alu_e ? (cpred ^ h) : h; // // ALU result shifter // assign alu_shift[1:0] = {plr[14], plr[13]}; //признак режима сдвига АЛУ, и частично - определитель, как интерпретировать шину Y //plr[18] == 1 - словная операция, 0 - байтовая //plr[27] == 1 - сдвиг вправо, 0 - влево //plr[26:25] - режим сдвига АЛУ // 00 - арифметический // 01 - ещё какой-то особенный // 10 - циклический // 11 - нет сдвига, доп. операции assign shift_code[1:0] = {plr[26], plr[25]}; //код вида сдвига assign fctl[0] = (shift_code == 2'b00); //00 арифметический сдвиг assign fctl[1] = (shift_code == 2'b01); //01 какой-то особенный сдвиг assign fctl[2] = (shift_code == 2'b10); //10 циклический сдвиг // 000 влево, в младший бит вдвигается 0, ASL // 001 влево, в младший бит вдвигается 0, ASL // 010 влево, в младший бит вдвигается С, ROL // 011 нет сдвига, перестановка байт на входе АЛУ с шины X // 100 вправо, старший бит копируется, ASR // 101 вправо, в старший бит вдвигается перенос из старшего разряда АЛУ в текущей операции // 110 вправо, в старший бит вдвигается C, ROR // 111 нет сдвига assign au_swapX = ~plr[27] & (shift_code == 2'b11) & (alu_shift == 2'b11); //011 - команда перестановки байтов на шине Х assign alu_s_fc = (shift_code != 2'b11) & (alu_shift == 2'b11); //признак операции сдвига assign fbitc = fctl[2] & gpr[14][0]; //если х10 (ROL,ROR), то берём бит C из PSW, иначе 0 (для ASL,ASR и оп. х01) //а не надо ли тут для операции х01 брать c[0]? //по аналогии со сдвигом вправо //если словная операция, то f[8], чтобы при сдвиге не портилось слово. //если байтовая, то зависит от кода сдвига assign fbit7 = plr[18] ? f[8] : (fctl[0] & f[7] //арифметический сдвиг, байтовая операция | fctl[1] & c[7] //сдвиг код 01, байтовая операция | fbitc); //циклический сдвиг, байтовая операция) //при байтовой операции старший байт значения не имеет, поэтому //корректностью результата fbit15 можно пренебречь assign fbit15 = fctl[0] & f[15] //арифметический сдвиг, любая операция | fctl[1] & c[15] //сдвиг код 01, любая операция | fbitc; //циклический сдвиг, любая операция //если операция сдвига, то если сдвиг вправо, то двигаем по-отдельности байты, если сдвиг влево, // то двигаем всё слово влево и в мл.бит или С или 0, //если сдвига нету, то просто f как есть assign alu = alu_s ? (plr[27] ? {fbit15, f[15:9], fbit7, f[7:1]} : {f[14:0], fbitc}) : f; //если операция арифметическая, то если словная операция, то c[15] иначе c[7], для логической - 0 assign fmux[0] = alu_e & (plr[18] ? c[15] : c[7]); //перенос при арифметической операции //если сдвиг вправо, то f[0], а если влево, то если словная операция то f[15], если байтовая, то f[7] assign fmux[1] = plr[27] ? f[0] : (plr[18] ? f[15] : f[7]); //перенос при сдвигах //будет ли переполнение в арифметической операции assign fmux[2] = plr[18] ? (c[14] ^ c[15]) : (c[6] ^ c[7]); // // Флаги состояния результата операции АЛУ // //если сдвиг, то бит С - из f (результат сдвига), если нет, то результат арифметической операции assign flag[0] = alu_s ? fmux[1] : (cl ? ~fmux[0] : fmux[0]) ; // C //если байтовая операция, то старший байт игнорируем, иначе проверяем оба байта assign flag[2] = (~plr[18] | (alu[15:8] == 8'o000)) & (alu[7:0] == 8'o000); // Z //если словная операция, то бит 15 иначе бит 7 результата операции assign flag[3] = plr[18] ? alu[15] : alu[7]; // N //если операция сдвига, то по сути C ^ N или арифм переполнение. (как-то странно сложно) //если не сдвиг, то если арифметическая операция, то арифметическое переполнение, иначе 0 assign flag[1] = alu_s ? ((fmux[1] ^ flag[3]) | fmux[2]) : (alu_e & fmux[2]); // V // // Original strobes: // // assign au_astb = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])); // assign au_qstbx = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]); // assign wire3 = (alu_shift == 2'b01) ? ustb : au_alsl; //если wire3 и ожидать завершения записи на шине МПИ assign au_astb = wire3 & wait_write_complete; //признак записи результатов в регистр адреса А //если wire3 и ожидать освобождения регистра A assign au_qstbx = wire3 & wait_areg_free; //признак записи результатов в регистр Q // // X bus (12 entries) // AU_RSX0 - general purpose regs // AU_RSX1 - general purpose regs // AU_QSX - qbus temporary reg // AU_PSWX - PSW // // AU_ALSx - ALU result strobe (writeonly) // AU_ASTB - A address register (readonly) // AU_ASTB - A address register (readonly) // AU_QSTBX - Qbus temporary reg (readonly) // AU_QSTBX - Qbus temporary reg (readonly) // AU_IS0 - ALU X argument (readonly) // AU_IS1 - ALU X argument (readonly) // // Y bus, inverted (9 entries) // AU_RSY0 - general purpose regs // AU_RSY1 - general purpose regs // AU_QSY - Qbus temporary reg // AU_PSWY - PSW // // AU_ALSx - ALU result strobe (writeonly)) // AU_VSELY - vector generator (Y-writeonly) // AU_CSELY - constant generator (Y-writeonly) // ALU_U - ALU Y argument (readonly) // assign x = au_alsl ? (au_alsh ? alu : {8'o000, alu[7:0]}) : xr; assign y = yr; //флаг завершения операций в АЛУ и что надо сохранять результаты assign alu_op_complete = alu_busy_rp & ustb_h; always @(posedge pin_clk_n) begin // //фиксируем для АЛУ входные параметры с шин X и Y // xreg <= au_swapX ? {x[7:0], x[15:8]} : x; //если надо - переставим байты местами yreg <= y; //фиксируем условия работы АЛУ cl <= cl_fc; alu_a <= alu_a_fc; alu_b <= alu_b_fc; alu_c <= alu_c_fc; alu_d <= alu_d_fc; alu_e <= alu_e_fc; alu_x <= alu_x_fc; alu_s <= alu_s_fc; // // ALU general purpose registers // //надо сохранять младший байт результата работы АЛУ au_alsl <= alu_op_complete; //а если была словная операция - то и старший байт au_alsh <= alu_op_complete & plr[18]; if (au_astb) //сохраняем в регистре адреса A текущее содержимое шины X areg <= x; end always @(posedge pin_clk_p) begin if (au_alsl) //если операции в АЛУ завершились freg <= flag; //то фиксируем флаги end[свернуть]
в этом коде многое инвертировано, в результате шина Y и всё, что с ней связано, получается инвертированным, и нужно ещё в других местах это учесть. Не знаю, как насчёт нужности и полезности на практике, но оно в симуляции работало.
Последний раз редактировалось gid; 06.02.2019 в 12:33.
Интересно было посмотреть на реализацию, спасибо.
От 791402.idb не отказался бы, все лучше чем голый старт.
Вот 791402.zip
Поехал процессор, прочитал начальный вектор, перешел правильно, начал выполнять команды теста вычисления пи, потом где-то упал и стал постоянно чего то с тайм-аутом шины вычитывать. Время запускать 791401 для отладки![]()
Блог : http://collectingrd.kxk.ru/ . В ЛС прошу не писать, все сообщения MMTEMA@MAIL.RU
В это сложно поверить, но асинхронная модель 1801ВМ2 прошла заводские тесты 791401 (основные арифметические операции) и 691404 (прерывания и исключения):
- выложил на гитхабе (ссылки в первом посте темы)
- выгрузил все CAD файлы в отдельную репку и сделал ее гит-подмодулем с именем cad11
- репка стала всего 13 мегабайт и исходники и CAD файлы теперь можно выкачивать отдельно
- по факту проект теперь разбит на две репки, одна включена в другую, и можно работать независимо
- теперь можно не злоупотреблять git push origin --force чтобы убирать лишние версии больших CAD файлов
Есть еще странности, почему-то перед прерываниями и исключениями (типа emt) читает безадресно вектор начального пуска.
Для halt и тайм-аутов шины оно так и должно быть, но для обычных векторных прерываний вроде бы нет.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)