nabbla (nabbla1) wrote,
nabbla
nabbla1

Category:

QuatCore: Hello, World!

Залил этот процессор в ПЛИС 5576ХС4Т1 - и запустил.



РАБОТАЕТ!

Правда, заработала она не с первого раза, заставив меня поволноваться. Уже в субботу к ночи всё было готово, первая прошивка - и чего-то происходит, по UART побежали данные, но какой-то мусор, причём останавливаться он не желал. А сегодня нашёл, в чём была проблема - она была идиотской.

Но начать стоит с доработки модуля UART для QuatCore и описания программы Hello, World...


В прошлый раз модуль вроде бы был готов, но в него закралась ошибка, в одном месте не заменил st на DoStart, из-за чего модуль застревал на месте, если его просили передать следующий байт, а он ещё не передал предыдущий. Я его понимаю - тоже не люблю, когда над душой стоят :) Но поправить всё-таки надо:

`include "math.v"

module QuatCoreUARTtx (input clk, input [7:0] DestAddr, input [15:0] DataBus, output busy, output txd);

 parameter CLKfreq = 4_000_000;
 parameter BAUDrate = 1_000_000;

 localparam sIdle  = 4'b0000;
 localparam sStart = 4'b0110;
 localparam sB1   = 4'b0111;
 localparam sB2     = 4'b1000;
 localparam sB3  = 4'b1001;
 localparam sB4  = 4'b1010;
 localparam sB5  = 4'b1011;
 localparam sB6  = 4'b1100;
 localparam sB7  = 4'b1101;
 localparam sB8  = 4'b1110;
 localparam sStop =  4'b1111;

 wire [3:0] State;
 wire isStopState;
 wire isIdle = (~State[3]) & (~State[2]); //shortcut as not all states are used
 
 wire st = ~DestAddr[7];
 wire DoStart = st & isIdle;
 wire [7:0] Data = DataBus[7:0];
 wire ce;  //count enable
 reg r_ce = 1'b0;
 reg r_set = 1'b0;
 always @(posedge clk) begin
  r_ce <= ce;
  r_set <= ce | DoStart | isIdle;
 end
 
 lpm_counter StateMachine (
    .clock (clk),
    .cnt_en (r_ce),
    .sset (DoStart),
    .q (State),
    .cout (isStopState) );
 defparam
  StateMachine.lpm_direction = "UP",
  StateMachine.lpm_port_updown = "PORT_UNUSED",
  StateMachine.lpm_type = "LPM_COUNTER",
  StateMachine.lpm_width = 4,
  StateMachine.lpm_svalue = sStart;

 localparam DividerBits = `CLOG2(((CLKfreq + BAUDrate / 2) / BAUDrate - 1));
 localparam Limit = (CLKfreq + BAUDrate / 2) / BAUDrate - 2;

 lpm_counter Divider (
   .clock (clk),
   .sset (r_set),
   .cout (ce) );
  defparam
    Divider.lpm_direction = "DOWN",
    Divider.lpm_port_updown = "PORT_UNUSED",
    Divider.lpm_type = "LPM_COUNTER",
    Divider.lpm_width = DividerBits,
    Divider.lpm_svalue = Limit;
       
 reg [8:0] ShiftReg = 9'b1111_1111_1;
 assign txd = ShiftReg[0];

 assign busy = st & (~isIdle);

always @(posedge clk) if (DoStart | r_ce)
  ShiftReg <= DoStart? {Data, 1'b0} : {1'b1, ShiftReg[8:1]};

endmodule



Теперь модуль рабочий. По умолчанию стоят параметры "для отладки", с делением частоты всего в 4 раза, чтобы на симуляторе не приходилось ставить огромные времена моделирования.

Глянем, как он встраивается в общую схему процессора:



Мы его сажаем на шину DataBus и на шину DestAddr, а также от него к счётчику инструкций QuatCorePC идёт провод busy.

Счётчик инструкций мы немножко модернизировали:


Всё изменение состояло в замене одного входа busy на два: ALUbusy и UARTbusy, объединённых по "ИЛИ".

Приведём код программы HelloWorld:

