Restructered pre-import
This commit is contained in:
425
Old Pages/Electronics/FPGAWorkshop17Notes.md
Executable file
425
Old Pages/Electronics/FPGAWorkshop17Notes.md
Executable file
@@ -0,0 +1,425 @@
|
||||
## PicoBlaze Flow / Tutorial
|
||||
|
||||
**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.
|
||||
|
||||
<figure>
|
||||
<img src="Picoblaze_flow.png" title="File:Picoblaze_flow.png" />
|
||||
<figcaption><a
|
||||
href="File:Picoblaze_flow.png">File:Picoblaze_flow.png</a></figcaption>
|
||||
</figure>
|
||||
|
||||
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:
|
||||
|
||||
1. top_level.v
|
||||
1. embedded_kcpsm3.v
|
||||
1. kcpsm3.v
|
||||
2. prog_rom.vhd - This is the file generated by the assembler.
|
||||
2. project_constraints.ucf
|
||||
|
||||
In general, a picoblaze design would look like this
|
||||
|
||||
1. top_level.v
|
||||
1. embedded_kcpsm3.v
|
||||
1. kcpsm3.v
|
||||
1. prog_rom.vhd - This is the file generated by the
|
||||
assembler.
|
||||
2. periperal1.v
|
||||
3. periperal2.v
|
||||
1. sub_module1.v
|
||||
2. ....
|
||||
4. other logic as needed
|
||||
2. project_constraints.ucf
|
||||
|
||||
## Example \#1
|
||||
|
||||
### 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:
|
||||
|
||||
1. Set the processor to Xilinx picoblaze
|
||||
2. Under the VHDL tab, set the entity name to "prog_rom"
|
||||
3. Set the vhdl source file to the ROM_form.vhd file we copied earlier.
|
||||
4. 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.
|
||||
|
||||
**note: the picoblaze assembly files and the openpicide project file
|
||||
need to be in the same directory**
|
||||
|
||||
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. You now need to comment out line 29, defining the
|
||||
constraint for SW1, from the UCF file. After that is commented out, you
|
||||
can 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
|
||||
|
||||
## Example \#2
|
||||
|
||||
### 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!
|
||||
|
||||
### picoblaze_example2.psm source
|
||||
|
||||
;
|
||||
; simple example code, shifting
|
||||
; wait longer too
|
||||
;
|
||||
start: LOAD s9, 0xA5 ; 10100101 ; <---- THIS CHANGED
|
||||
drive_wave: OUTPUT s9, 0x02 ; write s9 register to userbit
|
||||
LOAD S2, 0x2F ; S2 initial value <---- THIS CHANGED
|
||||
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 ; <---- THIS CHANGED
|
||||
JUMP drive_wave
|
||||
|
||||
## Example \#3
|
||||
|
||||
### Lets add 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.
|
||||
You'll also need to create a new OpenPicIDE project with the source used
|
||||
in the following example. Make sure that SW1 is not commented out in
|
||||
your UCF file.
|
||||
|
||||
### picoblaze_example3.v 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;
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
### picoblaze_example3.psm
|
||||
|
||||
;
|
||||
; 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
|
||||
|
||||
However, that code is a bit hard to read!! It can be much easier to read
|
||||
mnemonics instead of hex value and register id's. After getting the code
|
||||
above working, go ahead and add the following to the top of your
|
||||
picoblaze assembly source.
|
||||
|
||||
;
|
||||
; Make it human readable with mnemonics!
|
||||
;
|
||||
|
||||
NAMEREG S0, I_VAR
|
||||
NAMEREG S1, J_VAR
|
||||
NAMEREG S2, K_VAR
|
||||
NAMEREG S9, WAVE_VAR
|
||||
NAMEREG S8, SCRATCH_VAR
|
||||
|
||||
CONSTANT INITIAL_I, 0xFF
|
||||
CONSTANT INITIAL_J, 0xFF
|
||||
CONSTANT INITIAL_K, 0x2F
|
||||
CONSTANT INITIAL_WAVE, 0xA5 ;10100101
|
||||
CONSTANT BITMASK, 0x01
|
||||
;
|
||||
|
||||
After adding this section to your code, go through and replace the
|
||||
following items
|
||||
|
||||
- Register references, sX, should be replaced with the variable names
|
||||
- Constants which are named should be replaced.
|
||||
|
||||
After replacing the constants, you're code should look like this
|
||||
|
||||
start: LOAD WAVE_VAR, INITIAL_WAVE ;
|
||||
drive_wave: OUTPUT WAVE_VAR, 0x02 ; write s9 register to userbit
|
||||
LOAD K_VAR, INITIAL_K ; S2 initial value
|
||||
loop2: LOAD J_VAR, INITIAL_J ; S1 initial value
|
||||
loop1: LOAD I_VAR, INITIAL_I ; S0 initial value
|
||||
loop0: SUB I_VAR, 0x01
|
||||
JUMP NZ, loop0
|
||||
SUB J_VAR, 0x01
|
||||
JUMP NZ, loop1
|
||||
SUB K_VAR, 0x01
|
||||
JUMP NZ, loop2
|
||||
; Read the inport to s8
|
||||
INPUT SCRATCH_VAR , 0x01
|
||||
; test bit 0, if 1, set carry flag
|
||||
TEST SCRATCH_VAR , BITMASK
|
||||
; if (s8[0] == 1) invert_wave else shift_wave\
|
||||
JUMP C, invert_wave
|
||||
; shift the wave and drive it
|
||||
shift_wave: RL WAVE_VAR ; shift left register
|
||||
JUMP drive_wave
|
||||
; invert the wave and drive it
|
||||
invert_wave: XOR WAVE_VAR, 0xFF ;toggle register
|
||||
JUMP drive_wave
|
||||
|
||||
## Run the simulator
|
||||
|
||||
Now we have mnemonics entered into our code, we can easily tweak it.
|
||||
First, we can change the I_Var, J_Var, K_Var, to be smaller values, such
|
||||
as 0x0F. You can then step through the program, or just run it, in the
|
||||
OpenPicIDE simulator.
|
||||
|
||||
## Acknowledgements / References
|
||||
|
||||
This was based on a simple example found here
|
||||
<http://forums.xilinx.com/xlnx/board/message?board.id=PicoBlaze&thread.id=780>
|
||||
The Picoblaze download can be found here
|
||||
<http://www.xilinx.com/products/ipcenter/picoblaze-S3-V2-Pro.htm>
|
||||
OpenPicIDE is available here <http://openpicide.org>
|
||||
|
||||
[Category:FPGAWorkshop](Category:FPGAWorkshop "wikilink")
|
||||
Reference in New Issue
Block a user