FPGAWorkshop17Notes: Difference between revisions
From HacDC Wiki
Williamgibb (talk | contribs) No edit summary |
Williamgibb (talk | contribs) No edit summary |
||
Line 47: | Line 47: | ||
Copy and paste the contents of these files from the wiki [see below]. You should note that your missing a file, prog_rom, which is in the embedded_kcpsm3 module. Do not attempt to implement the design - it will not work until we generate the program ROM. | Copy and paste the contents of these files from the wiki [see below]. You should note that your missing a file, prog_rom, which is in the embedded_kcpsm3 module. Do not attempt to implement the design - it will not work until we generate the program ROM. | ||
When openpicide opens, you'll want to create a project. You should save the project file in your 'assembly' folder. Under the settings for the project, you'll need to do the following: | When openpicide opens, you'll want to create a project. You should save the project file in your 'assembly' folder as "picoblaze_example1". Under the settings for the project, you'll need to do the following: | ||
# Set the processor to Xilinx picoblaze | # Set the processor to Xilinx picoblaze | ||
# | # Under the VHDL tab, set the entity name to "prog_rom" | ||
# Set the vhdl source file to the ROM_form.vhd file we copied earlier. | # Set the vhdl source file to the ROM_form.vhd file we copied earlier. | ||
# You can leave the rest of the settings to their default values. | # You can leave the rest of the settings to their default values. | ||
You'll then need to create a new file - use the new file button in the upper left corner, or go to '''File''' -> '''New'''. Copy and paste the 1st example source file from the wiki. Using the '''Picoblaze Menu''' Run a syntax check on the code to make sure it is correct, and then generate a VHDL memory file from the code. Save the file as "prog_rom_example1.vhd" in your assembly section. You can now move back to ISE. | |||
You'll then need to create a new file - use the new file button in the upper left corner. Copy and paste the 1st example source file from the wiki. Run a syntax check on the code to make sure it is correct, and then generate a VHDL memory file from the code. Save the file as "prog_rom_example1.vhd" in your assembly section. You can now move back to ISE. | |||
Now, add the program file "prog_rom_example1.vhd" to your project, using "Add Copy of Source". You'll notice that the prog_rom module is no longer missing, and you can now implement the design. After programming the board, you should now see the LED's flipping on and off; if so, you have a working Picoblaze toolchain. | Now, add the program file "prog_rom_example1.vhd" to your project, using "Add Copy of Source". You'll notice that the prog_rom module is no longer missing, and you can now implement the design. After programming the board, you should now see the LED's flipping on and off; if so, you have a working Picoblaze toolchain. | ||
=== constraints.ucf === | === constraints.ucf === | ||
This constraints file can be used with the design examples covered in this tutorial. | |||
<pre> | <pre> | ||
Line 65: | Line 66: | ||
# UCF For Picoblaze Examples | # UCF For Picoblaze Examples | ||
# | # | ||
# Period constraint for 50MHz operation | # Period constraint for 50MHz operation, assume a 50% duty cycle, +/- 10% | ||
# | # | ||
NET "CLK_50MHZ" PERIOD = 20.0ns HIGH 40%; | NET "CLK_50MHZ" PERIOD = 20.0ns HIGH 40%; | ||
Line 147: | Line 148: | ||
</pre> | </pre> | ||
=== | === example #1 source === | ||
<pre> | |||
; | |||
; simple example code, original | |||
; | |||
start: LOAD s9, 0xAA | |||
drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit | |||
LOAD S2, 0x0F ; S2 initial value | |||
loop2: LOAD S1, 0xFF ; S1 initial value | |||
loop1: LOAD s0, 0xFF ; S0 initial value | |||
loop0: SUB s0, 0x01 | |||
JUMP NZ, loop0 | |||
SUB s1, 0x01 | |||
JUMP NZ, loop1 | |||
SUB s2, 0x01 | |||
JUMP NZ, loop2 | |||
; | |||
XOR s9, 0xFF ;toggle register | |||
JUMP drive_wave | |||
</pre> | |||
=== Expanding on the example === | |||
Create a new picoblaze project, in the assembly directory. Use the source from example #2 to create a new program rom file. You can name this program rom "prog_rom_example2.vhd". Copy this into your ISE project, and then remove the original prog_rom_example1.vhd from your project. Rebuild the project and reprogram your board. Your LEDs should be shifty now, instead of inverting! | |||
=== example #2 source === | |||
<pre> | |||
; | |||
; simple example code, shifting | |||
; wait longer too | |||
; | |||
start: LOAD s9, 0xA5 ; 10100101 | |||
drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit | |||
LOAD S2, 0x2F ; S2 initial value | |||
loop2: LOAD S1, 0xFF ; S1 initial value | |||
loop1: LOAD s0, 0xFF ; S0 initial value | |||
loop0: SUB s0, 0x01 | |||
JUMP NZ, loop0 | |||
SUB s1, 0x01 | |||
JUMP NZ, loop1 | |||
SUB s2, 0x01 | |||
JUMP NZ, loop2 | |||
; | |||
RL s9 ; shift left register | |||
JUMP drive_wave | |||
</pre> | |||
=== Lets have some input === | |||
Lets read in a switch now! To do this, you can do one of two things. You can add a input port, and add the multiplexed input re g manually. I've already built this example, so you can create a new ISE project. Can call this project "picoblaze_example3". Follow the instructions from earlier in the tutorial, but use the following verilog source file. | |||
=== example #3 source === | |||
<pre> | |||
module picoblaze_example3( | |||
input FPGA_RESET, | |||
input CLK_50MHZ, | |||
input SW1, | |||
output [7:0] LED | |||
); | |||
wire clock = CLK_50MHZ; | |||
// reset is active high. | |||
// if no reset signal input | |||
// then tie reset to zero here. | |||
wire reset = FPGA_RESET; | |||
wire [7:0] port_id; | |||
wire write_strobe; | |||
wire read_strobe; | |||
wire [7:0] out_port; | |||
reg [7:0] in_port; | |||
wire [7:0] switches; | |||
wire interrupt=0; | |||
wire interrupt_ack; | |||
embedded_kcpsm3 EMBEDDED( | |||
.port_id(port_id), | |||
.write_strobe(write_strobe), | |||
.read_strobe(read_strobe), | |||
.out_port(out_port), | |||
.in_port(in_port), | |||
.interrupt(interrupt), | |||
.interrupt_ack(interrupt_ack), | |||
.reset(reset), | |||
.clk(clock) | |||
); | |||
// only one bit written to by picoblaze, the LED. | |||
// therefore don't need to decode port_id. | |||
// if write_strobe asserts, grab out_port[0] and | |||
// hold it in userbit. | |||
reg [7:0] userbit = 0; | |||
always @(posedge clock) | |||
if(write_strobe) | |||
userbit <= out_port; | |||
end | |||
end | |||
// only one bit is read by picoblaze, the SW1. | |||
// therefore don't need to decode port_id. | |||
// if read_strobe asserts, grab swib out_port[0] and | |||
// hold it in userbit. | |||
always @(posedge clock) | |||
if(read_strobe) | |||
in_port <= switches; | |||
else | |||
in_port <= 8'bX; | |||
assign LED = userbit; | |||
assign switches = {7'b0, SW1}; | |||
endmodule | |||
</pre> | |||
=== example #3 source === | |||
<pre> | |||
; | |||
; simple example code, shifting and inverting | |||
; wait longer too | |||
; | |||
; read in a switch at each loop, if the switch is 1 then invert | |||
; the register instead of shifting it | |||
; | |||
; | |||
start: LOAD s9, 0xA5 ; 10100101 | |||
drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit | |||
LOAD S2, 0x2F ; S2 initial value | |||
loop2: LOAD S1, 0xFF ; S1 initial value | |||
loop1: LOAD s0, 0xFF ; S0 initial value | |||
loop0: SUB s0, 0x01 | |||
JUMP NZ, loop0 | |||
SUB s1, 0x01 | |||
JUMP NZ, loop1 | |||
SUB s2, 0x01 | |||
JUMP NZ, loop2 | |||
; Read the inport to s8 | |||
INPUT s8, 0x01 | |||
; test bit 0, if 1, set carry flag | |||
TEST s8, 0x01 | |||
; if (s8[0] == 1) invert_wave else shift_wave | |||
JUMP C, invert_wave | |||
; shift the wave and drive it | |||
shift_wave: RL s9 ; shift left register | |||
JUMP drive_wave | |||
; invert the wave and drive it | |||
invert_wave: XOR s9, 0xFF ;toggle register | |||
JUMP drive_wave | |||
</pre> | |||
=== Acknowledgements === | |||
This was based on a simple example found here |
Revision as of 21:05, 6 March 2010
PicoBlaze Flow Instructions
THIS SET OF INSTRUCTIONS ASSUMES THE READER IS FAMILIAR WITH THE ISE SUITE FLOW FOR CREATING, IMPLEMENTING AND PROGRAMING PROJECTS.
Overview of Picoblaze / ISE Development flow
The PicoBlaze development flow is different from the FPGA flow we've seen so far. We have to use a new tool, a PicoBlaze assembler, in conjunction with the ISE tool set.
I reccomend placing a folder named 'asssembly' or something else memorable in the root of your desired ISE project. This will keep an entire project togetheer in a single directory. You'll want to copy the ROM_form.vhd file from the picoblaze processor distribution to a convenient place, such as ./assembly directory or your project directory. We'll need to have a copy of this to use later.
The new tool we'll be working with today is openpicide. It is a project management IDE, Syntax check, program assembler and device simulator. It is opensource project, based on the QT framework. We'll be using it to generate the program ROM as a VHDL block ram file, which will be used with our design. The structure of our example project will look like the following:
- top_level.v
- embedded_kcpsm3.v
- kcpsm3.v
- prog_rom.vhd - This is the file generated by the assembler.
- embedded_kcpsm3.v
- project_constraints.ucf
In general, a picoblaze design would look like this
- top_level.v
- embedded_kcpsm3.v
- kcpsm3.v
- prog_rom.vhd - This is the file generated by the assembler.
- kcpsm3.v
- periperal1.v
- periperal2.v
- sub_module1.v
- ....
- other logic as needed
- embedded_kcpsm3.v
- project_constraints.ucf
Picoblaze simple example / toolchain tutorial
To begin, make sure you've got Xilinx ISE and OpenpicIDE installed. You can obtain openpicIDE here http://openpicide.org/ You'll also need to get the picoblaze download package.
First, we'll create the ISE project. Create a new project called picoblaze_example1 in your projects directory. Add copies of the following files from the picoblaze download package.
- embedded_kcpsm3.v
- kcpsm3.v
Then create 2 new source files
- constraints.ucf
- picoblaze_example1.v.
Copy and paste the contents of these files from the wiki [see below]. You should note that your missing a file, prog_rom, which is in the embedded_kcpsm3 module. Do not attempt to implement the design - it will not work until we generate the program ROM.
When openpicide opens, you'll want to create a project. You should save the project file in your 'assembly' folder as "picoblaze_example1". Under the settings for the project, you'll need to do the following:
- Set the processor to Xilinx picoblaze
- Under the VHDL tab, set the entity name to "prog_rom"
- Set the vhdl source file to the ROM_form.vhd file we copied earlier.
- You can leave the rest of the settings to their default values.
You'll then need to create a new file - use the new file button in the upper left corner, or go to File -> New. Copy and paste the 1st example source file from the wiki. Using the Picoblaze Menu Run a syntax check on the code to make sure it is correct, and then generate a VHDL memory file from the code. Save the file as "prog_rom_example1.vhd" in your assembly section. You can now move back to ISE.
Now, add the program file "prog_rom_example1.vhd" to your project, using "Add Copy of Source". You'll notice that the prog_rom module is no longer missing, and you can now implement the design. After programming the board, you should now see the LED's flipping on and off; if so, you have a working Picoblaze toolchain.
constraints.ucf
This constraints file can be used with the design examples covered in this tutorial.
# # UCF For Picoblaze Examples # # Period constraint for 50MHz operation, assume a 50% duty cycle, +/- 10% # NET "CLK_50MHZ" PERIOD = 20.0ns HIGH 40%; # # soldered 50MHz Clock. # NET "CLK_50MHZ" LOC = "C9" | IOSTANDARD = LVTTL; # Simple LEDs # Require only 3.5mA. # NET "LED<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "LED<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "LED<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "LED<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "led<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "led<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "led<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; NET "led<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 4; # Simple switches # Pull UP resistors used to stop floating condition during switching. # sw0 NET "FPGA_RESET" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP; # sw1 NET "SW1" LOC = L14 | | IOSTANDARD = LVTTL | PULLUP;
picoblaze_example1.v
module picoblaze_example1( input FPGA_RESET, input CLK_50MHZ, output [7:0] LED ); wire clock = CLK_50MHZ; // reset is active high. // if no reset signal input // then tie reset to zero here. wire reset = FPGA_RESET; wire [7:0] port_id; wire write_strobe; wire read_strobe; wire [7:0] out_port; wire [7:0] in_port=0; wire interrupt=0; wire interrupt_ack; embedded_kcpsm3 EMBEDDED( .port_id(port_id), .write_strobe(write_strobe), .read_strobe(read_strobe), .out_port(out_port), .in_port(in_port), .interrupt(interrupt), .interrupt_ack(interrupt_ack), .reset(reset), .clk(clock) ); // only one bit written to by picoblaze, the LED. // therefore don't need to decode port_id. // if write_strobe asserts, grab out_port[0] and // hold it in userbit. reg [7:0] userbit = 0; always @(posedge clock) begin if(write_strobe) begin userbit <= out_port; end end assign LED = userbit; endmodule
example #1 source
; ; simple example code, original ; start: LOAD s9, 0xAA drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit LOAD S2, 0x0F ; S2 initial value loop2: LOAD S1, 0xFF ; S1 initial value loop1: LOAD s0, 0xFF ; S0 initial value loop0: SUB s0, 0x01 JUMP NZ, loop0 SUB s1, 0x01 JUMP NZ, loop1 SUB s2, 0x01 JUMP NZ, loop2 ; XOR s9, 0xFF ;toggle register JUMP drive_wave
Expanding on the example
Create a new picoblaze project, in the assembly directory. Use the source from example #2 to create a new program rom file. You can name this program rom "prog_rom_example2.vhd". Copy this into your ISE project, and then remove the original prog_rom_example1.vhd from your project. Rebuild the project and reprogram your board. Your LEDs should be shifty now, instead of inverting!
example #2 source
; ; simple example code, shifting ; wait longer too ; start: LOAD s9, 0xA5 ; 10100101 drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit LOAD S2, 0x2F ; S2 initial value loop2: LOAD S1, 0xFF ; S1 initial value loop1: LOAD s0, 0xFF ; S0 initial value loop0: SUB s0, 0x01 JUMP NZ, loop0 SUB s1, 0x01 JUMP NZ, loop1 SUB s2, 0x01 JUMP NZ, loop2 ; RL s9 ; shift left register JUMP drive_wave
Lets have some input
Lets read in a switch now! To do this, you can do one of two things. You can add a input port, and add the multiplexed input re g manually. I've already built this example, so you can create a new ISE project. Can call this project "picoblaze_example3". Follow the instructions from earlier in the tutorial, but use the following verilog source file.
example #3 source
module picoblaze_example3( input FPGA_RESET, input CLK_50MHZ, input SW1, output [7:0] LED ); wire clock = CLK_50MHZ; // reset is active high. // if no reset signal input // then tie reset to zero here. wire reset = FPGA_RESET; wire [7:0] port_id; wire write_strobe; wire read_strobe; wire [7:0] out_port; reg [7:0] in_port; wire [7:0] switches; wire interrupt=0; wire interrupt_ack; embedded_kcpsm3 EMBEDDED( .port_id(port_id), .write_strobe(write_strobe), .read_strobe(read_strobe), .out_port(out_port), .in_port(in_port), .interrupt(interrupt), .interrupt_ack(interrupt_ack), .reset(reset), .clk(clock) ); // only one bit written to by picoblaze, the LED. // therefore don't need to decode port_id. // if write_strobe asserts, grab out_port[0] and // hold it in userbit. reg [7:0] userbit = 0; always @(posedge clock) if(write_strobe) userbit <= out_port; end end // only one bit is read by picoblaze, the SW1. // therefore don't need to decode port_id. // if read_strobe asserts, grab swib out_port[0] and // hold it in userbit. always @(posedge clock) if(read_strobe) in_port <= switches; else in_port <= 8'bX; assign LED = userbit; assign switches = {7'b0, SW1}; endmodule
example #3 source
; ; simple example code, shifting and inverting ; wait longer too ; ; read in a switch at each loop, if the switch is 1 then invert ; the register instead of shifting it ; ; start: LOAD s9, 0xA5 ; 10100101 drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit LOAD S2, 0x2F ; S2 initial value loop2: LOAD S1, 0xFF ; S1 initial value loop1: LOAD s0, 0xFF ; S0 initial value loop0: SUB s0, 0x01 JUMP NZ, loop0 SUB s1, 0x01 JUMP NZ, loop1 SUB s2, 0x01 JUMP NZ, loop2 ; Read the inport to s8 INPUT s8, 0x01 ; test bit 0, if 1, set carry flag TEST s8, 0x01 ; if (s8[0] == 1) invert_wave else shift_wave JUMP C, invert_wave ; shift the wave and drive it shift_wave: RL s9 ; shift left register JUMP drive_wave ; invert the wave and drive it invert_wave: XOR s9, 0xFF ;toggle register JUMP drive_wave
Acknowledgements
This was based on a simple example found here