vak: (Default)
Товарищи взялись заменить Verilog на Python. Проект называется Amaranth. Есть отдельный симулятор.

Проект на Гитхабе: amaranth-lang/amaranth

Есть несколько реализаций процессора RISC-V на Amaranth.
vak: (Знайка)
Свет не сошёлся клином на Altera и Xilinx. Немецкая фирма Cologne Chip производит FPGA собственной архитектуры под названием GateMate. Olimex выпускает платы для разработчиков GateMateA1-EVB по цене от 50 евро.

Народ запихнул в эту FPGA процессор 8080 и запустил на нём древнюю игрушку Space Invaders. Исходники на Верилоге: gitlab.com/x653/spaceinvaders-fpga

vak: (Default)
Я как-то упоминал про Fractran, а вот народ реализовал его в хардвере. Написано на языке Clash, который по сути специализированный Хаскель. Превращается в Verilog и дальше может быть загружено в FPGA, к примеру.

Исходники: github.com/jleightcap/tt07/blob/main/docs/info.md
vak: (Default)
Раз уж оригинальный Z80 приказал долго жить, народ решил изваять оперсорсный аналог. Исходники на Verilog с открытой лицензией. Цель проекта - разработать замену Z80 в 8-битных домашних компьютерах, таких как ZX Spectrum. Первое изготовление клона Z80 запланировано на июнь 2024 года.



Исходники: github.com/rejunity/z80-open-silicon
module z80 (
    input  wire         clk,
    input  wire         cen,
    input  wire         reset_n,
    input  wire         wait_n,
    input  wire         int_n,
    input  wire         nmi_n,
    input  wire         busrq_n,

    input  wire [7:0]   di,
    output wire [7:0]   dout,

    output wire [15:0]  A,
    output wire         m1_n,
    output wire         mreq_n,
    output wire         iorq_n,
    output wire         rd_n,
    output wire         wr_n,
    output wire         rfsh_n,
    output wire         halt_n,
    output wire         busak_n
);
Тестбенч у них, правда, совсем никакой. Можно было бы доразвить и погонять реальный код.
vak: (Default)
Народ взялся придумать новый язык на замену Верилогу. Называется Veryl: как бы напоминает Verilog, но с человеческим лицом, улучшенный в сторону Rust. Исходный код транслируется в классический SystemVerilog, причём читабельный.

Если у вас уже имеется Rust, то Veryl устанавливается командой:
cargo install veryl veryl-ls
Создание нового проекта:
veryl new project-name
Сборка проекта:
veryl build
Для прикола можно попробовать нашу любимую мэсм6 на Veryl переписать.
vak: (Default)
Прикольный проект: позволяет программировать микроконтроллер RP2040 на языке Verilog. Для компиляции в Си используется Verilator.

https://github.com/tvlad1234/FakePGA

Так выглядит мигание светодиодом, верхний модуль:
`include "sr_latch.v"
`include "blinker.v"

module top (
input i_clk,
input i_s,
input i_r,
output o_led
);

wire latchQ;
wire latchNotQ;
sr_latch myLatch(i_s, i_r, latchQ, latchNotQ);

wire blinkOut;
blinker myBlinker(i_clk, blinkOut);

assign o_led = blinkOut * latchQ;

endmodule
Сигналы привязываются к ножкам микросхемы посредством файла конфигурации:
// Clock frequency in Hz
CLOCK_FREQ 5000;

// Input mapping
INPUTS
{
ADD_IN{TOP i_s, 14, PULLUP}; // Maps port i_s to GPIO14 and pulls it up
ADD_IN{TOP i_r, 15, PULLUP}; // Maps port i_r to GPIO15 and pulls it up
}

// Output mapping
OUTPUTS
{
ADD_OUT{TOP o_led, PICO_DEFAULT_LED_PIN}; // Maps port o_led to the default LED pin
}
vak: (Default)
Меня давно интересовало, откуда взялись хардверные регистры, главный механизм хранения битов информации. В электронике они обозначаются термином D-flip-flop, по русски часто называют D-триггер. Буковка D в названии значащая, так как существуют флип-флопы и триггеры других видов.

Есть в этом гейте некоторая магия. Дальше )
vak: (Default)
Шпаргалка по установке бесплатной линуксной версии симулятора Questa, бывшего Modelsim. Для чайников: это такая хрень, которая позволяет запускать код, написанный на языке Verilog или SystemVerilog. Или VHDL.

