DMAC - FIFO for DMAC
#FIFO for DMAC
- 기존 FIFO에서 data in port와 data out port를 3개 늘려서 구현
- 내부에 3개의 Register File을 Instance
module fifo_for_DMAC(
clk,
reset_n,
wr_en,
rd_en,
din0,
din1,
din2,
dout0,
dout1,
dout2,
data_count,
full,
empty,
wr_ack,
wr_err,
rd_ack,
rd_err
);
input clk, reset_n, wr_en, rd_en;
input [7:0] din0, din1, din2;
output reg [7:0] dout0, dout1, dout2;
output [3:0] data_count;
output reg full, empty, wr_ack, wr_err, rd_ack, rd_err;
reg we,re;
reg [2:0] state, next_state;
reg [3:0] data_count, next_data_count;
reg [2:0] head, next_head;
reg [2:0] tail, next_tail;
reg [7:0] next_dout0, next_dout1, next_dout2;
wire [7:0] r_data0, r_data1, r_data2;
regfile U0_regfile(.clk(clk), .wAddr(tail), .wData(din0), .we(we), .rAddr(head), .rData(r_data0)); //call regfile
regfile U1_regfile(.clk(clk), .wAddr(tail), .wData(din1), .we(we), .rAddr(head), .rData(r_data1)); //call regfile
regfile U2_regfile(.clk(clk), .wAddr(tail), .wData(din2), .we(we), .rAddr(head), .rData(r_data2)); //call regfile
/////////State Encoding/////////
parameter IDLE_STATE = 3'b000;
parameter WRITE_STATE = 3'b001;
parameter READ_STATE = 3'b010;
parameter WR_ERR_STATE = 3'b011;
parameter RD_ERR_STATE = 3'b100;
//re value set by next_state
always@(next_state)
case(next_state)
READ_STATE:re = 1'b1; //if state is Read, re signal is 1
default:re = 1'b0; //default re siganl is 0
endcase
//2 to 1 multiplexer's roll
always@(re, r_data0)
if(re)next_dout0 <= r_data0; //if re is 1, r_data is stored at next_dout0
else next_dout0 <=8'h00; //else 8'h00 is stored at next_dout0
always@(re, r_data1)
if(re)next_dout1 <= r_data1; //if re is 1, r_data is stored at next_dout1
else next_dout1 <=8'h00; //else 8'h00 is stored at next_dout1
always@(re, r_data2)
if(re)next_dout2 <= r_data2; //if re is 1, r_data is stored at next_dout1
else next_dout2 <=8'h00; //else 8'h00 is stored at next_dout1
//next state logic
always @(wr_en, rd_en, state, next_state, data_count) //sensitive list
begin
case(state)
IDLE_STATE : //at IDLE_STATE
if(wr_en == 0 && rd_en == 0) next_state = IDLE_STATE; //if wr_en and rd_en are 0, IDLE_STATE
else if(wr_en == 1 && data_count < 8) next_state = WRITE_STATE; //if wr_en is 1 and data_count < 8, WRITE_STATE
else if(rd_en == 1 && data_count > 0) next_state = READ_STATE; //if rd_en is 1 and data_count > 0, READ_STATE
else if(wr_en == 1 && data_count == 8) next_state = WR_ERR_STATE;//if wr_en is 1 and data_count = 8, WR_ERR_STATE
else if(rd_en == 1 && data_count == 0) next_state = RD_ERR_STATE;//if rd_en is 1 and data_count = 0, RD_ERR_STATE
else next_state = 3'bxxx;
WRITE_STATE : //at WRITE_STATE
if(wr_en == 1 && data_count < 8) next_state = WRITE_STATE; //if wr_en is 1 and data_count < 8, WRITE_STATE
else if(wr_en == 1 && data_count == 8) next_state = WR_ERR_STATE;//if wr_en is 1 and data_count = 8, WR_ERR_STATE
else if(wr_en == 0 && rd_en == 0) next_state = IDLE_STATE; //if wr_en and rd_en are 0, IDLE_STATE
else if(rd_en == 1) next_state = READ_STATE; //if rd_en is 1, READ_STATE(적어도 data_count is bigger than 1 at WRITE_STATE)
else next_state = 3'bxxx;
READ_STATE : //at READ_STATE
if(rd_en == 1 && data_count > 0) next_state = READ_STATE; //if rd_en is 1 and data_count > 0, READ_STATE
else if(rd_en == 1 && data_count == 0) next_state = RD_ERR_STATE;//if rd_en is 1 and data_count = 0, RD_ERR_STATE
else if(wr_en == 1) next_state = WRITE_STATE; //if wr_en is 1 WRITE_STATE(적어도 data_count is smaller than 7 at READ_STATE)
else if(rd_en == 0 && wr_en == 0) next_state = IDLE_STATE; //if wr_en and rd_en are 0, IDLE_STATE
else next_state = 3'bxxx;
WR_ERR_STATE : //at WR_ERR_STATE
if(wr_en == 1) next_state = WR_ERR_STATE; //if wr_en is 1, WR_ERR_STATE
else if(rd_en == 1) next_state = READ_STATE; //if rd_en is 1, READ_STATE(data_count is 8 at WR_ERR_STATE)
else if(wr_en == 0 && rd_en == 0) next_state = IDLE_STATE; //if wr_en and rd_en are 0, IDLE_STATE
else next_state = 3'bxxx;
RD_ERR_STATE : //at RD_ERR_STATE
if(rd_en == 1) next_state = RD_ERR_STATE; //if rd_en is 1, RD_ERR_STATE
else if(wr_en == 1) next_state = WRITE_STATE; //if wr_en is 1, WRITE_STATE(data_count is 0 at RD_ERR_STATE)
else if(rd_en == 0 &&wr_en == 0) next_state = IDLE_STATE; //if wr_en and rd_en are 0, IDLE_STATE
else next_state = 3'bxxx;
default: next_state = 3'bxxx;
endcase
end
//sequential logic part(memory part)
always @(posedge clk or negedge reset_n)
begin
if(!reset_n) begin
state <= IDLE_STATE;
data_count <= 0;
head <= 0;
tail <= 0;
dout0 <= 0;
dout1 <= 0;
dout2 <= 0;
end
else if(reset_n)begin
state <= next_state;
data_count <= next_data_count;
head <= next_head;
tail <= next_tail;
dout0 <= next_dout0;
dout1 <= next_dout1;
dout2 <= next_dout2;
end
else begin
state <= 3'bxxx;
data_count <= 4'bxxxx;
head <= 3'bxxx;
tail <= 3'bxxx;
dout0 <= 8'bxxxxxxxx;
dout1 <= 8'bxxxxxxxx;
dout2 <= 8'bxxxxxxxx;
end
end
always @(state, data_count)
begin
case(state)
IDLE_STATE :
if(data_count == 0) {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b010000;
else if(data_count == 8) {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b100000;
else {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b000000;
WRITE_STATE :
if(data_count == 8) {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b101000;
else {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b001000;
WR_ERR_STATE : {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b100100;
READ_STATE :
if(data_count == 0) {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b010010;
else {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b000010;
RD_ERR_STATE : {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'b010001;
default : {full, empty, wr_ack, wr_err, rd_ack, rd_err} = 6'bxxxxxx;
endcase
end
always @(next_state, head, tail, data_count)
begin
case(next_state)
IDLE_STATE : begin //at IDLE_STATE current head, tail, data_count value are stored
next_head = head; // at next_head, next_tail, next_data_count value
next_tail = tail; // we is 0
next_data_count = data_count;
we = 1'b0;
end
WRITE_STATE : begin
next_head = head; //at WRITE_STATE current head, tail + 1, data_count value + 1 are stored
next_tail = tail + 3'b1; // at next_head, next_tail, next_data_count value
next_data_count = data_count + 4'b1; // we is 1
we = 1'b1; // because of WRITE_STATE state, tail is increased by 1
end
WR_ERR_STATE : begin
next_head = head; //at WE_ERR current head, tail, data_count value are stored
next_tail = tail; // at next_head, next_tail, next_data_count value
next_data_count = data_count; // we is 0
we = 1'b0;
end
READ_STATE : begin
next_head = head + 3'b1; //at READ_STATE current head + 1, tail, data_count value - 1 are stored
next_tail = tail; // at next_head, next_tail, next_data_count value
next_data_count = data_count - 4'b1; // we is 0
we = 1'b0; // because of READ_STATE state, head is increased by 1
end
RD_ERR_STATE : begin
next_head = head; //at RD_ERR_STATE current head, tail, data_count value are stored
next_tail = tail; // at next_head, next_tail, next_data_count value
next_data_count = data_count; // we is 0
we = 1'b0;
end
default : begin
next_head = 3'bxxx;
next_tail = 3'bxxx;
next_data_count = 4'bxxxx;
we = 1'bx;
end
endcase
end
endmodule