//
//				crc1632.v - FCS Calculation for AX.25 and IEEE 802.3
//
//						(C) Copyright 2010 John B. Stephensen
//
// This Verilog source file and all its derivatives are licensed only for
// personal non-profit educational use in the Amateur Radio Service and
// the license is not transferrable. The information is provided as-is for
// experimental purposes and the author does not warranty its freedom
// from defects or its suitability for any specific application.
// 
// This module calculates the FCS for AX.25 and IEEE 802.3 using the polynomials
// X^16 + X^12 + X^5 + 1 specified for HDLC and X^32 + X^26 + X^23 + X^22 + X^16
// + X^12 + X^11 + X^10 + X^8 + X^7 + X^5 + X^4 + x^2 + x + 1 as described in
// appendix C of the DIX Ethernet "Blue Book". The data input is 8 or 16 bits
// wide as specified by WIDTH and clocked by the master clock, MCLK. Internally,
// bits are processed serially and clocked by the double rate bit clock, DCLK.
// The rising edges of MCLK and DCLK are synchronous and state changes occur on
// the positive going edges. CRC processing takes 4 clock cycles per byte or 8
// clock cycles per word.
//
// There are 3 input ports to allow writing bytes or words for CRC calculation
// and for initializing the CRCs to all ones:
//
//    15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 0 |                               |             Data              | Byte In
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 1 |                              Data                             | Word In
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 3 |                                                               | Reset
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// There are 3 output ports to read accumulated CRCs:
//
//    15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 0 |                           LSW CRC-32                          |
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 1 |                           MSW CRC-32                          |
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 2 |                             CRC-16                            |
//   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
//	BSY = CRC engine busy
//
// 58 slices used. 250 MHz maximum MCLK rate. 339 MHz maximum DCLK rate.
//
// Normal Warnings:
//		Input <ioaddr<2>> is never used.
//		Input <iord> is never used.
//
module crc1632 (
    input iocs,			// select this modeul
	 input [2:0] ioaddr,	// I/O address
	 input [15:0] din,	// input ports
	 input iowr,
	 output [15:0] dout,	// output ports
	 input iord,		
    input mclk,			// master clock
	 input dclk,			// double rate bit clock
	 input rst
    );
// internal signals
wire iv;				// input valid
reg init;			// initialize CRCs
reg s;				// select bit for CRC calculation
reg [3:0] c;		// bit counter
reg [7:0] d0,d1;	// input shift registers
wire e;				// shift enable
wire d;				// input bit
wire dx,dy;			// common factors
reg [0:31] x;		// CRC-32 shift register
reg [0:15] y;		// CRC-16 shift register
reg [15:0] omux;	// output multiplexer
// decode register addresses
assign iv = iocs & iowr & ~ioaddr[1];
// save input word and shift out LS dibit first
always @ (posedge mclk)
begin
	if (rst|init) c <= 0;									// reset to zero (idle state)
	else if (iv) c <= {ioaddr[0],~ioaddr[0],2'b00};	// load sets number of dibits
	else if (e) c <= c - 1;									// and then counts down to zero
	if (iv) d0 <= {din[14],din[12],din[10],din[8],din[6],din[4],din[2],din[0]};
	else d0 <= {1'b0,d0[7:1]};								// shift out even bits
	if (iv) d1 <= {din[15],din[13],din[11],din[9],din[7],din[5],din[3],din[1]};
	else d1 <= {1'b0,d1[7:1]};								// shift out odd bits
	init <= iocs & iowr & (ioaddr[1:0] == 3);			// sync. init to master clock
end
assign d = s ? d1[0] : d0[0];	// convert dibits to bits, LSB first
assign e = |c;							// counter is not zero
// calculate CRC
assign dx = d^x[31];	// XOR input data and last accumulated CRC bit
assign dy = d^y[15];
always @ (posedge dclk)
begin
	// multiplxer select line
	if (init) s <= 0;
	else s <= ~s;
	// X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+x^2+x+1
	if (init) x <= 32'hFFFFFFFF; 
	else if (e) x <= {dx,dx^x[0],dx^x[1],x[2],dx^x[3],dx^x[4],x[5],dx^x[6],dx^x[7],
							x[8],dx^x[9],dx^x[10],dx^x[11],x[12:14],dx^x[15],x[16:20],
							dx^x[21],dx^x[22],x[23:24],dx^x[25],x[26:30]};
	// Y^16 + Y^12 + Y^5 + 1
	if (init) y <= 16'hFFFF; 
	else if (e) y <= {dy,y[0:3],dy^y[4],y[5:10],dy^y[11],y[12:14]};
end
// output multiplexer
always @ (posedge mclk)
begin
	case (ioaddr[1:0])
	0: omux <= ~x[16:31];
	1: omux <= ~x[0:15];
	2: omux <= ~y;
	3: omux <= 0;
	default: omux <= 16'hxxxx;
	endcase
end
// connect output
assign dout = omux;
endmodule