(1) С этого сайта на закладке Individual Files скачиваем пакет "QuestaSetup-21.1.1.850-linux.run".

(2) Делаем файл выполняемым и запускаем. При установке выбираем версию Starter Edition.

(3) Дополнительно ставим нужные линуксные библиотеки: "sudo apt install lsb".

(4) Добавляем папку <dir>/questa_fse/linux_x86_64 в PATH. После этого Modelsim можно вызывать из командной строки.

(5) Вызываем lmhostid, чтобы определить уникальный идентификатор компьютера. Получим одно или несколько значений, каждое из 12 шестнадцатеричных цифр. Нужно только одно значение, любое.
$ lmhostid
lmhostid - Copyright (c) 1989-2019 Flexera. All Rights Reserved.
The FlexNet host ID of this machine is ""e7e664a4555e f96512dc7fc4""
Only use ONE from the list of hostids.
(6) На этом сайте регистрируемся и создаём лицензию "Questa-Intel FPGA Starter Edition". Это бесплатно. В качестве идентификатора выбираем NIC ID и вводим полученное на предыдущем шаге значение. Файл лицензии приходит по email.

(7) Сохраняем файл лицензии и устанавливаем переменную окружения LM_LICENSE_FILE, указывающую его полный путь.

vak: (Default)
Ещё одна удачная книжка про RISC-V: "Inside an Open-Source Processor". Состоит из двух частей:
  • описание архитектуры RISC-V, включая системные регистры;
  • подробное описание реализации 32-битного процессора RISC-V на языке Verilog для программируемой логики.
Исходники процессора находятся здесь: https://github.com/montedalrymple/yrv

vak: (Default)
Небезызвестная китайская фирма Alibaba выложила в открытый доступ исходники четырёх процессоров RISC-V собственной разработки. Всё написано на классическом Верилоге.
  • E902 - 32-битный микроконтроллер с упрощённым 2-стадийным конвейером (PDF).
  • E906 - 32-битный микроконтроллер, полноценный 5-стадийный конвейер.
  • C906 - 64-битный процессор с виртуальной памятью и плавающей арифметикой.
  • C910 - 64-битный процессор с 12-стадийным суперскалярным конвейером (PDF). Многоядерность, запускается Линукс.
vak: (Default)
В прошлый раз я показал демо с двумя процессами, работающими параллельно, но без всякого взаимодействия. Давайте теперь добавим взаимодействие. Введём понятие сигнала. Поскольку я веду дело к моделированию цифровой логики, такой термин будет в самый раз.

Сигнал это по сути переменная, значение которой процессы могут использовать или изменять. С точки зрения хардвера сигнал состоит из одного или нескольких битов (в нашем случае до 64 битов). Но самое полезное в концепции сигнала - что процессы могут реагировать на его изменение. Обычно в моделировании каждый процесс определяет значение одного сигнала (выход), и при этом использует значения других сигналов (входы). Когда сигнал изменяет значение, процессы, чувствительные к нему, разблокируются и получают возможность перевычислить свои выходы.

Введём класс signal_t, реализующий сигналы. Создавать сигналы будем в виде глобальных переменных. Все процессы могут ссылаться на нужные им сигналы. Каждому сигналу дадим имя в виде строки - пригодится при отладке. Вторым аргументом конструктора сигналу можно присвоить начальное значение (необязательное). По умолчанию это ноль. Текущее значение сигнала можно опросить методом get(). Вот пример создания четырёх сигналов:
signal_t clk("clock");     // Синхросигнал
signal_t reset("reset"); // Общий сброс
signal_t enable("enable"); // Сигнал разрешения для счётчика
signal_t count("count"); // 4-битный счётчик
В предыдущем посте упоминался процесс - генератор синхросигнала. Вот он в законченном виде. Метод simulator::set() изменяет значение нужного сигнала на указанное значение.
co_void_t do_clock(simulator_t &sim)
{
for (;;) {
sim.set(clk, 1);
co_await sim.delay(1);
sim.set(clk, 0);
co_await sim.delay(1);
}
}
Но установка значений сигналов это еще не взаимодействие процессов. Взаимодействие начинается, когда процессы реагируют на изменение сигналов. Каждый процесс определяет для себя, какие сигналы его интересуют, и по какому фронту: переднему, заднему или обоим.