;Hello, world для QuatCore
%include "Win1251.inc"
.rodata
    Hello   Int16 'H','e','l','l','o',',','w','o','r','l','d','!',13,10,'(','f','r','o','m',' ','Q','u','a','t','C','o','r','e',')',-32768
    Wolf    Int16 'П','р','Ю','в','е','т',',',' ','В','О','Л','К','У','!','!','!',-32768
.data
    Stack   dw  ?
.code
    main proc
                    SP      Stack
                    X       Wolf
                    CALL    print
        @@endless:  JMP     @@endless
    main endp
    
    ;X указывает на начало строки текста
    ;конец обозначается отрицательным числом (у нас НЕТ ФЛАГА НУЛЯ!!!)
    ;пока что процедура категорически неряшливая:
    ;меняет значение X и регистра i.
    print proc
                    i       0
        @@start:    Acc     [X+i]   ;не меняет флаг знака
                    SUB     0       ;а вот это меняет!
                    JL      @@finish
                    UART0   Acc
                    i++     0
                    JMP     @@start
        @@finish:   JMP     [--SP]
    print endp



У нас появилась новая директива %include, это "директива препроцессора" - по мере обработки этого файла %include заменяется на содержимое указанного файла. Вот что содержится в Win1251.inc:

;кодировка Win1251 (для общения по UART с компьютером)
;отдельный файл кодировки у нас будет для LCD-экранчика
.data  ;артефакт нашего компилятора - он обрабатывает EQU только внутри DATA-сегмента
    ' '     EQU 0x20
    '!'     EQU 0x21
    '"'     EQU 0x22
    '#'     EQU 0x23
    '$'     EQU 0x24
    '%'     EQU 0x25
    '&'     EQU 0x26
    ''''    EQU 0x27
    '('     EQU 0x28
    ')'     EQU 0x29
    '*'     EQU 0x2A
    '+'     EQU 0x2B
    ','     EQU 0x2C
    '-'     EQU 0x2D
    '.'     EQU 0x2E
    '/'     EQU 0x2F
    
    '0'     EQU 0x30
    '1'     EQU 0x31
    '2'     EQU 0x32
    '3'     EQU 0x33
    '4'     EQU 0x34
    '5'     EQU 0x35
    '6'     EQU 0x36
    '7'     EQU 0x37
    '8'     EQU 0x38
    '9'     EQU 0x39
    ':'     EQU 0x3A
    ';'     EQU 0x3B
    '<'     EQU 0x3C
    '='     EQU 0x3D
    '>'     EQU 0x3E
    '?'     EQU 0x3F
    
    '@'     EQU 0x40
    'A'     EQU 0x41
    'B'     EQU 0x42
    'C'     EQU 0x43
    'D'     EQU 0x44
    'E'     EQU 0x45
    'F'     EQU 0x46
    'G'     EQU 0x47
    'H'     EQU 0x48
    'I'     EQU 0x49
    'J'     EQU 0x4A
    'K'     EQU 0x4B
    'L'     EQU 0x4C
    'M'     EQU 0x4D
    'N'     EQU 0x4E
    'O'     EQU 0x4F
    'P'     EQU 0x50
    'Q'     EQU 0x51
    'R'     EQU 0x52
    'S'     EQU 0x53
    'T'     EQU 0x54
    'U'     EQU 0x55
    'V'     EQU 0x56
    'W'     EQU 0x57
    'X'     EQU 0x58
    'Y'     EQU 0x59
    'Z'     EQU 0x5A
    '['     EQU 0x5B
    '\'     EQU 0x5C
    ']'     EQU 0x5D
    '^'     EQU 0x5E
    '_'     EQU 0x5F
    
    '`'     EQU 0x60
    'a'     EQU 0x61
    'b'     EQU 0x62
    'c'     EQU 0x63
    'd'     EQU 0x64
    'e'     EQU 0x65
    'f'     EQU 0x66
    'g'     EQU 0x67
    'h'     EQU 0x68
    'i'     EQU 0x69
    'j'     EQU 0x6A
    'k'     EQU 0x6B
    'l'     EQU 0x6C
    'm'     EQU 0x6D
    'n'     EQU 0x6E
    'o'     EQU 0x6F
    'p'     EQU 0x70
    'q'     EQU 0x71
    'r'     EQU 0x72
    's'     EQU 0x73
    't'     EQU 0x74
    'u'     EQU 0x75
    'v'     EQU 0x76
    'w'     EQU 0x77
    'x'     EQU 0x78
    'y'     EQU 0x79
    'z'     EQU 0x7A
    '{'     EQU 0x7B
    '|'     EQU 0x7C
    '}'     EQU 0x7D
    '~'     EQU 0x7E
    
    'Ё'     EQU 0xA8
    'ё'     EQU 0xB8
    
    'А'     EQU 0xC0
    'Б'     EQU 0xC1
    'В'     EQU 0xC2
    'Г'     EQU 0xC3
    'Д'     EQU 0xC4
    'Е'     EQU 0xC5
    'Ж'     EQU 0xC6
    'З'     EQU 0xC7
    'И'     EQU 0xC8
    'Й'     EQU 0xC9
    'К'     EQU 0xCA
    'Л'     EQU 0xCB
    'М'     EQU 0xCC
    'Н'     EQU 0xCD
    'О'     EQU 0xCE
    'П'     EQU 0xCF
    'Р'     EQU 0xD0
    'С'     EQU 0xD1
    'Т'     EQU 0xD2
    'У'     EQU 0xD3
    'Ф'     EQU 0xD4
    'Х'     EQU 0xD5
    'Ц'     EQU 0xD6
    'Ч'     EQU 0xD7
    'Ш'     EQU 0xD8
    'Щ'     EQU 0xD9
    'Ъ'     EQU 0xDA
    'Ы'     EQU 0xDB
    'Ь'     EQU 0xDC
    'Э'     EQU 0xDD
    'Ю'     EQU 0xDE
    'Я'     EQU 0xDF
    
    'а'     EQU 0xE0
    'б'     EQU 0xE1
    'в'     EQU 0xE2
    'г'     EQU 0xE3
    'д'     EQU 0xE4
    'е'     EQU 0xE5
    'ж'     EQU 0xE6
    'з'     EQU 0xE7
    'и'     EQU 0xE8
    'й'     EQU 0xE9
    'к'     EQU 0xEA
    'л'     EQU 0xEB
    'м'     equ 0xEC
    'н'     equ 0xED
    'о'     equ 0xEE
    'п'     equ 0xEF
    'р'     equ 0xF0
    'с'     equ 0xF1
    'т'     equ 0xF2
    'у'     equ 0xF3
    'ф'     equ 0xF4
    'х'     equ 0xF5
    'ц'     equ 0xF6
    'ч'     equ 0xF7
    'ш'     equ 0xF8
    'щ'     equ 0xF9
    'ъ'     equ 0xFA
    'ы'     equ 0xFB
    'ь'     equ 0xFC
    'э'     equ 0xFD
    'ю'     equ 0xFE
    'я'     equ 0xFF



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

В итоге, у нашего компилятора очень специфическое понимание одинарной кавычки ('): она лишь заставляет парсер не искать пробелов/табов/ключевых слов между двумя такими кавычками, а воспринимать всё содержимое, включая и сами кавычки, как одну лексическую единицу, а именно - как метку. И разумеется, метка должна быть так или иначе задана - в файле win1251.inc им присвоены числовые значения.

Ещё один плюс - нам совершенно пофигу, в какой кодировке писать сами файлы HelloWorld.asm и win1251.inc, лишь бы эта кодировка была ОДНА И ТА ЖЕ. А дальше что захотим - может UTF8, может юникод-16, или старую добрую 1-байтовую - работать будет.

Смотрим дальше.
.rodata



это уже довольно давнее "приобретение" - read-only data. Поскольку у нас, по счастью, внутри QuatCore нет никакого MMU, сегментов, страниц памяти и прочей хрени - отличие между .data и .rodata "в железе" отсутствует. А вот эмулятор отслеживает, какие ячейки памяти "только для чтения", а какие - нет, и во время отладки грязно выругается, если была произведена запись куда не просят, что иногда позволяет быстро найти проблему.

Hello   Int16 'H','e','l','l','o',',','w','o','r','l','d','!',13,10,'(','f','r','o','m',' ','Q','u','a','t','C','o','r','e',')',-32768



Напомним: директивы Int16 и dw (define word) тоже "в железе" полностью эквивалентны - выделяется по 2 байта памяти. Отличие - в эмуляторе, он отображает содержимое памяти либо как беззнаковое целое (dw) либо как знаковое (Int16). На каждый символ у нас в итоге уходит по 2 байта - так и задумано. Расточительно, зато удобно для нашего 16-битного процессора, которому с отдельными байтами работать тяжеловато, не для того он был разработан. А чуть позже мы найдём применение и старшим 8 битам :)

Одно из них - окончание строки. Опять же, у нас ФЛАГ НУЛЯ в процессоре отсутствует как класс! До сих пор он был нам совершенно без надобности, хватало отношений "больше-меньше" и "переполнение-нет переполнения". И вводить его не хочется, поэтому у нас конец строки будет кодироваться не нулём, а отрицательным числом.

    Wolf    Int16 'П','р','Ю','в','е','т',',',' ','В','О','Л','К','У','!','!','!',-32768


это вторая наша строка, "ПрЮвет ВОЛКУ!!!". Всё то же самое.

.data
    Stack   dw  ?


Нам пока хватает стека на 1 элемент :) Напоминаем, что вопросик - это тоже директива скорее для эмулятора. "Аппаратно" память в любом случае будет инициализирована целиком, и вопросы заменятся нулями. Но если эмулятор попытается прочесть неинициализированную ячейку - то грязно выругается, и это уже помогло мне пару раз в отладке.

Наконец, смотрим программный код. Главная процедура:
    main proc
                    SP      Stack
                    X       Wolf
                    CALL    print
        @@endless:  JMP     @@endless
    main endp



Компилятору плевать на самом деле, как она называется. Просто он начинает заполнять память программ, начиная с нулевого адреса. Вообще, proc/endp имеет удивительно маленькое значение. Они лишь задают область видимости локальных меток (тех, что начинаются с @@), а имя процедуры само служит меткой. И может, самое важное - с данными директивами сам код проще для восприятия человеком.

Раз мы вызываем процедуру print, значит, нужно инициализировать стек, иначе он может затереть нашу строку адресом возврата.
В адресный регистр X помещаем адрес строки, которую хотим "напечатать".
Запускаем процедуру - и после этого застреваем в бесконечном цикле, а что нам ещё делать? Вернуться в операционную систему - вот только у нас нет операционной системы :)

И наконец, смотрим код процедуры print:
    print proc
                    i       0
        @@start:    Acc     [X+i]   ;не меняет флаг знака
                    SUB     0       ;а вот это меняет!
                    JL      @@finish
                    UART0   Acc
                    i++     0
                    JMP     @@start
        @@finish:   JMP     [--SP]
    print endp



Инициализируем индексный регистр i. Загружаем очередной "символ". Сейчас у нас АЛУ устроено так, что загрузка значения в аккумулятор не меняет флаг S (а вот регистра переполнения как такового нет, определяется напрямую из двух старших бит аккумулятора), поэтому чтобы определить, что это уже конец строки - мы вычитаем нолик. Понятно, ничего не изменится, но флаг будет стоять.

Если там отрицательное число - мы выходим из цикла, и возвращаемся из процедуры. Можно было бы придумать команду условного прыжка с абсолютной адресацией, какой-нибудь AJL (Absolute Jump if Less), тогда мы могли бы сразу выйти из процедуры, командой

AJL  [--SP]


но кажется, что это довольно редко бывает полезно. Во всём "аффинном алгоритме" такая возможность не понадобилась ни разу.

Наконец, если это ещё не конец строки, то мы посылаем текущий символ по UART, прибавляем единичку к переменной - и продолжаем цикл.

Данная реализация не позволяет работать со строками длиннее 31 символа, поскольку сейчас ширина всех регистров i,j,k объявлена 5 бит. Это, в принципе, настраивается. Либо можно вместо индекса прибавлять единицу к адресному регистру X, но это сложнее - нужно его загрузить в аккумулятор, прибавить 1 - и загрузить назад.

Весь QuatCore, теперь в комплекте с UART, сейчас занимает 450 ЛЭ. Это при 4-битном PC, но всё-таки 8-битных адресных регистрах. Можно было бы их для Hello,World сократить до 6 бит, и ещё аккумулятор укоротить с 32 бит до 18 бит, получится совсем компактно, но это будет не очень показательно - если уж нам нужен Hello, World, мы бы вообще обошлись без процессора.

Приведём листинг оперативной памяти, RamContents.txt:
Hello:      00   72
Hello[1]:   01   101
Hello[2]:   02   108
Hello[3]:   03   108
Hello[4]:   04   111
Hello[5]:   05   44
Hello[6]:   06   119
Hello[7]:   07   111
Hello[8]:   08   114
Hello[9]:   09   108
Hello[10]:  0A  100
Hello[11]:  0B  33
Hello[12]:  0C  13
Hello[13]:  0D  10
Hello[14]:  0E  40
Hello[15]:  0F  102
Hello[16]:  10  114
Hello[17]:  11  111
Hello[18]:  12  109
Hello[19]:  13  32
Hello[20]:  14  81
Hello[21]:  15  117
Hello[22]:  16  97
Hello[23]:  17  116
Hello[24]:  18  67
Hello[25]:  19  111
Hello[26]:  1A  114
Hello[27]:  1B  101
Hello[28]:  1C  41
Hello[29]:  1D  32768
Wolf:       1E  207
Wolf[1]:    1F  240
Wolf[2]:    20  222
Wolf[3]:    21  226
Wolf[4]:    22  229
Wolf[5]:    23  242
Wolf[6]:    24  44
Wolf[7]:    25  32
Wolf[8]:    26  194
Wolf[9]:    27  206
Wolf[10]:   28  203
Wolf[11]:   29  202
Wolf[12]:   2A  211
Wolf[13]:   2B  33
Wolf[14]:   2C  33
Wolf[15]:   2D  33
Wolf[16]:   2E  32768
Stack:      2F  ????
            30  ????
            31  ????
            32  ????
            33  ????
            34  ????
            35  ????
            36  ????
            37  ????
            38  ????
            39  ????
            3A  ????
            3B  ????
            3C  ????
            3D  ????
            3E  ????
            3F  ????


(возможно, стоит в HEX значения указывать, как-то так "исторически сложилось", что у меня они в десятичной форме)

И листинг программы, RomContents.txt:
    main proc
0  FD2F                      SP      Stack
1  CD1E                      X       Wolf
2  F3B0                      CALL    print
3  B803          @@endless:  JMP     @@endless
    main endp
    print proc
4  A000                      i       0
5  80C4          @@start:    Acc     [X+i]   ;не меняет флаг знака
6  8300                      SUB     0       ;а вот это меняет!
7  B004                      JL      @@finish
8  0080                      UART0   Acc
9  A400                      i++     0
A  B805                      JMP     @@start
B  B8FF          @@finish:   JMP     [--SP]
    print endp



Вот теперь пора запускать симуляцию:


Инициализируется стек, заносится адрес строки, вызывается процедура. Там обнуляется регистр i, загружается первый символ, проверяется, что он не последний - и вызывается передача по UART. И на этом ПРОЦЕССОР НЕ ОСТАНАВЛИВАЕТСЯ - он "озадачил блок" - и продолжает выполнение - прибавил единичку, перепрыгнул в начало цикла, загрузил очередной символ, убедился, что он тоже ещё не последний - и снова запустил передачу по UART. И ВОТ ТОЛЬКО СЕЙЧАС ОН ЗАСТРЯЛ - UART не может принять в себя следующий байт, пока не отправил предыдущий! Понятно, мы могли бы добавить внутрь UART очередь, то бишь FIFO, чтобы он мог вобрать в себя целую строку, тогда процессор отщёлкал бы всю строку моментально, но это не отменяет ситуации, когда FIFO переполнится, и тогда удобнее всего, чтобы поведение было таким же - остановить процессор, пока буфер немножко не освободится. В подавляющем числе реализаций в микроконтроллерах все эти ситуации нужно отслеживать самостоятельно, конфигурируя под десяток регистров - длина FIFO, отсечки, по которым будут производиться действия, вид действия и пр. Это всё замечательно и очень гибко, но я изначально здесь хотел "отладочный порт", предельно простой для использования, и типичное поведение "однозадачной программы" - написал print, и к концу выполнения знаешь, что всё уже напечатано :)

Ладно, поехали дальше.


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

И наконец, взглянем "с высоты птичьего полёта":


Дойдя до индекса 0F, процессор "завершает выполнение", перейдя в бесконечный цикл, а UART ещё передаёт последний байт, после чего также переходит в режим ожидания.

Выглядит многообещающе :)

Осталось попробовать прошить это безобразие в ПЛИС. Создаём "схемотехнический символ" QuatCore и кидаем его на "общую схему". Там очень много всего понакидано, с единственной целью - по возможности не замкнуть разные выходы друг с другом и не оставить "висящих в воздухе" проводов, подключённых как входы.



В самом низу - весь процессор в виде "коробочки". Большинство выходов - отладочные, мы к ним тыкались на симуляции. Реально I/O выход до сих пор всего один, это UART_TX. И всего один вход - Reset!

Мы подключили процессор к выходу тактовой частоты Ethernet-контроллера, где по умолчанию должны быть комфортные нам 4 МГц. Это всяко не 80 МГц, идущие с основного генератора тактовой частоты - это для нас самую малость перебор :)

Ещё двух модулей, FastFreqDivider и Toggle, поначалу тут не было.

Я запустил синтез, потом вспомнил, что надо задать частоту UART, поставил там 57600 бит/с, ностальгия, у меня модем обычно столько давал :) Снова запустил синтез, прошиваю по JTAG в SRAM, т.е не во flash-конфигуратор, а напрямую в ПЛИС. Вижу - что-то передаётся по UART, но полная каша. К тому же она не думает кончаться, и затихает только если я нажму Reset (вывел Reset самого процессора на отдельную кнопочку). Пока Reset нажат - тишина (кто бы сомневался) - потом отпускаю - снова каша.

Странно: а на симуляторе работало. Но там было деление частоты в UART всего в 4 раза. Вроде там всё как надо сделано, уж сколько я с этим UART развлекался, но мало ли - запустил на симуляторе с 57600. Не хватило времени, 2 мс, чтобы дождаться окончания передачи, открыл Vector Waveform File, поднял там время до 10 мс. Снова запускаю - и ВОТ ЖЕ ЗАРАЗА, И ЗДЕСЬ НЕ ДУМАЕТ ОСТАНАВЛИВАТЬСЯ!

Т.е вроде бы проблему локализовал - UART на высокой выходной частоте работает, на низкой - что-то сбивает, и возможно, зацикливается неким непостижимым образом.

Времени было свыше 12 ночи, а на следующий день хотел пойти на лыжах, так что отложил отладку на потом.

И вот сегодня, со свежими силами, нашёл, в чём дело. Дело было не в UART.

На симуляторе всё зациклилось из-за подлянки в Vector Waveform File: когда его расширяешь, он в конец добавляет не просто нули, а циклически повторяет уже существующий участок. Благодаря этому clock оказывается какой надо - уже хорошо. А вот reset начинает срабатывать каждые 2 мс, и немудрено что процессор зацикливается - он каждые 2 мс начинает выполнять программу заново :)

А с неполадками "в железе" у меня закрались подозрения, что тактовая частота может идти не та. И чтобы её проверить, я поставил делитель частоты с 4 МГц до 2 Гц, и затем Toggle, который по каждому "пичку" переключает своё состояние. В итоге светодиод должен был мигать с частотой 1 Гц.

Включаю - он мигает ну ЯВНО БЫСТРЕЕ!

Переправляю в делителе с 4 МГц до 33 МГц, запускаю ещё раз - да, теперь раз в секунду.

Но почему же Ethernet у меня выдаёт 33 МГц, он же при включении должен давать 4 МГц? А потому что ЗАШИТАЯ ВО FLASH прошивка занималась ровно тем, что настраивала Ethernet на 33 МГц, а при прошивке ПЛИС по JTAG Ethernet оставалась со включённым питанием, и не думала возвращаться к 4 МГц.

В общем, прошил я свой процессор во FLASH, переткнул питание всей платки целиком - и получил долгожданный "ПрЮвет ВОЛКУ!!!"
Tags: ПЛИС, зверушки, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Нахождение двух самых отдалённых точек

    Пока компьютер долго и упорно мучал симуляцию, я пытался написать на ассемблере алгоритм захвата на ближней дистанции. А сейчас на этом коде можно…

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 11 comments

Recent Posts from This Journal

  • Нахождение двух самых отдалённых точек

    Пока компьютер долго и упорно мучал симуляцию, я пытался написать на ассемблере алгоритм захвата на ближней дистанции. А сейчас на этом коде можно…

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…