Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1

в 13:19, , рубрики: Altera, fpga, imagination technologies, mips, MIPS microAptiv UP, MIPSfpga, SPI, uart, Verilog, vhdl, xilinx, Анализ и проектирование систем, ПЛИС, программирование микроконтроллеров

MIPSfpga представляет собой предназначенный для образовательных целей микропроцессор MIPS32 microAptiv фирмы Imagination, который имеет кэш-память и блок управления памятью. Код процессора на языке Verilog доступен пользователю и может использоваться для моделирования и реализации процессора на FPGA плате.

В даной статье будет описано на примере Digilent cmodA7 как портировать процессор MIPSfpga-plus на другие платы.

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 1

На сегодняшний день MIPSFPGA портирован на популярные платы таких фирм как ALTERA и Xilinx, среди них Basys 3, Nexys4 ddr, и другие (полный список находится на github). Такие платы наиболее популярны среди разработчиков на FPGA. Цена на такие платы довольно не маленькая, да и загружаются программы в ядро MIPSfpga с использованием интерфейса EJTAG и адаптера Bus Blaster ценой около 50$. Адаптер Bus Blaster получает команды по высокоскоростному кабелю USB 2.0 и преобразует их в последовательный протокол EJTAG, это позволяет загружать программы в ядро MIPSfpga и управлять отладкой программ, которые на нем выполняются. Проблема с относительно дорогим Bus Blaster была решена введением в систему MIPSfpga ряда улучшений. Улучшеный вариант системи MIPSfpga, названый MIPSfpga-plus включает в себя такие новые функции:

— Возможность загрузки программного обеспечения с использованием USB-to-UART коннектора ценой в $ 5 FTDI вместо $ 50 Bus Blaster, который иногда не так уж и легко достать.

— Возможность изменять тактовую частоту на лету с 50 или 25 МГц до 1 Гц (один цикл в секунду) для наблюдения за работой процессора в режиме реального времени, включая промахи в кэш-памяти и перенаправления конвеера.

— Пример интеграции датчика освещенности с протоколом SPI.

— Небольшая последовательность инициализации программного обеспечения, которая вписывается в 1 КБ вместо 32 КБ памяти, что позволяет переносить MIPSfpga на более широкий выбор плат FPGA без использования внешней памяти. Реализация UART описана в статье: MIPSfpga и UART.

Создание проекта в Xilinx Vivado с MIPSfpga-plus

Кто работал с MIPSFPGA-plus на платах фирмы Xilinx, могут пропустить данный этап. В связи с постоянно растущим количеством различных FPGA плат и набирающим популярность проектом по предоставлению исходников промышленных процессоров для университетов (а именно на базовую конфигурацию экономичного процессорного ядра MIPS microAptiv UP). Подробнее тут: Исходники промышленных процессоров станут доступными для университетов?, инструкция по портированию системы MIPSfpga+ в новую плату по мнению автора не будет лишней:

1. Для начала нужно получить пакет c системой MIPSFPGA. Подробная инструкция о том как это сделать:

mipsfpga-download-instruction

Если у вас уже есть MIPSfpga система и требуется использование usb-to-uart преобразователя (в плате cmodA7, а так же на многих других платах фирмы Xilinx есть встроенный uart), то вам потребуется скачать актуальную версию расширения MIPSfpga-plus:

Mipsfpga-plus

2. Для плат фирмы Xilinx используется программное обеспечение Vivado, актуальную версию можно скачать по ссылке:

Download Vivado

3. Теперь давайте создадим новый проект в Vivado:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 2

Выбираем где будет хранится созданный проект:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 3

Жмем далее:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 4

Выбираем RTL проект и жмем далее:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 5

Теперь добавим файлы системы оригинального MIPSfpga:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 6

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 7

А так же MIPSfpga-plus которые находятся в архиве скачаном с mipsfpga-plus:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 8

Добавим в проект модуль uart о котором ранее шла речь:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 9

Пропускаем создание IP и файлов констрейнов создадим их позже:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 10

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 11

Далее нужно либо выбрать микросхему либо добавить вашу плату.

Плата Digilent cmod A7 была выбрана в связи с ее не большой ценой и наличием АЦП которое мы потом используем. Чтобы выбрать FPGA схему нужно прочитать на вашу плату документацию, на cmodA7 размещен чип xc7a35tcpg236-1:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 12

