Difference between revisions of "Extend IOP16 minimal example"
Jump to navigation
Jump to search
Blwikiadmin (talk | contribs) |
Blwikiadmin (talk | contribs) |
||
(133 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= Overview = | = Overview = | ||
− | + | This is a guide to extending the [https://github.com/douggilliland/IOP16/tree/main/Higher_Level_Examples/TestIOP16_Minimal minimal IOP example] by adding [[IOP16_Peripheral_Support|IOP16 Peripherals]] to the minimal design | |
− | * | + | |
+ | * This is not the same as [[Embed_IOP16|Embedding the IOP16 into another design]] | ||
* This guide requires general familiarity with [[IOP16_16-bit_I/O_CPU_Design|IOP16 16-bit I/O CPU Design]] | * This guide requires general familiarity with [[IOP16_16-bit_I/O_CPU_Design|IOP16 16-bit I/O CPU Design]] | ||
+ | * This example does not cover porting to a different FPGA card | ||
+ | ** Will need to adjust I/O pin assignments if a different FPGA is used | ||
== Steps == | == Steps == | ||
− | * Copy baseline design | + | * Start with baseline (minimal) design |
+ | * Copy/clone baseline (minimal) design | ||
+ | * Build baseline (minimal) design | ||
+ | * Copy design to new folder | ||
* Select/add peripherals | * Select/add peripherals | ||
* Create new peripherals | * Create new peripherals | ||
* Write assembly code | * Write assembly code | ||
+ | * Build/test | ||
+ | |||
+ | == Baseline Design == | ||
+ | |||
+ | Starts from [https://github.com/douggilliland/IOP16/tree/main/Higher_Level_Examples/TestIOP16_Minimal|minimal IOP example] | ||
+ | |||
+ | * Similar to [https://www.arduino.cc/en/pmwiki.php?n=Tutorial/Blink 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 = | ||
+ | |||
+ | * Clone the two repositories to the same directory level since relative paths are used for source files | ||
+ | ** [https://github.com/douggilliland/IOP16 IOP16 GitHub repository] | ||
+ | ** [https://github.com/douggilliland/Design_A_CPU Design a CPU GitHub repository] | ||
+ | * Example copies files to TestBuild folder | ||
+ | * There are a lot of extra files in the two unzipped folders (380MB) | ||
+ | |||
+ | == Alternately download ZIP files == | ||
+ | |||
+ | * Alternately you can download the two ZIP files from GitHub | ||
+ | |||
+ | [[file:IOP16_PortingGuide_Download-Zip-Files.PNG]] | ||
+ | |||
+ | * Unzip these two folders into the same folder | ||
+ | |||
+ | [[file:IOP16_PortingGuide_Unzipped-to-Folder.PNG]] | ||
+ | |||
+ | * Rename the folders to remove the -main from the folder path | ||
+ | |||
+ | [[file:IOP16_PortingGuide_Remove-main.PNG]] | ||
+ | |||
+ | * Result | ||
+ | |||
+ | [[file:IOP16_PortingGuide_BuildFolderStructure.PNG]] | ||
+ | |||
+ | = Build Minimal Design = | ||
− | + | Start by building the [https://github.com/douggilliland/IOP16/tree/main/Higher_Level_Examples/TestIOP16_Minimal minimal example] in Quartus II | |
− | * | + | * Open the Project file (TestIOP16B.qpf) in Quartus II |
− | ** | + | * Relative path: ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_Minimal |
− | *** | + | |
− | *** | + | [[file:IOP16_PortingGuide_Open-Project-File.PNG]] |
+ | |||
+ | * Entities in Quartus should look like | ||
+ | |||
+ | [[file: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 | ||
+ | |||
+ | [[file:IOP16_PortingGuide_Selecting_ROM_2.PNG]] | ||
+ | |||
+ | * Hit finish | ||
+ | ** Check for error message | ||
+ | |||
+ | [[file:IOP16_PortingGuide_ROM_Error.PNG]] | ||
+ | |||
+ | * Re-point to the ROM file | ||
+ | * Make sure to select .MIF file extension | ||
+ | |||
+ | [[file:IOP16_PortingGuide_ROM_TestTimer.PNG]] | ||
+ | |||
+ | == Build Again / Download == | ||
+ | |||
+ | * Build again | ||
+ | * Should be no error messages | ||
+ | * Result | ||
+ | |||
+ | [[file:IOP16_PortingGuide_FirstBuildResults.PNG]] | ||
+ | |||
+ | * Download to FPGA | ||
+ | * Make sure pointing to the right folder | ||
+ | |||
+ | [[file:IOP16_PortingGuide_DownloadFPGA.PNG]] | ||
+ | |||
+ | * User LED should be blinking | ||
+ | |||
+ | = Copy Design to new folder = | ||
+ | |||
+ | * Copy from folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_Minimal | ||
+ | |||
+ | [[file:IOP16_PortingGuide_CopyFrom.PNG]] | ||
+ | |||
+ | * Copy to folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_UART_Loopback | ||
+ | |||
+ | [[file:IOP16_PortingGuide_CopyTo.PNG]] | ||
+ | |||
+ | * Build (as above) | ||
+ | |||
+ | [[file: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 Peripherals = | ||
+ | |||
+ | * Pick from [[IOP16_Peripheral_Support|Supported peripherals list]] | ||
+ | |||
+ | == Select UART for example == | ||
+ | |||
+ | * This example will add [[IOP16_UART|UART peripheral]] | ||
+ | ** 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 | ||
+ | <pre> | ||
+ | -- 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) | ||
+ | </pre> | ||
+ | |||
+ | === Add UART files to project === | ||
+ | |||
+ | [[file:IOP16_PortingGuide_AddFiles.PNG]] | ||
+ | |||
+ | * Select VHDL files from \TestBuild\Design_A_CPU\Peripherals\UART folder | ||
+ | |||
+ | [[file:IOP16_PortingGuide_AddUARTFiles.PNG]] | ||
+ | |||
+ | === Add UART pins to top level entity pins list === | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | ... | ||
+ | </pre> | ||
+ | |||
+ | === Add to signals list === | ||
+ | |||
+ | <pre> | ||
+ | -- 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 | ||
+ | </pre> | ||
+ | |||
+ | === Add UART instance to section after begin === | ||
+ | |||
+ | <pre> | ||
+ | -- 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 | ||
+ | ); | ||
+ | </pre> | ||
+ | |||
+ | === Add Baud Rate Generator instance === | ||
+ | |||
+ | * Sets baud rate to 115,200 baud | ||
+ | |||
+ | <pre> | ||
+ | -- 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 | ||
+ | ); | ||
+ | </pre> | ||
+ | |||
+ | === Add Chip selects logic === | ||
+ | |||
+ | * Make sure to set the address of the UART (0x08-0x09 in this instance) | ||
+ | |||
+ | <pre> | ||
+ | -- 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'; | ||
+ | </pre> | ||
+ | |||
+ | === Add UART output data to w_periphIn === | ||
+ | |||
+ | * Make sure to set the address of the UART (0x08-0x09 in this instance) | ||
+ | |||
+ | <pre> | ||
+ | -- 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"; | ||
+ | </pre> | ||
+ | |||
+ | * 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 = | = 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
Contents
- 1 Overview
- 2 Copy/Clone Sources
- 3 Build Minimal Design
- 4 Copy Design to new folder
- 5 Select Peripherals
- 5.1 Select UART for example
- 5.1.1 Update Memory Map
- 5.1.2 Add UART files to project
- 5.1.3 Add UART pins to top level entity pins list
- 5.1.4 Add to signals list
- 5.1.5 Add UART instance to section after begin
- 5.1.6 Add Baud Rate Generator instance
- 5.1.7 Add Chip selects logic
- 5.1.8 Add UART output data to w_periphIn
- 5.1.9 Update Pins List
- 5.1.10 Verify no build issues
- 5.1 Select UART for example
- 6 Create new peripherals
- 7 Write Assembly code
- 8 Test the build
- 9 Debug using SignalTap
Overview
This is a guide to extending the minimal IOP example by adding IOP16 Peripherals to the minimal design
- This is not the same as Embedding the IOP16 into another design
- This guide requires general familiarity with IOP16 16-bit I/O CPU Design
- This example does not cover porting to a different FPGA card
- Will need to adjust I/O pin assignments if a different FPGA is used
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
- Timer Unit - 1 second timer
Copy/Clone Sources
- Clone the two repositories to the same directory level since relative paths are used for source files
- Example copies files to TestBuild folder
- There are a lot of extra files in the two unzipped folders (380MB)
Alternately download ZIP files
- Alternately you can download the two ZIP files from GitHub
- Unzip these two folders into the same folder
- Rename the folders to remove the -main from the folder path
- Result
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
- Entities in Quartus should look like
- 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
- Hit finish
- Check for error message
- Re-point to the ROM file
- Make sure to select .MIF file extension
Build Again / Download
- Build again
- Should be no error messages
- Result
- Download to FPGA
- Make sure pointing to the right folder
- User LED should be blinking
Copy Design to new folder
- Copy from folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_Minimal
- Copy to folder ..\TestBuild\IOP16\Higher_Level_Examples\TestIOP16_UART_Loopback
- Build (as above)
- Make sure to update ROM file (as above)
- Make sure pointing to the right folder when downloading
- Test (as above)
Select Peripherals
- Pick from Supported peripherals list
Select UART for example
- This example will add UART peripheral
- Will set up UART in loopback
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
- Select VHDL files from \TestBuild\Design_A_CPU\Peripherals\UART folder
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
- 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)
- Set path to new code
- Make sure to set extension to .MIF
- Resources
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
UART Loopback build
- Branches of the trees that capture these changes
Debug using SignalTap
- SignalTap is an embedded Logic Analyzer
- Can be used to debug designs
- Right click on device Settings
- Select .stp file
- Select Tools, Signal Tap Logic Analyzer
- Add nodes
- Compile
- Download
- Start capture
- Press reset to trigger