Porting MIPSfpga to other boards and integrating peripherals into the system. Part 1

MIPSfpga is an Imagination MIPS32 microAptiv microprocessor designed for educational purposes, which has a cache memory and memory management unit. Verilog processor code is available to the user and can be used to model and implement the processor on an FPGA board.

This article will describe using the example of Digilent cmodA7 how to port the MIPSfpga-plus processor to other boards.



To date, MIPSFPGA has been ported to popular boards by companies such as ALTERA and Xilinx, including Basys 3, Nexys4 ddr, and others (the full list is on github) Such boards are most popular among FPGA developers. The price of such boards is rather small, and programs are loaded into the MIPSfpga core using the EJTAG interface and the Bus Blaster adapter for about $ 50. The Bus Blaster adapter receives commands via a high-speed USB 2.0 cable and converts them to the EJTAG serial protocol, this allows you to load programs into the MIPSfpga kernel and control the debugging of programs that run on it. The problem with the relatively expensive Bus Blaster was resolved by introducing a number of improvements to the MIPSfpga system. An improved version of MIPSfpga called MIPSfpga-plus includes these new features:

- The ability to download software using a USB-to-UART connector priced at $ 5 FTDI instead of the $ 50 Bus Blaster, which is sometimes not so easy to get.

- Ability to change the clock frequency on the fly from 50 or 25 MHz to 1 Hz (one cycle per second) to monitor the processor in real time, including cache misses and conveyor redirection.

- An example of integrating a light sensor with the SPI protocol.

- A small initialization sequence of software that fits into 1 KB instead of 32 KB of memory, which allows you to transfer MIPSfpga to a wider selection of FPGA boards without using external memory. The implementation of UART is described in the article: MIPSfpga and UART .

Creating a project in Xilinx Vivado 2016.4 (64 bit) with MIPSfpga-plus


Before adding various peripherals to MIPSfpga +, you need to load and run the system on FPGA. Some steps of this instruction can be skipped if you have a board from the list below:
Ported Boards
basys3
de0
de0_cv
de0_nano
de1
de10_lite
de2_115nexys4
nexys4_ddr

MIPSfpga-plus has already been ported to these boards and can be downloaded here:

github.com/MIPSfpga/mipsfpga-plus/tree/master/boards

Otherwise, if you have a different board from the FPGA listed, the processor cannot be ported to it make up a lot of work. The following instruction is written for this, which is given as an example with my cmodA7 board.

1. First you need to get a package with the MIPSFPGA system. Detailed instructions on how to do this:

mipsfpga-download-instruction

You will also need to download the current version of the MIPSfpga-plus extension:

Mipsfpga-plus

2. For Xilinx boards, Vivado software is used, the current version can be downloaded from the link:

Download Vivado

3. Now let's create a new project in Vivado:



Choose where the created project will be stored:



Click next:



Select an RTL project and click next:



Now add the system files of the original MIPSfpga:





As well as MIPSfpga-plus which are in the archive downloaded from mipsfpga-plus :



Add the uart module that was discussed earlier to the project:



Skip the creation of IP and the file of files, create them later:





Next, you either need to select a chip or add your board.

The Digilent cmod A7 board was chosen due to its low price and the availability of the ADC, which we then use. To select the FPGA circuit, you need to read the documentation on your board, on the cmodA7 the xc7a35tcpg236-1 chip is located:



Another way is to add the file of your board to the Vivado library, this method is better because, firstly, remembering the name of the board is more convenient than a chip, and secondly, if you want to use block designer in Vivado in the future, you will have additional tools for convenient work with board interfaces, IP cores, etc. You can download them on GitHub , you need to save these files in ~ \ Vivado \ 2015.1 \ data \ boards \ (relevant for Vivado 2015.1 and newer).





So we created a project with MIPSfpga-plus.

Porting instructions using the example of a Digilent CmodA7 board based on the Artix-7 chip


In short, there is an Artix-7 chip on board the cmodA7 board, it has 20800 LUT, 41600 FF, 225 KB block memory, 48 pins, 2 of which are ADC outputs, there is also a usb-uart converter, Quad-SPI Flash, and JTAG, 2 clock buttons, as well as 5 LEDs 3 of which are RGB ( datasheet ).

To transfer the MIPSfpga system to the cmodA7 board, follow these steps:

Step 1. Write a shell module that establishes the correspondence between the I / O of MIPSfpga and the I / O of the cmodA7 board.
Step 2. Reduce the memory capacity of the MIPSfpga system to match the cmodA7 board.
Step 3. Add a restriction file that sets the correspondence between the I / O of the board and the conclusions of the FPGA package.