Другим способом является добавление файла вашей платы в библиотеку Vivado, этот способ лучше тем что, во первых, запомнить название платы удобней чем чипа, во вторых если вы в будущем захотите использовать block designer в Vivado, то у вас будет дополнительный инструментарий для удобной работы с интерфейсами платы, IP ядрами, и т.д. Скачать их можно на GitHub, сохранить эти файлы нужно в ~Vivado2015.1databoards (актуально для Vivado 2015.1 и новее).

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 13

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 14

Вот мы и создали проект с MIPSfpga-plus.

Инструкция по портированию на примере платы Digilent CmodA7 на базе микросхемы Artix-7

Если вкратце то на борту платы cmodA7 находится чип семейства Artix-7, имеет 20800 LUT, 41600 FF, 225 KB блочной памяти, имеется 48 пинов, среди которых 2 является выходами АЦП, также имеется usb-uart преобразователь, Quad-SPI Flash, и JTAG, 2 тактовые кнопки, а также 5 светодиодов 3 из которых это RGB (даташит).

Чтобы перенести систему MIPSfpga на плату cmodA7, следует:

Шаг 1. Написать модуль-оболочку, который устанавливает соответствие между вводами/выводами MIPSfpga и вводами/выводами платы Basys3
Шаг 2. Уменьшить объем памяти системы MIPSfpga для соответствия плате Basys3
Шаг 3. Добавить файл ограничений, который устанавливает соответствие между вводами/выводами платы и выводами корпуса FPGA.

Шаг 1. Добавим новый файл оболочки cmoda7.v

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 15

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 16

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 17

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 18

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 19

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 20

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 21

Установим cmoda7.v топ модулем в иерархии системы.

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 22

Так как на плате cmoda7 нет переключателей которые можно было бы использовать для понижения частоты процессора (эта модификация появилась в MIPSfpga-plus), этот модуль просто не был включен в модуль оболочку. Так же можно исключить выход EJTAG к которому подключается BUS Blaster.

Для начала нужно добавить заголовочный файл конфигурации шины AHB_lite.

`include "mfp_ahb_lite_matrix_config.vh"

Усовершенствованная высокопроизводительная шина (Advanced High-performance Bus, AHB) является открытым интерфейсом, который используется во многих микропроцессорных системах, особенно во встроенных. Шина AHB облегчает организацию соединения нескольких устройств. AHB-Lite является упрощенной версией AHB с одним ведущим устройством.

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 23

Эта конфигурация имеет одно ведущее устройство, процессор MIPSfpga, и три ведомых: RAM0, RAM1 и GPIO, которые представляют собой (соответственно) два блока ОЗУ и модуль доступа к устройствам ввода/вывода платы. Мы как раз и будем работать с блоком GPIO и писать модули взаимодействия с периферией.

Пропишем основные порты ввода-вывода:

module cmoda7
              (
                  input               i_clk,
                  input               i_btn0, 
                  input               i_btn1,
                  input               RsRx,

                  output [ 6:0]       seg,   
                  output              dp,
                  output [ 3:0]       an,
                  output              led0_r,
                  output              led0_g,
                  output              led0_b,

                  inout  [ 7:0]       JA
                  
               );

i_clk — сигнал тактового генератора платы частотой (для cmodA7 12 МГц).
i_btn0 — кнопка используется для перезагрузки процессора.
i_btn1 — n/c.
RsRx — сигнал приема по uart.
seg, dp, an, — контакты для подключения семисегментного 4 разрядного индикатора.
led_r, led_g, led_b, — выводи размещённого на плате RGB Led.
JA — Pmod интерфейс.

Основными сигналами являются сигнал тактовой частоты и reset (i_btn0) остальные для подключения периферии.

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 24

Основной целью модуля cmoda7.v является создание экземпляра системы MIPSfpga-plus (mipsfpga_sys) и ее соединение с вводами/выводами платы.


    wire clock;
    wire reset = i_btn0;
    
    wire display_clock;
    wire [7:0] anodes;

    wire [`MFP_N_BUTTONS           - 1:0] IO_Buttons;
    wire [`MFP_7_SEGMENT_HEX_WIDTH - 1:0] IO_7_SegmentHEX;
    
    assign IO_Buttons  = { { `MFP_N_BUTTONS  -  2 { 1'b0 } } , i_btn0, i_btn1 };

mfp_system mfp_system
    (
        .SI_ClkIn         ( clock            ), 
        .SI_Reset         ( reset            ),
             
        .HADDR            (                  ),
        .HRDATA           (                  ),
        .HWDATA           (                  ),
        .HWRITE           (                  ),

        .EJ_TRST_N_probe  (                  ),
        .EJ_TDI           (                  ),
        .EJ_TDO           (                  ),
        .EJ_TMS           (                  ),
        .EJ_TCK           (                  ),
        .SI_ColdReset     (                  ),
        .EJ_DINT          (   1'b0           ),

        .IO_Switches      (                  ),
        .IO_Buttons       ( IO_Buttons       ),
        .IO_RedLEDs       (                  ),
        .IO_GreenLEDs     (                  ), 
        .IO_7_SegmentHEX  ( IO_7_SegmentHEX  ),
        
        `ifdef MFP_DEMO_LIGHT_SENSOR
        .SPI_CS           (   JA [0]         ),
        .SPI_SCK          (   JA [3]         ),
        .SPI_SDO          (   JA [2]         ),
        `endif
        
        .UART_RX          ( RsRx             ),
        .UART_TX          (                  )
    );

`ifdef MFP_DEMO_LIGHT_SENSOR
    assign JA [1] = 1'b0;
`endif

MFP_DEMO_LIGHT_SENSOR будем использовать при тестировании портированой системы. Как видим на выходе системы mfp_system будет 32-х разрядная шина IO_7_SegmentHEX которую мы выводим в модуль дешифратора 4-х разрядного 7 сегментного индикатора, подключим в оболочку модуль екземпляра «mfp_multi_digit_display»:

mfp_multi_digit_display multi_digit_display
    (
        .clock          (   display_clock   ),
        .resetn         ( ~ reset           ),
        .number         (   IO_7_SegmentHEX ),

        .seven_segments (   seg             ),
        .dot            (   dp              ),
        .anodes         (   an              )
    );

При создании дешифратора стоит узнать является ли индикатор с общим анодом или катодом.
Код дешифратора семисегментного индикатора с общим анодом имеет такой вид:

module mfp_single_digit_seven_segment_display
(
    input      [3:0] digit,
    output reg [6:0] seven_segments
);

    always @*
        case (digit)
        'h0: seven_segments = 'b1000000;  // a b c d e f g
        'h1: seven_segments = 'b1111001;
        'h2: seven_segments = 'b0100100;  //   --a--
        'h3: seven_segments = 'b0110000;  //  |     |
        'h4: seven_segments = 'b0011001;  //  f     b
        'h5: seven_segments = 'b0010010;  //  |     |
        'h6: seven_segments = 'b0000010;  //   --g--
        'h7: seven_segments = 'b1111000;  //  |     |
        'h8: seven_segments = 'b0000000;  //  e     c
        'h9: seven_segments = 'b0011000;  //  |     |
        'ha: seven_segments = 'b0001000;  //   --d-- 
        'hb: seven_segments = 'b0000011;
        'hc: seven_segments = 'b1000110;
        'hd: seven_segments = 'b0100001;
        'he: seven_segments = 'b0000110;
        'hf: seven_segments = 'b0001110;
        endcase

endmodule

//--------------------------------------------------------------------

module mfp_multi_digit_display
(
    input             clock,
    input             resetn,
    input      [31:0] number,

    output reg [ 6:0] seven_segments,
    output reg        dot,
    output reg [ 7:0] anodes
);

    function [6:0] bcd_to_seg (input [3:0] bcd);

        case (bcd)
        'h0: bcd_to_seg = 'b1000000;  // a b c d e f g
        'h1: bcd_to_seg = 'b1111001;
        'h2: bcd_to_seg = 'b0100100;  //   --a--
        'h3: bcd_to_seg = 'b0110000;  //  |     |
        'h4: bcd_to_seg = 'b0011001;  //  f     b
        'h5: bcd_to_seg = 'b0010010;  //  |     |
        'h6: bcd_to_seg = 'b0000010;  //   --g--
        'h7: bcd_to_seg = 'b1111000;  //  |     |
        'h8: bcd_to_seg = 'b0000000;  //  e     c
        'h9: bcd_to_seg = 'b0010000;  //  |     |
        'ha: bcd_to_seg = 'b0001000;  //   --d-- 
        'hb: bcd_to_seg = 'b0000011;
        'hc: bcd_to_seg = 'b1000110;
        'hd: bcd_to_seg = 'b0100001;
        'he: bcd_to_seg = 'b0000110;
        'hf: bcd_to_seg = 'b0001110;
        endcase

    endfunction

    reg [2:0] i;

    always @ (posedge clock or negedge resetn)
    begin
        if (! resetn)
        begin
            seven_segments <=   bcd_to_seg (0);
            dot            <= 0;
            anodes         <= 8'b00000001;

            i <= 0;
        end
        else
        begin
            seven_segments <=  bcd_to_seg (number [i * 4 +: 4]);
            dot            <= 0;
            anodes         <= (1 << i);

            i <= i + 1;
        end
    end

endmodule

Как можно увидеть по каждому переднему фронту clock в seven_segments выводится соответствующий сигнал bcd_to_seg, а переключение между разрядами индикатора производится с помощью переключения активного сигнала на соответствующих анодах (либо катодах).

Так как на вход процессора поступает сигнал в частотой в 50 МГц который мы создадим далее, если ми будем с такой частотой менять значения на индикаторе наш глаз не будет замечать эти изменения(для нормального отображения значений на 7 сегментном индикаторе необходима частота приблизительно в 763 Гц). Для этого подключим экземпляр делителя частоты:

   mfp_clock_divider_50_MHz_to_763_Hz mfp_clock_divider_50_MHz_to_763_Hz
        (clock, display_clock);

В исходных файлах делителя частоты с 50 MГц в 763 Гц нет. Поэтому мы добавим его в файл mfp_clock_dividers.v:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 25

module mfp_clock_divider_50_MHz_to_763_Hz
(
    input  clki,
    output clko
);

    mfp_clock_divider
    # (.DIV_POW_SLOWEST (16))
    mfp_clock_divider
    (
        .clki    ( clki ),
        .sel_lo  ( 1'b1 ),
        .sel_mid ( 1'b0 ),
        .clko    ( clko )
    );

endmodule

На вход системы поступают сигналы reset и clock, RsRx, IO_Buttons. Но у нас на входе топ модуля сигнал i_clk, а не clock. Дело в том что на плате присутствует тактовый генератор в 12 МГц, а процессор в FPGA может работать на частотах 50 МГц и выше, а что делать если у вас другая плата с другой тактовой частотой (например Nexys 4 DDR имеет тактовую частоту 100 МГц). Решается проблема созданием IP ядра Clocking Wizard (PLL), для этого откроем IP каталог:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 26

Откроем Clocking Wizard:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 27

Вкладку board оставляем как есть, либо настраиваем нужные нам входы и переходим на вкладку clocking options можно выбрать либо MMCM имеет более широкий диапазон входных частот 10...800МГц, чем PLL 19...800МГц, поскольку на cmoda7 всего 12 МГц выбираем MMCM, но для других плат можно выбирать другие параметры:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 28

Во вкладке output clocks устанавливаем частоту 50 МГц (с частотой можно и нужно экспериментировать, так на других FPGA могут быть другие характеристики):

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 29

Также убираем reset и locked:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 30

Port renaming, MMCM setting и Summary смотрим и оставляем как есть, жмем ОК, ОК, в следующем окне выбираем generate:

image

Последним штрихом сделаем непрерывное присваивание для RGB Led, поскольку как видно из схемы в плавающем состоянии они будут тускло светится, а мы хотим что бы они были выключены:

image

assign led0_r = 1'b1;
assign led0_g = 1'b1;
assign led0_b = 1'b1;

В конце напишем:

endmodule

Модуль оболочка создан, перейдем к изменению размера памяти.

Шаг 2. Уменьшаем объем памяти системы MIPSfpga для соответствия плате cmoda7

Плата cmoda7 имеет 225 Кбайт блоковой памяти. Таким образом, два блока памяти (128 Кбайт ОЗУ сброса и 256 Кбайт ОЗУ программ) не помещаются на плате cmoda7. Так как, загрузочный код может уместиться в 32 Кбайт, и можно ограничить потребности программ объемом 64 Кбайт. Таким образом, общая необходимая память (32 Kбайт + 64 Kбайт = 96 Kбайт) соответствует объему памяти платы cmoda7. Оставшиеся 225-96 = 129 Kбайт памяти могут быть использованы для других нужд системы MIPSfpga, например, в качестве кэш-памяти.

Уменьшить объем памяти можно, изменив размер памяти, заявленный в заголовочном файле Verilog который мы подключали в файл оболочку «mfp_ahb_lite_matrix_config.vh». Открываем файл mipsfpga_ahb_const.vh. Адреса ОЗУ сброса (или ОЗУ загрузки) состоят из 13 бит. Таким образом, объем ОЗУ сброса равен 213 32-битных слов = 215 байт = 32 Kбайт.

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 33

`define H_RAM_RESET_ADDR_WIDTH  13 

Адреса ОЗУ программ состоят из 14 бит. Таким образом, объем ОЗУ программ равен 214 32-битных слов = 216 байт = 64 Kбайт.

`define H_RAM_ADDR_WIDTH  14

Шаг 3. Создаем файл ограничений cmoda7

Теперь создадим «cmoda7.xdc» который устанавливает соответствие между внешними сигналами модуля-оболочки и выводами корпуса FPGA платы cmoda7 (xdc файл с полным списком выводов для cmoda7):

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 34

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 35


## Clock signal 12 MHz
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports i_clk]
create_clock -period 83.330 -name sys_clk_pin -waveform {0.000 41.660} -add [get_ports i_clk]

## Buttons
set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports i_btn0]
set_property -dict {PACKAGE_PIN B18 IOSTANDARD LVCMOS33} [get_ports i_btn1]

## LEDs
set_property -dict {PACKAGE_PIN B17 IOSTANDARD LVCMOS33} [get_ports led0_b]
set_property -dict {PACKAGE_PIN B16 IOSTANDARD LVCMOS33} [get_ports led0_g]
set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS33} [get_ports led0_r]

## Pmod Header JA
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {JA[0]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {JA[1]}]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports {JA[2]}]
set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {JA[3]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {JA[4]}]
set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS33} [get_ports {JA[5]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {JA[6]}]
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports {JA[7]}]