Введём класс sensitivity_t, каждый объект которого будет привязывать один сигнал к одному (текущему) процессу, по заданному фронту. Если нужна чувствительность к нескольким сигналам - процесс вправе создать несколько таких привязок.

Вот пример реализации 4-битного синхронного счётчика, со сбросом и сигналом разрешения. Как традиционно принято в цифровой логике, счетчик изменяет значение по переднему фронту синхросигнала:
co_void_t do_counter(simulator_t &sim)
{
sensitivity_t hook(sim, clk, POSEDGE);
for (;;) {
co_await co_await_t{};
if (reset.get() != 0) {
sim.set(count, 0);
} else if (enable.get() != 0) {
sim.set(count, (count.get() + 1) & 15);
std::cout << '(' << sim.time() << ") Increment Counter " << count.get() << std::endl;
}
}
}
Для знакомых с языком Verilog - вышеуказанная процедура в точности соответствует следующему коду на Верилоге:
always @(posedge clk)
if (reset)
count <= 0;
else if (enable)
count <= (count + 1) & 15;
Также нам понадобится управляющий процесс, чтобы сформировать сигналы сброса и разрешения:
co_void_t master(simulator_t &sim)
{
std::cout << '(' << sim.time() << ") Started" << std::endl;
co_await sim.delay(10);
sim.set(reset, 1);
std::cout << '(' << sim.time() << ") Asserting Reset" << std::endl;
co_await sim.delay(20);
sim.set(reset, 0);
std::cout << '(' << sim.time() << ") De-Asserting Reset" << std::endl;
co_await sim.delay(10);
std::cout << '(' << sim.time() << ") Asserting Enable" << std::endl;
sim.set(enable, 1);
co_await sim.delay(40);
std::cout << '(' << sim.time() << ") De-Asserting Enable" << std::endl;
sim.set(enable, 0);
std::cout << '(' << sim.time() << ") Terminating simulation" << std::endl;
sim.finish();
}
Главная программа создаёт три процесса и запускает симуляцию:
int main()
{
simulator_t sim;
sim.make_process("clock", do_clock);
sim.make_process("counter", do_counter);
sim.make_process("master", master);
sim.run();
}
Компилируем и запускаем:
$ make demo2
g++-10 -std=c++20 -fcoroutines -c demo2.cpp
g++-10 -std=c++20 -fcoroutines -c simulator.cpp
g++-10 -std=c++20 -fcoroutines demo2.o simulator.o -o demo2
$ ./demo2
(0) Started
(10) Asserting Reset
(30) De-Asserting Reset
(40) Asserting Enable
(40) Increment Counter 0
(42) Increment Counter 1
(44) Increment Counter 2
(46) Increment Counter 3
(48) Increment Counter 4
(50) Increment Counter 5
(52) Increment Counter 6
(54) Increment Counter 7
(56) Increment Counter 8
(58) Increment Counter 9
(60) Increment Counter 10
(62) Increment Counter 11
(64) Increment Counter 12
(66) Increment Counter 13
(68) Increment Counter 14
(70) Increment Counter 15
(72) Increment Counter 0
(74) Increment Counter 1
(76) Increment Counter 2
(78) Increment Counter 3
(80) De-Asserting Enable
(80) Terminating simulation
Исходники можно взять здесь: https://github.com/sergev/simulation-with-coroutines
vak: (Default)
В языке Rust есть интересная фича: кооперативная многозадачность, реализованная в форме async/await и future. Интересно, можно ли на её основе сбацать простой симулятор цифровой логики. Когда-то я сделал такое на простом Си ("Симулятор RTL - это очень просто"). Но в Си пришлось задействовать setjmp/longjmp для переключение потоков, а тут вроде всё нужное прямо в языке дано.

Имеется хорошая статья, объясняющая подробности кооперативной многозадачности в Русте: https://os.phil-opp.com/async-await/
vak: (Default)
Вячеслав Овсиенко закончил реверс-инжиниринг процессора 1801ВМ2. Исходный код и скрипты для сборки находятся здесь: https://github.com/1801BM1/cpu11/tree/master/vm2

Процессор К1801ВМ2 имеет архитектуру DEC PDP-11, включая расширенный набор команд EIS. Он был разработан в 1982 году, и на нём выпускались компьютеры ДВК-3 и УКНЦ.

vak: (Default)
Я тут по жизни вращаюсь промеж разработчиков RTL, и по моим наблюдениям, среди профессионалов предпочитающие VHDL встречаются примерно один к десяти.