Step 1. Add a new cmoda7.v shell file
















Install cmoda7.v top module in the hierarchy of the system.



Since there are no switches on the cmoda7 board that could be used to lower the processor frequency (this modification appeared in MIPSfpga-plus), this module was simply not included in the shell module. You can also exclude the EJTAG output to which the BUS Blaster is connected.

First, add the AHB_lite bus configuration header file.

`include "mfp_ahb_lite_matrix_config.vh"

The Advanced High-performance Bus (AHB) is an open interface that is used in many microprocessor systems, especially in embedded systems. AHB makes it easy to connect multiple devices. AHB-Lite is a simplified version of AHB with one master.



This configuration has one master device, a MIPSfpga processor, and three slaves: RAM0, RAM1 and GPIO, which are (respectively) two RAM blocks and an access module to the I / O devices of the board. We will just work with the GPIO block and write modules for interacting with peripherals.

Let's write the main input / output ports:

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 - signal of the clock generator of the board with a frequency (for cmodA7 12 MHz).
i_btn0 - the button is used to restart the processor.
i_btn1 - n / c.
RsRx - uart receive signal.
seg, dp, an, - contacts for connecting a seven-segment 4-bit indicator.
led_r, led_g, led_b, - the conclusions of the RGB Led placed on the board.
JA - Pmod interface.

The main signals are the clock signal and reset (i_btn0) the rest to connect peripherals.



The main goal of the cmoda7.v module is to create an instance of the MIPSfpga-plus system (mipsfpga_sys) and connect it to the I / O of the board.


    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

We will use MFP_DEMO_LIGHT_SENSOR when testing a ported system. As we see at the output of the mfp_system system, there will be a 32-bit IO_7_SegmentHEX bus which we will output to the decoder module of the 4-bit 7 segment indicator, we will connect the mfp_multi_digit_display instance module to the shell:

mfp_multi_digit_display multi_digit_display
    (
        .clock          (   display_clock   ),
        .resetn         ( ~ reset           ),
        .number         (   IO_7_SegmentHEX ),
        .seven_segments (   seg             ),
        .dot            (   dp              ),
        .anodes         (   an              )
    );

When creating a decoder, you should find out if the indicator is with a common anode or cathode.
The code of the seven-segment indicator decoder with a common anode is as follows:

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

As you can see on each rising edge of clock, the corresponding signal bcd_to_seg is output in seven_segments, and switching between the indicator bits is done by switching the active signal on the corresponding anodes (or cathodes).

Since a signal at a frequency of 50 MHz arrives at the input of the processor, which we will create later, if we change the values ​​on the indicator with such a frequency, our eye will not notice these changes (for a normal display of the values ​​on the 7 segment indicator, a frequency of approximately 763 Hz is necessary) . To do this, connect an instance of the frequency divider:

   mfp_clock_divider_50_MHz_to_763_Hz mfp_clock_divider_50_MHz_to_763_Hz
        (clock, display_clock);

In the source files, there is no frequency divider from 50 MHz to 763 Hz. Therefore, we will add it to the mfp_clock_dividers.v file:



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

The reset and clock, RsRx, IO_Buttons signals are input to the system. But we have at the input of the top module the signal is i_clk, not clock. The fact is that there is a 12 MHz clock on the board, and the FPGA processor can operate at frequencies of 50 MHz and higher, but what if you have another card with a different clock frequency (for example, the Nexys 4 DDR has a clock frequency of 100 MHz). The problem is solved by creating the Clocking Wizard (PLL) IP core. To do this, open the IP directory:



Open the Clocking Wizard:



leave the board tab as it is, or configure the inputs we need and go to the clocking options tab, you can choose either MMCM has a wider range of input frequencies 10. ..800MHz than PLL 19 ... 800MHz, since on cmoda7 we select only 12 MHz MMCM, but for other boards you can choose other parameters:



In the output clocks tab, set the frequency to 50 MHz (you can and should experiment with the frequency, so there may be other characteristics on other FPGAs):



Also remove reset and locked:



Port renaming, MMCM setting and Summary, look and leave it as it is, click OK, OK, in the next window, select generate:

image

The last stroke is to make a continuous assignment for RGB Led, because as you can see from the scheme in a floating state, they will be dimly lit, and we want them to be turned off:

image

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

At the end we write:

endmodule

The shell module is created, let's move on to resizing the memory.

Step 2. Reduce the MIPSfpga system memory to match the cmoda7 board


The cmoda7 board has 225 KB of block memory. Thus, two memory blocks (128 Kbytes of RAM reset and 256 Kbytes of RAM program) do not fit on the cmoda7 board. Since, the boot code can fit in 32 Kbytes, and you can limit the needs of programs of 64 Kbytes. Thus, the total required memory (32 Kbytes + 64 Kbytes = 96 Kbytes) corresponds to the memory size of the cmoda7 board. The remaining 225-96 = 129 Kbytes of memory can be used for other needs of the MIPSfpga system, for example, as a cache memory.

You can reduce the amount of memory by changing the size of the memory declared in the Verilog header file that we included in the mfp_ahb_lite_matrix_config.vh shell file. Open the mipsfpga_ahb_const.vh file. The addresses of the reset RAM (or boot RAM) consist of 13 bits. Thus, the amount of reset RAM is 213 32-bit words = 215 bytes = 32 Kbytes.



`define H_RAM_RESET_ADDR_WIDTH  13 

RAM addresses of programs consist of 14 bits. Thus, the amount of program RAM is 214 32-bit words = 216 bytes = 64 Kbytes.

`define H_RAM_ADDR_WIDTH  14

Step 3. Create a cmoda7 constraint file


Now create a “cmoda7.xdc” which sets the correspondence between the external signals of the shell module and the pins of the FPGA cmoda7 board ( xdc file with the complete list of pins for 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]

For example, the following line establishes the correspondence between the i_clk input and the output of the FPGA L17 housing, which receives a 12 MHz clock signal from the cmoda7 board.

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]

Also, in the restriction file, you need to add the following output time limits for signals:

# 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 Test


We can test the processor ported to our board, for this we need to go into the configuration file "mfp_ahb_lite_matrix_config.vh" and uncomment the line:

`define MFP_DEMO_LIGHT_SENSOR



Thus, we connected the Veriog-written SPI interface module to the AHB Lite bus for connection to the Digilent PmodALS light sensor .

SPI module
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




The connection diagram is shown in the figure:



The sensor is connected to the Pmod port, the outputs of which are described in "cmoda7.xdc" are registered as 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]}]

The RTL scheme can be examined in the RTL Analisys → Schematic tab, where the SPI interface module “mfp_pmod_als_spi_receiver” is located in “mfp_system”:



In order to load the created project into FPGA, you need to generate the bitstream file “cmoda7.bit”, for this, in the Program and Debug tab → Generate Bitstream and wait for the operation to complete:



After creating the bitstream file, you need to download it to the board, for this, in the Program and Debug tab → open Open Hardware Manager → Open Target → Auto Connect → Program Device and load the system:



Download software for working with the sensor


For the processor to communicate with the sensor, you need to write a program and load it into the RAM1 unit, which is also connected to the AHB Lite bus.

The MIPSfpga processor is programmed using Imagination's Codescape development tools . Install the Codescape SDK and OpenOCD. Codescape supports programming in both C and assembly language.

To download the code into the system, go to the downloaded folder mipsfpga plus → github → mipsfpga-plus → programs → 01_light_sensor open “mfp_memory_mapped_registers.h”.

#define MFP_LIGHT_SENSOR_ADDR   0xBF800014
и
#define MFP_LIGHT_SENSOR        (* (volatile unsigned *) MFP_LIGHT_SENSOR_ADDR  )

Next, open main.c and write a couple of lines:

#include "mfp_memory_mapped_registers.h"
int main ()
{
    int n = 0;
    for (;;)
    {
        MFP_7_SEGMENT_HEX = MFP_LIGHT_SENSOR;
    }
    return 0;
}

After in the folder we find a script that compiles the code:

02_compile_and_link

We generate a motorola_s_record file:

08_generate_motorola_s_record_file

Check to which COM port the USB UART converter is connected:

11_check_which_com_port_is_used

Change the file 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%

where a is the COM port number to which the USB UART converter is connected. And load the program:

12_upload_to_the_board_using_uart

The result of porting the system can be seen in the video:



To understand the processor, and the ability to write new modules in the hardware description language (Verilog, VHDL), as well as circuitry, computer architecture, microarchitecture (organization of the processor pipeline) and assembly language programming, and much more that will help you get started in learning of everything related to electronics, it is recommended to read the book about which it is written in the article: A free tutorial on electronics, computer architecture, and low-level programming in Russian .

The next part will describe how to connect various peripherals to the MIPSfpga system using the Digilent Pmod KYPD keyboard , built-in ADC, and Nokia LCD display as an example .

Porting MIPSfpga to other boards and integrating peripherals into the system. Part 2

Also popular now: