шесть операций на одном сумматоре

Или как минимазировать ресурсы в АЛУ процессора.

Нередко замечал в коде на верилог для fpga частое использование операции +. Чуть ли не в каждом пункте case. Это привело меня к мысли, что использовать чужой код на верилоге может быть менее привлекательной идей чем написать свой собственной код.

Поэтому я попытался своими силами реализовать АЛУ на верилоге, но так, чтобы ресурсы использовались по минимуму. И у меня получилось реализовать шесть операций на одном сумматоре. В зависимости от операции (ADD, ADC, SUB, SBB, INC, DEC) второй операнд и carryin коммутируются либо на входной операнд либо, на ноль, затем этот скоммутированный операнд повторно коммутируется, где выбирается либо он сам либо его инверсия.
Таким образом мы настраиваем функцию с помощью четырех параметров.

На верилоге это выглядит так:

assign b0 = zero_b ? 8'b0 : b_i;
assign b  = inv_b ? ~b0 : b0;

assign carryin0 = zero_c ? 1'b0 : c_i;
assign carryin = inv_c ? ~carryin0 : carryin0;

 /* verilator lint_off WIDTH */
assign sum = a_i + b + carryin;
/* verilator lint_on WIDTH */

//...

// ...внутри always

case (cmd)
// ALU_CMD_ADC correspond to default settings
`ALU_CMD_ADD:
               zero_c = 1'b1;
`ALU_CMD_SUB:
               {inv_b,zero_c,inv_c} = 3'b111;
`ALU_CMD_SBB:
               {inv_b,inv_c} = 2'b11;
`ALU_CMD_INC:
              {zero_b, zero_c, inv_c} = 3'b111;

Условные инструкции i8080

Изучение таймингов инструкций в i8080 дает нам информацию об особенностях, или если там можно сказать — странностях их реализации. Например 10 тактов инструкции jmp возможны если 2 последних такта накладываются на первые два такта следующей инструкции. Это в принципе ожидаемо. А вот почему условный переход тоже всегда 10 тактов независимо от истинности условия это загадка. Например, условный вызов подпрограммы или условный возврат имеет разную длину в зависимости от истиности условия. Почему же так не происходит в случае j<условие> инструкции? Интересно, же.

Пластик вместо текстолита. Или как я делал VGA вывод

Вы когда нибудь паяли на пластике?
Проходя через детский отдел товаров, мое внимание привлек кусочек пластика. «Вот на чем я буду крепить vga разъем» — подумал я и незамедлительно купил его. Что называется «из говна и палок».
Закончив самую неприятную часть (не любитель я паять vga разьем), оставалось только реализовать самопальный видео-контроллер на fpga. Результат работы на втором фото. Там аппаратный текстовый режим 64x25, с атрибутами, а также со шрифтом, вытянутым из нач. загрузчика компьютера «Специалист»

Текстовый аппаратный режим на fpga
Текстовый аппаратный режим на fpga
Read more...Collapse )

Загадка первой инструкции

Сижу разбираюсь со схемотехникой компьютера "Специалист". Знаете почему самой первой командой, которую исполняет этот компьютер, является команда перехода на следующую команду? Сегодня я, наконец, понял почему это так.
Дело в том, что ПЗУ содержащее начальный загрузчик, находится по адресу 0С000h. А после старта компьютера, он начинает исполнять команду по адресу 0, где даже нет еще загруженной программы. Чтобы он мог начать выполнение с команды в ПЗУ, сразу после старта, старшие два бита адреса внешне принудительно устанавливаются в 1. Процессор думает что он исполняет команду по адресу 0, а на самом деле он исполняет инструкцию по адресу 0С000h. Чтобы внутренний адрес (счетчик команд), что в процессоре, привести в соответствие с адресом выполняемой команды, для этого и делается команда перехода. С этого момента старшие биты уже можно не устанавливать принудительно.

неблокирующее присваивание в verilog

По факту, похоже я недогоняю почему в следующем коде d поменяет значение на 30-й единице времени а не двадцатой:

initial begin

        c = 1'b1;

        d = 1'b0;

        #10 c <= 1'b0;

        d <= #20 c;

end


Т.е. получается два последних переноса выполняются последовательно, а не «конкурентно», как было сказано про неблокирующие присваивания.

