Monday, June 29, 2009

Multiple MIG 3.0 / 3.1 cores

How do you implement multiple DDR2 MIG cores in a single design? I guess the first question is how do you implement and integrate a single MIG core? I have been using the Core Generator from within ISE to add cores to my design. A MIG core is added by creating the core from within ISE which also automatically adds the generated xco file to the project. What does this mean for a MIG core? Let's assume you've named the core mig_a. A MIG core is open source - it creates all the sources under the folder
ipcore_dir/mig_a/user_design/rtl
or
ipcore_dir/mig_a/example_design/rtl
When you compile your project with the mig_a.xco file in your project, then it's just like you've added all of the rtl sources manually. This will enable you to instantiate the module mig_a.

Remember that you must take the UCF constraints as created in
ipcore_dir/mig_a/user_design/par/mig_a.ucf
and copy them over to your main UCF file.

In order to implement two DDR2 cores you would create mig_a.xco and mig_b.xco. The first issue you run into is with conflicting UCF constraints due to both mig_a and mig_b using identically named constraints. This is easy to solve, and shouldn't cause too much of a headache. If someone knows of a better way to do this I'd love a comment explaining.

The next issue is conflicting source component names. Here's the simple trick to solve those. DON'T USE THE XCO FILES! The DDR2 cores' source files are identical! The only difference in them are the parameters used at the top level instantiation file. Insert the files
ipcore_dir/mig_a/user_design/rtl/*.v and
ipcore_dir/mig_b/user_design/rtl/mig_b.v.

The final issue is the conflicting IODELAY_GRP name which by default in MIG's cores is set as "IODELAY_MIG." This should be changed in mig_a.v or mig_b.v but preferably in both for clarity's sake so that they don't conflict with each other. Use names like "IODELAY_MIG_A" and "IODELAY_MIG_B."

This solves all the conflicting component issues. You can now freely update your cores from MIG 3.0 to 3.1 without having to manually modify any files. You are using the Xilinx created files just as they are and without any ugly conflicts.

bye

Sunday, June 21, 2009

multi-dimensional array ports and variable bit selects

As a software programmer who moved to VHDL and then to Verilog, I have always found Verilog's language limitations to be very frustrating. One of my biggest complaints is Verilog's inability to use multi-dimensional arrays in port declarations.

For example:
module test(
input reg [7:0] a [2:0]
);
is illegal in Verilog. The only way to do this is:
module test(
input reg [23:0] a
);
What I had previously found myself doing was declaring the port level array as flat, and then converting it inside a standard generate block to the originally intended multi-dimensional array.

This is much clunkier than necessary. Variable bit-selects in Verilog allow for a much easier design. You can easily access the bits you require with this:

always @(posedge clk) begin : indexing process
integer i, index, found;
found = 0;
for(i = 0; i < 3; i = i + 1) begin
if(!found) begin
if(get_this_index[i]) begin
index = i;
found = 1;
end
end
end
if(found) begin
my_data <= a[index * 8+:8];
// my_data <= a_non_flat[index];
end
end

*** Note the +: notation. The first value is the start bit in the array, and the second value is the number of bits going up the array ( -: would go down the array). This shouldn't be confused with normal x:y notation. This is what makes pulling the correct bits out so easy.

This easily allows for parameterized modules with both compile-time bit widths and compile-time number of elements. The lack of multi-dimensional ports is made up for by variable bit selects. Of course you do need to remember the size of each "index" of data otherwise you'll be accessing the wrong bits...

Be enlightened,

Thursday, June 11, 2009

ISE internal infrastructure - does it exist?

I've been using ISE 11.1 for a couple months now and I must say that it makes me cringe when I think about the code that created this monster.

The good - Everything done outside of ISE. I have noticed that the tools which are the backend of ISE and everything they do are very reliable. At least from all of my experience. I'm guessing this is because they are pretty simple single threaded programs who know how to do the work they were built to do.

The bad - ISE. I am very sympathetic to the pains of writing a GUI which has to synchronize all sorts of other tasks. I know this is a very difficult task. You never know when the user will click something or when he might stop a process. ISE has to keep track of temporary files, source file changes, statuses and lots of other things. It's clear that the job is not easy. On the other hand Xilinx is a huge company and has the resources and responsibility to provide its users with a much better product.

In my experience ISE has many stability issues and quirks. I have learned to take them in stride. What I find shocking is that these bugs come from a very bad low-level infrastructure in the program, and not just a random assortment of small mistakes. (This is a huge assumption, but it is based both on my extensive experience with software and multithreaded applications, and on my experience with ISE.)

Example: When you change your source files in an external editor you see that ISE processes those changes only once you change focus back to ISE. Why??? That must be the strangest thing ever. It can actually take ISE seconds (why so long???) before it updates it's statuses - and you can see that in the ISE Processes window. If you click Generate Bitstream, or Synthesize before it has processed and updates its status then it will be ignored ostensibly because the files are up-to-date. This strikes me as an extraordinarily bad way to update internal ISE project status. Once a file is changed ISE should immediately process that and mark that file and all subsequent files as out-of-date.

Hoping for better with ISE 11.2 but seriously doubting it