Wednesday, September 11, 2013

Reverse a singly linked list


static void _inPlaceRev( Node *cursor, Node *prev) {
  if(!cursor) { 
    return;
  }
  _inPlaceRev(head, tail, cursor->next, cursor);
  cursor->next = prev;
}

static void inPlaceRev(LinkedList * _my) {
  _inPlaceRev(_my->head, NULL);
  //swap the head and tail
  _my->head ^= _my->tail;
  _my->tail ^= _my->head;
  _my->head ^= _my->tail;

}

Monday, May 13, 2013

Object Oriented C

Since C is the mother of all the object oriented languages such as Objective c, c++, java, c#, and everything else, then C should have had SOME ability to be object oriented.

Object orientation is really, a pattern that helps reduce low level problems, such as memory management and encapsulation.  So, before Object oriented patterns became native, people in C would make the pattern.  I have made something that resembles that pattern.

The pattern includes:
1) data encapsulation
2) public member functions.

Object Oriented Linked List

Thursday, March 14, 2013

Send STDERR to terminal output. STDOUT to file

How to send STDERR to the terminal output and the STDOUT to a file.

Normally the STDOUT and STDERR are both sent to the terminal output.

To split them up we can use ">" and "2>" for STDOUT and STDERR respectively.

generic example
( cool_prog > cool_file ) 2>&1

**note, the parentheses are required or else it will not work**

The Explanation:

cool_prog will attempt to send thing into STDOUT.  The ">" will send it into cool_file.
cool_prog will attempt to send thing into STDERR.  The "2>&1" will send it to terminal output.

">&" should achieve the same effect as "2>&1"

To find more look at these links

http://www.macobserver.com/tips/macosxcl101/2002/20020607.shtml

http://www.tldp.org/LDP/abs/html/io-redirection.html

Friday, January 18, 2013

How to use cellular ram from micron M45W8MW16

Purpose/Goal/Desire:
To use the micron cellular ram as if it was a block ram.
A cpu is useless without ram.  My original approach was to use
block ram to create a ROM to store the main program files. and then
to use block ram for general purpose ram to store the stack and heap stuff.
When it came down to synthesis, I found that I only had enough block ram
for the rom.  I had two options, buy a bigger machine, or use micron's block ram.
It took a large sum of time to figure out how to use it, but in the end it paid off.

Remember that this is a guide in using asynchronous mode.  Its slower, but it makes everything
more homogenous.  And since I'm using it as a ram, I have no idea where the cpu is going to set/get the data.

Stuff that you need to make it work:

  1.  spec sheet
    1. They added an extra T to the name, making it harder to find
  2. Spartan 6 on nexus 3
    1. it has enough bram for a 32kx16 rom.  If you have a bigger board then you probably don't need to use the micron cellular ram.
  3. A guide for asynchronous mode
    1. pay attention to only slides 13,14, 21, and 22
  4. xilinx (i used version 14, but other versions should still work)

Gotchas

  1. You gotta let the device power on before you can use it. see init state in the FSM
  2. The specs say that you can do async read and write in 70 ns.  True, but once you add the commands to start the device up you get closer to 100 ns.
  3. using tristate buffers on the bidirectional dq bus is a must.
  4. The specs brag about the memory running at 80mhz, but that is for burst/page mode which are much harder to use.  Async mode will get you 10mhz.


my FSM

T : timer 10 ns

//These pins are used to talk to the celular ram  (memory_interface <--> cellular_ram);
addr_o : out std_logic_vector( addr_width-1 downto 0);
clk_o : out  std_logic;
addr_valid_o :out std_logic;
cntl_reg_enable_o : out std_logic;
chip_enable_o : out std_logic;
output_enable_o : out std_logic;
write_en_o : out std_logic;
lower_byte_en_o : out std_logic;
upper_byte_en_o : out std_logic;
data_io : inout std_logic_vector( data_width-1 downto 0);
wait_i : in std_logic;
//These are the pins used to help interface the memory as if it were a block ram ( some module <--> memory_interface);
addr_i : in std_logic_vector (addr_width-1 downto 0);
we_i : in std_logic ;
data_i : in std_logic_vector (data_width-1 downto 0);
data_o : out std_logic_vector (data_width-1 downto 0);
clk_i : in std_logic;
go_i : in std_logic //top module should set this to 0.  when ready to use, set to 1 for one cycle (max 90 ns) then bring down.  when go_i is high it will read or write otherwise it will be idle.;

View this high level pic to see where everything falls in place

Code: the stuff you probably just wanna take and play with right out of the box and probably the only thing you care about

memory interface

component used to interact with the memory interface

The two links above are synthesis able.  I linked them together in a wrapper file, loaded them on to the FPGA and crossed my fingers.  The first link goes to the source code for the memory interface.  It lets you use the memory as if it was a block ram.  But be warned....you may only read/write every 100ns.  Any slower will cause unexpected data.  Going slower is pretty much acceptable.  Oh yeah, remember to toggle the go_i input when you want to read/write.

the second link takes you to what looks like a massively long entity.  In actuality it has several architectures.  Each architecture has a different test.  One of them writes to 16k memory arrays one after the other, then reads them one after another.  Another test jumps really far to write and then jumps to read each of them.



Tuesday, October 30, 2012

vhdl random number generator for test benches

 LIBRARY ieee;
  USE ieee.std_logic_1164.ALL;
  USE ieee.math_real.ALL;   -- for UNIFORM, TRUNC functions
  USE ieee.numeric_std.ALL;

tb: process
VARIABLE seed1, seed2: positive;               -- Seed values for random generator
VARIABLE rand: real;                           -- Random real-number value in range 0 to 1.0
VARIABLE int_rand: integer;                    -- Random integer value in range 0..4095
variable time_var1, time_var2: time ;
begin
uniform(seed1, seed2,rand); -- generate random number
int_rand := INTEGER(trunc(rand*4096.0)); -- rescale to 0..4069, find integer part
int_rand := to_integer((to_unsigned(int_rand, 14)) );
time_var2 := (10 ms + (int_rand*1 us)); --save random time n a variable
rand_clock2 <= time_var2; --Save time to a signal so I can see it in waveform
wait for time_var2; --wait for duration random time

end process;

some explaination.....
the uniform function generates a psudo random number.  It is a "real" number so once it is generated the value must be truncated and then converted into an integer.

In this example I chose to turn that integer into a value that would vary the time delays.


References

Monday, September 3, 2012

Verilog Arrays

2d arrays always confuse me, so to save me some headache I'll post what I know about verilog arrays here for reference.

------------------------------------------------------------------------------------
reg [7:0] w; // bus of width 8.  aka std_logic_vector(7 downto 0);

(picture)
[7][6][5][4][3][2][1][0]

------------------------------------------------------------------------------------
reg arr [0:3]; // array of size 4 with 1 bit elements. aka array (0 to 3) of std_logic;

(picture)
[0]
[1]
[2]
[3]
------------------------------------------------------------------------------------

reg [7:0] arr [0:3];// 2d array.  aka array (0 to 3) of std_logic_vector(7 downto 0);

(picture)

key
(...)  --  index
[...]  --  stored value


(7)(6)(5)(4)(3)(2)(1)(0)
[0][1][2][3][4][5][6][7](0)
[8][9][a][b][c][d][e][f](1)
[g][h][i][j][k][l][m][n](2)
[o][p][q][r][s][t][u][v](3)

to access the elements in the array you need to use the operator []

arr[2]; // will give access to row 2. aka return an 8 bit word.
        // will return an value of "ghijklmn"

arr[0][3:2];// will go to row 0 then access columns 3 to 2
            // will return a value of "45"

arr[row][column];
//notes  you can slice a column in to different sizes, but you can only access one row at a time.






Verilog vs VHDL

UCR started me off with VHDL.  It was definately a struggle to learn how to avoid all the little errors.  The errors were of course my own fault for not realizing the nature of how hardware logic works.  Software does things differently then hardware does it, and I struggled with vhdl until I had learned the differences.  In the end, I developed a fondness for the HDL.

After graduation, it was up to me to decide my education.  My self taught education.  Verilog was the popular HDL in america and it would be a good idea to learn it since that is where everyone is at.  I gave it a shot and to my surprise, it was vastly more easy.  It probably has more to do with my experience with vhdl then the simplicity of the language.  I had already understood hardware so it was easy to learn the new language.

The two languages are essentially two different interfaces with the same thing.

The basic components like AND, REG, and COUNTER were finished with ease.  But I discovered a problem when I tried synthesising the counter.

Here is a snippet of code
==========
...

wire [WIDTH-1:0] reg2adder_w, adder2reg_w;

sreg_gen #( .WIDTH(WIDTH))
sreg(
.clock(clock), .reset(reset), .en(enable),
.data_i( adder2reg_w),
.data_o( reg2adder)
);
assign count = reg2adder;

...
=====
end snippit


look at the snippit and tell me if you see a problem.......got it? there is no wire named"reg2adder".  It was a typo and verilog responds by giving me warnings.  It responds by implicitly creating a wire called "reg2adder" of bitwidth 1.  So it gives me warnings telling me that the data_o is 32 bits and it is trying to shove it into reg2adder which is 1 bits.  This makes 31 of data_o's bits unconnected!

In VHDL, this would have turned out differently.  In VHDL it would have simply said something along the lines of "ERROR:reg2adder not declared".  Thats a much easier explanation then the warning I had recieved for verilog .

I've heard that verilog tends to sweep errors under the rug, but I didn't think it would make a mistake on something so simple.....

So the moral of the story is to make sure that you are using the right wire names cause apparently, verilog won't catch it for you.

VHDL one.... Verilog zero....