Двадцать лет назад один чувак провёл забавное соревнование: нашёл добровольцев-разработчиков и дал им реальное задание на время. Девять человек писали на Verilog, пять на VHDL. Надо было за 90 минут сделать загружаемый 9-битный счётчик с инкрементом на 3, декрементом на 5, четностью и переносом.

http://www.angelfire.com/in/rajesh52/contest.html

Из девяти писавших на Verilog один не уложился в отведённое время, трое выдали дизайн, который не прошёл тесты, и пятеро произвели вполне функциональный результат.

Ни один из предпочёвших VHDL не справился с задачей.

В то время, в 1997 году, Verilog и VHDL выглядели инструментами более-менее сравнимого уровня. Но в 2002 году изобрели SystemVerilog, и чаша весов необратимо перевесила.

vak: (Default)
TinyFPGA - плата FPGA на основе чипа Lattice iCE40 LP8K. В качестве софта используется Yosys, Verilog-синтезатор с открытыми исходными текстами. Плату можно купить за $55 на Ebay.



Вот так выглядит пример мигания светодиодом:



В чипе FPGA имеется 7680 элементарных ячеек (LUT4 плюс триггер) и 16 килобайт блочной памяти. В принципе, должно хватить для МЭСМ-6 в минимальной конфигурации.

Интересно, что в качестве среды программирования задействован редактор Atom. Может быть и нам такой подход сгодится.
vak: (Default)
МЭСМ-6 уже проходит несколько тестов: работают команды uj, vtm, utm, mtj, vzm, v1m, j+m, vjm, vlm, utc, wtc.

Я добавил в фазу decode автоматическое приращение счётчика команд (PC), теперь некоторые команды выполняются за один такт (vtm, utm, mtj. j+m).

Описание микроархитектуры по мере разработки постепенно образуется на странице: https://github.com/besm6/mesm6/wiki/Microarchitecture
vak: (Default)
Процессор МЭСМ-6 научился извлекать команды из памяти, и уже пытается их выполнять. На скриншоте показана трассировка выполнения первой пультовой программы. Серым цветом показаны микрокоманды, зелёным - изменение состояния регистров, коричневым - команды БЭСМ-6. Пока все команды выполняются как NOP.

vak: (Default)
Платформа состоит из основной платы DE10-Nano ($130) и нашлёпки Super Expansion Board ($60).

На плате DE10-Nano стоит FPGA Intel CycloneV 5CSEBA6U23I7 со встроенным 2-ядерным процессором ARM Cortex-A9. Плюс гигабайт памяти DDR, micro-SD, порты HDMI, Ethernet, USB, ADC.



Дополнительная плата DE-10 Super Expansion Board добавляет часы реального времени, разъём VGA, 32 мегабайта статической памяти, порты VGA и аудио, ещё одну micro-SD и вентилятор.



Исходники и документация лежат на Гитхабе: https://github.com/MiSTer-devel/Main_MiSTer/wiki

Вот пример реализации БК-0011 на этой платформе: https://github.com/MiSTer-devel/BK0011M_MiSTer
vak: (Default)
Надыбал исходные коды микропрограммной реализации процессора ZPU: github.com/sergev/zpu-avalanche

Надо прикинуть, сложно ли будет переделать его на 24-битный размер команды и 48-битное слово.

"The ZPU is a very small, 32-bit processor, advertised by the developer Zylin as “the worlds smallest 32-bit CPU with GCC toolchain” [14]. The hardware description is licensed under a FreeBSD license and the software under the GNU General Public License (GPL). Both license models offer free redistribution and adaption of the sources, which is a prerequisite for modifications of the design.

The architecture of one ZPU Core is shown in Figure 2. It consists of only three main components: 1. The control and execution unit Execute does the instruction execution and address calculation; 2. The instruction decoder Decode x4 which fetches up to four instructions for decoding; 3. The stack registers Stack A and Stack B where two words from the main memory (Memory) stack are temporarily stored. The ZPU is a stack-based architecture; apart from Stack A and Stack B the ZPU has no further registers. Every calculation is done by first fetching the appropriate words sequentially from the stack to the registers and then executing the instruction. Afterwards the result is written back to main memory. Although the internal execution has several stages, no pipelining is present. This simplifies the control logic because no hazards can occur."

(из статьи "Designing and Manufacturing of Real Embedded Multi-Core CPUs: A Holistic Teaching Approach in Computer Architecture")