MIPSfpga представляет собой предназначенный для образовательных целей микропроцессор MIPS32 microAptiv фирмы Imagination, который имеет кэш-память и блок управления памятью. Код процессора на языке Verilog доступен пользователю и может использоваться для моделирования и реализации процессора на FPGA плате.
В даной статье будет описано на примере Digilent cmodA7 как портировать процессор MIPSfpga-plus на другие платы.
На сегодняшний день 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:
2. Для плат фирмы Xilinx используется программное обеспечение Vivado, актуальную версию можно скачать по ссылке:
3. Теперь давайте создадим новый проект в Vivado:
Выбираем где будет хранится созданный проект:
Жмем далее:
Выбираем RTL проект и жмем далее:
Теперь добавим файлы системы оригинального MIPSfpga:
А так же MIPSfpga-plus которые находятся в архиве скачаном с mipsfpga-plus:
Добавим в проект модуль uart о котором ранее шла речь:
Пропускаем создание IP и файлов констрейнов создадим их позже:
Далее нужно либо выбрать микросхему либо добавить вашу плату.
Плата Digilent cmod A7 была выбрана в связи с ее не большой ценой и наличием АЦП которое мы потом используем. Чтобы выбрать FPGA схему нужно прочитать на вашу плату документацию, на cmodA7 размещен чип xc7a35tcpg236-1:
Другим способом является добавление файла вашей платы в библиотеку Vivado, этот способ лучше тем что, во первых, запомнить название платы удобней чем чипа, во вторых если вы в будущем захотите использовать block designer в Vivado, то у вас будет дополнительный инструментарий для удобной работы с интерфейсами платы, IP ядрами, и т.д. Скачать их можно на GitHub, сохранить эти файлы нужно в ~Vivado2015.1databoards (актуально для Vivado 2015.1 и новее).
Вот мы и создали проект с 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
Установим cmoda7.v топ модулем в иерархии системы.
Так как на плате 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, и три ведомых: 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) остальные для подключения периферии.
Основной целью модуля 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:
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 каталог:
Откроем Clocking Wizard:
Вкладку board оставляем как есть, либо настраиваем нужные нам входы и переходим на вкладку clocking options можно выбрать либо MMCM имеет более широкий диапазон входных частот 10...800МГц, чем PLL 19...800МГц, поскольку на cmoda7 всего 12 МГц выбираем MMCM, но для других плат можно выбирать другие параметры:
Во вкладке output clocks устанавливаем частоту 50 МГц (с частотой можно и нужно экспериментировать, так на других FPGA могут быть другие характеристики):
Также убираем reset и locked:
Port renaming, MMCM setting и Summary смотрим и оставляем как есть, жмем ОК, ОК, в следующем окне выбираем generate:
Последним штрихом сделаем непрерывное присваивание для RGB Led, поскольку как видно из схемы в плавающем состоянии они будут тускло светится, а мы хотим что бы они были выключены:
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байт.
`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):
## 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
Таким образом мы подключили написанный на Verilog модуль интерфейса SPI к шине AHB Lite для соединения с датчиком освещённости PmodALS фирмы Digilent.
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
Схема подключения изображена на рисунке:
Датчик подключен к порту 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»:
Что бы загрузить в FPGA созданный проект нужно сгенерировать bitstream файл «cmoda7.bit», для этого во вкладке Program and Debug → Generate Bitstream и подождать завершения операции:
После создания bitstream файла нужно его загрузить в плату, для этого во вкладке Program and Debug → откроем Open Hardware Manager → Open Target → Auto Connect → Program Device и загрузим систему:
Загрузка программы для работы с датчиком
Чтобы процессор обменивался с датчиком данными нужно написать программу и загрузить в блок 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