## GPIO Pins 1 - 6   7_segment_ind
set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {seg[1]}]
set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {an[1]} ]
set_property -dict {PACKAGE_PIN A16 IOSTANDARD LVCMOS33}[get_ports {an[2]} ]
set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {seg[5]}]
set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33}[get_ports {seg[0]}]
set_property -dict {PACKAGE_PIN H1 IOSTANDARD LVCMOS33} [get_ports {an[3]} ]

## GPIO Pins 43 - 48  7_segment_ind
set_property -dict {PACKAGE_PIN U3 IOSTANDARD LVCMOS33} [get_ports {seg[3]}]
set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {seg[4]}]
set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports dp    ]
set_property -dict {PACKAGE_PIN W7 IOSTANDARD LVCMOS33} [get_ports {seg[2]}]
set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS33} [get_ports {seg[6]}]
set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {an[0]} ]

## UART
#set_property -dict { PACKAGE_PIN J18   IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L7N_T1_D10_14 Sch=uart_rxd_out
set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports RsRx]

Например, следующая строка устанавливает соответствие между входом i_clk и выводом корпуса FPGA L17, на который поступает тактовый сигнал с частотой 12 МГц с платы cmoda7.

set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports i_clk]
create_clock -period 83.330 -name sys_clk_pin -waveform {0.000 41.660} -add [get_ports i_clk]