Квантовые компьютеры. Кажется это уже было

Не могу сказать, что я понимаю архитектуру будущих квантовых компьютеров. Пожалуй все я я знаю это то что они будут использовать т.н. суперпозицию квантовых состояний (одновременное нахождение в нескольких состояниях) для параллельных вычислений и тем самым добивается (в теории) ускорения на порядки как минимум некоторых оптимизационных задач. И знаете что? А ведь такие задачи уже сейчас можно ускорить на порядки (практически мгновенно — со скоростью света), с помощью примитивного аналогового компьютера, который, к слову, был доступен еще до появления цифровых компьютеров. Хотите. например найти оптимальный путь на кaрте. Не проблема. C помощью обычный резисторов строите эквивалентную схему. Ответ через какую точку проходит оптимальный путь даст нам обычный вольтметр. Я часто замечал как компьютер призадумывается чтобы проложить оптимальный путь. А электрической схеме из резисторов требуется всего лишь время для прохождения света из одного конца в другой. Как свет и электричество решает эту задачу так быстро? Ответ: c помощью той же суперпозии всех возможных путей света. Выходит что обычная схема из резисторов это уже квантовый компьютер, причем доступный нам давным давно.

Интерференция в клеточном автомате. Причины неудачи

В очередной раз потерпел фиаско, пытаясь смоделировать интерференцию с помощью клеточного автомата. Но в этот раз стала понятна причина. Пытаясь понять почему, я построил дерево, показывающае вклад каждой ячейки в каждую через n шагов:

data Expr a = At !Index  | PlusMul [(a, Expr a)]

Cтрою его с помощью следующего шага:

step = do cur <- at

          left <- atLeft

          right <- atRight

          return $ PlusMul [((1/3), cur), ((1/3), left), ((1/3), right)]

step это контекстная функция (читалка) которая строится из примитивных читалок at, atLeft, atRight. Она принимает текущий контекст (тек позицию и ее значение,  значение соседей) и возвращает новое значение для текущей позиции. (Другими словами это т.н. reader монада). 

Применяя этот шаг ко всем ячейкам многократно, мы тем самым строим деревья. Например, чтобы применить два раза ко всем ячейкам я делаю это следующим образом:

initial `coBindZ` step `coBindZ` step 

(initial тут изначальный контект состоящих из ...,At -1 At 0, At 1,... а название coBind как бы должно нам намекать что контекст это комонада)

В принципе, этого можно было и не делать, так как, взглянув на структуру дерева и то как оно строится уже становится понятна причина неудачи. Дело в том что, несмотря на то что одни ячейки могут встречаться в дереве чаще других, любой отдельный путь до любой ячейки в дереве равнозначный и одинаковой длины.Если бы мы хотели чтобы какие-то пути с помощью фаз взаимогасились, то нам нужны были бы разные фазы. А здесь разнице фаз просто неоткуда взятся ввиду равнозначности всех путей.

Read more...Collapse )

Неожиданный выбор между IntMap, Map HashMap и Array в haskell

Долго мучался выбирая между различными реализациями словарей в плане производительности операции объединения с функцией. Хотел для каждого (key,value) плодить маленькие локальные мапы, с последующим объединением. Своего рода, моноид. Но затем, неожиданно решил, что используя обратное отображение - окружения (соседних элементов) в текущую ячейку, будет проще с производительностью. и выбрал комонаду ZipList a = MkZip [a] !Int [a] вместо словарей. Посмотрим, действительно ли это проще и производительнее. Фактически это функциональный аналог указателей с дешевыми инкрементами.  


шкала давления - ноль или один

Вот что меня сбивает с толку, так это шкала давления в барах. Когда пишут что выпускной клапан открывается при 1.3 бара, а впускной открывается при 0.10, значит ли это что на монометре я увижу не 1.3 бара, а 0.3 бара (минус атмосферное давление снаружи)?


barell shifter в logisim

Ранее я постил реализацию сдвига вправо на верилоге. Но нашел у себя в архиве более раннюю свою реализацию в logisim.
В отличии от реализации в прошлом посте, в этой реализации  есть сдвиг в обе стороны. Причем без дублирования логики сдвига.


'