Цитата Сообщение от gid Посмотреть сообщение
Какие? Разве модуль может использовать что-то, что не описано как входной параметр или как внутренняя переменная? Если может, то модуль надо переписать так чтобы он использовал только то, что прямо задано во входных параметрах.
В-общем случае можно "достать" переменные из других модулей, но я таким не злоупотреблял. То есть вопрос закрыт.

Цитата Сообщение от gid Посмотреть сообщение
Это потому что у нас модуль маленький и простой.
Я все равно не вижу причин чтобы хранить входные переменные внутри модуля - заходят они все равно все сразу кучкой, а детектор фронтов нужен только на clk, проще выделить события clk в отдельные методы.

Цитата Сообщение от gid Посмотреть сообщение
Тут надо бы ещё определиться с такой вещью. Какая модель первична. Описанная на верилоге или на си? Т.е. Нужно ли и на си сохранять более менее понятный код, по которому можно разобраться в работе?
Это смотря какие планы по дальнейшему использованию эмулятора. Лично я, возможно, буду использовать чтобы разобраться с микрокодом, на подходе еще микрокод от ВМ1Г. Мне некритично, я могу и с модельсимом поработать. Но, весьма вероятно, что найдутся еще люди которым будет интересно тоже на работу микрокода посмотреть и поизучать как работают отдельные инструкции. В любом случае, получится очень точный потактовый эмулятор ВМ1, который не надо будет отлаживать на предмет совпадения с оригиналом - это получается автоматически.

Цитата Сообщение от gid Посмотреть сообщение
Если взять что посложнее, например vm1_qbus.v, то там функция assign неприлично разрастётся и возникнет желание разбить её на несколько частей, хотя бы чтобы самому не запутаться. Но если один раз написать и забыть, и больше туда не заглядывать - то сойдёт.
Да вроде там нет очень глубокого вложения функций, да и файл основной всего ~2K строк. Для начала можно написать как есть, там видно будет, интересно это кому то еще или нет.

Цитата Сообщение от gid Посмотреть сообщение
Имея одну функцию assign и целую кучу awaysов на все случаи жизни,
Так always всего два - про положительному и отрицательному фронту такта, и в каждом из блоков один из них пустой. То есть - по факту всего два метода и никакого запоминания входных сигналов, никаких детекторов и прочего.

Цитата Сообщение от gid Посмотреть сообщение
придётся извне вызывать сперва assign, потом разные awaysы, которые необходимо, потом ещё раз assign, т.е. самим выполнить необходимую работу.
Да, я там в апдейте предыдущего поста подробно основной цикл расписал.

Цитата Сообщение от gid Посмотреть сообщение
Мой же метод предполагает, один раз вызвать одну функцию, там внутри
Да, функция одна, но тут показан далеко не весь код - нет видно кто и как вызывает ее, формирует входные параметры и где хранит результат. Это я к вопросу создания снашлота чтобы обеспечить "одновременность". В моем случае функции две, но параметры нужны только одной и их можно тупо брать сразу из выходных переменных модулей, не парясь о снапшоте. То есть - данные модуля хранятся в самом же модуле и нигде больше - самое соответствие парадигме ООП, имхо.

Цитата Сообщение от gid Посмотреть сообщение
всё само прокрутится по заданным алгоритмам, и на выходе будет конечный результат, который можно использовать снаружи.
Насчет "само" я не понял, будет сгенерирован какой-то неявный С++ код чтобы "прокрутить по алгоритмам" ? Или эта реализация таки будет возложена на вызывающую сторону - обдумать где взять параметры (текущие/снапшот) и куда сложить результат?


Цитата Сообщение от gid Посмотреть сообщение
Теперь нужно на верилоге написать модуль, который использует модуль ir13 внутри себя, например 16 битный сдвиговый регистр
Сделал 16-битный сдвиговый регистр, младший байт может загружаться параллельно и потом сдвигаться в старший байт, в зависимости от переменной mode_s. Последовательно выводимые данные из старшего разряда печатаются на консоль. Пример большой, но больше половины это создание внешних сигналов, сама эмуляция вполне простая.

Код:
ir13    low_byte;
ir13    high_byte;
BOOL    global_change;

BOOL    rst_n;
BYTE    mode_s;
BYTE    parallel_data_in;
BOOL    serial_data_in;

void main(void)
{
    //
    // Initial reset, both registers
    //
    rst_n   = 0;
    mode_s  = 0;
    parallel_data_in    = 0;
    serial_data_in      = 0;
    generate_event(EVENT_INPUT_CHANGE);
    //
    // Parallel load in low-byte, high byte always shifts
    //
    rst_n               = 1;
    parallel_data_in    = 0x55;         // load 'U' character
    mode_s              = 3;            //
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
//
// Not needed in this example
//
//  generate_event(EVENT_CLOCK_FALL);
//
    mode_s              = 2;
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');

    mode_s              = 3;
    parallel_data_in    = 0x53;         // load 'S' character
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');

    mode_s              = 2;
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');

    mode_s              = 3;
    parallel_data_in    = 0x42;         // load 'B' character
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);

    mode_s              = 2;
    generate_event(EVENT_INPUT_CHANGE);
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');

    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
    generate_event(EVENT_CLOCK_RISE);   printf("%c", (high_byte.q & 0x80) ? '1' : '0');
}

void assign_process(void)
{
    for(;;)
    {
        global_change = FALSE;

        low_byte.assign(rst_n, mode_s, parallel_data_in, serial_data_in, 0);
        high_byte.assign(rst_n, 2, 0, (low_byte.q & 0x80), 0);

        if (!global_chabge)
        {
            break;
        }
    }
}

void always_process_p(void)
{
    low_byte.always_p();
    high_byte.always_p();
}

void always_process_n(void)
{
    low_byte.always_n();
    high_byte.always_n();
}

//
// Отдельный поток/функция, обрабатывающая события эмулятора:
//  - измнение входных сигналов
//  - положительный и отрицательный фронты тактовой
//
for(;;)
{
    switch(wait_event())
    {
        case EVENT_INPUT_CHANGE:
        {
            //
            // Назначаем нужные входные сигналы всей схемы
            // Обрабатываем assign всех модулей
            //
            assign_process();
            break;
        }
        case EVENT_CLOCK_RISE:
        {
            //
            // Обрабатываем положительный фронт тактовой
            //
            always_process_p();
            assign_process();
            break;
        }
        case EVENT_CLOCK_FALL:
        {
            //
            // Обрабатываем отрицательный фронт тактовой
            //
            always_process_n();
            assign_process();
            break;
        }
    }
}