FPGARelated.com
Blogs

PicoBlaze - Program RAM Access for an Interactive Monitor

Victor YurkovskyJune 14, 20132 comments

I have a confession to make: I love PicoBlaze!  There are many reasons to love it.  It is a tiny CPU (96 Spartan3 slices or 26 Spartan6 slices plus a BRAM).  It is simple.  It is bug-free.  It's pretty fast.  It can reduce the size and the complexity of your design - instead of debugging a big state machine, just throw one (or more) of these in.  Add a serial output and you can debug your fpga from inside out!

However, there are a few problems.  The instruction set is not too enjoyable.  If you want C, you can't have it (I can live with that...There are some attempts, I am told).  The tools for linux are not great.  In particular, it doesn't seem to be possible to use the JTAG loader in linux (am I wrong? Has anyone done it?), and I do not like Windows.  That means I have to assemble, run data2mem and reconfigure my design every time I change Pico code.  There seems to be no way to load code into an existing design (in linux anyway).

Another thing I miss is an interactive monitor running over the serial port.  I like interactive debugging.  Unfortunately, you can't read or write to the BRAM, so you can't dump code or write a loader, making existing attempts at monitors less useful.

Let's fix the memory writing problem first.

Hardware to read and write BRAM.

Since the PicoBlaze uses a single port of a BRAM, we can use the other port for reading and writing via an IO-addressed device.  PicoBlaze is an 8-bit processor, but the address bus is 10 bits wide.  The instruction bus is even worse- its a whopping 18 bits wide.

While we could address the second BRAM port as 8-bit memory, we would lose the 2 remaining bits ( they are in parity bits available in 9-, 18- and 36-bit modes).  9-bit addressing gets too confusing - the weird ninth bit and the addresses being renumbered in a strange way.  Since the goal is to see what's in the Pico's program memory, let's just stick with 18 bits.

The most straightforward solution is to implement 3x 8-bit ports for data, and 2x 8-bit ports for the address, capable of reading and writing.  The address will be held in an 18-bit wide flip-flop array.  Since incrementing is pretty much free in hardware, we may as well dedicate a port to the incrementor and save all the adds with carry in software.

Changes to the PicoBlaze Program ROM

The Pico is normally connected to a single-ported BRAM.  A dual-ported one is required here, so let's fix that first. 

Where is program memory instantiated?  There is a file called ROM_form.v (or its vhdl equivalent elsewhere) that is used as a template to generate the BRAM instance, by the assembler.  It needs to be changed to something dual-ported like this:

RAMB16_S18_S18 ram_1024_x_18(
  .DIA  (16'h0000),
  .DIPA   (2'b00),
  .ENA  (1'b1),
  .WEA  (1'b0),
  .SSRA (1'b0),
  .CLKA (clk),
  .ADDRA  (address),
  .DOA  (instruction[15:0]),
  .DOPA (instruction[17:16]),
// adding 2nd port for monitor
  .DIB  (mtoram[15:0]),
  .DIPB   (mtoram[17:16]),
  .ENB  (1'b1),
  .WEB  (mwr),
  .SSRB (1'b0),
  .CLKB (clk),
  .ADDRB  (maddr),
  .DOB  (mfromram[15:0]),
  .DOPB (mfromram[17:16])
);


Of course, we need to connect the new PORTB memory ports to the outside, so the module declaration in the template file is expanded accordingly:

module {name} (address, instruction, clk,
  maddr,mfromram,mtoram,mwr);

Changes to the top module

The instance of PicoBlaze now looks like this in our top module:

 embedded_kcpsm3 cpu(
  port_id,
  write_strobe,
  read_strobe,
  out_port,
  in_port,
  interrupt, interrupt_ack,
  0, //not using reset
  clk,
// monitor ram
  maddr[9:0],
  mfromram[17:0],
  mtoram[17:0],
  mwr
)

Now we need to decode the IO space, which depends on what else you have in your PicoBlaze system.  I only have a serial port at locations 0 and 1, allowing for a quick and dirty solution:

// IO input mux
always @ (*)
case(port_id[3:0])
4'h0: in_port = {3'b000,rx_data_present, rx_full, rx_half_full, tx_full, tx_half_full};
4'h1: in_port = rx_data[7:0];
4'h2: in_port = maddr[9:8];
4'h3: in_port = maddr[7:0];
4'h4: in_port = mfromram[17:16];
4'h5: in_port = mfromram[15:8];
4'h6: in_port = mfromram[7:0];
default: in_port = 8'h12;
endcase

//output:

always @(posedge clk)
if(write_strobe)
case(port_id[2:0])
//address ports
3'h2: maddr[9:8] ‹= out_port;
   3'h3: maddr[7:0] ‹= out_port;
   //data ports
3'h4: mtoram[17:16] ‹= out_port;
   3'h5: mtoram[15:8] ‹= out_port;
   3'h6: mtoram[7:0] ‹= out_port;
  //incrementor
3'h7: maddr ‹= maddr + 1;
  endcase
//
always @(*) begin
if(write_strobe)
case(port_id[2:0])
3'h4: mwr=1;
3'h5: mwr=1;
3'h6: mwr=1;
default: mwr=0;
endcase
end

It's sloppy but does the job. If someone wishes to make a clean module, please opensource it and let me know!

A Quick Test

CONSTANT STATUS,0
CONSTANT UART,1
CONSTANT MADDR_HI,2
CONSTANT MADDR_LO,3
CONSTANT MRAM_HI,4
CONSTANT MRAM_ME,5
CONSTANT MRAM_LO,6
CONSTANT MADDR_INC,7

            ;load address 0
            load      s4,00
            output    s4,MADDR_HI
            load      s4,00
            output    s4,MADDR_LO
            ;read it back and display the address
            input     s4,MADDR_HI
            call      hex2
            input     s4,MADDR_LO
            call      hex2
            call      sp 
            ;
            ; read the data MADDR and display it...
            input     s4,MRAM_HI
            call      hex2
            input     s4,MRAM_ME
            call      hex2
            input     s4,MRAM_LO
            call      hex2
            call      cr

hex2 outputs a 2-digit hex number in s4 to my serial port; cr and sp are carriage return and space, respectively.

My serial port terminal shows

0000 000400

According to documentation, 000400 is in fact LOAD S4,00. 

Similar tests show that writing and incrementing works too.

Now what?

The Picoblaze now has access to its own program ROM, that is RAM...  It is now capable of running a monitor, modifying its own code and loading code via serial port.  These are all good things.

At a future date I will try to tackle a small monitor program for the PicoBlaze.  Unless you beat me to it - in which case, please share your tools and solutions with all of us. 


Xilinx and Spartan3 and PicoBlaze are registered trademarks of Xilinx Inc.


[ - ]
Comment by filipe.calasansSeptember 11, 2014
I've worked with picoblaze for a while, and despite it is a very tiny IP, characteristic that can be very worthy sometimes, it is very limited concerned to resources. I would pointout that interfacing Picoblaze is not too trivial, the port_in, port_out brings some issues, added the fact it is a 8-bit microcontroller makes difficult to interface memories, once we have to build register banks to hold the address. Finally the lack of C compilers to Picoblazze makes things still more painfull. I think unless you have educational propose in using Picoblaze, I would prefer using a Microblaze. Ps: There is a free version released by the Xilinx, despite its is a little bit limited I think it is a good option to substitute the picoblaze.
[ - ]
Comment by Abyss44June 28, 2015
Hellou,

there are new tools for Picoblaze development. Take a look at
http://www.moravia-microsystems.com/multitarget-development-system/

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Please login (on the right) if you already have an account on this platform.

Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: