?

Log in

LiveJournal for Vadim Radionov.

View:User Info.
View:Friends.
View:Calendar.
View:Memories.
You're looking at the latest 20 entries. Missed some entries? Then simply jump back 20 entries.

Sunday, February 19th, 2017

Subject:Конвертация объектника для симуляции в верилог
Time:8:31 am.
Оказывается, в утилите objcopy есть прекрасный флажок: -O verilog позволяющий преобразовать elf формат в вид пригодный
для загрузки в верилог с помощью $readmemh задачи.

скажем мы хотим просимулировать следующий код в верилог:

void test() {
int arg1 = *((int *)0x100);
int arg2 = *((int *)0x104);
*((int *)0x108) = arg1 + arg2;
}

Функция читает два слова по адресу 0x100 и 0x104, суммирует их и записывает результат по адресу 0x108.
В качестве платформы для которой мы будем испытывать симуляцию выберем RISC V, поэтому наш Makefile будет выглядеть следующим образом:

OBJCOPY := riscv32-unknown-elf-objcopy
GCC := riscv32-unknown-elf-gcc

code.hex: test.o
$(OBJCOPY) -O verilog test.o code.hex
test.o: test.c
$(GCC) -O3 -c test.c
После сборки, code.hex будет выглядеть следующим образом:

@00000000
03 27 40 10 83 27 00 10 B3 87 E7 00 23 24 F0 10
67 80 00 00

Здесь содержатся две команды lw, команда add, и команды sw и ret (jalr zero, 0(ra)).

Для наглядности, вот вывод команды objdump для test.o:

00000000 <test>:
0: 10402703         lw a4,260(zero) # 104 <test+0x104>
4: 10002783         lw a5,256(zero) # 100 <test+0x100>
8: 00e787b3         add a5,a5,a4
c: 10f02423         sw a5,264(zero) # 108 <test+0x108>
10: 00008067         ret

Чтобы просимулировать этот код, в верилог мы загружаем code.hex,
устанавливаем PC в ноль, а регистр возврата ra инициализируем значением EXIT_ADDR (0x400).
Загружаем начальные значения в память по адресам 0x100 и 0x104. Затем запускаем на выполнение и вычитываем результат
из памяти по адресу 0x108:

initial begin
$readmemh(PROGRAM_FILE, MEM);
PC = 0;
R[1] = EXIT_ADDR;
write_mem('h100,3);
write_mem('h104,5);
while (PC <= 'h10)
  begin
    fetch;
    execute;
  end
$display("PC = %h", PC);
$display("result = %d", read_mem('h108));
$finish;
end

Здесь выше представлена высокоуровневая поведенческая модель (вернее ее часть с циклом). Для синтезирования она не годится, а вот для проверки правильности нашего понимания ISA очень даже годится.

Вот результат выполнения симуляции:

fetch: IR = 10402703
fetch: IR = 10002783
fetch: IR = 00e787b3
fetch: IR = 10f02423
fetch: IR = 00008067
PC = 00000400
result =          8

Как видим, результат правильный: 3+5=8. PC принимает значение EXIT_ADDR.
Comments: Read 3 orAdd Your Own.

Wednesday, February 1st, 2017

Subject:сложение когда нет регистра с флагами и переносом
Time:8:23 am.
Решил проверить как на 32 битном Risc V (riscv32i) выглядит сложение 64битных чисел:

   0: 00050793         mv a5,a0
 4: 00c50533         add a0,a0,a2
 8: 00f537b3         sltu a5,a0,a5
 c: 00d585b3         add a1,a1,a3
10: 00b785b3         add a1,a5,a1


Дело в том, что на riscv нет статусного регистра с хранимым переносом, поэтому нет команды adc. Вместо нее используется sltu и дополнительный add. Как я понимаю, на MIPS тоже самое.
Непривычно, конечно. Но говорят, что отсутствие флагов упрощает реализацию высокопроизводительных микроархитектур.
Кстати, как и отсутствие branch delay slot'ов.
Comments: Add Your Own.

Saturday, December 31st, 2016

Subject:считаем биты, номер младшей и старшей единицы
Time:1:28 am.
В этот раз вроде работает правильно:


mbc = 0x12131210
hbc = 0xffffaa50
cbc = 0x3ee9e994
> print "val,\tmb,\thb,\tcb"
> for val in range(16):
>     mb = (mbc >> (val << 1)) & 3
>     hb = (hbc >> (val << 1)) & 3
>    cb = (cbc >> (val << 1)) & 3
>    print bin(val),"\t", bin(mb),"\t", bin(hb),"\t",cb

val, mb, hb, cb
0b0  0b0  0b0  0
0b1  0b0  0b0  1
0b10  0b1  0b1  1
0b11  0b0  0b1  2
0b100  0b10  0b10  1
0b101  0b0  0b10  2
0b110  0b1  0b10  2
0b111  0b0  0b10  3
0b1000  0b11  0b11  1
0b1001  0b0  0b11  2
0b1010  0b1  0b11  2
0b1011  0b0  0b11  3
0b1100  0b10  0b11  2
0b1101  0b0  0b11  3
0b1110  0b1  0b11  3
0b1111  0b0  0b11  0

Comments: Add Your Own.

Sunday, December 25th, 2016

Subject:магия цифр или симуляция с помощью lut
Time:9:50 pm.
если я правильно понял, то следующая формула найдет самую младшую единицу в четырех мл. разрядах x и подсчитает ее смещение

x = x & 0xf;
shift = (0xf4 >> x) & 1 | (((0xe >> x) & 1) << 1);

Самое забавное это то как я получил ее:

написал логику на verilog, затем с помощью yosys синтезировал в схему с использованием lut'ов. Результат записал обратно в verilog. Откуда и взял константы для формулы:
Comments: Read 3 orAdd Your Own.

Wednesday, December 14th, 2016

Subject:связывание разделяемых библиотек
Time:10:57 am.
Проверил свою догадку: если брать адрес функции malloc, или любой функции из сторонней библиотеки,
то в каждой библиотеке этот адрес функции malloc будет различным.
Действительно, так и есть. Адрес указывает на внутренности секции .plt. своей библиотеки или исполняемого модуля.

Это чтобы минимизировать таблицу переразмещений.
Comments: Add Your Own.

Sunday, October 16th, 2016

Subject:оптимальная схема быстрого сдвига для FPGA
Time:10:13 am.
Эту схему еще называют barrel shifter.

Ее можно делать на 2:1 мультиплексерах. При этом требуется log2(width) слоев из мультиплексоров.
Второй способ предлагает использовать 4:1 мультиплексоры. В этом случае соседние слои объединяются в один.
Хорош он тем, что идеально ложится на ПЛИС, где используются 6-ти входовые таблицы преобразования (LUT).
Но вот у меня в хозяйстве имеется Cyclone IV, построенный на 4-х входовых таблицах (LUT).
Для 4:1 мультиплексора этого мало, а для 2:1 мультиплексора идеальным была бы 3-x входовая таблица. Один вход получается незадействован. А значит и вся схема будет ложиться на Cyclone IV менее чем оптимально.

Интересно, можно ли реализовать это схему более оптимально на 4-x входовых таблицах?

Моя текущая реализация на verilog под катом:


Read more...Collapse )
Comments: Add Your Own.

Thursday, October 6th, 2016

Subject:распараллеливание Load/Store и DataOp
Time:8:30 am.
RISC процессор разделяет команды загрузки/сохранения из памяти с обычными командами,
Казалось бы эти независимые местами команды можно исполнять параллельно, Поскольку загрузка и сохранения требует дополнительный цикл для своей работы, второй цикл можно нагрузить выполнением следующей команды. Однак RISC процессор не такой. Он использует тот же исполнительный блок что и все команды, поэтому вместо параллельного исполнения получаем остановку конвеера на один и больше циклов.
Как решить это проблему? Нужно для Load/Store добавить второй исполнительный блок. И заодно поломать себе голову чем его загрузить в остальные моменты (гипертрединг?)
Comments: Add Your Own.

Subject:Автомат Мура - чистая академщина?
Time:7:06 am.
В  теории цифровых автоматов всегда рассказывают про два вида автоматов: Мура и Мили.
Однако непонятно кто в здравом уме станет делать схему с большим числом состояний и циклов. Где нужные сигналы приходят с задержкой в один такт. Поэтому автомат Мура отдает какой-то академщиной.
Это все равно что рассказывать про ресурсивное вычисление чисел фибоначи.
Comments: Add Your Own.

Monday, September 26th, 2016

Subject:RISC I и СALLINT
Time:8:47 am.
В архитектуре RISC I есть одна странность. Называется она окном регистров. Всего там 6-ть окон. Так что при большей вложенности возникает исключение. Но что характерно, CALLINT который вызывает обработчик прерывания, тоже нуждается в сдвиге окна. Как они разрешили эту коллизию совершенно непонятно.
Comments: Add Your Own.

Sunday, June 26th, 2016

Subject:синтезируемость $readmemb в verilog
Time:10:04 pm.
Бытует распространненое заблуждение, что следующая конструкция на verilog не синтезируемая, и работает только в симуляторе:

initial
begin
  $readmemb("single_port_rom_init.txt", rom);
end

Враки все это. Еще как синтезируема. Только что опробовал на fpga. Естественно, сама прошивка из файла не читает, это инструкция для синтезатора. (а не только для симулятора). Тоже самое работает и для ram. Собственно, rom внутри fpga это как раз ram только запись не используется.
Comments: Add Your Own.

Saturday, June 25th, 2016

Subject:rtl coding style
Time:9:28 pm.
Люди в отрасли подкинули интересную ссылку:

https://www.doulos.com/knowhow/vhdl_designers_guide/rtl_coding/

Правда, к идее описывать "что", а не "как", пришел задолго до этого. Приятно, было увидеть в статье именно мультиплексор в качестве примера. У меня же таким примером был демультиплексор. :)
Comments: Add Your Own.

Sunday, June 19th, 2016

Subject:простейший двоичный калькурятор на светодиодах
Time:8:10 pm.
Сделать из платы DE0-Nano калькулятор надо еще постараться. Из штатных средств там только 4 dip переключателя, две push кнопки. И восемь светодиодов.
Конечно, есть еще всякие ножки к которым можно подключить что угодно, вплоть до клавиатуры и vga, но тут без паяльника не обойтись.


Процессора тоже нет. Ибо это голый fpga. Что хочешь то и лепи из него. Хоть Risc процессор. Но не будем спешить с risk процессором, оставим это занятие на закуску и попробуем сделать все с нуля:

Read more...Collapse )


Вот и все. Не так сложно, правда? И мы подобрались на один шаг ближе к созданию своего универсального процессора. :)
Comments: Add Your Own.

Monday, June 13th, 2016

Subject:прямое управление счетчиком на fpga с помощью кнопок
Time:9:31 am.
В руководстве к DE0-Nano сказано, что кнопки (их там две) избавлены от дребезга (через специальную микросхему) и поэтому могут быть использованы в качестве источника тактов.
Например, можно сделать инкрементирование счетчика при нажатии на одну из кнопок и сброс по другой:
(кнопки инвертированны, когда отжаты, дают лог. единицу)

reg [2:0] counter;

always @(negedge KEY[0] or negedge KEY[1])
   if (~KEY[0])
     counter <= 1'b0;
   else
     counter <= counter + 1'b1;

Этот пример работает  только потому что только одна из кнопок служит источником тактов, а другая лишь сбрасывает (ассинхронно) состояние.
Но если мы захотим по второй кнопке делать декремент, вещи становятся намного сложнее. Потому что теперь вход
будет зависеть от того какую кнопку мы нажали, и если кнопки будут еще и служить часами то стабильный сигнал на вход будет приходить слишком поздно по отношению к фронту тактирующего сигнала.
Я так и не нашел способа, не используя третий источник тактов, как реализовать это. Хотя на verilog все смотрится логично, на реальном железе это работать не будет. Потому что там для триггеров есть такое понятие как setup и hold время. Не соблюдая которое схема работать не будет.

Пришлось вернуться к использованию CLOCK_50 (так называется вход куда подается сигнал тактирующего генератора на 50Mh)
При этом фронт сигналов от кнопок отлавлиется уже по другому:

reg key_pressed;
reg key_pressed_prev;
wire key_clicked;

assign key_clicked = key_pressed &  ~key_pressed_prev;

always @(posedge CLOCK_50) begin
  key_pressed <= ~key;
  key_pressed_prev <= key_pressed;
end

Здесь используются два триггера соединенных последовательно. Это позволяет иметь два состояния кнопки разделенных во времени в один такт.

Проделывая это для двух кнопок мы будем иметь два сигнала: key_0_clicked и key_1_clicked, которые можно использовать
для управления счетчиков:

reg [2:0] counter;

always @(posedge CLOCK_50)
  if (key_0_clicked)
     counter <= counter - 1'b1;
  else if (key_1_clicked)
    counter <= counter + 1'b1;

Вот и все. Правда, по прежнему остается риск словить метастабильное состояние в триггерах читающих состояние кнопки.
Мне кажется, в худшем случае такое нажатие будет просто проигнорированно. Что в о общем-то не страшно. Поскольку и без этого бывает нажимаешь не в удачном месте и кнопка не срабатывает.
Comments: Add Your Own.

Saturday, June 11th, 2016

Subject:мой первый цифровой дизайн для пощупать :))
Time:8:39 pm.
доупрощал свой первый живой пример для DE0-Nano fpga платы до следующего состояния:

module light (SW, LED);
 input [3:0] SW;
 output [7:0] LED;
   
 assign LED = SW[0] << SW[3:1];
endmodule

И что характерно работает. Три переключателя говорят где светить. Четвертый говорит а светить ли вообще.
Время реакции порядка 6нс. Самый быстрый интерактивный дизайн. :))
Comments: Add Your Own.

Subject:компактность и читаемость в verilog
Time:1:28 pm.
Не будет сюрпризом узнать что для повышения читаемости кода приходится жертвовать компактностью. Но оно того стоит.

Следующие в конце два фрагмента на verilog описывают одно и тоже - демультиплексор. Но второй вариант ближе к описанию того, что мы хотим собственно.
(правда, изменив немного интерфейс, второй вариант можно сократить на две строки)

Как я понимаю, компилятор второй вариант превращает в первый. Оба варианта, на fpga от аltera (Cyclon IV), занимают ровно восемь логических элемента LE (которые содержат внутри LUT (lookup table) на три четыре входа)

// вариант 1
...
 assign f1 = x1 & ~x2 & ~x3 & ~x4;
 assign f2 = x1 & x2 & ~x3 & ~x4;
 assign f3 = x1 & ~x2 & x3 & ~x4;
 assign f4 = x1 & x2 & x3 & ~x4;
 assign f5 = x1 & ~x2 & ~x3 & x4;
 assign f6 = x1 & x2 & ~x3 & x4;
 assign f7 = x1 & ~x2 & x3 & x4;
 assign f8 = x1 & x2 & x3 & x4;
...
// вариант 2

 assign sel = {x4,x3,x2};
 always @*
    case (sel)
       3'b000: out = { 7'b0, x1 };
       3'b001: out = { 6'b0, x1, 1'b0 };
       3'b010: out = { 5'b0, x1, 2'b0 };
       3'b011: out = { 4'b0, x1, 3'b0 };
       3'b100: out = { 3'b0, x1, 4'b0 };
       3'b101: out = { 2'b0, x1, 5'b0 };
       3'b110: out = { 1'b0, x1, 6'b0 };
       3'b111: out = { x1, 7'b0 };
       default: out = 8'bx;
     endcase
   
 assign {f8, f7, f6, f5, f4, f3, f2, f1} = out;
Comments: Read 5 orAdd Your Own.

Monday, May 9th, 2016

Subject:старый добрый 8080 (он же 580вм) и как работает mov
Time:9:23 am.
Открыл для себя оригинальное руководство интел по процессору 8080. До этого сталкивался только с отечественной литературой по аналогу (580). Очень толково расписано. Вплоть до того, что и на каком такте происходит.
Вот например, мне непонятно было почему простая операция mov (01 ddd sss) занимает столько тактов.

И вот объяснение:
1 такт: извлекаем инструкцию из памяти
2 такт: инкрементируем pc
3 такт: копируем инструкцию во временный регистр (TMP/IR)
4 такт: копируем регистр sss во временный регистра TMP
5 такт: копируем из временного регистра TMP в ddd

