Difference between revisions of "Extend IOP16 minimal example"

From Land Boards Wiki
Jump to navigation Jump to search
 
(45 intermediate revisions by the same user not shown)
Line 19: Line 19:
 
* Build/test
 
* Build/test
  
= Baseline Design =
+
== Baseline Design ==
  
 
Starts from [https://github.com/douggilliland/IOP16/tree/main/Higher_Level_Examples/TestIOP16_Minimal|minimal IOP example]
 
Starts from [https://github.com/douggilliland/IOP16/tree/main/Higher_Level_Examples/TestIOP16_Minimal|minimal IOP example]
Line 125: Line 125:
  
 
* Pick from [[IOP16_Peripheral_Support|Supported peripherals list]]
 
* Pick from [[IOP16_Peripheral_Support|Supported peripherals list]]
 +
 +
== Select UART for example ==
 +
 
* This example will add [[IOP16_UART|UART peripheral]]
 
* This example will add [[IOP16_UART|UART peripheral]]
 
** Will set up [[IOP16_UART|UART]] in loopback
 
** Will set up [[IOP16_UART|UART]] in loopback
 +
 +
=== Update Memory Map ===
  
 
* Update Memory map in comments at start of TestIOP16B.vhd to add UART addresses
 
* Update Memory map in comments at start of TestIOP16B.vhd to add UART addresses
Line 138: Line 143:
 
</pre>
 
</pre>
  
* Add UART files to project
+
=== Add UART files to project ===
  
 
[[file:IOP16_PortingGuide_AddFiles.PNG]]
 
[[file:IOP16_PortingGuide_AddFiles.PNG]]
Line 146: Line 151:
 
[[file:IOP16_PortingGuide_AddUARTFiles.PNG]]
 
[[file:IOP16_PortingGuide_AddUARTFiles.PNG]]
  
* Add UART pins to top level entity pins list
+
=== Add UART pins to top level entity pins list ===
  
 
<pre>
 
<pre>
Line 166: Line 171:
 
</pre>
 
</pre>
  
* Add to signals list
+
=== Add to signals list ===
  
 
<pre>
 
<pre>
Line 172: Line 177:
 
signal w_wrUart : std_logic;
 
signal w_wrUart : std_logic;
 
signal w_rdUart : std_logic;
 
signal w_rdUart : std_logic;
signal w_UartDataOut : std_logic_vector(7 downto 0);
 
 
...
 
...
 
-- Interfaces
 
-- Interfaces
Line 181: Line 185:
 
</pre>
 
</pre>
  
* Add UART instance to section after begin
+
=== Add UART instance to section after begin ===
  
 
<pre>
 
<pre>
Line 199: Line 203:
 
     txClkEn => serialEn,
 
     txClkEn => serialEn,
 
   -- Serial I/F
 
   -- Serial I/F
     urxd     => urxd1,
+
     rxd     => rxd1,
     utxd     => utxd1,
+
     txd     => txd1,
     urts   => urts1,
+
     n_rts   => rts1,
     ucts   => ucts1
+
     n_cts   => cts1
 
   );
 
   );
 
</pre>
 
</pre>
  
* Add Baud Rate Generator instance
+
=== Add Baud Rate Generator instance ===
 +
 
 +
* Sets baud rate to 115,200 baud
  
 
<pre>
 
<pre>
Line 217: Line 223:
 
   )
 
   )
 
   PORT map (
 
   PORT map (
   i_CLOCK_50 => i_CLOCK_50,
+
   i_CLOCK_50 => i_clk,
 
   o_serialEn => serialEn
 
   o_serialEn => serialEn
 
);
 
);
 
</pre>
 
</pre>
  
* Add Chip selects logic
+
=== Add Chip selects logic ===
 +
 
 
* Make sure to set the address of the UART (0x08-0x09 in this instance)
 
* Make sure to set the address of the UART (0x08-0x09 in this instance)
  
Line 231: Line 238:
 
</pre>
 
</pre>
  
* Add UART output data to w_periphIn
+
=== Add UART output data to w_periphIn ===
 +
 
 
* Make sure to set the address of the UART (0x08-0x09 in this instance)
 
* Make sure to set the address of the UART (0x08-0x09 in this instance)
  
Line 244: Line 252:
 
* May have to fix some signal names
 
* May have to fix some signal names
 
** i_CLOCK_50 -> i_clk
 
** i_CLOCK_50 -> i_clk
 +
 +
=== Update Pins List ===
 +
 +
* New pins may need to be added
 +
 +
=== Verify no build issues ===
 +
 +
* Fix issues until it builds
 +
* Test nothing broke
 +
** LED should blink
  
 
= Create new peripherals =
 
= Create new peripherals =
 +
 +
* Patterned like above example
 +
* Takes in signals w_periphAdr, w_periphOut, w_periphWr, w_periphRd
 +
* Create out signal and add to mux
 +
* Create needed signals
 +
* Create strobes
  
 
= Write Assembly code =
 
= Write Assembly code =
 +
 +
== Add stack if needed ==
 +
 +
* If code will contain single level subroutine, fix cpu_001 calling instance
 +
<pre>
 +
IOP16: ENTITY work.cpu_001
 +
-- Need to pass down instruction RAM and stack sizes
 +
  generic map (
 +
    INST_ROM_SIZE_PASS => 512, -- Small code size since program is "simple"
 +
    STACK_DEPTH_PASS  => 1    -- Single level subroutine (not nested)
 +
)
 +
</pre>
 +
* If code will contain nested subroutines, fix cpu_001 calling instance
 +
<pre>
 +
IOP16: ENTITY work.cpu_001
 +
-- Need to pass down instruction RAM and stack sizes
 +
  generic map (
 +
    INST_ROM_SIZE_PASS => 512, -- Small code size since program is "simple"
 +
    STACK_DEPTH_PASS  => 4    -- Deeper stack
 +
)
 +
</pre>
 +
 +
== Edit example ==
 +
 +
* Start from existing code example \TestBuild\IOP16\IOP16_Code\testTimer folder
 +
* Copy to \TestBuild\IOP16\IOP16_Code\UART_Loopback folder
 +
 +
[[file:IOP16_PortingGuide_UARTLoopbackFolder.PNG]]
 +
 +
* Open UART_Loopback.csv in spreadsheet program (LibreOffice CALC, Excel, etc)
 +
 +
{| class="wikitable"
 +
! LABEL
 +
! OPCODE
 +
! REG_LABEL
 +
! OFFSET_ADDR
 +
! COMMENT
 +
! V3.0.0
 +
|-
 +
| START
 +
| IOW
 +
| 0X08
 +
| 0X00
 +
| WRITE TO LED
 +
|
 +
|-
 +
|
 +
| LRI
 +
| 0X00
 +
| 0X01
 +
| TIME 1 SEC
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X00
 +
| 0X06
 +
| STORE TO START TIMER
 +
|
 +
|-
 +
| WAITDUN
 +
| IOR
 +
| 0X01
 +
| 0X04
 +
| READ TIMER
 +
|
 +
|-
 +
|
 +
| ARI
 +
| 0X01
 +
| 0X01
 +
| CHECK BUSY
 +
|
 +
|-
 +
|
 +
| BNZ
 +
| WAITDUN
 +
|
 +
|
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X09
 +
| 0X00
 +
| WRITE TO LED
 +
|
 +
|-
 +
|
 +
| LRI
 +
| 0X00
 +
| 0X01
 +
| TIME 1 SEC
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X00
 +
| 0X06
 +
| STORE TO START TIMER
 +
|
 +
|-
 +
| WAITD2
 +
| IOR
 +
| 0X01
 +
| 0X04
 +
| READ TIMER
 +
|
 +
|-
 +
|
 +
| ARI
 +
| 0X01
 +
| 0X01
 +
| CHECK BUSY
 +
|
 +
|-
 +
|
 +
| BNZ
 +
| WAITD2
 +
|
 +
|
 +
|
 +
|-
 +
|
 +
| JMP
 +
| START
 +
|
 +
|
 +
|
 +
|-
 +
|}
 +
 +
* Edit code
 +
* Make sure to save as CSV
 +
 +
{| class="wikitable"
 +
! LABEL
 +
! OPCODE
 +
! REG_LABEL
 +
! OFFSET_ADDR
 +
! COMMENT
 +
! V3.0.0
 +
|-
 +
| START
 +
| JSR
 +
| INITURT
 +
|
 +
| INITIALIZE THE ACIA UART
 +
|
 +
|-
 +
|
 +
| LRI
 +
| 0X03
 +
| 0X01
 +
| LED INITIALLY OFF
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X03
 +
| 0X00
 +
| WRITE LED
 +
|
 +
|-
 +
| WAITRXD
 +
| IOR
 +
| 0X00
 +
| 0X08
 +
| READ UART STATUS
 +
|
 +
|-
 +
|
 +
| ARI
 +
| 0X00
 +
| 0X01
 +
| MASK RX DATA PRESENT BIT
 +
|
 +
|-
 +
|
 +
| BEZ
 +
| WAITRXD
 +
|
 +
| NO KBD DATA
 +
|
 +
|-
 +
|
 +
| IOR
 +
| 0X01
 +
| 0X09
 +
| READ UART DATA TO REG1
 +
|
 +
|-
 +
| WAITTXR
 +
| IOR
 +
| 0X00
 +
| 0X08
 +
| READ UART STATUS
 +
|
 +
|-
 +
|
 +
| ARI
 +
| 0X00
 +
| 0X02
 +
| MASK TX EMPTY BIT
 +
|
 +
|-
 +
|
 +
| BEZ
 +
| WAITTXR
 +
|
 +
| TX NOT YET READY
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X01
 +
| 0X09
 +
| WRITE OUT DATA TO UART
 +
|
 +
|-
 +
|
 +
| XRI
 +
| 0X03
 +
| 0X01
 +
| TOGGLE THE LED
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X03
 +
| 0X00
 +
| WRITE LED
 +
|
 +
|-
 +
|
 +
| JMP
 +
| WAITRXD
 +
|
 +
| RINSE AND REPEAT
 +
|
 +
|-
 +
| INITURT
 +
| LRI
 +
| 0X00
 +
| 0X03
 +
| RESET UART COMMAND
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X00
 +
| 0X08
 +
| WRITE UART CMD REG
 +
|
 +
|-
 +
|
 +
| LRI
 +
| 0X00
 +
| 0X20
 +
| TX CTRLS RTS
 +
|
 +
|-
 +
|
 +
| IOW
 +
| 0X00
 +
| 0X08
 +
| WRITE UART CMD REG
 +
|
 +
|-
 +
|
 +
| RTS
 +
|
 +
|
 +
|
 +
|
 +
|-
 +
|}
 +
 +
== Assemble ==
 +
 +
* Use Assembler to create .MIF and .LST files
 +
* Assembler is in \TestBuild\Design_A_CPU\Assembler folder
 +
* If Python 3 is installed double click pyAssemble_cpu_001.py to run
 +
* Browse to .\TestBuild\IOP16\IOP16_Code\UART_Loopback folder
 +
* Select UART_Loopback.csv file
 +
* Output .MIF and .LST files will be written to folder
 +
 +
=== Update .MIF file in ROM ===
 +
 +
* Update (as above)
 +
 +
[[file:IOP16_PortingGuide_Selecting_ROM_2.PNG]]
 +
 +
* Set path to new code
 +
* Make sure to set extension to .MIF
 +
 +
[[file:IOP16_PortingGuide_Selecting_ROM_3.PNG]]
 +
 +
* Resources
 +
 +
[[file:IOP16_PortingGuide_AppResources.PNG]]
  
 
= Test the build =
 
= Test the build =
 +
 +
* Download code to FPGA
 +
* Run puTTY
 +
** 115,200 baud
 +
** RTS/CTS handshake
 +
* Type on keyboard
 +
* Chars will loopback on serial
 +
* LED will toggle on/off with each character
 +
 +
[[file:IOP16_PortingGuide_puTTY_Cap.PNG]]
 +
 +
== UART Loopback build ==
 +
 +
* Branches of the trees that capture these changes
 +
** [https://github.com/douggilliland/IOP16/tree/UARTLoopback IOP-16 UARTLoopback Tree]
 +
** [https://github.com/douggilliland/Design_A_CPU/tree/UARTLoopback Design a CPU UARTLoopback Tree]
 +
 +
= Debug using SignalTap =
 +
 +
* SignalTap is an embedded Logic Analyzer
 +
** Can be used to debug designs
 +
* Right click on device Settings
 +
* Select .stp file
 +
 +
[[file:IOP16_PortingGuide_SignalTapDebug01.PNG]]
 +
 +
* Select Tools, Signal Tap Logic Analyzer
 +
 +
[[file:IOP16_PortingGuide_SignalTapDebug02.PNG]]
 +
 +
* Add nodes
 +
 +
[[file:IOP16_PortingGuide_SignalTapDebug03.PNG]]
 +
 +
# Compile
 +
# Download
 +
# Start capture
 +
# Press reset to trigger
 +
 +
[[file:IOP16_PortingGuide_SignalTapDebug04.PNG]]

Latest revision as of 10:46, 14 April 2022

Overview

This is a guide to extending the minimal IOP example by adding IOP16 Peripherals to the minimal design

Steps

  • Start with baseline (minimal) design
  • Copy/clone baseline (minimal) design
  • Build baseline (minimal) design
  • Copy design to new folder
  • Select/add peripherals
  • Create new peripherals
  • Write assembly code
  • Build/test

Baseline Design

Starts from IOP example

  • Similar to Arduino "Blink Sketch" and uses the following resources
    • Timer Unit - 1 second timer
      • The Timer unit can be removed if not needed
      • Timer makes Blink easier
    • On-board LED

Copy/Clone Sources

Alternately download ZIP files

  • Alternately you can download the two ZIP files from GitHub

IOP16 PortingGuide Download-Zip-Files.PNG

  • Unzip these two folders into the same folder

IOP16 PortingGuide Unzipped-to-Folder.PNG

  • Rename the folders to remove the -main from the folder path

IOP16 PortingGuide Remove-main.PNG

  • Result

IOP16 PortingGuide BuildFolderStructure.PNG

Build Minimal Design

Start by building the minimal example in Quartus II

  • Open the Project file (TestIOP16B.qpf) in Quartus II
  • Relative path: ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_Minimal

IOP16 PortingGuide Open-Project-File.PNG

  • Entities in Quartus should look like

IOP16 PortingGuide Entities.PNG

  • Build FPGA (click the blue "Start Compilation arrow)

Fix ROM File Path

  • Quartus does not verify the ROM file was correct
    • Could be buried in the status messages
    • Likely need to re-point to the ROM .MIF file since Quartus II sometimes "forgets"
    • Double click on the IOP_ROM file

IOP16 PortingGuide Selecting ROM 2.PNG

  • Hit finish
    • Check for error message

IOP16 PortingGuide ROM Error.PNG

  • Re-point to the ROM file
  • Make sure to select .MIF file extension

IOP16 PortingGuide ROM TestTimer.PNG

Build Again / Download

  • Build again
  • Should be no error messages
  • Result

IOP16 PortingGuide FirstBuildResults.PNG

  • Download to FPGA
  • Make sure pointing to the right folder

IOP16 PortingGuide DownloadFPGA.PNG

  • User LED should be blinking

Copy Design to new folder

  • Copy from folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_Minimal

IOP16 PortingGuide CopyFrom.PNG

  • Copy to folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_UART_Loopback

IOP16 PortingGuide CopyTo.PNG

  • Build (as above)

IOP16 PortingGuide Open-UART Project-File.PNG

  • Make sure to update ROM file (as above)
  • Make sure pointing to the right folder when downloading
  • Test (as above)

Select Peripherals

Select UART for example

Update Memory Map

  • Update Memory map in comments at start of TestIOP16B.vhd to add UART addresses
-- IOP16 MEMORY Map
-- 0X00      - KEY1 Pushbutton (R)
-- 0X00      - User LED (W)
-- 0x04-0x07 - Timer Unit
-- 0X08      - UART (Cmd/Stat) (r/w)
-- 0X09      - UART (Data) (r/w)

Add UART files to project

IOP16 PortingGuide AddFiles.PNG

  • Select VHDL files from \TestBuild\Design_A_CPU\Peripherals\UART folder

IOP16 PortingGuide AddUARTFiles.PNG

Add UART pins to top level entity pins list

entity TestIOP16B is
  port
  (
    -- Clock and Reset
    i_clk     : in std_logic := '1';		-- Clock (50 MHz)
    i_n_reset : in std_logic := '1';		-- SW2 on FPGA the card
    -- The key and LED on the FPGA card 
    i_key1    : in std_logic := '1';		-- SW1 on the FPGA card
    o_UsrLed  : out std_logic := '1';		-- USR LED on the FPGA card
		
    rxd1      : in std_logic := '1';		-- Hardware Handshake needed
    txd1      : out std_logic;
    cts1      : in std_logic := '1';
    rts1      : out std_logic;
    ...

Add to signals list

-- Decodes/Strobes
signal w_wrUart				:	std_logic;
signal w_rdUart				:	std_logic;
...
-- Interfaces
signal w_UartDataOut			:	std_logic_vector(7 downto 0);
...
-- Serial clock enable
signal serialEn      		: std_logic;		-- 16x baud rate clock

Add UART instance to section after begin

-- 6850 style UART
UART: entity work.bufferedUART
  port map (
    clk     			=> i_CLOCK_50,
    -- Strobes
    n_wr				=> not w_wrUart,
    n_rd    			=> not w_rdUart,
    -- CPU 
    regSel  			=> w_periphAdr(0),
    dataIn  			=> w_periphOut,
    dataOut 			=> w_UartDataOut,
    -- Clock strobes
    rxClkEn 			=> serialEn,
    txClkEn 			=> serialEn,
   -- Serial I/F
    rxd     			=> rxd1,
    txd     			=> txd1,
    n_rts   			=> rts1,
    n_cts   			=> cts1
  );

Add Baud Rate Generator instance

  • Sets baud rate to 115,200 baud
-- Baud Rate Generator
-- These clock enables are asserted for one period of input clk, at 16x the baud rate.
-- Set baud rate in BAUD_RATE generic
BAUDRATEGEN	:	ENTITY work.BaudRate6850
  GENERIC map (
    BAUD_RATE	=> 115200
  )
  PORT map (
  i_CLOCK_50	=> i_clk,
  o_serialEn	=> serialEn
);

Add Chip selects logic

  • Make sure to set the address of the UART (0x08-0x09 in this instance)
-- Strobes/Selects
w_wrUart <= '1' when ((w_periphAdr(7 downto 1)="0000100") and (w_periphWr = '1')) else '0';
w_rdUart <= '1' when ((w_periphAdr(7 downto 1)="0000100") and (w_periphRd = '1')) else '0';

Add UART output data to w_periphIn

  • Make sure to set the address of the UART (0x08-0x09 in this instance)
-- Peripheral bus read mux
w_periphIn <=	"0000000"&w_keyBuff when w_periphAdr=x"00"							else
                w_timerOut          when w_periphAdr(7 downto 2) = "000001"	else
                w_UartDataOut       when w_periphAdr(7 downto 1) = "0000100"	else
                x"00";
  • May have to fix some signal names
    • i_CLOCK_50 -> i_clk

Update Pins List

  • New pins may need to be added

Verify no build issues

  • Fix issues until it builds
  • Test nothing broke
    • LED should blink

Create new peripherals

  • Patterned like above example
  • Takes in signals w_periphAdr, w_periphOut, w_periphWr, w_periphRd
  • Create out signal and add to mux
  • Create needed signals
  • Create strobes

Write Assembly code

Add stack if needed

  • If code will contain single level subroutine, fix cpu_001 calling instance
IOP16: ENTITY work.cpu_001
-- Need to pass down instruction RAM and stack sizes
  generic map 	( 
    INST_ROM_SIZE_PASS => 512, -- Small code size since program is "simple"
    STACK_DEPTH_PASS   => 1    -- Single level subroutine (not nested)
)
  • If code will contain nested subroutines, fix cpu_001 calling instance
IOP16: ENTITY work.cpu_001
-- Need to pass down instruction RAM and stack sizes
  generic map 	( 
    INST_ROM_SIZE_PASS => 512, -- Small code size since program is "simple"
    STACK_DEPTH_PASS   => 4    -- Deeper stack
)

Edit example

  • Start from existing code example \TestBuild\IOP16\IOP16_Code\testTimer folder
  • Copy to \TestBuild\IOP16\IOP16_Code\UART_Loopback folder

IOP16 PortingGuide UARTLoopbackFolder.PNG

  • Open UART_Loopback.csv in spreadsheet program (LibreOffice CALC, Excel, etc)
LABEL OPCODE REG_LABEL OFFSET_ADDR COMMENT V3.0.0
START IOW 0X08 0X00 WRITE TO LED
LRI 0X00 0X01 TIME 1 SEC
IOW 0X00 0X06 STORE TO START TIMER
WAITDUN IOR 0X01 0X04 READ TIMER
ARI 0X01 0X01 CHECK BUSY
BNZ WAITDUN
IOW 0X09 0X00 WRITE TO LED
LRI 0X00 0X01 TIME 1 SEC
IOW 0X00 0X06 STORE TO START TIMER
WAITD2 IOR 0X01 0X04 READ TIMER
ARI 0X01 0X01 CHECK BUSY
BNZ WAITD2
JMP START
  • Edit code
  • Make sure to save as CSV
LABEL OPCODE REG_LABEL OFFSET_ADDR COMMENT V3.0.0
START JSR INITURT INITIALIZE THE ACIA UART
LRI 0X03 0X01 LED INITIALLY OFF
IOW 0X03 0X00 WRITE LED
WAITRXD IOR 0X00 0X08 READ UART STATUS
ARI 0X00 0X01 MASK RX DATA PRESENT BIT
BEZ WAITRXD NO KBD DATA
IOR 0X01 0X09 READ UART DATA TO REG1
WAITTXR IOR 0X00 0X08 READ UART STATUS
ARI 0X00 0X02 MASK TX EMPTY BIT
BEZ WAITTXR TX NOT YET READY
IOW 0X01 0X09 WRITE OUT DATA TO UART
XRI 0X03 0X01 TOGGLE THE LED
IOW 0X03 0X00 WRITE LED
JMP WAITRXD RINSE AND REPEAT
INITURT LRI 0X00 0X03 RESET UART COMMAND
IOW 0X00 0X08 WRITE UART CMD REG
LRI 0X00 0X20 TX CTRLS RTS
IOW 0X00 0X08 WRITE UART CMD REG
RTS

Assemble

  • Use Assembler to create .MIF and .LST files
  • Assembler is in \TestBuild\Design_A_CPU\Assembler folder
  • If Python 3 is installed double click pyAssemble_cpu_001.py to run
  • Browse to .\TestBuild\IOP16\IOP16_Code\UART_Loopback folder
  • Select UART_Loopback.csv file
  • Output .MIF and .LST files will be written to folder

Update .MIF file in ROM

  • Update (as above)

IOP16 PortingGuide Selecting ROM 2.PNG

  • Set path to new code
  • Make sure to set extension to .MIF

IOP16 PortingGuide Selecting ROM 3.PNG

  • Resources

IOP16 PortingGuide AppResources.PNG

Test the build

  • Download code to FPGA
  • Run puTTY
    • 115,200 baud
    • RTS/CTS handshake
  • Type on keyboard
  • Chars will loopback on serial
  • LED will toggle on/off with each character

IOP16 PortingGuide puTTY Cap.PNG

UART Loopback build

Debug using SignalTap

  • SignalTap is an embedded Logic Analyzer
    • Can be used to debug designs
  • Right click on device Settings
  • Select .stp file

IOP16 PortingGuide SignalTapDebug01.PNG

  • Select Tools, Signal Tap Logic Analyzer

IOP16 PortingGuide SignalTapDebug02.PNG

  • Add nodes

IOP16 PortingGuide SignalTapDebug03.PNG

  1. Compile
  2. Download
  3. Start capture
  4. Press reset to trigger

IOP16 PortingGuide SignalTapDebug04.PNG