| // SPDX-FileCopyrightText: | |
| // 2021 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 = 174 // ComRate = f_CLK / Boud_rate (e.g., 20 MHz/115200 Boud = 174) | |
| ) ( | |
| 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 |