Так же в файл ограничений нужно добавить следующие выходные временные ограничения для сигналов:

# I/O virtual clock
create_clock -period 83.330 -name "clk_virt"

# tsu/th constraints
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports i_btn0]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports i_btn0]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports i_btn1]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports i_btn1]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports led0_b]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports led0_b]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports led0_g]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports led0_g]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports led0_r]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports led0_r]

## PMOD ALS
set_output_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {JA[0]}]
set_output_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {JA[0]}]
set_output_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {JA[1]}]
set_output_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {JA[1]}]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {JA[2]}]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {JA[2]}]
set_output_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {JA[3]}]
set_output_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {JA[3]}]

set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {seg[*]}]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {seg[*]}]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports {an[*]}]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports {an[*]}]
set_input_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports dp]
set_input_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports dp]
set_output_delay -clock "clk_virt" -min -add_delay 0.000 [get_ports RsRx]
set_output_delay -clock "clk_virt" -max -add_delay 10.000 [get_ports RsRx]

Тест MIPSfpga

Мы можем протестировать портированый на нашу плату процессор, для этого нужно зайти в файл конфигурации «mfp_ahb_lite_matrix_config.vh» и расскоментируем строку:

`define MFP_DEMO_LIGHT_SENSOR

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 36

Таким образом мы подключили написанный на Verilog модуль интерфейса SPI к шине AHB Lite для соединения с датчиком освещённости PmodALS фирмы Digilent.

Модуль SPI

module mfp_pmod_als_spi_receiver
(
    input             clock,
    input             reset_n,
    output            cs,
    output            sck,
    input             sdo,
    output reg [15:0] value
);

    reg [21:0] cnt;
    reg [15:0] shift;

    always @ (posedge clock or negedge reset_n)
    begin       
        if (! reset_n)
            cnt <= 22'b100;
        else
            cnt <= cnt + 22'b1;
    end

    assign sck = ~ cnt [3];
    assign cs  =   cnt [8];

    wire sample_bit = ( cs == 1'b0 && cnt [3:0] == 4'b1111 );
    wire value_done = ( cnt [21:0] == 22'b0 );

    always @ (posedge clock or negedge reset_n)
    begin       
        if (! reset_n)
        begin       
            shift <= 16'h0000;
            value <= 16'h0000;
        end
        else if (sample_bit)
        begin       
            shift <= (shift << 1) | sdo;
        end
        else if (value_done)
        begin       
            value <= shift;
        end
    end

endmodule

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 37

Схема подключения изображена на рисунке:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 38

Датчик подключен к порту Pmod, выходи которого описаны в «cmoda7.xdc» прописаны как JA[7..0].

## Pmod Header JA
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {JA[0]}]
...
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports {JA[7]}]

Полученую RTL схему можно доследить во вкладке RTL Analisys → Schematic, где модуль интерфейса SPI «mfp_pmod_als_spi_receiver» находится в «mfp_system»:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 39

Что бы загрузить в FPGA созданный проект нужно сгенерировать bitstream файл «cmoda7.bit», для этого во вкладке Program and Debug → Generate Bitstream и подождать завершения операции:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 40

После создания bitstream файла нужно его загрузить в плату, для этого во вкладке Program and Debug → откроем Open Hardware Manager → Open Target → Auto Connect → Program Device и загрузим систему:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 - 41

Загрузка программы для работы с датчиком

Чтобы процессор обменивался с датчиком данными нужно написать программу и загрузить в блок RAM1 который так же подключён к шине AHB Lite.

Процессор MIPSfpga программируют с использованием инструментов разработки Codescape компании Imagination. Установите Codescape SDK и OpenOCD. Codescape поддерживает программирование как на языке C, так и на языке ассемблера.

Для загрузки кода в систему нужно перейти в папку скачаного mipsfpga plus → github → mipsfpga-plus → programs→ 01_light_sensor откроем «mfp_memory_mapped_registers.h».

#define MFP_LIGHT_SENSOR_ADDR   0xBF800014

и

#define MFP_LIGHT_SENSOR        (* (volatile unsigned *) MFP_LIGHT_SENSOR_ADDR  )

далее откроем main.c и напишем пару строк:

#include "mfp_memory_mapped_registers.h"

int main ()
{
    int n = 0;

    for (;;)
    {
        MFP_7_SEGMENT_HEX = MFP_LIGHT_SENSOR;
    }

    return 0;
}

После в папке находим скрипт который компилирует код:

02_compile_and_link

Генерируем motorola_s_record файл:

08_generate_motorola_s_record_file

Проверяем к какому СОМ порту подключен USB UART преобразователь:

11_check_which_com_port_is_used

Изменяем файл 12_upload_to_the_board_using_uart:

set a=7 
mode com%a% baud=115200 parity=n data=8 stop=1 to=off xon=off odsr=off octs=off dtr=off rts=off idsr=off type program.rec >.COM%a%

где а – номер СОМ порта, к которому подключен USB UART преобразователь. И загружаем программу:

12_upload_to_the_board_using_uart

Результат портирования системы можно посмотреть на видео:

Для понимания работы процессора, и возможности написания новых модулей на языке описания аппаратуры (Verilog, VHDL), а так же схемотехники, архитектуры компьютера, микроархитектуры (организация процессорного конвейера) и программирования на ассемблере, и много чего другого что поможет вам взять старт в изучении всего что связано с электроникой рекомендуется прочитать книгу про которую написано в статье: Бесплатный учебник электроники, архитектуры компьютера и низкоуровневого программирования на русском языке.

В следующей части будет описано как подключать различную периферию в систему MIPSfpga на примере клавиатуры Digilent Pmod KYPD, встроенной АЦП, и LCD дисплея от Nokia.

Автор: oleh_plotnikov

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js