`timescale 1 ns / 1 ps module upload_protocol_intan# ( parameter CLK_PERIOD = 10 , parameter CHANNLE_QTY = 64 ) ( input clk , input rst_n , input enable , output interrupt , input pulse_ms , input [32-1:0] upload_round_qty_set , input reset_package_id , input [32-1:0] package_overtime_ms , input [32-1:0] s_axis_trigger_tdata , input s_axis_trigger_tvalid , output reg s_axis_trigger_tready , input [ 8-1:0] s_axis_eeg_tdata , input s_axis_eeg_tlast , output reg s_axis_eeg_tready , input s_axis_eeg_tvalid , input m_axis_record_tfull , output reg [ 8-1:0] m_axis_record_tdata , output reg [ 1-1:0] m_axis_record_tkeep , output reg m_axis_record_tlast , input m_axis_record_tready , output reg m_axis_record_tvalid ); //***************************************************************************** // localparam definition //***************************************************************************** localparam ST_IDLE = 4'h0 ; localparam ST_WAIT = 4'h1 ; localparam ST_MSG_HEAD = 4'h2 ; localparam ST_MSG_DATA_H = 4'h3 ; localparam ST_MSG_RECORD = 4'h4 ; localparam ST_MSG_DATA_T = 4'h5 ; localparam ST_MSG_REG_VAL = 4'h6 ; localparam ST_MSG_DA_AD = 4'h7 ; localparam ST_MSG_TRIG_IN = 4'h8 ; localparam ST_MSG_TRIG_OUT = 4'h9 ; localparam ST_MSG_CRC = 4'hA ; localparam ST_ADDITIONAL = 4'hB ; localparam HEAD_LTH = 12 ; localparam REG_LTH = 32 ; localparam DA_AD_LTH = 32 ; localparam TRIG_IN_LTH = 2 ; localparam TRIG_OUT_LTH = 2 ; localparam ADDL_LTH = 12 ; //***************************************************************************** // Internal register and wire declarations //***************************************************************************** reg [ 4-1:0] cstate ; reg [ 4-1:0] nstate ; wire [ 8-1:0] msg_head[0:HEAD_LTH-1] ; reg [32-1:0] package_id ; reg [32-1:0] overtime_ms ; reg [32-1:0] trigger_word ; wire [ 8-1:0] trigger_in_byte[0:15] ; // wire [ 8-1:0] trigger_out_byte[0:15] ; wire [ 8-1:0] msg_crc[0:1] ; reg [32-1:0] upload_round_qty ; reg [32-1:0] upload_rounds_cnt ; reg [32-1:0] upload_bytes_cnt ; wire [32-1:0] upload_bytes_cnt_add1 ; reg [32-1:0] upload_record_bytes_cnt ; wire [16-1:0] crc16_out ; reg [16-1:0] crc16 ; wire [ 8-1:0] upload_addl[0:12-1] ; reg [ 8-1:0] byte_cnt ; reg upload_break ; reg upload_disable ; //***************************************************************************** // Instantiation //***************************************************************************** //***************************************************************************** // Function //***************************************************************************** function automatic [15:0] crc16_d8; input [15:0] crcIn; input [7:0] data; begin crc16_d8[0] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ crcIn[8] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]; crc16_d8[1] = crcIn[9]; crc16_d8[2] = crcIn[10]; crc16_d8[3] = crcIn[11]; crc16_d8[4] = crcIn[12]; crc16_d8[5] = crcIn[13]; crc16_d8[6] = crcIn[0] ^ crcIn[14] ^ data[0]; crc16_d8[7] = crcIn[0] ^ crcIn[1] ^ crcIn[15] ^ data[0] ^ data[1]; crc16_d8[8] = crcIn[1] ^ crcIn[2] ^ data[1] ^ data[2]; crc16_d8[9] = crcIn[2] ^ crcIn[3] ^ data[2] ^ data[3]; crc16_d8[10] = crcIn[3] ^ crcIn[4] ^ data[3] ^ data[4]; crc16_d8[11] = crcIn[4] ^ crcIn[5] ^ data[4] ^ data[5]; crc16_d8[12] = crcIn[5] ^ crcIn[6] ^ data[5] ^ data[6]; crc16_d8[13] = crcIn[6] ^ crcIn[7] ^ data[6] ^ data[7]; crc16_d8[14] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6]; crc16_d8[15] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7]; end endfunction //***************************************************************************** always@( posedge clk or negedge rst_n ) begin if( !rst_n ) cstate <= ST_IDLE; else cstate <= nstate; end always@( * ) begin case ( cstate ) ST_IDLE: if ( enable && s_axis_eeg_tvalid ) nstate <= ST_MSG_HEAD; else nstate <= ST_IDLE; ST_WAIT: if ( !enable || upload_rounds_cnt == upload_round_qty || overtime_ms == package_overtime_ms || m_axis_record_tfull ) nstate <= ST_MSG_CRC; else if ( s_axis_eeg_tvalid ) nstate <= ST_MSG_HEAD; else nstate <= ST_WAIT; ST_MSG_HEAD: if ( byte_cnt == HEAD_LTH-1 ) nstate <= ST_MSG_DATA_H; else nstate <= ST_MSG_HEAD; ST_MSG_DATA_H: if ( byte_cnt == 48-1 ) nstate <= ST_MSG_RECORD; else nstate <= ST_MSG_DATA_H; ST_MSG_RECORD: if ( s_axis_eeg_tready && s_axis_eeg_tvalid && s_axis_eeg_tlast ) nstate <= ST_MSG_DATA_T; else nstate <= ST_MSG_RECORD; ST_MSG_DATA_T: if ( byte_cnt == 16-1 ) nstate <= ST_MSG_REG_VAL; else nstate <= ST_MSG_DATA_T; ST_MSG_REG_VAL: if ( byte_cnt == REG_LTH-1 ) nstate <= ST_MSG_DA_AD; else nstate <= ST_MSG_REG_VAL; ST_MSG_DA_AD: if ( byte_cnt == DA_AD_LTH-1 ) nstate <= ST_MSG_TRIG_IN; else nstate <= ST_MSG_DA_AD; ST_MSG_TRIG_IN: if ( byte_cnt == TRIG_IN_LTH-1 ) nstate <= ST_MSG_TRIG_OUT; else nstate <= ST_MSG_TRIG_IN; ST_MSG_TRIG_OUT: if ( byte_cnt == TRIG_OUT_LTH-1 ) nstate <= ST_WAIT; else nstate <= ST_MSG_TRIG_OUT; ST_MSG_CRC: if ( byte_cnt == 2-1 ) nstate <= ST_ADDITIONAL; else nstate <= ST_MSG_CRC; ST_ADDITIONAL: if ( byte_cnt == ADDL_LTH-1 ) nstate <= upload_break? ST_WAIT:ST_IDLE; else nstate <= ST_ADDITIONAL; default: nstate <= ST_IDLE; endcase end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_disable <= 1'b0; else if ( cstate == ST_ADDITIONAL && nstate != ST_ADDITIONAL ) upload_disable <= m_axis_record_tfull; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_break <= 1'b0; else if ( cstate == ST_WAIT && (upload_rounds_cnt != upload_round_qty && overtime_ms != package_overtime_ms) && m_axis_record_tfull && !upload_disable ) upload_break <= 1'b1; else if ( cstate == ST_ADDITIONAL && nstate != ST_ADDITIONAL ) upload_break <= 1'b0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) package_id <= 0; else if ( reset_package_id ) package_id <= 0; else if ( cstate == ST_MSG_TRIG_OUT && nstate == ST_WAIT ) package_id <= package_id + 1'b1; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_round_qty <= 0; else if ( cstate == ST_IDLE ) upload_round_qty <= upload_round_qty_set; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) s_axis_trigger_tready <= 1'b0; else if ( cstate == ST_MSG_DA_AD && nstate == ST_MSG_TRIG_IN ) s_axis_trigger_tready <= 1'b1; else s_axis_trigger_tready <= 1'b0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) trigger_word <= 0; else if ( s_axis_trigger_tvalid && s_axis_trigger_tready ) trigger_word <= s_axis_trigger_tdata; else if ( nstate == ST_WAIT ) trigger_word <= 0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) s_axis_eeg_tready <= 1'b0; else if ( cstate == ST_MSG_RECORD || nstate == ST_MSG_RECORD ) s_axis_eeg_tready <= 1'b1; else s_axis_eeg_tready <= 1'b0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) overtime_ms <= 0; else if ( s_axis_eeg_tvalid ) overtime_ms <= 0; else if ( pulse_ms ) overtime_ms <= overtime_ms + 1'b1; end always @ ( posedge clk ) begin if ( cstate == ST_IDLE ) crc16 <= 16'hFFFF; else if ( cstate != ST_MSG_CRC && m_axis_record_tvalid && m_axis_record_tready ) crc16 <= crc16_out; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) byte_cnt <= 0; else if ( cstate != nstate ) byte_cnt <= 0; else byte_cnt <= byte_cnt + 1'b1; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) begin m_axis_record_tdata <= 0; m_axis_record_tkeep <= 1'b1; m_axis_record_tvalid <= 1'b0; end else if ( cstate == ST_MSG_HEAD ) begin m_axis_record_tdata <= msg_head[byte_cnt]; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_DATA_H ) begin m_axis_record_tdata <= 8'd0; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_RECORD && s_axis_eeg_tvalid && s_axis_eeg_tready ) begin m_axis_record_tdata <= s_axis_eeg_tdata; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_DATA_T ) begin m_axis_record_tdata <= 8'd0; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_REG_VAL ) begin m_axis_record_tdata <= 8'd0; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_DA_AD ) begin m_axis_record_tdata <= 8'd0; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_TRIG_IN ) begin m_axis_record_tdata <= trigger_in_byte[byte_cnt]; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_TRIG_OUT ) begin m_axis_record_tdata <= 8'd0; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_MSG_CRC ) begin m_axis_record_tdata <= msg_crc[byte_cnt]; m_axis_record_tvalid <= 1'b1; end else if ( cstate == ST_ADDITIONAL ) begin m_axis_record_tdata <= upload_addl[byte_cnt]; m_axis_record_tvalid <= 1'b1; end else m_axis_record_tvalid <= 1'b0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) begin m_axis_record_tlast <= 1'b0; end else if ( cstate == ST_ADDITIONAL && (byte_cnt == ADDL_LTH-1) ) begin m_axis_record_tlast <= 1'b1; end else m_axis_record_tlast <= 1'b0; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_rounds_cnt <= 0; else if ( cstate == ST_IDLE ) upload_rounds_cnt <= 0; else if ( s_axis_eeg_tready && s_axis_eeg_tvalid && s_axis_eeg_tlast ) upload_rounds_cnt <= upload_rounds_cnt + 1'b1; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_bytes_cnt <= 0; else if ( cstate == ST_IDLE ) upload_bytes_cnt <= 0; else if ( (cstate != ST_ADDITIONAL) && m_axis_record_tvalid && m_axis_record_tready ) upload_bytes_cnt <= upload_bytes_cnt + 1'b1; end always @ ( posedge clk or negedge rst_n ) begin if ( !rst_n ) upload_record_bytes_cnt <= 0; else if ( cstate == ST_IDLE ) upload_record_bytes_cnt <= 0; else if ( cstate == ST_MSG_RECORD && s_axis_eeg_tvalid && s_axis_eeg_tready ) upload_record_bytes_cnt <= upload_record_bytes_cnt + 1'b1; end //***************************************************************************** // Wire assignment //***************************************************************************** assign msg_head[ 0] = 8'h0b; assign msg_head[ 1] = 8'h2f; assign msg_head[ 2] = 8'h71; assign msg_head[ 3] = 8'h49; assign msg_head[ 4] = 8'h8a; assign msg_head[ 5] = 8'h2c; assign msg_head[ 6] = 8'h54; assign msg_head[ 7] = 8'h8d; assign msg_head[ 8] = package_id[ 7: 0]; assign msg_head[ 9] = package_id[15: 8]; assign msg_head[10] = package_id[23:16]; assign msg_head[11] = package_id[31:24]; assign trigger_in_byte[ 0] = trigger_word[ 7: 0]; assign trigger_in_byte[ 1] = trigger_word[15: 8]; assign trigger_in_byte[ 2] = trigger_word[23:16]; assign trigger_in_byte[ 3] = trigger_word[31:24]; assign trigger_in_byte[ 4] = 8'd0; assign trigger_in_byte[ 5] = 8'd0; assign trigger_in_byte[ 6] = 8'd0; assign trigger_in_byte[ 7] = 8'd0; assign trigger_in_byte[ 8] = 8'd0; assign trigger_in_byte[ 9] = 8'd0; assign trigger_in_byte[10] = 8'd0; assign trigger_in_byte[11] = 8'd0; assign trigger_in_byte[12] = 8'd0; assign trigger_in_byte[13] = 8'd0; assign trigger_in_byte[14] = 8'd0; assign trigger_in_byte[15] = 8'd0; assign crc16_out = crc16_d8(crc16, m_axis_record_tdata); assign msg_crc[0] = crc16[15: 8]; assign msg_crc[1] = crc16[ 7: 0]; assign upload_bytes_cnt_add1 = upload_bytes_cnt + 1'b1; assign upload_addl[ 0] = upload_bytes_cnt_add1[ 7: 0]; assign upload_addl[ 1] = upload_bytes_cnt_add1[15: 8]; assign upload_addl[ 2] = upload_bytes_cnt_add1[23:16]; assign upload_addl[ 3] = upload_bytes_cnt_add1[31:24]; assign upload_addl[ 4] = upload_rounds_cnt[ 7: 0]; assign upload_addl[ 5] = upload_rounds_cnt[15: 8]; assign upload_addl[ 6] = upload_rounds_cnt[23:16]; assign upload_addl[ 7] = upload_rounds_cnt[31:24]; assign upload_addl[ 8] = upload_record_bytes_cnt[ 7: 0]; assign upload_addl[ 9] = upload_record_bytes_cnt[15: 8]; assign upload_addl[10] = upload_record_bytes_cnt[23:16]; assign upload_addl[11] = upload_record_bytes_cnt[31:24]; endmodule