| // SPDX-FileCopyrightText: |
| // 2022 Nguyen Dao |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| module config_UART #(
|
| parameter Mode = 0, // [0:auto|1:hex|2:bin] auto selects between ASCII-Hex and binary mode and takes a bit more logic,
|
| // bin is for faster binary mode, but might not work on all machines/boards
|
| // auto uses the MSB in the command byte (the 8th byte in the comload header) to set the mode
|
| // "1//- ////" is for hex mode, "0//- ////" for bin mode
|
| parameter ComRate = 217 // ComRate = f_CLK / Boud_rate (e.g., 25 MHz/115200 Boud = 217)
|
| ) (
|
| input CLK,
|
| input Rx,
|
| output reg [31:0] WriteData,
|
| output ComActive,
|
| output reg WriteStrobe,
|
| output [7:0] Command,
|
| output reg ReceiveLED
|
| );
|
|
|
| //constant TimeToSendValue : integer := 16777216-1; //200000000;
|
| localparam TimeToSendValue = 16777-1; //200000000;
|
| //localparam CRC_InitValue = 16'b1111111111111111;
|
| localparam TestFileChecksum = 20'h4FB00;
|
|
|
| function [4:0] ASCII2HEX;
|
| input [7:0] ASCII;
|
| begin
|
| case (ASCII)
|
| 8'h30: ASCII2HEX = 5'b00000;// 0
|
| 8'h31: ASCII2HEX = 5'b00001;
|
| 8'h32: ASCII2HEX = 5'b00010;
|
| 8'h33: ASCII2HEX = 5'b00011;
|
| 8'h34: ASCII2HEX = 5'b00100;
|
| 8'h35: ASCII2HEX = 5'b00101;
|
| 8'h36: ASCII2HEX = 5'b00110;
|
| 8'h37: ASCII2HEX = 5'b00111;
|
| 8'h38: ASCII2HEX = 5'b01000;
|
| 8'h39: ASCII2HEX = 5'b01001;
|
| 8'h41: ASCII2HEX = 5'b01010; // A
|
| 8'h61: ASCII2HEX = 5'b01010; // a
|
| 8'h42: ASCII2HEX = 5'b01011; // B
|
| 8'h62: ASCII2HEX = 5'b01011; // b
|
| 8'h43: ASCII2HEX = 5'b01100; // C
|
| 8'h63: ASCII2HEX = 5'b01100; // c
|
| 8'h44: ASCII2HEX = 5'b01101; // D
|
| 8'h64: ASCII2HEX = 5'b01101; // d
|
| 8'h45: ASCII2HEX = 5'b01110; // E
|
| 8'h65: ASCII2HEX = 5'b01110; // e
|
| 8'h46: ASCII2HEX = 5'b01111; // F
|
| 8'h66: ASCII2HEX = 5'b01111; // f
|
| default: ASCII2HEX = 5'b10000; // The MSB encodes if there was an unknown code -> error
|
| endcase
|
| end
|
| endfunction
|
|
|
| //typedef enum{HighNibble, LowNibble} ReceiveStateType; //systemverilog
|
| localparam HighNibble = 1, LowNibble = 0;
|
| //ReceiveStateType ReceiveState;
|
| reg ReceiveState = HighNibble;
|
| reg [3:0] HighReg;
|
| wire [4:0] HexValue; // a 1'b0 MSB indicates a valid value on [3..0]
|
| reg [7:0] HexData; // the received byte in hexmode mode
|
| reg HexWriteStrobe; // we received two hex nibles and have a result byte
|
|
|
| reg [11:0] ComCount;
|
| reg ComTick;
|
| //typedef enum{WaitForStartBit, DelayAfterStartBit, GetBit0, GetBit1, GetBit2, GetBit3, GetBit4, GetBit5, GetBit6, GetBit7, GetStopBit} ComStateType;
|
| //ComStateType ComState;
|
| localparam WaitForStartBit=0, DelayAfterStartBit=1, GetBit0=2, GetBit1=3, GetBit2=4, GetBit3=5, GetBit4=6, GetBit5=7, GetBit6=8, GetBit7=9, GetStopBit=10;
|
| reg [3:0] ComState = WaitForStartBit;
|
| reg [7:0] ReceivedWord;
|
| reg RxLocal;
|
|
|
| //signal W0, W1, W2, W3, W4, W5, W6, W7 : std_logic_vector(7 downto 0);
|
|
|
| reg [23:0] ID_Reg;
|
| reg [31:0] Start_Reg;
|
| reg [15:0] Size_Reg;
|
| reg [15:0] CRC_Reg;
|
| reg [7:0] Command_Reg;
|
| reg [7:0] Data_Reg;
|
|
|
| wire [7:0] ReceivedByte;
|
|
|
| reg TimeToSend;
|
| reg [14:0] TimeToSendCounter;
|
|
|
| //typedef enum{Idle, GetID_00, GetID_AA, GetID_FF, GetCommand, EvalCommand, GetData} PresentType;
|
| //PresentType PresentState;
|
| localparam Idle=0, GetID_00=1, GetID_AA=2, GetID_FF=3, GetCommand=4, EvalCommand=5, GetData=6;
|
| reg [2:0] PresentState = Idle;
|
|
|
| //typedef enum{Word0, Word1, Word2, Word3} GetWordType;
|
| //GetWordType GetWordState;
|
| localparam Word0=0, Word1=1, Word2=2, Word3=3;
|
| reg [1:0] GetWordState=Word0;
|
|
|
| reg LocalWriteStrobe;
|
|
|
| reg ByteWriteStrobe;
|
|
|
| //wire [31:0] Data_Reg32;
|
|
|
| //wire [15:0] Word_Count;
|
|
|
| reg [19:0] CRCReg,b_counter;
|
| //wire [7:0] ReceivedWordDebug;
|
| reg [22:0] blink;
|
|
|
| initial begin
|
| CRCReg = TestFileChecksum;
|
| b_counter = TestFileChecksum;
|
| blink = 23'b00000000000000000000000;
|
| end
|
|
|
| always @ (posedge CLK)
|
| begin : P_sync
|
| RxLocal <= Rx;
|
| end// CLK;
|
|
|
| always @ (posedge CLK)
|
| begin : P_com_en
|
| if (ComState == WaitForStartBit) begin
|
| ComCount <= ComRate/2;// @ 25 MHz
|
| ComTick <= 1'b0;
|
| end else if (ComCount==0) begin
|
| ComCount <= ComRate;
|
| ComTick <= 1'b1;
|
| end else begin
|
| ComCount <= ComCount - 1;
|
| ComTick <= 1'b0;
|
| end
|
| end
|
|
|
| always @ (posedge CLK)
|
| begin : P_COM
|
| case(ComState)
|
| WaitForStartBit: begin
|
| if (RxLocal==1'b0) begin
|
| ComState <= DelayAfterStartBit;
|
| ReceivedWord <= 0;
|
| end
|
| end
|
| DelayAfterStartBit: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit0;
|
| end
|
| end
|
| GetBit0: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit1;
|
| ReceivedWord[0] <= RxLocal;
|
| end
|
| end
|
| GetBit1: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit2;
|
| ReceivedWord[1] <= RxLocal;
|
| end
|
| end
|
| GetBit2: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit3;
|
| ReceivedWord[2] <= RxLocal;
|
| end
|
| end
|
| GetBit3: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit4;
|
| ReceivedWord[3] <= RxLocal;
|
| end
|
| end
|
| GetBit4: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit5;
|
| ReceivedWord[4] <= RxLocal;
|
| end
|
| end
|
| GetBit5: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit6;
|
| ReceivedWord[5] <= RxLocal;
|
| end
|
| end
|
| GetBit6: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetBit7;
|
| ReceivedWord[6] <= RxLocal;
|
| end
|
| end
|
| GetBit7: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= GetStopBit;
|
| ReceivedWord[7] <= RxLocal;
|
| end
|
| end
|
| GetStopBit: begin
|
| if (ComTick==1'b1) begin
|
| ComState <= WaitForStartBit;
|
| end
|
| end
|
| endcase
|
| // scan order:
|
| // <-to_modules_scan_in <- LSB_W0..MSB_W0 <- LSB_W1.... <- LSB_W7 <- from_modules_scan_out
|
| // W8(7..1)
|
| if (ComState==GetStopBit && ComTick==1'b1) begin
|
| case (PresentState)
|
| GetID_00: ID_Reg[23:16] <= ReceivedWord;
|
| GetID_AA: ID_Reg[15:8] <= ReceivedWord;
|
| GetID_FF: ID_Reg[7:0] <= ReceivedWord;
|
| // when GetSize0 => Size_Reg(15 downto 8) <= ReceivedWord;
|
| // when GetSize1 => Size_Reg(7 downto 0) <= ReceivedWord;
|
| // when GetCRC_H => CRC_Reg(15 downto 8) <= ReceivedWord;
|
| // when GetCRC_L => CRC_Reg(7 downto 0) <= ReceivedWord;
|
| GetCommand: Command_Reg <= ReceivedWord;
|
| GetData: Data_Reg <= ReceivedWord;
|
| endcase
|
| end
|
| end//CLK
|
|
|
| always @(posedge CLK)
|
| begin : P_FSM
|
| case(PresentState)
|
| Idle: begin
|
| if (ComState==WaitForStartBit && RxLocal==1'b0) begin
|
| PresentState <= GetID_00;
|
| end
|
| end
|
| GetID_00: begin
|
| if (TimeToSend==1'b1) begin
|
| PresentState<=Idle;
|
| end else if (ComState==GetStopBit && ComTick==1'b1) begin
|
| PresentState <= GetID_AA;
|
| end
|
| end
|
| GetID_AA: begin
|
| if (TimeToSend==1'b1) begin
|
| PresentState<=Idle;
|
| end else if (ComState==GetStopBit && ComTick==1'b1) begin
|
| PresentState <= GetID_FF;
|
| end
|
| end
|
| GetID_FF: begin
|
| if (TimeToSend==1'b1) begin
|
| PresentState<=Idle;
|
| end else if (ComState==GetStopBit && ComTick==1'b1) begin
|
| PresentState <= GetCommand;
|
| end
|
| end
|
| // GetSize1:
|
| // if TimeToSend=1'b1 begin PresentState<=Idle;
|
| // elsif ComState=GetStopBit && ComTick=1'b1 begin PresentState <= GetSize0; end if;
|
| // GetSize0:
|
| // if TimeToSend=1'b1 begin PresentState<=Idle;
|
| // elsif ComState=GetStopBit && ComTick=1'b1 begin PresentState <= GetCommand; end if;
|
| GetCommand: begin
|
| if (TimeToSend==1'b1) begin
|
| PresentState<=Idle;
|
| end else if (ComState==GetStopBit && ComTick==1'b1) begin
|
| PresentState <= EvalCommand;
|
| end
|
| end
|
| EvalCommand: begin
|
| if (ID_Reg==24'h00AAFF && (Command_Reg[6:0]=={3'b000,4'h1} || Command_Reg[6:0]=={3'b000,4'h2})) begin
|
| PresentState <= GetData;
|
| end else begin
|
| PresentState <= Idle;
|
| end
|
| end
|
| GetData: begin
|
| if (TimeToSend==1'b1) begin
|
| PresentState<=Idle;
|
| end
|
| end
|
| endcase
|
| end//CLK
|
| assign Command = Command_Reg;
|
|
|
| if (Mode==0 || Mode==1) begin : L_hexmode// mode [0:auto|1:hex|2:bin]
|
| assign HexValue = ASCII2HEX(ReceivedWord);
|
| always @ (posedge CLK)
|
| begin
|
| if (PresentState!=GetData) begin
|
| ReceiveState <= HighNibble;
|
| end else if (ComState==GetStopBit && ComTick==1'b1 && HexValue[4]==1'b0) begin
|
| if(ReceiveState==HighNibble) begin
|
| ReceiveState <= LowNibble;
|
| end
|
| end else begin
|
| ReceiveState <= HighNibble;
|
| end
|
| //end// CLK
|
| if (ComState==GetStopBit && ComTick==1'b1 && HexValue[4]==1'b0) begin
|
| if(ReceiveState==HighNibble) begin
|
| HighReg <= HexValue[3:0];
|
| HexWriteStrobe <= 1'b0;
|
| end else begin// LowNibble
|
| HexData <= {HighReg,HexValue[3:0]};
|
| HexWriteStrobe <= 1'b1;
|
| end
|
| end else begin
|
| HexWriteStrobe <= 1'b0;
|
| end
|
| end// CLK
|
| end
|
|
|
| always @(posedge CLK)
|
| begin : P_checksum
|
| if (PresentState==GetCommand) begin // init before data arrives
|
| CRCReg <= 0;
|
| b_counter <= 0;
|
| end else if (Mode==1 || (Mode==0 && Command_Reg[7]==1'b1)) begin // mode [0:auto|1:hex|2:bin]
|
| // if hex mode or if auto mode with detected hex mode in the command register
|
| if (ComState==GetStopBit && ComTick==1'b1 && HexValue[4]==1'b0 && PresentState==GetData && ReceiveState==LowNibble) begin
|
| CRCReg <= CRCReg + {HighReg,HexValue[3:0]};
|
| b_counter <= b_counter+1;
|
| end
|
| end else begin// binary mode
|
| if (ComState==GetStopBit && ComTick==1'b1 && (PresentState==GetData)) begin
|
| CRCReg <= CRCReg + ReceivedWord;
|
| b_counter <= b_counter +1;
|
| end
|
| end// checksum computation
|
|
|
| if (PresentState==GetData) begin
|
| ReceiveLED <= 1'b1; // receive process in progress
|
| end else if ((PresentState==Idle) && (CRCReg!=TestFileChecksum)) begin
|
| //ReceiveLED <= blink(blink'high);
|
| ReceiveLED <= blink[22];
|
| end else begin
|
| ReceiveLED <= 1'b0; // receive process was OK
|
| end
|
|
|
| blink <= blink-1;
|
|
|
| end //CLK
|
|
|
| always @(posedge CLK)
|
| begin : P_bus
|
| if (PresentState==EvalCommand) begin
|
| LocalWriteStrobe <= 1'b0;
|
| end else if (PresentState==GetData && ComState==GetStopBit && ComTick==1'b1) begin
|
| LocalWriteStrobe <= 1'b1;
|
| end else begin
|
| LocalWriteStrobe <= 1'b0;
|
| end
|
|
|
| if (Mode==2 || (Mode==0 && Command_Reg[7]==1'b0)) begin // mode [0:auto|1:hex|2:bin]
|
| // if binary mode or if auto mode with detected binary mode in the command register
|
| ByteWriteStrobe <= LocalWriteStrobe; // delay Strobe to ensure that data is valid when applying CLK
|
| // should further prevent glitches in ICAP CLK
|
| end else begin
|
| ByteWriteStrobe <= HexWriteStrobe;
|
| end
|
| end// CLK
|
|
|
| always @(posedge CLK)
|
| begin : P_WordMode
|
| if (PresentState==EvalCommand) begin
|
| GetWordState <= Word0;
|
| WriteData <= 0;
|
| end else begin
|
| case(GetWordState)
|
| Word0: begin
|
| if (ByteWriteStrobe==1'b1) begin
|
| WriteData[31:24] <= ReceivedByte;
|
| GetWordState <= Word1;
|
| end
|
| end
|
| Word1: begin
|
| if (ByteWriteStrobe==1'b1) begin
|
| WriteData[23:16] <= ReceivedByte;
|
| GetWordState <= Word2;
|
| end
|
| end
|
| Word2: begin
|
| if (ByteWriteStrobe==1'b1) begin
|
| WriteData[15:8] <= ReceivedByte;
|
| GetWordState <= Word3;
|
| end
|
| end
|
| Word3: begin
|
| if (ByteWriteStrobe==1'b1) begin
|
| WriteData[7:0] <= ReceivedByte;
|
| GetWordState <= Word0;
|
| end
|
| end
|
| endcase
|
| end
|
|
|
| if (ByteWriteStrobe==1'b1 && GetWordState==Word3) begin
|
| WriteStrobe <= 1'b1;
|
| end else begin
|
| WriteStrobe <= 1'b0;
|
| end
|
| end// CLK
|
|
|
| //ComLoaderActive <= 1'b0;
|
| assign ReceivedByte = (Mode==2 || (Mode==0 && Command_Reg[7]==1'b0)) ? Data_Reg : HexData; // mode [0:auto|1:hex|2:bin]
|
| // if binary mode or if auto mode with detected binary mode in the command register
|
| // ReceivedWordDebug <= Data_Reg when (Mode="bin" OR (Mode="auto" && Command_Reg(7)=1'b0)) else HexData;
|
| assign ComActive = (PresentState==GetData) ? 1'b1 : 1'b0;
|
|
|
| always @(posedge CLK)
|
| begin : P_TimeOut
|
| if (PresentState==Idle || ComState==GetStopBit) begin
|
| //Init TimeOut
|
| TimeToSendCounter <= TimeToSendValue;
|
| TimeToSend <= 1'b0;
|
| end else if (TimeToSendCounter>0) begin
|
| TimeToSendCounter <= TimeToSendCounter - 1;
|
| TimeToSend <= 1'b0;
|
| end else begin
|
| TimeToSendCounter <= TimeToSendCounter;
|
| TimeToSend <= 1'b1; // force FSM to go back to idle when inactive
|
| end
|
| end//CLK
|
|
|
| endmodule |