Причем микроархитектура, похоже, такова что нельзя в одном такте читать и писать в регистр (однопортовый регистровый файл?)

И почему нельзя инкрементировать pc и извлекать из регистра в одном такте? Общая внутренняя шина?
Comments: Add Your Own.

Friday, May 6th, 2016

Subject:первый fpga для ознакомления
Time:11:24 pm.
Прям не знаю что и выбрать. Хочется уже поиграться с цифровым дизайном в железе. Нашел два варианта для начала. Может попробовать Панчула в штатах выцепить (планирую посетить долину на недельку в конце месяца). Вдруг посоветует что-нибудь.

https://raspberry.com.ua/p/de0-nano-altera-cyclone-iv-fpga…/
https://raspberry.com.ua/p/mojo-fpga-development-board/
Comments: Add Your Own.

Tuesday, December 22nd, 2015

Subject:грабли при программировании в chromium
Time:6:14 pm.
Дважды натыкаюсь на одни и те же грабли. В результате, выработал правило:
никогда не вызывай инлайн метод за пределами либы (.a), к которую входит класс.
Наверняка собираются они с разными флагами. И не факт что поле находится по тому же адресу.
Хуже всего, что, кажется, этому правилу код chromium сам не следует. Помнится получил креш, когда WebContents пытался обратиться к кешу дергая inline метод из net либы. Метод тупо возвращал ноль, хотя поле было не нулевым. Перенес в .сс и все стало нормально.
Comments: Add Your Own.

Sunday, December 20th, 2015

Subject:изучая Lenses в haskell
Time:11:15 am.
Если использовать Lenses в сочетании со state monad (не путать с costate comonad),
то код выглядит как типичная императивная программа с мутабельными полями. Правда, работает оно менее эффективно.

https://github.com/ekmett/lens/blob/master/examples/Pong.hs

каждая модификации одного поля приводит к создании новой полной копии. А если надо обновить все поля, то копий будет в n раз больше.

Перефразируя старый прикол про lisp, получится, что каждая достаточно большая хаскель программа содержит в себе половину корявого интерпретатора Си.

Шутки, шутками, но Lense действительно позволяет элегантно и легко получать модифицированные копии древовидных структур.
Comments: Read 3 orAdd Your Own.

Wednesday, September 17th, 2014

Subject:java: комбинаторы вместо лямбды
Time:9:55 am.
Все джависты наверное знают, что в 8-ой джаве появились лямбды. Дело конечно хорошее, но вот лично мне так и не довелось их использовать в java. Во первых, потому что включен режим совместимости с 1.6, во вторых я нашел в проекте лучший способ. Я использую комбинаторы для построения геттеров (из более простых геттеров).
Что это дало в отличии от лямбды.
1) не порождается новый класс на каждый чих.
2) построенные с помощью комбинаторов геттеры умеют рапортовать, что они делают и в каком месте что-то пошло не так.
Как следствие, геттеры + комбинаторы просто идеальны для построения валидаторов респонсов, когда требуется не только провалидировать, но и еще сгенерировать репорт.

пример:

один из наших валидаторов в рапорте представляет себя вот так:

 metaInfo . entries . (first with key == "bla-bla-bla") . notEmpty( val )

а вот так конструируется этот геттер:

public static final IGetter<Response, Boolean> notEmptyBlaBlaValue = dot(metaInfo, entries, firstWith( eq(key, "bla-bla-bla")), notEmpty(val));

Я немного подсластил выражение, используя статический импорт для entries, dot, firstWith, eq, key, notEmpty. На самом деле, у себя для геттеров полей я не использую статический импорт, чтобы небыло путаницы скажем между BarGetters.notEmpty и FooGetters.notEmpty. Но для иллюстрации сходства с рапортом я все же отойду от этого правила.

Как видим, даже без лямбды можно строить всякие предикаты, и что характерно, вложенные глубоко в контекст - тоже.
Comments: Add Your Own.

LiveJournal for Vadim Radionov.

View:User Info.
View:Friends.
View:Calendar.
View:Memories.
You're looking at the latest 20 entries. Missed some entries? Then simply jump back 20 entries.