|
//////////////////////////////////////////////////////////////////
|
|
////
|
|
////
|
|
//// CRCAHB CORE BLOCK
|
|
////
|
|
////
|
|
////
|
|
//// This file is part of the APB to I2C project
|
|
////
|
|
//// http://www.opencores.org/cores/apbi2c/
|
|
////
|
|
////
|
|
////
|
|
//// Description
|
|
////
|
|
//// Implementation of APB IP core according to
|
|
////
|
|
//// crcahb IP core specification document.
|
|
////
|
|
////
|
|
////
|
|
//// To Do: Things are right here but always all block can suffer changes
|
|
////
|
|
////
|
|
////
|
|
////
|
|
////
|
|
//// Author(s): - Julio Cesar
|
|
////
|
|
/////////////////////////////////////////////////////////////////
|
|
////
|
|
////
|
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG
|
|
////
|
|
////
|
|
////
|
|
//// This source file may be used and distributed without
|
|
////
|
|
//// restriction provided that this copyright statement is not
|
|
////
|
|
//// removed from the file and that any derivative work contains
|
|
//// the original copyright notice and the associated disclaimer.
|
|
////
|
|
////
|
|
//// This source file is free software; you can redistribute it
|
|
////
|
|
//// and/or modify it under the terms of the GNU Lesser General
|
|
////
|
|
//// Public License as published by the Free Software Foundation;
|
|
//// either version 2.1 of the License, or (at your option) any
|
|
////
|
|
//// later version.
|
|
////
|
|
////
|
|
////
|
|
//// This source is distributed in the hope that it will be
|
|
////
|
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
////
|
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
////
|
|
//// PURPOSE. See the GNU Lesser General Public License for more
|
|
//// details.
|
|
////
|
|
////
|
|
////
|
|
//// You should have received a copy of the GNU Lesser General
|
|
////
|
|
//// Public License along with this source; if not, download it
|
|
////
|
|
//// from http://www.opencores.org/lgpl.shtml
|
|
////
|
|
////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
module crc_control_unit
|
module crc_control_unit
|
(
|
(
|
//OUTPUTS
|
//OUTPUTS
|
output reg [1:0] byte_sel,
|
output reg [1:0] byte_sel,
|
output bypass_byte0,
|
output bypass_byte0,
|
output buffer_full,
|
output buffer_full,
|
output read_wait,
|
output read_wait,
|
output bypass_size,
|
output bypass_size,
|
output set_crc_init_sel,
|
output set_crc_init_sel,
|
output clear_crc_init_sel,
|
output clear_crc_init_sel,
|
output crc_out_en,
|
output crc_out_en,
|
output byte_en,
|
output byte_en,
|
output reset_pending,
|
output reset_pending,
|
//INPUTS
|
//INPUTS
|
input [1:0] size_in,
|
input [1:0] size_in,
|
input write,
|
input write,
|
input reset_chain,
|
input reset_chain,
|
input clk,
|
input clk,
|
input rst_n
|
input rst_n
|
);
|
);
|
|
|
//States definition for state_full
|
//States definition for state_full
|
localparam EMPTY = 2'b00;
|
localparam EMPTY = 2'b00;
|
localparam WRITE_1 = 2'b01;
|
localparam WRITE_1 = 2'b01;
|
localparam WRITE_2 = 2'b10;
|
localparam WRITE_2 = 2'b10;
|
localparam BYPASS = 2'b11;
|
localparam BYPASS = 2'b11;
|
|
|
//States definition for state_byte
|
//States definition for state_byte
|
localparam IDLE = 3'b100;
|
localparam IDLE = 3'b100;
|
localparam BYTE_0 = 3'b000;
|
localparam BYTE_0 = 3'b000;
|
localparam BYTE_1 = 3'b001;
|
localparam BYTE_1 = 3'b001;
|
localparam BYTE_2 = 3'b010;
|
localparam BYTE_2 = 3'b010;
|
localparam BYTE_3 = 3'b011;
|
localparam BYTE_3 = 3'b011;
|
|
|
//States definition for state_reset
|
//States definition for state_reset
|
localparam NO_RESET = 3'b000;
|
localparam NO_RESET = 3'b000;
|
localparam RESET = 3'b001;
|
localparam RESET = 3'b001;
|
localparam WAIT = 3'b010;
|
localparam WAIT = 3'b010;
|
localparam WRITE = 3'b011;
|
localparam WRITE = 3'b011;
|
localparam RESET_2 = 3'b100;
|
localparam RESET_2 = 3'b100;
|
|
|
//Coding for size signal
|
//Coding for size signal
|
localparam BYTE = 2'b00;
|
localparam BYTE = 2'b00;
|
localparam HALF_WORD = 2'b01;
|
localparam HALF_WORD = 2'b01;
|
localparam WORD = 2'b10;
|
localparam WORD = 2'b10;
|
|
|
//Flops Definition
|
//Flops Definition
|
reg [1:0] state_full;
|
reg [1:0] state_full;
|
reg [2:0] state_byte;
|
reg [2:0] state_byte;
|
reg [2:0] state_reset;
|
reg [2:0] state_reset;
|
|
|
//Internal signals
|
//Internal signals
|
reg [1:0] next_state_full;
|
reg [1:0] next_state_full;
|
reg [2:0] next_state_byte;
|
reg [2:0] next_state_byte;
|
reg [2:0] next_state_reset;
|
reg [2:0] next_state_reset;
|
|
|
wire last_byte;
|
wire last_byte;
|
wire has_data;
|
wire has_data;
|
|
|
|
|
//FSM for management of writes in the input buffers
|
//FSM for management of writes in the input buffers
|
//Definition of state register
|
//Definition of state register
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if(!rst_n)
|
if(!rst_n)
|
state_full <= EMPTY;
|
state_full <= EMPTY;
|
else
|
else
|
state_full <= next_state_full;
|
state_full <= next_state_full;
|
end
|
end
|
|
|
//This signal indicates that the last byte is in processing
|
//This signal indicates that the last byte is in processing
|
assign last_byte = (size_in == BYTE && state_byte == BYTE_0) ||
|
assign last_byte = (size_in == BYTE && state_byte == BYTE_0) ||
|
(size_in == HALF_WORD && state_byte == BYTE_1) ||
|
(size_in == HALF_WORD && state_byte == BYTE_1) ||
|
(size_in == WORD && state_byte == BYTE_3) ;
|
(size_in == WORD && state_byte == BYTE_3) ;
|
|
|
//Next state Logic
|
//Next state Logic
|
always @(*)
|
always @(*)
|
begin
|
begin
|
next_state_full = state_full;
|
next_state_full = state_full;
|
case(state_full)
|
case(state_full)
|
EMPTY : next_state_full = (write) ? WRITE_1 : EMPTY;
|
EMPTY : next_state_full = (write) ? WRITE_1 : EMPTY;
|
WRITE_1:
|
WRITE_1:
|
begin
|
begin
|
if(last_byte)
|
if(last_byte)
|
begin
|
begin
|
if(!write)
|
if(!write)
|
next_state_full = EMPTY;
|
next_state_full = EMPTY;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if(write)
|
if(write)
|
next_state_full = WRITE_2;
|
next_state_full = WRITE_2;
|
end
|
end
|
end
|
end
|
WRITE_2:
|
WRITE_2:
|
begin
|
begin
|
if(last_byte)
|
if(last_byte)
|
next_state_full = (write) ? BYPASS : WRITE_1;
|
next_state_full = (write) ? BYPASS : WRITE_1;
|
end
|
end
|
BYPASS :
|
BYPASS :
|
begin
|
begin
|
if(last_byte && !write)
|
if(last_byte && !write)
|
next_state_full = WRITE_1;
|
next_state_full = WRITE_1;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
//The flag full indicates that buffer is full and any attempt of writing must wait
|
//The flag full indicates that buffer is full and any attempt of writing must wait
|
assign buffer_full = (state_full == WRITE_2 && !last_byte) ||
|
assign buffer_full = (state_full == WRITE_2 && !last_byte) ||
|
(state_full == BYPASS && !last_byte);
|
(state_full == BYPASS && !last_byte);
|
|
|
assign read_wait = (state_byte != IDLE);
|
assign read_wait = (state_byte != IDLE);
|
|
|
//This signal controls the selection of the byte0
|
//This signal controls the selection of the byte0
|
//When bypass_byte0 = 1 the input of byte_ff is taken
|
//When bypass_byte0 = 1 the input of byte_ff is taken
|
//Otherwise, its output is taken
|
//Otherwise, its output is taken
|
assign bypass_byte0 = (state_full != BYPASS);
|
assign bypass_byte0 = (state_full != BYPASS);
|
|
|
//This signal indicates that there are data in the second position of the buffer
|
//This signal indicates that there are data in the second position of the buffer
|
assign has_data = (state_full == WRITE_2) ||
|
assign has_data = (state_full == WRITE_2) ||
|
(state_full == BYPASS ) ;
|
(state_full == BYPASS ) ;
|
|
|
|
|
//FSM for management of readings in the buffer
|
//FSM for management of readings in the buffer
|
//Definition of state register
|
//Definition of state register
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if(!rst_n)
|
if(!rst_n)
|
state_byte <= IDLE;
|
state_byte <= IDLE;
|
else
|
else
|
state_byte <= next_state_byte;
|
state_byte <= next_state_byte;
|
end
|
end
|
|
|
always @(*)
|
always @(*)
|
begin
|
begin
|
next_state_byte = state_byte;
|
next_state_byte = state_byte;
|
case(state_byte)
|
case(state_byte)
|
IDLE: next_state_byte = (write) ? BYTE_0 : IDLE;
|
IDLE: next_state_byte = (write) ? BYTE_0 : IDLE;
|
BYTE_0:
|
BYTE_0:
|
begin
|
begin
|
if(size_in == BYTE)
|
if(size_in == BYTE)
|
begin
|
begin
|
if(!write && !has_data)
|
if(!write && !has_data)
|
next_state_byte = IDLE;
|
next_state_byte = IDLE;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
next_state_byte = BYTE_1;
|
next_state_byte = BYTE_1;
|
end
|
end
|
end
|
end
|
BYTE_1:
|
BYTE_1:
|
begin
|
begin
|
if(size_in == HALF_WORD)
|
if(size_in == HALF_WORD)
|
begin
|
begin
|
if(has_data || (write && !buffer_full))
|
if(has_data || (write && !buffer_full))
|
next_state_byte = BYTE_0;
|
next_state_byte = BYTE_0;
|
else
|
else
|
next_state_byte = IDLE;
|
next_state_byte = IDLE;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
next_state_byte = BYTE_2;
|
next_state_byte = BYTE_2;
|
end
|
end
|
end
|
end
|
BYTE_2:
|
BYTE_2:
|
begin
|
begin
|
next_state_byte = BYTE_3;
|
next_state_byte = BYTE_3;
|
end
|
end
|
BYTE_3:
|
BYTE_3:
|
begin
|
begin
|
if(has_data || (write && !buffer_full))
|
if(has_data || (write && !buffer_full))
|
next_state_byte = BYTE_0;
|
next_state_byte = BYTE_0;
|
else
|
else
|
next_state_byte = IDLE;
|
next_state_byte = IDLE;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
//The signal byte_sel controls the number of byte that will be processed by CRC Unit
|
//The signal byte_sel controls the number of byte that will be processed by CRC Unit
|
always @(*)
|
always @(*)
|
begin
|
begin
|
byte_sel = 2'b00;
|
byte_sel = 2'b00;
|
case(state_byte)
|
case(state_byte)
|
BYTE_0: byte_sel = BYTE_0;
|
BYTE_0: byte_sel = BYTE_0;
|
BYTE_1: byte_sel = BYTE_1;
|
BYTE_1: byte_sel = BYTE_1;
|
BYTE_2: byte_sel = BYTE_2;
|
BYTE_2: byte_sel = BYTE_2;
|
BYTE_3: byte_sel = BYTE_3;
|
BYTE_3: byte_sel = BYTE_3;
|
endcase
|
endcase
|
end
|
end
|
//This signal controls the selection of the metadata size
|
//This signal controls the selection of the metadata size
|
//When bypass_size = 1 the input of size_ff is taken
|
//When bypass_size = 1 the input of size_ff is taken
|
//Otherwise, its output is taken
|
//Otherwise, its output is taken
|
assign bypass_size = !( (state_full != BYPASS && state_byte != BYTE_0) ||
|
assign bypass_size = !( (state_full != BYPASS && state_byte != BYTE_0) ||
|
(state_full == BYPASS)
|
(state_full == BYPASS)
|
);
|
);
|
|
|
//This signal enables the write in the crc_out register
|
//This signal enables the write in the crc_out register
|
assign crc_out_en = (state_byte != IDLE);
|
assign crc_out_en = (state_byte != IDLE);
|
|
|
//
|
//
|
assign byte_en = (state_byte == BYTE_0 && (size_in == HALF_WORD || size_in == WORD) && state_full != BYPASS) ||
|
assign byte_en = (state_byte == BYTE_0 && (size_in == HALF_WORD || size_in == WORD) && state_full != BYPASS) ||
|
(last_byte && has_data);
|
(last_byte && has_data);
|
|
|
//FSM for control of reset of chained operation
|
//FSM for control of reset of chained operation
|
//Definition of state register
|
//Definition of state register
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if(!rst_n)
|
if(!rst_n)
|
state_reset <= NO_RESET;
|
state_reset <= NO_RESET;
|
else
|
else
|
state_reset <= next_state_reset;
|
state_reset <= next_state_reset;
|
end
|
end
|
|
|
always @(*)
|
always @(*)
|
begin
|
begin
|
next_state_reset = state_reset;
|
next_state_reset = state_reset;
|
case(state_reset)
|
case(state_reset)
|
NO_RESET:
|
NO_RESET:
|
begin
|
begin
|
if((reset_chain && !has_data && state_byte != IDLE && !last_byte) || (reset_chain && has_data && last_byte))
|
if((reset_chain && !has_data && state_byte != IDLE && !last_byte) || (reset_chain && has_data && last_byte))
|
next_state_reset = RESET;
|
next_state_reset = RESET;
|
if(reset_chain && has_data && !last_byte)
|
if(reset_chain && has_data && !last_byte)
|
next_state_reset = WAIT;
|
next_state_reset = WAIT;
|
end
|
end
|
RESET:
|
RESET:
|
begin
|
begin
|
if(last_byte)
|
if(last_byte)
|
next_state_reset = NO_RESET;
|
next_state_reset = NO_RESET;
|
else
|
else
|
next_state_reset = (write) ? WRITE : RESET;
|
next_state_reset = (write) ? WRITE : RESET;
|
end
|
end
|
WAIT:
|
WAIT:
|
begin
|
begin
|
if(last_byte)
|
if(last_byte)
|
next_state_reset = (write) ? WRITE : RESET;
|
next_state_reset = (write) ? WRITE : RESET;
|
else
|
else
|
next_state_reset = WAIT;
|
next_state_reset = WAIT;
|
end
|
end
|
WRITE:
|
WRITE:
|
begin
|
begin
|
if(reset_chain)
|
if(reset_chain)
|
next_state_reset = (last_byte) ? RESET : RESET_2;
|
next_state_reset = (last_byte) ? RESET : RESET_2;
|
else
|
else
|
next_state_reset = (last_byte) ? NO_RESET : WRITE;
|
next_state_reset = (last_byte) ? NO_RESET : WRITE;
|
end
|
end
|
RESET_2:
|
RESET_2:
|
begin
|
begin
|
if(last_byte)
|
if(last_byte)
|
next_state_reset = (write) ? WRITE : RESET;
|
next_state_reset = (write) ? WRITE : RESET;
|
else
|
else
|
next_state_reset = RESET_2;
|
next_state_reset = RESET_2;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
//This signal set the crc_init_sel flop
|
//This signal set the crc_init_sel flop
|
//When seted this flop turn on the chained operation of crc
|
//When seted this flop turn on the chained operation of crc
|
assign set_crc_init_sel = (state_byte == BYTE_0);
|
assign set_crc_init_sel = (state_byte == BYTE_0);
|
|
|
//This signal clear the crc_init_sel
|
//This signal clear the crc_init_sel
|
//The clear get priority over set
|
//The clear get priority over set
|
assign clear_crc_init_sel = (state_reset == NO_RESET && last_byte && reset_chain) ||
|
assign clear_crc_init_sel = (state_reset == NO_RESET && last_byte && reset_chain) ||
|
(state_byte == IDLE && reset_chain ) ||
|
(state_byte == IDLE && reset_chain ) ||
|
(state_reset == RESET && last_byte ) ||
|
(state_reset == RESET && last_byte ) ||
|
(state_reset == WRITE && last_byte ) ||
|
(state_reset == WRITE && last_byte ) ||
|
(state_reset == RESET_2 && last_byte ) ;
|
(state_reset == RESET_2 && last_byte ) ;
|
|
|
assign reset_pending = (state_reset != NO_RESET);
|
assign reset_pending = (state_reset != NO_RESET);
|
|
|
endmodule
|
endmodule
|
|
|