Sunday, November 27, 2011

My 1st Verilog, FIFO/ buffer for the 8080-type parallel interface module

We learn VHDL in academics. Engg. education is not just about learning from acads, its about applying the knowledge and leverage what you learnt.
Few years back, when I 1st learnt VHDL, i preferred C over it, any day. That is, till VHDL demonstrated its potential to me. Now when I make this transition from VHDL to Verilog, the story repeats itself. I prefer VHDL over Verilog :) At least I dont have to bother about syncing with things that are sensitive to an edge + a level.

My 1st Verilog.. a FIFO that goes between processor and the interface, to temporarily buffer the data till the interface send it across. Inspired from Net + my own learning from errors additions.
http://asic-world.com/examples/verilog/syn_fifo.html#Synchronous_FIFO


`timescale 1ns / 1ps

module fifo(
    proc_input,
    data_in,
    ready,
    clk, rst, done, wr_data,
    empty,
    full
    );

output [15:0] data_in;
output ready, empty, full;

input [15:0] proc_input;
input clk, rst, done, wr_data;

// ram = 2 ^ addr_width * 16 bit wide 
parameter ADDR_WIDTH = 4;
parameter RAM_DEPTH = (1 << ADDR_WIDTH); // 2 ^addr_width
parameter WORD_LENGTH = 16;

//-----------Internal variables-------------------
reg [ADDR_WIDTH-1:0] wr_ptr;
reg [ADDR_WIDTH-1:0] rd_ptr;
reg [ADDR_WIDTH :0] count;
reg [15:0] data_in; //if not initialized, it will be trimmed during optimization 
reg ready; // otherwise while assigning you get error:  Reference to scalar wire 'ready' is not a legal reg or variable lvalue
reg [WORD_LENGTH-1:0] mem [0:RAM_DEPTH-1];

assign full = (count == (RAM_DEPTH-1));
assign empty = (count == 0);

always @ (posedge clk or posedge rst) //cant have 1 posedge and non-edge triggered in sensi list
begin : WRITE
  if (rst)
    wr_ptr <= 0;
  else if(wr_data && (count != RAM_DEPTH-1)) //not full
    begin
wr_ptr <= wr_ptr + 1; //latch implied due to incomplete if 
  end
end

always @ (posedge done or posedge rst)
begin : READ_POINTER
  if (rst) begin
    rd_ptr <= 0;
  end else if (done && (count!=0)) begin
    rd_ptr <= rd_ptr + 1;
  end
end
// check if no need of done in if condition
//Xst:2111 - Clock of counter <rd_ptr> seems to be also used in the data or control logic of that element.

// the compiler wants count, rd_ptr and mem in the sensitivity list..shouldnt be used
always  @ (done, rst)
begin : READ_DATA
  if (rst) begin
    data_in <= 0; //data_in is  a register. one cant write data directly to port
ready <= 0;
  end else if (done && (count!=0)) begin //check trigger on done
    data_in <= mem[rd_ptr];
ready <= 1;
  end else begin
data_in <= 0; //to prevent latch on data_in. //should have been high z, but dunno how to represent that
ready <= 0;
  end
end

always @ (posedge clk or posedge rst)
begin : COUNTER
  if (rst)
    count <= 0;
  else if (done && (count != 0))
    count <= count - 1;
  else if (wr_data && (count != RAM_DEPTH))
    count <= count + 1;
end
//logically read and write can occur in parallel
//but without "else if" we get error that logic doesnt match FF template

always @ (wr_ptr, proc_input, wr_data)
begin
if (wr_data)
mem[wr_ptr] <= proc_input; //again a data_width size latch on mem_0 to mem_ram depth
end
endmodule

Notes: working mostly, yet to check corner cases..empty and full stuff
Have to check post-synthesis simulation..because of warnings that some signals may be trimmed..I dont want that to happen!!

2) Top level module: the code that made the chip..
contains modifications from the code published on the blog..
https://docs.google.com/document/d/1dOrttZW5EQFiEWcgUszROuMYu9jLKAuesl3KUhRyPsE/edit

2 comments:

  1. Structural module:

    fsm_veri_try1 FSM(
    .clk (clk),
    .rst (rst),
    .ready (connect_ready),
    .rs_in (rs_in),
    .asu (asu),
    .dsu (dsu),
    .ahold (ahold),
    .dhold (dhold),
    .en_active (en_active),
    .en_deactive (en_deactive),
    .data_in (connect_data_in),
    .dbus (dbus),
    .rs (rs),
    .CSb (CSb),
    .en (en),
    .done (connect_done)
    );

    fifo FIFO(
    .proc_input (proc_input),
    .data_in (connect_data_in),
    .ready (connect_ready),
    .clk (clk),
    .rst (clk),
    .done (connect_done),
    .wr_data (wr_data),
    .empty (empty),
    .full (full)
    );

    ReplyDelete
  2. Hi, my name is Michail, and I am from Moscow, doing electronics as a hobby. Probably I am stupid, but wasn't able to find any contacts of you :-) Just wanted to chat a bit. Drop me a message to 3@14.by if you wish.

    ReplyDelete