diff --git a/controller/verilog/nanosoc_stream_adp_io.v b/controller/verilog/nanosoc_stream_adp_io.v new file mode 100755 index 0000000000000000000000000000000000000000..0b27e1807d11173560bd16ebcaa3c7b6b9e3880a --- /dev/null +++ b/controller/verilog/nanosoc_stream_adp_io.v @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// NanoSoC ASCII Debug Protocol Controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright � 2021-2, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +// TODO: DM - I think this file is redundant if we move to nanosoc_manager_adp + +module nanosoc_stream_adp_io #( + parameter PROMPT_CHAR = "]" + )( + // Ports of Axi Slave Bus Interface com_rx + input wire ahb_hclk, + input wire ahb_hresetn, + + output wire com_rx_tready, + input wire [7:0] com_rx_tdata, + input wire com_rx_tvalid, + + // Ports of Axi Master Bus Interface com_tx + output wire com_tx_tvalid, + output wire [7:0] com_tx_tdata, + input wire com_tx_tready, + + // Ports of Axi Slave Bus Interface stdio_rx + output wire stdio_rx_tready, + input wire [7:0] stdio_rx_tdata, + input wire stdio_rx_tvalid, + + // Ports of Axi Master Bus Interface stdio_tx + output wire stdio_tx_tvalid, + output wire [7:0] stdio_tx_tdata, + input wire stdio_tx_tready, + + output wire [7 : 0] gpo8, + input wire [7 : 0] gpi8, + + output wire [31:0] ahb_haddr, + output wire [ 2:0] ahb_hburst, + output wire ahb_hmastlock, + output wire [ 3:0] ahb_hprot, + output wire [ 2:0] ahb_hsize, + output wire [ 1:0] ahb_htrans, + output wire [31:0] ahb_hwdata, + output wire ahb_hwrite, + input wire [31:0] ahb_hrdata, + input wire ahb_hready, + input wire ahb_hresp + ); + + nanosoc_adp_control #( + .PROMPT_CHAR (PROMPT_CHAR) + ) u_adp_control ( + .HCLK (ahb_hclk ), + .HRESETn (ahb_hresetn ), + .HADDR32_o (ahb_haddr ), + .HBURST3_o (ahb_hburst ), + .HMASTLOCK_o (ahb_hmastlock ), + .HPROT4_o (ahb_hprot ), + .HSIZE3_o (ahb_hsize ), + .HTRANS2_o (ahb_htrans ), + .HWDATA32_o (ahb_hwdata ), + .HWRITE_o (ahb_hwrite ), + .HRDATA32_i (ahb_hrdata ), + .HREADY_i (ahb_hready ), + .HRESP_i (ahb_hresp ), + .GPO8_o (gpo8 ), + .GPI8_i (gpi8 ), + .COMRX_TREADY_o(com_rx_tready), + .COMRX_TDATA_i(com_rx_tdata), + .COMRX_TVALID_i(com_rx_tvalid), + .STDRX_TREADY_o(stdio_rx_tready), + .STDRX_TDATA_i(stdio_rx_tdata), + .STDRX_TVALID_i(stdio_rx_tvalid), + .COMTX_TVALID_o(com_tx_tvalid), + .COMTX_TDATA_o(com_tx_tdata), + .COMTX_TREADY_i(com_tx_tready), + .STDTX_TVALID_o(stdio_tx_tvalid), + .STDTX_TDATA_o(stdio_tx_tdata), + .STDTX_TREADY_i(stdio_tx_tready) + ); + + +endmodule diff --git a/controller/verilog/socshute_adp_control.v b/controller/verilog/socshute_adp_control.v new file mode 100755 index 0000000000000000000000000000000000000000..27b51296b3ba78eda6bedd582a375004b862315c --- /dev/null +++ b/controller/verilog/socshute_adp_control.v @@ -0,0 +1,746 @@ +//----------------------------------------------------------------------------- +// SoCShute ASCII Debug Protocol Controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright (C) 2021-3, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +//`define ADPBASIC 1 +`define ADPFSMDESIGN 1 + +module socshute_adp_control #( + parameter PROMPT_CHAR = "]" +)( + // AHB-lite interface + input wire HCLK, + input wire HRESETn, + output wire [31:0] HADDR32_o, + output wire [ 2:0] HBURST3_o, + output wire HMASTLOCK_o, + output wire [ 3:0] HPROT4_o, + output wire [ 2:0] HSIZE3_o, + output wire [ 1:0] HTRANS2_o, + output wire [31:0] HWDATA32_o, + output wire HWRITE_o, + input wire [31:0] HRDATA32_i, + input wire HREADY_i, + input wire HRESP_i, + + // COMIO interface + output wire [ 7:0] GPO8_o, + input wire [ 7:0] GPI8_i, + input wire [ 7:0] COMRX_TDATA_i, + input wire COMRX_TVALID_i, + output wire COMRX_TREADY_o, + output wire [ 7:0] COMTX_TDATA_o, + output wire COMTX_TVALID_o, + input wire COMTX_TREADY_i, + + // STDIO interface + input wire [ 7:0] STDRX_TDATA_i, + input wire STDRX_TVALID_i, + output wire STDRX_TREADY_o, + output wire [ 7:0] STDTX_TDATA_o, + output wire STDTX_TVALID_o, + input wire STDTX_TREADY_i +); + +wire COM_RXE_i = !COMRX_TVALID_i; +wire COM_TXF_i = !COMTX_TREADY_i; + +//wire adp_rx_req = COMRX_TVALID_i & COMRX_TREADY_o; +//wire std_rx_req = STDRX_TVALID_i & STDRX_TREADY_o; + + +wire STD_TXF_i = !STDTX_TREADY_i; +wire STD_RXE_i = !STDRX_TVALID_i; + +`ifdef ADPBASIC + localparam BANNERHEX = 32'h50c1ab01; +`else + localparam BANNERHEX = 32'h50c1ab04; +`endif + +localparam CMD_bad = 4'b0000; +localparam CMD_A = 4'b0001; // set Address +localparam CMD_C = 4'b0010; // Control +localparam CMD_R = 4'b0011; // Read word, addr++ +localparam CMD_S = 4'b0100; // Status/STDIN +localparam CMD_W = 4'b0101; // Write word, addr++ +localparam CMD_X = 4'b0110; // eXit +`ifndef ADPBASIC +localparam CMD_F = 4'b1000; // Fill (wordocunt) from addr++ +localparam CMD_M = 4'b1001; // set read Mask +localparam CMD_P = 4'b1010; // Poll hardware (count) +localparam CMD_U = 4'b1011; // (Binary) Upload (wordocunt) from addr++ +localparam CMD_V = 4'b1100; // match Value +`endif + + +function FNvalid_adp_entry; // Escape char +input [7:0] char8; + FNvalid_adp_entry = (char8[7:0] == 8'h1b); +endfunction + +function [3:0] FNvalid_cmd; +input [7:0] char8; +case (char8[7:0]) +"A": FNvalid_cmd = CMD_A; +"a": FNvalid_cmd = CMD_A; +"C": FNvalid_cmd = CMD_C; +"c": FNvalid_cmd = CMD_C; +"R": FNvalid_cmd = CMD_R; +"r": FNvalid_cmd = CMD_R; +"S": FNvalid_cmd = CMD_S; +"s": FNvalid_cmd = CMD_S; +"W": FNvalid_cmd = CMD_W; +"w": FNvalid_cmd = CMD_W; +"X": FNvalid_cmd = CMD_X; +"x": FNvalid_cmd = CMD_X; +`ifndef ADPBASIC +"F": FNvalid_cmd = CMD_F; +"f": FNvalid_cmd = CMD_F; +"M": FNvalid_cmd = CMD_M; +"m": FNvalid_cmd = CMD_M; +"P": FNvalid_cmd = CMD_P; +"p": FNvalid_cmd = CMD_P; +"U": FNvalid_cmd = CMD_U; +"u": FNvalid_cmd = CMD_U; +"V": FNvalid_cmd = CMD_V; +"v": FNvalid_cmd = CMD_V; +`endif +default: + FNvalid_cmd = 0; +endcase +endfunction + +function FNvalid_space; // space or tab char +input [7:0] char8; + FNvalid_space = ((char8[7:0] == 8'h20) || (char8[7:0] == 8'h09)); +endfunction + +function FNnull; // space or tab char +input [7:0] char8; + FNnull = (char8[7:0] == 8'h00); +endfunction + +function FNexit; // EOF +input [7:0] char8; + FNexit = ((char8[7:0] == 8'h04) || (char8[7:0] == 8'h00)); +endfunction + +function FNvalid_EOL; // CR or LF +input [7:0] char8; + FNvalid_EOL = ((char8[7:0] == 8'h0a) || (char8[7:0] == 8'h0d)); +endfunction + +function FNuppercase; +input [7:0] char8; + FNuppercase = (char8[6]) ? (char8 & 8'h5f) : (char8); +endfunction + + +function [2:0] FNsize_inc; +// top 2 bits encode 01 (byte), 10 (halfword), 11 (word) 00 - no parameter +input [2:0] cnt8; +case (cnt8[2:0]) +3'b000: FNsize_inc = 3'b010; +3'b010: FNsize_inc = 3'b011; +3'b011: FNsize_inc = 3'b100; +3'b100: FNsize_inc = 3'b101; +default: + FNsize_inc = 3'b111; +endcase +endfunction + +function [1:0] FNparam2size; +// top 2 bits encode 01 (byte), 10 (halfword), 11 (word) 00 - no parameter +input [1:0] parm2; +case (parm2[1:0]) +2'b01: FNparam2size = 2'b00; // 8-bit +2'b10: FNparam2size = 2'b01; // 16-bit +2'b11: FNparam2size = 2'b10; // 32-bit +default: + FNparam2size = 2'b10;// default to 32-bit +endcase +endfunction + +function [34:0] FNBuild_size3_param32_hexdigit; +input [34:0] param32; +input [7:0] char8; +case (char8[7:0]) +"\t":FNBuild_size3_param32_hexdigit = 35'b0; // tab starts new (zeroed) param32 +" ": FNBuild_size3_param32_hexdigit = 35'b0; // space starts new (zeroed) param32 +"x": FNBuild_size3_param32_hexdigit = 35'b0; // hex prefix starts new (zeroed) param32 +"X": FNBuild_size3_param32_hexdigit = 35'b0; // hex prefix starts new (zeroed) param32 +"0": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0000}; +"1": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0001}; +"2": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0010}; +"3": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0011}; +"4": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0100}; +"5": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0101}; +"6": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0110}; +"7": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b0111}; +"8": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1000}; +"9": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1001}; +"A": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1010}; +"B": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1011}; +"C": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1100}; +"D": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1101}; +"E": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1110}; +"F": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1111}; +"a": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1010}; +"b": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1011}; +"c": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1100}; +"d": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1101}; +"e": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1110}; +"f": FNBuild_size3_param32_hexdigit = {FNsize_inc(param32[34:32]),param32[27:0],4'b1111}; +default: FNBuild_size3_param32_hexdigit = param32; // EOL etc returns param32 unchanged +endcase +endfunction + + +function [7:0] FNmap_hex_digit; +input [3:0] nibble; +case (nibble[3:0]) +4'b0000: FNmap_hex_digit = "0"; +4'b0001: FNmap_hex_digit = "1"; +4'b0010: FNmap_hex_digit = "2"; +4'b0011: FNmap_hex_digit = "3"; +4'b0100: FNmap_hex_digit = "4"; +4'b0101: FNmap_hex_digit = "5"; +4'b0110: FNmap_hex_digit = "6"; +4'b0111: FNmap_hex_digit = "7"; +4'b1000: FNmap_hex_digit = "8"; +4'b1001: FNmap_hex_digit = "9"; +4'b1010: FNmap_hex_digit = "a"; +4'b1011: FNmap_hex_digit = "b"; +4'b1100: FNmap_hex_digit = "c"; +4'b1101: FNmap_hex_digit = "d"; +4'b1110: FNmap_hex_digit = "e"; +4'b1111: FNmap_hex_digit = "f"; +default: FNmap_hex_digit = "0"; +endcase +endfunction + +// as per Vivado synthesis mapping +`ifdef ADPFSMDESIGN +localparam ADP_WRITEHEX = 6'b000000 ; +localparam ADP_WRITEHEXS = 6'b000001 ; +localparam ADP_WRITEHEX9 = 6'b000010 ; +localparam ADP_WRITEHEX8 = 6'b000011 ; +localparam ADP_WRITEHEX7 = 6'b000100 ; +localparam ADP_WRITEHEX6 = 6'b000101 ; +localparam ADP_WRITEHEX5 = 6'b000110 ; +localparam ADP_WRITEHEX4 = 6'b000111 ; +localparam ADP_WRITEHEX3 = 6'b001000 ; +localparam ADP_WRITEHEX2 = 6'b001001 ; +localparam ADP_WRITEHEX1 = 6'b001010 ; +localparam ADP_WRITEHEX0 = 6'b001011 ; +localparam ADP_LINEACK = 6'b001100 ; +localparam ADP_LINEACK2 = 6'b001101 ; +localparam ADP_PROMPT = 6'b001110 ; +localparam ADP_IOCHK = 6'b001111 ; +localparam ADP_STDOUT = 6'b010000 ; +localparam ADP_STDOUT1 = 6'b010001 ; +localparam ADP_STDOUT2 = 6'b010010 ; +localparam ADP_STDOUT3 = 6'b010011 ; +localparam ADP_RXCMD = 6'b010100 ; +localparam ADP_RXPARAM = 6'b010101 ; +localparam ADP_ACTION = 6'b010110 ; +localparam ADP_SYSCTL = 6'b010111 ; +localparam ADP_READ = 6'b011000 ; +localparam ADP_SYSCHK = 6'b011001 ; +localparam ADP_STDIN = 6'b011010 ; +localparam ADP_WRITE = 6'b011011 ; +localparam ADP_EXIT = 6'b011100 ; +localparam STD_IOCHK = 6'b011101 ; +localparam STD_RXD1 = 6'b011110 ; +localparam STD_RXD2 = 6'b011111 ; +localparam STD_TXD1 = 6'b100000 ; +localparam STD_TXD2 = 6'b100001 ; +localparam ADP_UCTRL = 6'b100010 ; +localparam ADP_UREADB = 6'b100011 ; +localparam ADP_UWRITE = 6'b100100 ; +localparam ADP_POLL = 6'b100101 ; +localparam ADP_POLL1 = 6'b100110 ; +localparam ADP_POLL2 = 6'b100111 ; +localparam ADP_FCTRL = 6'b101000 ; +localparam ADP_FWRITE = 6'b101001 ; +localparam ADP_ECHOCMD = 6'b101010 ; +localparam ADP_ECHOBUS = 6'b101011 ; +localparam ADP_UNKNOWN = 6'b101100 ; +reg [5:0] adp_state ; +`else +// one-hot encoded explicitly +localparam ADP_WRITEHEX = 45'b000000000000000000000000000000000000000000001 ; // = 6'b000000 ; +localparam ADP_WRITEHEXS = 45'b000000000000000000000000000000000000000000010 ; // = 6'b000001 ; +localparam ADP_WRITEHEX9 = 45'b000000000000000000000000000000000000000000100 ; // = 6'b000010 ; +localparam ADP_WRITEHEX8 = 45'b000000000000000000000000000000000000000001000 ; // = 6'b000011 ; +localparam ADP_WRITEHEX7 = 45'b000000000000000000000000000000000000000010000 ; // = 6'b000100 ; +localparam ADP_WRITEHEX6 = 45'b000000000000000000000000000000000000000100000 ; // = 6'b000101 ; +localparam ADP_WRITEHEX5 = 45'b000000000000000000000000000000000000001000000 ; // = 6'b000110 ; +localparam ADP_WRITEHEX4 = 45'b000000000000000000000000000000000000010000000 ; // = 6'b000111 ; +localparam ADP_WRITEHEX3 = 45'b000000000000000000000000000000000000100000000 ; // = 6'b001000 ; +localparam ADP_WRITEHEX2 = 45'b000000000000000000000000000000000001000000000 ; // = 6'b001001 ; +localparam ADP_WRITEHEX1 = 45'b000000000000000000000000000000000010000000000 ; // = 6'b001010 ; +localparam ADP_WRITEHEX0 = 45'b000000000000000000000000000000000100000000000 ; // = 6'b001011 ; +localparam ADP_LINEACK = 45'b000000000000000000000000000000001000000000000 ; // = 6'b001100 ; +localparam ADP_LINEACK2 = 45'b000000000000000000000000000000010000000000000 ; // = 6'b001101 ; +localparam ADP_PROMPT = 45'b000000000000000000000000000000100000000000000 ; // = 6'b001110 ; +localparam ADP_IOCHK = 45'b000000000000000000000000000001000000000000000 ; // = 6'b001111 ; +localparam ADP_STDOUT = 45'b000000000000000000000000000010000000000000000 ; // = 6'b010000 ; +localparam ADP_STDOUT1 = 45'b000000000000000000000000000100000000000000000 ; // = 6'b010001 ; +localparam ADP_STDOUT2 = 45'b000000000000000000000000001000000000000000000 ; // = 6'b010010 ; +localparam ADP_STDOUT3 = 45'b000000000000000000000000010000000000000000000 ; // = 6'b010011 ; +localparam ADP_RXCMD = 45'b000000000000000000000000100000000000000000000 ; // = 6'b010100 ; +localparam ADP_RXPARAM = 45'b000000000000000000000001000000000000000000000 ; // = 6'b010101 ; +localparam ADP_ACTION = 45'b000000000000000000000010000000000000000000000 ; // = 6'b010110 ; +localparam ADP_SYSCTL = 45'b000000000000000000000100000000000000000000000 ; // = 6'b010111 ; +localparam ADP_READ = 45'b000000000000000000001000000000000000000000000 ; // = 6'b011000 ; +localparam ADP_SYSCHK = 45'b000000000000000000010000000000000000000000000 ; // = 6'b011001 ; +localparam ADP_STDIN = 45'b000000000000000000100000000000000000000000000 ; // = 6'b011010 ; +localparam ADP_WRITE = 45'b000000000000000001000000000000000000000000000 ; // = 6'b011011 ; +localparam ADP_EXIT = 45'b000000000000000010000000000000000000000000000 ; // = 6'b011100 ; +localparam STD_IOCHK = 45'b000000000000000100000000000000000000000000000 ; // = 6'b011101 ; +localparam STD_RXD1 = 45'b000000000000001000000000000000000000000000000 ; // = 6'b011110 ; +localparam STD_RXD2 = 45'b000000000000010000000000000000000000000000000 ; // = 6'b011111 ; +localparam STD_TXD1 = 45'b000000000000100000000000000000000000000000000 ; // = 6'b100000 ; +localparam STD_TXD2 = 45'b000000000001000000000000000000000000000000000 ; // = 6'b100001 ; +localparam ADP_UCTRL = 45'b000000000010000000000000000000000000000000000 ; // = 6'b100010 ; +localparam ADP_UREADB = 45'b000000000100000000000000000000000000000000000 ; // = 6'b100011 ; +localparam ADP_UWRITE = 45'b000000001000000000000000000000000000000000000 ; // = 6'b100100 ; +localparam ADP_POLL = 45'b000000010000000000000000000000000000000000000 ; // = 6'b100101 ; +localparam ADP_POLL1 = 45'b000000100000000000000000000000000000000000000 ; // = 6'b100110 ; +localparam ADP_POLL2 = 45'b000001000000000000000000000000000000000000000 ; // = 6'b100111 ; +localparam ADP_FCTRL = 45'b000010000000000000000000000000000000000000000 ; // = 6'b101000 ; +localparam ADP_FWRITE = 45'b000100000000000000000000000000000000000000000 ; // = 6'b101001 ; +localparam ADP_ECHOCMD = 45'b001000000000000000000000000000000000000000000 ; // = 6'b101010 ; +localparam ADP_ECHOBUS = 45'b010000000000000000000000000000000000000000000 ; // = 6'b101011 ; +localparam ADP_UNKNOWN = 45'b100000000000000000000000000000000000000000000 ; // = 6'b101100 ; +reg [44:0] adp_state ; +`endif + +reg [31:0] adp_bus_data; +reg banner ; +reg com_tx_req ; +reg [7:0] com_tx_byte ; +reg com_rx_ack ; +reg std_tx_req ; +reg [ 7:0] std_tx_byte; +reg std_rx_ack ; +reg adp_bus_req ; +reg adp_bus_write ; +reg adp_bus_err ; +reg [7:0] adp_cmd ; +reg [7:0] adp_cmdwid ; +reg [34:0] adp_param ; +reg [31:0] adp_addr ; +reg [1:0] adp_size ; +reg adp_addr_inc; +reg [31:0] adp_sys ; + +assign GPO8_o = adp_sys[7:0]; + +// ADP RX stream +wire com_rx_req = COMRX_TVALID_i; +wire [ 7:0] com_rx_byte = COMRX_TDATA_i; +assign COMRX_TREADY_o = com_rx_ack; +// ADP TX stream +wire com_tx_ack = COMTX_TREADY_i; +assign COMTX_TDATA_o = com_tx_byte; +assign COMTX_TVALID_o = com_tx_req; +// STD RX stream (from STDOUT) +wire std_rx_req = STDRX_TVALID_i; +wire [ 7:0] std_rx_byte = STDRX_TDATA_i; +assign STDRX_TREADY_o = std_rx_ack; +// STD TX stream (to STDIN) +wire std_tx_ack = STDTX_TREADY_i; +assign STDTX_TDATA_o = std_tx_byte; +assign STDTX_TVALID_o = std_tx_req; + +//AMBA AHB master as "stream" interface +reg ahb_dphase; +wire ahb_aphase = adp_bus_req & !ahb_dphase; +wire adp_bus_ack = ahb_dphase & HREADY_i; +// control pipe +always @(posedge HCLK or negedge HRESETn) + if(!HRESETn) + ahb_dphase <= 0; + else if (HREADY_i) + ahb_dphase <= (ahb_aphase); + +wire [1:0] byteaddr; + +assign byteaddr = (adp_size[1]) ? 2'b00 : (adp_size[0]) ? {adp_addr[1], 1'b0} : adp_addr[1:0]; + +assign HADDR32_o[31:2] = adp_addr[31:2]; +assign HADDR32_o[ 1:0] = byteaddr[1:0]; +assign HBURST3_o = 3'b001; // "INCR" burst signalled whenever transfer; +assign HMASTLOCK_o = 1'b0; +assign HPROT4_o[3:0] = {1'b0, 1'b0, 1'b1, 1'b1}; +assign HSIZE3_o[2:0] = {1'b0, adp_size}; +assign HTRANS2_o = {ahb_aphase,1'b0}; // non-seq +assign HWDATA32_o = (adp_size[1]) ? adp_bus_data + : (adp_size[0]) ? {2{adp_bus_data[15:0]}} + : {4{adp_bus_data[7:0]}} ; +assign HWRITE_o = adp_bus_write; + + +`ifndef ADPBASIC +reg [34:0] adp_val; +reg [31:0] adp_mask; +reg [31:0] adp_poll; +reg [31:0] adp_count; +reg adp_count_dec ; +wire adp_delay_done; +wire poll2_loop_next; +`endif + +// ADP_control flags in the 'C' control field +wire adp_disable; +wire adp_stdin_wait; + +// commnon interface handshake terms +wire com_rx_done = COMRX_TVALID_i & COMRX_TREADY_o; +wire com_tx_done = COMTX_TVALID_o & COMTX_TREADY_i; +wire std_rx_done = STDRX_TVALID_i & STDRX_TREADY_o; +wire std_tx_done = STDTX_TVALID_o & STDTX_TREADY_i; +wire adp_bus_done = (adp_bus_req & adp_bus_ack); + +// common task to set up for next state +task ADP_LINEACK_next; // prepare newline TX (and cancel any startup banner) +// begin com_tx_req <= 1; com_tx_byte <= 8'h0A; banner <= 0; adp_state <= ADP_LINEACK; end + begin com_tx_req <= 1; com_tx_byte <= 8'h0A; adp_state <= ADP_LINEACK; end +endtask +task ADP_PROMPT_next; // prepare prompt TX + begin com_tx_req <= 1; com_tx_byte <= PROMPT_CHAR; adp_state <= ADP_PROMPT; end +endtask +task ADP_BUSWRITEINC_next; // prepare bus write and addr++ on completion + begin adp_bus_req <=1; adp_bus_write <=1; adp_addr_inc <=1; end +endtask +task ADP_BUSREADINC_next; // prepare bus read and addr++ on completion + begin adp_bus_req <=1; adp_bus_write <=0; adp_addr_inc <=1; end +endtask + +task ADP_hexdigit_next; // output nibble +input [3:0] nibble; + begin com_tx_req <= 1; com_tx_byte <= FNmap_hex_digit(nibble[3:0]); end +endtask +task ADP_txchar_next; // output char +input [7:0] octet; + begin com_tx_req<= 1; com_tx_byte <= octet; end +endtask + +task com_rx_nxt; com_rx_ack <=1; endtask + +function FNcount_down_zero_next; // param about to be zero +input [31:0] counter; + FNcount_down_zero_next = !(|counter[31:1]); +endfunction + +always @(posedge HCLK or negedge HRESETn) + if(!HRESETn) begin + adp_state <= ADP_WRITEHEX ; + adp_bus_data <= BANNERHEX; + banner <= 1; // start-up HEX message + com_tx_req <= 0; // default no TX req + com_rx_ack <= 0; // default no RX ack + std_tx_req <= 0; // default no TX req + std_rx_ack <= 0; // default no RX ack + adp_bus_req <= 0; // default no bus transaction + adp_bus_err <= 0; // default no bus error + adp_cmd <= 0; + adp_param <= 0; + adp_size <= 2'b10; // default to 32-bit word size + adp_addr <= 0; + adp_addr_inc <= 0; + adp_bus_write<= 0; +`ifndef ADPBASIC + adp_count <= 0; + adp_count_dec<= 0; + adp_val <= 0; + adp_mask <= 0; + adp_sys <= 0; +`endif + end else begin // default states + adp_state <= adp_state; // default to hold current state + com_tx_req <= 0; // default no TX req + com_rx_ack <= 0; // default no RX ack + std_tx_req <= 0; // default no TX req + std_rx_ack <= 0; // default no RX ack + adp_bus_req <= 0; // default no bus transaction + adp_addr <= (adp_addr_inc & adp_bus_done) ? adp_addr + (1 << adp_size) : adp_addr; // address++ + adp_addr_inc <= 0; +`ifndef ADPBASIC + adp_count <= (adp_count_dec & adp_bus_done & |adp_count) ? adp_count - 1 : adp_count; // param-- + adp_count_dec<= 0; +`endif + case (adp_state) +// >>>>>>>>>>>>>>>> STDIO BYPASS >>>>>>>>>>>>>>>>>>>>>> + STD_IOCHK: // check for commsrx or STDOUT and not busy service, else loop back + if (com_rx_req) begin com_rx_ack <= 1; adp_state <= STD_RXD1; end // input char pending for STDIN +// else if (com_tx_ack & std_rx_req) begin std_rx_ack <= 1; adp_state <= STD_TXD1; end // STDOUT char pending and not busy + else if (std_rx_req) begin std_rx_ack <= 1; adp_state <= STD_TXD1; end // STDOUT char pending + STD_TXD1: // get STD out char + if (std_rx_done) + begin com_tx_byte <= std_rx_byte; com_tx_req <= 1; adp_state <= STD_TXD2; end + else std_rx_ack <= 1; // extend + STD_TXD2: // output char to ADP channel + if (com_tx_done) begin adp_state <= STD_IOCHK; end + else com_tx_req <= 1; // extend + STD_RXD1: // read rx char and check for ADP entry else STDIN ** + if (com_rx_done) begin + if (FNvalid_adp_entry(com_rx_byte)) + begin ADP_txchar_next(8'h0A); adp_state <= ADP_LINEACK; end // ADP prompt + else if (std_tx_ack) + begin std_tx_byte <= com_rx_byte; std_tx_req <= 1; adp_state <= STD_RXD2; end + else adp_state <= STD_IOCHK; // otherwise discard STDIN char and process OP data if blocked + end else com_rx_ack <= 1; // extend + STD_RXD2: // get STD in char + if (std_tx_done) begin adp_state <= STD_IOCHK; end + else std_tx_req <= 1; // extend + +// >>>>>>>>>>>>>>>> ADP Monitor >>>>>>>>>>>>>>>>>>>>>> + ADP_PROMPT: // transition after reset deassertion + if (com_tx_done) begin adp_state <= ADP_IOCHK; end + else com_tx_req <= 1; // extend + + ADP_IOCHK: // check for commsrx or STDOUT and not busy service, else loop back + if (std_rx_req) begin com_tx_byte <= "<"; com_tx_req <= 1; adp_state <= ADP_STDOUT; end + else if (com_rx_req) begin com_rx_ack <= 1; adp_state <= ADP_RXCMD; end + +// >>>>>>>>>>>>>>>> ADP <STDOUT> >>>>>>>>>>>>>>>>>>>>>> + ADP_STDOUT: // output "<" + if (com_tx_done) begin std_rx_ack <= 1; adp_state <= ADP_STDOUT1; end + else com_tx_req <= 1; // extend stream request if not ready + ADP_STDOUT1: // get STD out char + if (std_rx_done) begin com_tx_byte <= std_rx_byte; com_tx_req <= 1; adp_state <= ADP_STDOUT2; end + else std_rx_ack <= 1; // else extend + ADP_STDOUT2: // output char + if (com_tx_done) begin com_tx_byte <= ">"; com_tx_req <= 1; adp_state <= ADP_STDOUT3; end + else com_tx_req <= 1; // else extend + ADP_STDOUT3: // output ">" + if (com_tx_done) begin if (com_rx_req) begin com_rx_ack <= 1; adp_state <= ADP_RXCMD; end else adp_state <= ADP_IOCHK; end + else com_tx_req <= 1; // else extend + +// >>>>>>>>>>>>>>>> ADP COMMAND PARSING >>>>>>>>>>>>>>>>>>>>>> + ADP_RXCMD: // read and save ADP command + if (com_rx_done) begin + if (FNexit(com_rx_byte)) adp_state <= STD_IOCHK; // immediate exit + else if (FNvalid_space(com_rx_byte)) com_rx_ack <= 1; // retry for a command + else if (FNvalid_EOL(com_rx_byte)) begin adp_cmd <= "?"; adp_state <= ADP_LINEACK; end // no command, skip param + else begin adp_cmd <= com_rx_byte; adp_param <= 35'h0_00000000; com_rx_ack <= 1; adp_state <= ADP_RXPARAM; end // get optional parameter + end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_RXPARAM: // read and build hex parameter + if (com_rx_done) begin // RX byte + if (FNexit(com_rx_byte)) adp_state <= STD_IOCHK; // exit + else if (FNvalid_EOL(com_rx_byte)) +`ifndef ADPBASIC + begin adp_count <= adp_param[31:0]; adp_state <= ADP_ACTION; + adp_size <= FNparam2size(adp_param[34:33]); end // parameter complete on EOL +`else + begin adp_state <= ADP_ACTION; + adp_size <= FNparam2size(adp_param[34:33]); end // parameter complete on EOL +`endif + else + begin adp_param <= FNBuild_size3_param32_hexdigit(adp_param[34:0], com_rx_byte); com_rx_ack <= 1; end // build parameter + end + else com_rx_ack <= 1; + + ADP_ACTION: // parse command and action with parameter + if (FNexit(com_rx_byte)) + adp_state <= STD_IOCHK; + else if (FNvalid_cmd(adp_cmd) == CMD_A) + begin if (|adp_param[34:32]) adp_addr <= adp_param[31:0]; else adp_param <= {3'b111, adp_addr} ; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_C) begin + if (|adp_param[34:32] == 1'b0) // report GPO + begin adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 1) // clear selected bits in GPO + begin adp_sys[7:0] <= adp_sys[7:0] & ~adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 2) // set selected bits in GPO + begin adp_sys[7:0] <= adp_sys[7:0] | adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 3) // overwrite bits in GPO + begin adp_sys[7:0] <= adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else // 4 etc, report GPO + begin adp_state <= ADP_SYSCTL; end + end + else if (FNvalid_cmd(adp_cmd) == CMD_R) + begin adp_size <= FNparam2size(adp_param[34:33]); ADP_BUSREADINC_next; adp_state <= ADP_READ; +`ifndef ADPBASIC + adp_count_dec <= 1'b1; // optional loop param +`endif + end // no param required + else if (FNvalid_cmd(adp_cmd) == CMD_S) + begin adp_state <= ADP_SYSCHK; end + else if (FNvalid_cmd(adp_cmd) == CMD_W) + begin adp_size <= FNparam2size(adp_param[34:33]); adp_bus_data <= adp_param[31:0]; ADP_BUSWRITEINC_next; adp_state <= ADP_WRITE; end + else if (FNvalid_cmd(adp_cmd) == CMD_X) + begin com_tx_byte <= 8'h0a; com_tx_req <= 1; adp_state <= ADP_EXIT; end +`ifndef ADPBASIC + else if (FNvalid_cmd(adp_cmd) == CMD_U) + if (FNcount_down_zero_next(adp_param[31:0])) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_UCTRL; // non-zero count + else if (FNvalid_cmd(adp_cmd) == CMD_M) + begin if (|adp_param[34:32]) adp_mask <= adp_param[31:0]; else adp_param <= {3'b111,adp_mask}; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_P) + if (FNcount_down_zero_next(adp_param[31:0])) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_POLL; // non-zero count + else if (FNvalid_cmd(adp_cmd) == CMD_V) + begin if (|adp_param[34:32]) begin adp_size <= FNparam2size(adp_param[34:33]); adp_val <= adp_param[34:0]; end + else adp_param <= adp_val; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_F) + if (FNcount_down_zero_next(adp_param[31:0])) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_FCTRL; // non-zero count +`endif + else + begin ADP_txchar_next("?"); adp_state <= ADP_UNKNOWN; end // unrecognised/invald + +// >>>>>>>>>>>>>>>> ADP BUS WRITE and READ >>>>>>>>>>>>>>>>>>>>>> + + ADP_WRITE: // perform bus write at current address pointer (and auto increment) + if (adp_bus_done) begin adp_state <= ADP_ECHOCMD; adp_bus_err <= HRESP_i; end + else begin ADP_BUSWRITEINC_next; end // extend request + + ADP_READ: // perform bus read at current adp address (and auto increment) - and report in hex + if (adp_bus_done) begin adp_bus_data <= (byteaddr[1:0] == 2'b01) ? {HRDATA32_i[ 7: 0],HRDATA32_i[31: 8]} + : (byteaddr[1:0] == 2'b10) ? {HRDATA32_i[15: 0],HRDATA32_i[31:16]} + : (byteaddr[1:0] == 2'b11) ? {HRDATA32_i[23: 0],HRDATA32_i[31:24]} + : HRDATA32_i; + adp_bus_err <= HRESP_i; ADP_txchar_next("R"); adp_state <= ADP_ECHOBUS; + end + else begin + ADP_BUSREADINC_next; +`ifndef ADPBASIC + adp_count_dec<= 1'b1; +`endif + end // extend request + +`ifndef ADPBASIC + +// >>>>>>>>>>>>>>>> ADP BINARY UPLOAD >>>>>>>>>>>>>>>>>>>>>> + ADP_UCTRL: // set control value + begin com_rx_ack <= 1; adp_size <= 2'b00; adp_state <= ADP_UREADB; end // read next byte + ADP_UREADB: // read raw binary byte + if (com_rx_done) + begin adp_bus_data[31:0] <= {4{com_rx_byte}}; ADP_BUSWRITEINC_next; adp_count_dec <= 1; adp_state <= ADP_UWRITE; end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_UWRITE: // Write word to Addr++ + if (adp_bus_done) begin // auto address++, count-- + if (FNcount_down_zero_next(adp_count)) adp_state <= ADP_ECHOCMD; else begin adp_state <= ADP_UREADB; adp_bus_err <= adp_bus_err | HRESP_i; end + end else begin ADP_BUSWRITEINC_next; adp_count_dec <= 1; end // extend request + +// >>>>>>>>>>>>>>>> ADP BUS READ LOOP >>>>>>>>>>>>>>>>>>>>>> + ADP_POLL: // set poll value + begin adp_bus_req <= 1; adp_bus_write <= 0; adp_state <= ADP_POLL1; end + ADP_POLL1: // wait for read data, no addr++ + if (adp_bus_done) begin adp_bus_data <= HRDATA32_i; adp_count_dec <=1; adp_state <= ADP_POLL2; adp_bus_err <= adp_bus_err | HRESP_i; end + else begin adp_bus_req <= 1; adp_count_dec <=1; end + ADP_POLL2: + if (FNcount_down_zero_next(adp_count)) begin adp_state <= ADP_ECHOCMD; adp_bus_err <= 1'b1; end // timeout + else if (((adp_bus_data & adp_mask) ^ adp_val[31:0]) == 0) begin adp_state <= ADP_ECHOCMD; adp_param <= {1'b0, (adp_param[31:0] - adp_count)}; end // exact match + else adp_state <= ADP_POLL; + +// >>>>>>>>>>>>>>>> ADP (ZERO) FILL MEMORY >>>>>>>>>>>>>>>>>>>>>> + ADP_FCTRL: // set control value + begin adp_size <= FNparam2size(adp_val[34:33]); adp_bus_data <= adp_val[31:0]; ADP_BUSWRITEINC_next; adp_count_dec <= 1; adp_state <= ADP_FWRITE; end + ADP_FWRITE: // Write word to Addr++ + if (adp_bus_done) begin // auto address++, count-- + if (FNcount_down_zero_next(adp_count)) adp_state <= ADP_ECHOCMD; else begin adp_state <= ADP_FCTRL; adp_bus_err <= adp_bus_err | HRESP_i; end + end else begin ADP_BUSWRITEINC_next; adp_count_dec <= 1; end // extend request +`endif + + // >>>>>>>>>>>>>>>> ADP MISC >>>>>>>>>>>>>>>>>>>>>> + + ADP_UNKNOWN: // output "?" + if (com_tx_done) begin ADP_LINEACK_next; end + else com_tx_req <= 1; // extend stream request if not ready + + ADP_EXIT: // exit ADP mode + if (com_tx_done) adp_state <= STD_IOCHK; + else com_tx_req <= 1; // extend stream request if not ready + + ADP_SYSCHK: // check STDIN fifo + begin // no upper flags so STDIN char + if (std_tx_ack) begin std_tx_req <=1; std_tx_byte <= adp_param[7:0]; adp_state <= ADP_STDIN; end + else begin adp_bus_err <= 1'b1; adp_state <= ADP_ECHOCMD; end // signal error then echo comand + end + ADP_STDIN: // push char into STDIN + if (std_tx_done) begin adp_bus_data <= {24'b0,adp_param[7:0]}; ADP_txchar_next("S"); adp_state <= ADP_ECHOBUS; end + else std_tx_req <= 1; // extend + + ADP_SYSCTL: // read current status - and report in hex + begin adp_bus_data <= {GPI8_i[7:0],adp_sys[7:0],adp_param[15:0]}; ADP_txchar_next("C"); adp_state <= ADP_ECHOBUS; end + + ADP_ECHOCMD: // output command and (param) data + begin ADP_txchar_next(adp_cmd & 8'h5f); adp_bus_data <= adp_param[31:0]; adp_state <= ADP_ECHOBUS; end // output command char + ADP_ECHOBUS: // output command space and (bus) data + if (com_tx_done) begin adp_state <= ADP_WRITEHEXS; ADP_txchar_next(adp_bus_err ? "!" : " "); end // output space char, or "!" on bus error + else com_tx_req <= 1; // extend + + ADP_WRITEHEX: // output hex word with prefix + begin adp_state <= ADP_WRITEHEXS; ADP_txchar_next(adp_bus_err ? "!" : " "); end // output space char, or "!" on bus error + + ADP_WRITEHEXS: + if (com_tx_done) begin adp_state <= ADP_WRITEHEX9; ADP_txchar_next("0"); end // output "0" hex prefix + else com_tx_req <= 1; // extend + ADP_WRITEHEX9: + if (com_tx_done & adp_size[1]) begin adp_state <= ADP_WRITEHEX8; ADP_txchar_next("x"); end // output "x" hex prefix + else if (com_tx_done & adp_size[0]) begin adp_state <= ADP_WRITEHEX4; ADP_txchar_next("x"); end // output "x" hex prefix + else if (com_tx_done) begin adp_state <= ADP_WRITEHEX2; ADP_txchar_next("x"); end // output "x" hex prefix + else com_tx_req <= 1; // extend + ADP_WRITEHEX8: + if (com_tx_done) begin adp_state <= ADP_WRITEHEX7; ADP_hexdigit_next(adp_bus_data[31:28]); end // hex nibble 7 + else com_tx_req <= 1; // extend + ADP_WRITEHEX7: // output hex nibble 7 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX6; ADP_hexdigit_next(adp_bus_data[27:24]); end // hex nibble 6 + else com_tx_req <= 1; // extend + ADP_WRITEHEX6: // output hex nibble 6 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX5; ADP_hexdigit_next(adp_bus_data[23:20]); end // hex nibble 5 + else com_tx_req <= 1; // extend + ADP_WRITEHEX5: // output hex nibble 5 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX4; ADP_hexdigit_next(adp_bus_data[19:16]); end // hex nibble 4 + else com_tx_req <= 1; // extend + ADP_WRITEHEX4: // output hex nibble 4 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX3; ADP_hexdigit_next(adp_bus_data[15:12]); end // hex nibble 3 + else com_tx_req <= 1; // extend + ADP_WRITEHEX3: // output hex nibble 3 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX2; ADP_hexdigit_next(adp_bus_data[11: 8]); end // hex nibble 2 + else com_tx_req <= 1; // extend + ADP_WRITEHEX2: // output hex nibble 2 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX1; ADP_hexdigit_next(adp_bus_data[ 7: 4]); end // hex nibble 1 + else com_tx_req <= 1; // extend + ADP_WRITEHEX1: // output hex nibble 1 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX0; ADP_hexdigit_next(adp_bus_data[ 3: 0]); end // hex nibble 0 + else com_tx_req <= 1; // extend + ADP_WRITEHEX0: // output hex nibble 0 (if not startup banner then scan to end of line before lineack + if (com_tx_done) begin + adp_bus_err <= 1'b0; // clear sticky bus error flag + if (banner) begin ADP_LINEACK_next; end + else begin ADP_txchar_next(8'h0A); com_tx_req <= 1; adp_state <= ADP_LINEACK; end // newline and prompt + end else com_tx_req <= 1; // extend + + ADP_LINEACK: // write EOLN + if (com_tx_done) begin + begin ADP_txchar_next(8'h0D); adp_state <= ADP_LINEACK2; end + end else com_tx_req <= 1; // extend + ADP_LINEACK2: // CR + if (com_tx_done) begin + if (banner) begin banner <= 0; adp_state <= STD_IOCHK; end +`ifndef ADPBASIC + else if ((FNvalid_cmd(adp_cmd) == CMD_R) & |adp_count) //// non-zero count + begin ADP_BUSREADINC_next; adp_count_dec <= 1'b1; adp_state <= ADP_READ; end // +`endif + else begin ADP_txchar_next(PROMPT_CHAR); adp_state <= ADP_PROMPT; end + end else com_tx_req <= 1; // extend + default: + begin ADP_txchar_next("#"); adp_state <= ADP_UNKNOWN; end // default error + endcase + end + +endmodule \ No newline at end of file diff --git a/controller/verilog/socshute_ahb.v b/controller/verilog/socshute_ahb.v new file mode 100644 index 0000000000000000000000000000000000000000..a8c97312ab5d71ecc3aa331008b20899bf5afa26 --- /dev/null +++ b/controller/verilog/socshute_ahb.v @@ -0,0 +1,104 @@ +//----------------------------------------------------------------------------- +// SoCShute Top-level FT1248-AHB Debug Controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Mapstone (d.a.mapstone@soton.ac.uk) +// +// Copyright � 2021-3, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +module socshute_ahb #( + parameter PROMPT_CHAR = "]" +)( + // AHB-lite Master Interface + input wire HCLK, + input wire HRESETn, + output wire [31:0] HADDR32_o, + output wire [ 2:0] HBURST3_o, + output wire HMASTLOCK_o, + output wire [ 3:0] HPROT4_o, + output wire [ 2:0] HSIZE3_o, + output wire [ 1:0] HTRANS2_o, + output wire [31:0] HWDATA32_o, + output wire HWRITE_o, + input wire [31:0] HRDATA32_i, + input wire HREADY_i, + input wire HRESP_i, + + // APB Slave Interface + input wire PCLK, // Clock + input wire PCLKG, // Gated Clock + input wire PRESETn, // Reset + + input wire PSEL, // Device select + input wire [11:2] PADDR, // Address + input wire PENABLE, // Transfer control + input wire PWRITE, // Write control + input wire [31:0] PWDATA, // Write data + + output wire [31:0] PRDATA, // Read data + output wire PREADY, // Device ready + output wire PSLVERR, // Device error response + + // GPIO interface + output wire [ 7:0] GPO8_o, + input wire [ 7:0] GPI8_i +); + + // COMIO interface + wire [ 7:0] COMRX_TDATA_i; + wire COMRX_TVALID_i; + wire COMRX_TREADY_o; + wire [ 7:0] COMTX_TDATA_o; + wire COMTX_TVALID_o; + wire COMTX_TREADY_i; + + // STDIO interface + wire [ 7:0] STDRX_TDATA_i; + wire STDRX_TVALID_i; + wire STDRX_TREADY_o; + wire [ 7:0] STDTX_TDATA_o; + wire STDTX_TVALID_o; + wire STDTX_TREADY_i; + + // Instantiation of USRT Device + socshute_apb_usrt u_apb_usrt_com ( + .PCLK (PCLK), // Peripheral clock + .PCLKG (PCLKG), // Gated PCLK for bus + .PRESETn (PRESETn), // Reset + + .PSEL (PSEL), // APB interface inputs + .PADDR (PADDR), + .PENABLE (PENABLE), + .PWRITE (PWRITE), + .PWDATA (PWDATA), + + .PRDATA (PRDATA), // APB interface outputs + .PREADY (PREADY), + .PSLVERR (PSLVERR), + + .ECOREVNUM (4'h0), // Engineering-change-order revision bits + + .TX_VALID_o (stdio_rx_valid), + .TX_DATA8_o (stdio_rx_data8), + .TX_READY_i (stdio_rx_ready), + + .RX_VALID_i (stdio_tx_valid), + .RX_DATA8_i (stdio_tx_data8), + .RX_READY_o (stdio_tx_ready), + + .TXINT ( ), // Transmit Interrupt + .RXINT ( ), // Receive Interrupt + .TXOVRINT ( ), // Transmit Overrun Interrupt + .RXOVRINT ( ), // Receive Overrun Interrupt + .UARTINT ( ) // Combined Interrupt + ); + + // Instantiation of FT1248 Bus Master + + // Instantiation of ADP AHB Controller + + +endmodule \ No newline at end of file diff --git a/controller/verilog/socshute_apb_usrt.v b/controller/verilog/socshute_apb_usrt.v new file mode 100644 index 0000000000000000000000000000000000000000..8da2951ba09e63ecb71a8638f6899c72f2d3d1d1 --- /dev/null +++ b/controller/verilog/socshute_apb_usrt.v @@ -0,0 +1,1159 @@ +//----------------------------------------------------------------------------- +// SoCShute APB USRT adapted from Arm CMSDK APB UART +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright � 2021-3, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// The confidential and proprietary information contained in this file may +// only be used by a person authorised under and to the extent permitted +// by a subsisting licensing agreement from Arm Limited or its affiliates. +// +// (C) COPYRIGHT 2010-2011 Arm Limited or its affiliates. +// ALL RIGHTS RESERVED +// +// This entire notice must be reproduced on all copies of this file +// and copies of this file may only be made by a person if such person is +// permitted to do so under the terms of a subsisting license agreement +// from Arm Limited or its affiliates. +// +// SVN Information +// +// Checked In : $Date: 2017-10-10 15:55:38 +0100 (Tue, 10 Oct 2017) $ +// +// Revision : $Revision: 371321 $ +// +// Release Information : Cortex-M System Design Kit-r1p1-00rel0 +// +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Abstract : Simple APB UART +//----------------------------------------------------------------------------- +//------------------------------------- +// Programmer's model +// 0x00 R RXD[7:0] Received Data +// W TXD[7:0] Transmit data +// 0x04 RW STAT[3:0] +// [3] RX buffer overrun (write 1 to clear) +// [2] TX buffer overrun (write 1 to clear) +// [1] RX buffer full (Read only) +// [0] TX buffer full (Read only) +// 0x08 RW CTRL[3:0] TxIntEn, RxIntEn, TxEn, RxEn +// [6] High speed test mode Enable +// [5] RX overrun interrupt enable +// [4] TX overrun interrupt enable +// [3] RX Interrupt Enable +// [2] TX Interrupt Enable +// [1] RX Enable +// [0] TX Enable +// 0x0C R/Wc intr_status/INTCLEAR +// [3] RX overrun interrupt +// [2] TX overrun interrupt +// [1] RX interrupt +// [0] TX interrupt +// 0x10 RW BAUDDIV[19:0] Baud divider +// (minimum value is 16) +// 0x3E0 - 0x3FC ID registers +//------------------------------------- + +module socshute_apb_usrt ( +// -------------------------------------------------------------------------- +// Port Definitions +// -------------------------------------------------------------------------- + input wire PCLK, // Clock + input wire PCLKG, // Gated Clock + input wire PRESETn, // Reset + + input wire PSEL, // Device select + input wire [11:2] PADDR, // Address + input wire PENABLE, // Transfer control + input wire PWRITE, // Write control + input wire [31:0] PWDATA, // Write data + + input wire [3:0] ECOREVNUM,// Engineering-change-order revision bits + + output wire [31:0] PRDATA, // Read data + output wire PREADY, // Device ready + output wire PSLVERR, // Device error response + + output wire TX_VALID_o, + output wire [7:0] TX_DATA8_o, + input wire TX_READY_i, + + input wire RX_VALID_i, + input wire [7:0] RX_DATA8_i, + output wire RX_READY_o, + + output wire TXINT, // Transmit Interrupt + output wire RXINT, // Receive Interrupt + output wire TXOVRINT, // Transmit overrun Interrupt + output wire RXOVRINT, // Receive overrun Interrupt + output wire UARTINT); // Combined interrupt + +// Local ID parameters, APB UART part number is 0x821 +localparam ARM_CMSDK_APB_UART_PID4 = 8'h04; +localparam ARM_CMSDK_APB_UART_PID5 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID6 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID7 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID0 = 8'h21; +localparam ARM_CMSDK_APB_UART_PID1 = 8'hB8; +localparam ARM_CMSDK_APB_UART_PID2 = 8'h1B; +localparam ARM_CMSDK_APB_UART_PID3 = 4'h0; +localparam ARM_CMSDK_APB_UART_CID0 = 8'h0D; +localparam ARM_CMSDK_APB_UART_CID1 = 8'hF0; +localparam ARM_CMSDK_APB_UART_CID2 = 8'h05; +localparam ARM_CMSDK_APB_UART_CID3 = 8'hB1; + +// original external IOs +wire RXD = 1'b1; // Serial input +wire TXD; // Transmit data output +wire TXEN; // Transmit enabled +wire BAUDTICK; // Baud rate (x16) Tick + + + // -------------------------------------------------------------------------- + // Internal wires + // -------------------------------------------------------------------------- +// Signals for read/write controls +wire read_enable; +wire write_enable; +wire write_enable00; // Write enable for data register +wire write_enable04; // Write enable for Status register +wire write_enable08; // Write enable for control register +wire write_enable0c; // Write enable for interrupt status register +wire write_enable10; // Write enable for Baud rate divider +reg [7:0] read_mux_byte0; // Read data multiplexer for lower 8-bit +reg [7:0] read_mux_byte0_reg; // Register read data for lower 8-bit +wire [31:0] read_mux_word; // Read data multiplexer for whole 32-bit +wire [3:0] pid3_value; // constant value for lower 4-bit in perpherial ID3 + +// Signals for Control registers +reg [6:0] reg_ctrl; // Control register +reg [7:0] reg_tx_buf; // Transmit data buffer +reg [7:0] reg_rx_buf; // Receive data buffer +reg [19:0] reg_baud_div; // Baud rate setting + +// Internal signals + // Baud rate divider +reg [15:0] reg_baud_cntr_i; // baud rate divider counter i (integer) +wire [15:0] nxt_baud_cntr_i; +reg [3:0] reg_baud_cntr_f; // baud rate divider counter f (fraction) +wire [3:0] nxt_baud_cntr_f; +wire [3:0] mapped_cntr_f; // remapped counter f value +reg reg_baud_tick; // Register baud rate tick (16 times of baud rate) +reg baud_updated; // baud rate value has bee updated from APB +wire reload_i; // baud rate divider counter i reload +wire reload_f; // baud rate divider counter f reload +wire baud_div_en; // enable baud rate counter + + // Status +wire [3:0] uart_status; // UART status +reg reg_rx_overrun; // Receive overrun status register +wire rx_overrun; // Receive overrun detection +reg reg_tx_overrun; // Transmit overrun status register +wire tx_overrun; // Transmit overrun detection +wire nxt_rx_overrun; // next state for reg_rx_overrun +wire nxt_tx_overrun; // next state for reg_tx_overrun + // Interrupts +reg reg_txintr; // Transmit interrupt register +reg reg_rxintr; // Receive interrupt register +wire tx_overflow_intr;// Transmit overrun/overflow interrupt +wire rx_overflow_intr;// Receive overrun/overflow interrupt +wire [3:0] intr_state; // UART interrupt status +wire [1:0] intr_stat_set; // Set TX/RX interrupt +wire [1:0] intr_stat_clear; // Clear TX/RX interrupt + + // transmit +reg [3:0] tx_state; // Transmit FSM state +reg [4:0] nxt_tx_state; +wire tx_state_update; +wire tx_state_inc; // Bit pulse +reg [3:0] tx_tick_cnt; // Transmit Tick counter +wire [4:0] nxt_tx_tick_cnt; +reg [7:0] tx_shift_buf; // Transmit shift register +wire [7:0] nxt_tx_shift_buf; // next state for tx_shift_buf +wire tx_buf_ctrl_shift; // shift control for tx_shift_buf +wire tx_buf_ctrl_load; // load control for tx_shift_buf +reg tx_buf_full; // TX Buffer full +reg reg_txd; // Tx Data +wire nxt_txd; // next state of reg_txd +wire update_reg_txd; // update reg_txd +wire tx_buf_clear; // Clear buffer full status when data is load into TX shift register + + // Receive data sync and filter +reg rxd_sync_1; // Double flip-flop syncrhoniser +reg rxd_sync_2; // Double flip-flop syncrhoniser +reg [2:0] rxd_lpf; // Averaging Low Pass Filter +wire [2:0] nxt_rxd_lpf; +wire rx_shift_in; // Shift Register Input + + // Receiver +reg [3:0] rx_state; // Receiver FSM state +reg [4:0] nxt_rx_state; +wire rx_state_update; +reg [3:0] rx_tick_cnt; // Receiver Tick counter +wire [4:0] nxt_rx_tick_cnt; +wire update_rx_tick_cnt; +wire rx_state_inc;// Bit pulse +reg [6:0] rx_shift_buf;// Receiver shift data register +wire [6:0] nxt_rx_shift_buf; +reg rx_buf_full; // Receive buffer full status +wire nxt_rx_buf_full; +wire rxbuf_sample; // Sample received data into receive data buffer +wire rx_data_read; // Receive data buffer read by APB interface +wire [7:0] nxt_rx_buf; + +// Start of main code +// Read and write control signals +assign read_enable = PSEL & (~PWRITE); // assert for whole APB read transfer +assign write_enable = PSEL & (~PENABLE) & PWRITE; // assert for 1st cycle of write transfer +assign write_enable00 = write_enable & (PADDR[11:2] == 10'h000); +assign write_enable04 = write_enable & (PADDR[11:2] == 10'h001); +assign write_enable08 = write_enable & (PADDR[11:2] == 10'h002); +assign write_enable0c = write_enable & (PADDR[11:2] == 10'h003); +assign write_enable10 = write_enable & (PADDR[11:2] == 10'h004); + +// Write operations + // Transmit data register + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_tx_buf <= {8{1'b0}}; + else if (write_enable00) + reg_tx_buf <= PWDATA[7:0]; + end + + assign TX_DATA8_o = reg_tx_buf[7:0]; + + // Status register overrun registers + assign nxt_rx_overrun = (reg_rx_overrun & (~((write_enable04|write_enable0c) & PWDATA[3]))) | rx_overrun; + assign nxt_tx_overrun = (reg_tx_overrun & (~((write_enable04|write_enable0c) & PWDATA[2]))) | tx_overrun; + + // RX OverRun status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rx_overrun <= 1'b0; + else if (rx_overrun | write_enable04 | write_enable0c) + reg_rx_overrun <= nxt_rx_overrun; + end + + // TX OverRun status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_tx_overrun <= 1'b0; + else if (tx_overrun | write_enable04 | write_enable0c) + reg_tx_overrun <= nxt_tx_overrun; + end + + // Control register + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_ctrl <= {7{1'b0}}; + else if (write_enable08) + reg_ctrl <= PWDATA[6:0]; + end + + // Baud rate divider - integer + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_div <= {20{1'b0}}; + else if (write_enable10) + reg_baud_div <= PWDATA[19:0]; + end + +// Read operation + assign uart_status = {reg_rx_overrun, reg_tx_overrun, rx_buf_full, tx_buf_full}; + + assign pid3_value = ARM_CMSDK_APB_UART_PID3; + + // First level of read mux + always @(PADDR or reg_rx_buf or uart_status or reg_ctrl or intr_state or reg_baud_div + or ECOREVNUM or pid3_value) + begin + if (PADDR[11:5] == 7'h00) begin + case (PADDR[4:2]) + 3'h0: read_mux_byte0 = reg_rx_buf; + 3'h1: read_mux_byte0 = {{4{1'b0}},uart_status}; + 3'h2: read_mux_byte0 = {{1{1'b0}},reg_ctrl}; + 3'h3: read_mux_byte0 = {{4{1'b0}},intr_state}; + 3'h4: read_mux_byte0 = reg_baud_div[7:0]; + 3'h5, 3'h6, 3'h7: read_mux_byte0 = {8{1'b0}}; //default read out value + default: read_mux_byte0 = {8{1'bx}};// x propogation + endcase + end + else if (PADDR[11:6] == 6'h3F) begin + case (PADDR[5:2]) + 4'h0, 4'h1,4'h2,4'h3: read_mux_byte0 = {8{1'b0}}; //default read out value + // ID register - constant values + 4'h4: read_mux_byte0 = ARM_CMSDK_APB_UART_PID4; // 0xFD0 : PID 4 + 4'h5: read_mux_byte0 = ARM_CMSDK_APB_UART_PID5; // 0xFD4 : PID 5 + 4'h6: read_mux_byte0 = ARM_CMSDK_APB_UART_PID6; // 0xFD8 : PID 6 + 4'h7: read_mux_byte0 = ARM_CMSDK_APB_UART_PID7; // 0xFDC : PID 7 + 4'h8: read_mux_byte0 = ARM_CMSDK_APB_UART_PID0; // 0xFE0 : PID 0 APB UART part number[7:0] + 4'h9: read_mux_byte0 = ARM_CMSDK_APB_UART_PID1; // 0xFE0 : PID 1 [7:4] jep106_id_3_0. [3:0] part number [11:8] + 4'hA: read_mux_byte0 = ARM_CMSDK_APB_UART_PID2; // 0xFE0 : PID 2 [7:4] revision, [3] jedec_used. [2:0] jep106_id_6_4 + 4'hB: read_mux_byte0 = {ECOREVNUM[3:0],pid3_value[3:0]}; + // 0xFE0 : PID 3 [7:4] ECO revision, [3:0] modification number + 4'hC: read_mux_byte0 = ARM_CMSDK_APB_UART_CID0; // 0xFF0 : CID 0 + 4'hD: read_mux_byte0 = ARM_CMSDK_APB_UART_CID1; // 0xFF4 : CID 1 PrimeCell class + 4'hE: read_mux_byte0 = ARM_CMSDK_APB_UART_CID2; // 0xFF8 : CID 2 + 4'hF: read_mux_byte0 = ARM_CMSDK_APB_UART_CID3; // 0xFFC : CID 3 + default : read_mux_byte0 = {8{1'bx}}; // x propogation + endcase + end + else begin + read_mux_byte0 = {8{1'b0}}; //default read out value + end + end + + + + // Register read data + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + read_mux_byte0_reg <= {8{1'b0}}; + else if (read_enable) + read_mux_byte0_reg <= read_mux_byte0; + end + + // Second level of read mux + assign read_mux_word[ 7: 0] = read_mux_byte0_reg; + assign read_mux_word[19: 8] = (PADDR[11:2]==10'h004) ? reg_baud_div[19:8] : {12{1'b0}}; + assign read_mux_word[31:20] = {12{1'b0}}; + + + // Output read data to APB + assign PRDATA[31: 0] = (read_enable) ? read_mux_word : {32{1'b0}}; + assign PREADY = 1'b1; // Always ready + assign PSLVERR = 1'b0; // Always okay + +// -------------------------------------------- +// Baud rate generator + // Baud rate generator enable + assign baud_div_en = (reg_ctrl[1:0] != 2'b00); + assign mapped_cntr_f = {reg_baud_cntr_f[0],reg_baud_cntr_f[1], + reg_baud_cntr_f[2],reg_baud_cntr_f[3]}; + // Reload Integer divider + // when UART enabled and (reg_baud_cntr_f < reg_baud_div[3:0]) + // then count to 1, or + // when UART enabled then count to 0 + assign reload_i = (baud_div_en & + (((mapped_cntr_f >= reg_baud_div[3:0]) & + (reg_baud_cntr_i[15:1] == {15{1'b0}})) | + (reg_baud_cntr_i[15:0] == {16{1'b0}}))); + + // Next state for Baud rate divider + assign nxt_baud_cntr_i = (baud_updated | reload_i) ? reg_baud_div[19:4] : + (reg_baud_cntr_i - 16'h0001); + // Update at reload or decrement + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_cntr_i <= {16{1'b0}}; + else if (baud_updated | baud_div_en) + reg_baud_cntr_i <= nxt_baud_cntr_i; + end + + // Reload fraction divider + assign reload_f = baud_div_en & (reg_baud_cntr_f==4'h0) & + reload_i; + // Next state for fraction part of Baud rate divider + assign nxt_baud_cntr_f = + (reload_f|baud_updated) ? 4'hF : + (reg_baud_cntr_f - 4'h1); + + // Update at reload or decrement + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_cntr_f <= {4{1'b0}}; + else if (baud_updated | reload_f | reload_i) + reg_baud_cntr_f <= nxt_baud_cntr_f; + end + + // Generate control signal to update baud rate counters + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + baud_updated <= 1'b0; + else if (write_enable10 | baud_updated) + // Baud rate updated - to load new value to counters + baud_updated <= write_enable10; + end + + // Generate Tick signal for external logic + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_tick <= 1'b0; + else if (reload_i | reg_baud_tick) + reg_baud_tick <= reload_i; + end + + // Connect to external + assign BAUDTICK = reg_baud_tick; + +// -------------------------------------------- +// Transmit + + // Buffer full status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_buf_full <= 1'b0; + else if (write_enable00) // | tx_buf_clear) + tx_buf_full <= write_enable00; + else if (tx_buf_full & TX_READY_i) // AXI stream ack + tx_buf_full <= 0; + end + + assign TX_VALID_o = tx_buf_full; + + // Increment TickCounter + assign nxt_tx_tick_cnt = ((tx_state==4'h1) & reg_baud_tick) ? {5{1'b0}} : + tx_tick_cnt + {{3{1'b0}},reg_baud_tick}; + + // Registering TickCounter + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_tick_cnt <= {4{1'b0}}; + else if (reg_baud_tick) + tx_tick_cnt <= nxt_tx_tick_cnt[3:0]; + end + + // Increment state (except Idle(0) and Wait for Tick(1)) + assign tx_state_inc = (((&tx_tick_cnt)|(tx_state==4'h1)) & reg_baud_tick)|reg_ctrl[6]; + // state increment every cycle of high speed test mode is enabled + // Clear buffer full status when data is load into shift register + assign tx_buf_clear = ((tx_state==4'h0) & tx_buf_full) | + ((tx_state==4'hB) & tx_buf_full & tx_state_inc); + + // tx_state machine + // 0 = Idle, 1 = Wait for Tick, + // 2 = Start bit, 3 = D0 .... 10 = D7 + // 11 = Stop bit + always @(tx_state or tx_buf_full or tx_state_inc or reg_ctrl) + begin + case (tx_state) + 0: begin + nxt_tx_state = (tx_buf_full & reg_ctrl[0]) ? 5'h01 : 5'h00; // New data is written to buffer + end + 1, // State 1 : Wait for next Tick + 2,3,4,5,6,7,8,9,10: begin // State 2-10: Start bit, D0 - D7 + nxt_tx_state = tx_state + {3'b000,tx_state_inc}; + end + 11: begin // Stop bit , goto next start bit or Idle + nxt_tx_state = (tx_state_inc) ? ( tx_buf_full ? 5'h02:5'h00) : {1'b0, tx_state}; + end + default: + nxt_tx_state = {5{1'bx}}; + endcase + end + + assign tx_state_update = tx_state_inc | ((tx_state==4'h0) & tx_buf_full & reg_ctrl[0]) | (tx_state>4'd11); + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_state <= {4{1'b0}}; + else if (tx_state_update) + tx_state <= nxt_tx_state[3:0]; + end + + // Load/shift TX register + assign tx_buf_ctrl_load = (((tx_state==4'h0) & tx_buf_full) | + ((tx_state==4'hB) & tx_buf_full & tx_state_inc)); + assign tx_buf_ctrl_shift = ((tx_state>4'h2) & tx_state_inc); + + assign nxt_tx_shift_buf = tx_buf_ctrl_load ? reg_tx_buf[7:0] : {1'b1,tx_shift_buf[7:1]}; + + // Registering TX shift register + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_shift_buf <= {8{1'b0}}; + else if (tx_buf_ctrl_shift | tx_buf_ctrl_load) + tx_shift_buf <= nxt_tx_shift_buf; + end + + // Data output + assign nxt_txd = (tx_state==4'h2) ? 1'b0 : + (tx_state>4'h2) ? tx_shift_buf[0] : 1'b1; + + assign update_reg_txd = (nxt_txd != reg_txd); + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_txd <= 1'b1; + else if (update_reg_txd) + reg_txd <= nxt_txd; + end + + // Generate TX overrun error status + assign tx_overrun = tx_buf_full & (~tx_buf_clear) & write_enable00; + + // Connect to external + assign TXD = reg_txd; + assign TXEN = reg_ctrl[0]; + +// -------------------------------------------- +// Receive synchronizer and low pass filter + + // Doubling Flip-flop synxt_rx_tick_cntnchroniser + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + rxd_sync_1 <= 1'b1; + rxd_sync_2 <= 1'b1; + end + else if (reg_ctrl[1]) // Turn off synchronizer if receive is not enabled + begin + rxd_sync_1 <= RXD; + rxd_sync_2 <= rxd_sync_1; + end + end + + // Averaging low pass filter + assign nxt_rxd_lpf = {rxd_lpf[1:0], rxd_sync_2}; + // Registering stage for low pass filter + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rxd_lpf <= 3'b111; + else if (reg_baud_tick) + rxd_lpf <= nxt_rxd_lpf; + end + + // Averaging values + assign rx_shift_in = (rxd_lpf[1] & rxd_lpf[0]) | + (rxd_lpf[1] & rxd_lpf[2]) | + (rxd_lpf[0] & rxd_lpf[2]); + +// -------------------------------------------- +// Receive + + // Increment TickCounter + assign nxt_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) ? 5'h08 : + rx_tick_cnt + {{3{1'b0}},reg_baud_tick}; + + assign update_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) | reg_baud_tick; + + // Registering other register + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_tick_cnt <= {4{1'b0}}; + else if (update_rx_tick_cnt) + rx_tick_cnt <= nxt_rx_tick_cnt[3:0]; + end + + // Increment state + assign rx_state_inc = ((&rx_tick_cnt) & reg_baud_tick); + // Buffer full status + assign nxt_rx_buf_full = rxbuf_sample | (rx_buf_full & (~rx_data_read)); + + // Sample shift register when D7 is sampled +/// assign rxbuf_sample = ((rx_state==4'h9) & rx_state_inc); + assign rxbuf_sample = RX_VALID_i & !rx_buf_full; + + // Reading receive buffer (Set at 1st cycle of APB transfer + // because read mux is registered before output) + assign rx_data_read = (PSEL & (~PENABLE) & (PADDR[11:2]==10'h000) & (~PWRITE)); + // Generate RX overrun error status + assign rx_overrun = rx_buf_full & rxbuf_sample & (~rx_data_read); + + // rx_state machine + // 0 = Idle, 1 = Start of Start bit detected + // 2 = Sample Start bit, 3 = D0 .... 10 = D7 + // 11 = Stop bit + // 11, 12, 13, 14, 15: illegal/unused states + always @(rx_state or rx_shift_in or rx_state_inc or reg_ctrl) + begin + case (rx_state) + 0: begin + nxt_rx_state = ((~rx_shift_in) & reg_ctrl[1]) ? 5'h01 : 5'h00; // Wait for Start bit + end + 1, // State 1 : Wait for middle of start bit + 2,3,4,5,6,7,8,9: begin // State 2-9: D0 - D7 + nxt_rx_state = rx_state + {3'b000,rx_state_inc}; + end + 10: begin // Stop bit , goto back to Idle + nxt_rx_state = (rx_state_inc) ? 5'h00 : 5'h0A; + end + default: + nxt_rx_state = {5{1'bx}}; + endcase + end + + assign rx_state_update = rx_state_inc | ((~rx_shift_in) & reg_ctrl[1]); + + // Registering rx_state + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_state <= {4{1'b0}}; + else if (rx_state_update) + rx_state <= nxt_rx_state[3:0]; + end + + // Buffer full status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_buf_full <= 1'b0; + else if (rxbuf_sample | rx_data_read) + rx_buf_full <= nxt_rx_buf_full; + end + + // Sample receive buffer +/// assign nxt_rx_buf = {rx_shift_in, rx_shift_buf}; + assign nxt_rx_buf = RX_DATA8_i[7:0]; + + // Registering receive data buffer + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rx_buf <= {8{1'b0}}; + else if (rxbuf_sample) + reg_rx_buf <= nxt_rx_buf; + end + + // Shift register + assign nxt_rx_shift_buf= {rx_shift_in, rx_shift_buf[6:1]}; + // Registering shift buffer + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_shift_buf <= {7{1'b0}}; + else if (rx_state_inc) + rx_shift_buf <= nxt_rx_shift_buf; + end + + + +// -------------------------------------------- +// Interrupts + // Set by event + assign intr_stat_set[1] = reg_ctrl[3] & rxbuf_sample; // A new receive data is sampled + assign intr_stat_set[0] = reg_ctrl[2] & reg_ctrl[0] & tx_buf_full & tx_buf_clear; + // Falling edge of buffer full + // Clear by write to IntClear register + assign intr_stat_clear[1:0] = {2{write_enable0c}} & PWDATA[1:0]; + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_txintr <= 1'b0; + else if (intr_stat_set[0] | intr_stat_clear[0]) + reg_txintr <= intr_stat_set[0]; + end + + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rxintr <= 1'b0; + else if (intr_stat_set[1] | intr_stat_clear[1]) + reg_rxintr <= intr_stat_set[1]; + end + + assign rx_overflow_intr = reg_rx_overrun & reg_ctrl[5]; + assign tx_overflow_intr = reg_tx_overrun & reg_ctrl[4]; + + // Interrupt status for read back + assign intr_state = {rx_overflow_intr, tx_overflow_intr, reg_rxintr, reg_txintr}; + + // Connect to external + assign TXINT = reg_txintr; + assign RXINT = reg_rxintr; + assign TXOVRINT = tx_overflow_intr; + assign RXOVRINT = rx_overflow_intr; + assign UARTINT = reg_txintr | reg_rxintr | tx_overflow_intr | rx_overflow_intr; + + +`ifdef ARM_APB_ASSERT_ON + // ------------------------------------------------------------ + // Assertions + // ------------------------------------------------------------ +`include "std_ovl_defines.h" + + // Prepare signals for OVL checking + reg [15:0] ovl_last_reg_baud_cntr_i; + reg [3:0] ovl_last_reg_baud_cntr_f; + reg ovl_last_baud_div_en; + reg ovl_last_baud_updated; + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_last_reg_baud_cntr_i <= {16{1'b0}}; + ovl_last_reg_baud_cntr_f <= {4{1'b0}}; + ovl_last_baud_div_en <= 1'b0; + ovl_last_baud_updated <= 1'b0; + end + else + begin + ovl_last_reg_baud_cntr_i <= reg_baud_cntr_i; + ovl_last_reg_baud_cntr_f <= reg_baud_cntr_f; + ovl_last_baud_div_en <= baud_div_en; + ovl_last_baud_updated <= baud_updated; + end + end + + reg ovl_reg_hs_test_mode_triggered; // Indicate if HighSpeed testmode has been activated + wire ovl_nxt_hs_test_mode_triggered; + reg [7:0] ovl_reg_tx_tick_count; // For measuring width of TX state + wire [7:0] ovl_nxt_tx_tick_count; + reg [7:0] ovl_reg_rx_tick_count; // For measuring width of RX state + wire [7:0] ovl_nxt_rx_tick_count; + reg [3:0] ovl_reg_last_tx_state; // last state + reg [3:0] ovl_reg_last_rx_state; + reg [6:0] ovl_last_reg_ctrl; + + // Clear test mode indicator each time state is changed, set to 1 if high speed test mode is + // enabled + assign ovl_nxt_hs_test_mode_triggered = + (tx_state!=ovl_reg_last_tx_state) ? reg_ctrl[6]: (reg_ctrl[6] | ovl_reg_hs_test_mode_triggered); + + // Counter clear at each state change, increasement at each reg_baud_tick + assign ovl_nxt_tx_tick_count = (tx_state!=ovl_reg_last_tx_state) ? (8'h00) : + (ovl_reg_tx_tick_count + {{7{1'b0}}, reg_baud_tick}); + + // Counter clear at each state change, increasement at each reg_baud_tick + assign ovl_nxt_rx_tick_count = (rx_state!=ovl_reg_last_rx_state) ? (8'h00) : + (ovl_reg_rx_tick_count + {{7{1'b0}}, reg_baud_tick}); + + always@(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_reg_hs_test_mode_triggered <= 1'b0; + ovl_reg_last_tx_state <= 4'h0; + ovl_reg_last_rx_state <= 4'h0; + ovl_reg_tx_tick_count <= 8'h00; + ovl_reg_rx_tick_count <= 8'h00; + ovl_last_reg_ctrl <= 7'h00; + end + else + begin + ovl_reg_hs_test_mode_triggered <= ovl_nxt_hs_test_mode_triggered; + ovl_reg_last_tx_state <= tx_state; + ovl_reg_last_rx_state <= rx_state; + ovl_reg_tx_tick_count <= ovl_nxt_tx_tick_count; + ovl_reg_rx_tick_count <= ovl_nxt_rx_tick_count; + ovl_last_reg_ctrl <= reg_ctrl; + end + end + + // Signals for checking clearing of interrupts + reg ovl_last_txint; + reg ovl_last_rxint; + reg ovl_last_psel; + reg ovl_last_penable; + reg ovl_last_pwrite; + reg [31:0] ovl_last_pwdata; + reg [11:2] ovl_last_paddr; + reg ovl_last_rx_buf_full; + reg ovl_last_tx_shift_buf_0; + + + always@(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_last_txint <= 1'b0; + ovl_last_rxint <= 1'b0; + ovl_last_psel <= 1'b0; + ovl_last_penable <= 1'b0; + ovl_last_pwrite <= 1'b0; + ovl_last_paddr <= {10{1'b0}}; + ovl_last_pwdata <= {32{1'b0}}; + ovl_last_rx_buf_full <= 1'b0; + ovl_last_tx_shift_buf_0 <= 1'b0; + end + else + begin + ovl_last_txint <= TXINT; + ovl_last_rxint <= RXINT; + ovl_last_psel <= PSEL; + ovl_last_penable <= PENABLE; + ovl_last_pwrite <= PWRITE; + ovl_last_paddr <= PADDR; + ovl_last_pwdata <= PWDATA; + ovl_last_rx_buf_full <= rx_buf_full; + ovl_last_tx_shift_buf_0 <= tx_shift_buf[0]; + end + end + + // Ensure rx_state must not be 11, 12, 13, 14, 15 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "rx_state in illegal state") + u_ovl_rx_state_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((rx_state==4'hB)|(rx_state==4'hC)|(rx_state==4'hD)| + (rx_state==4'hE)|(rx_state==4'hF))); + + // Ensure tx_state must not be 12, 13, 14, 15 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "tx_state in illegal state") + u_ovl_tx_state_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((tx_state==4'hC)|(tx_state==4'hD)| + (tx_state==4'hE)|(tx_state==4'hF))); + + // Ensure reg_baud_cntr_i change only if UART is enabled + // or if write to baud rate divider + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divider change") + u_ovl_reg_baud_cntr_i_change + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_reg_baud_cntr_i!=reg_baud_cntr_i), + .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated ) + ); + + // Ensure reg_baud_div[19:4] >= reg_baud_cntr_i unless reg_baud_div just been programmed + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divided change") + u_ovl_reg_baud_cntr_i_range + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(reg_baud_cntr_i>reg_baud_div[19:4]), + .consequent_expr(baud_updated) + ); + + // Ensure reg_baud_cntr_f change only if UART is enabled + // or if write to baud rate divider + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divider change") + u_ovl_reg_baud_cntr_f_change + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_reg_baud_cntr_f!=reg_baud_cntr_f), + .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated ) + ); + + // Ensure tx_buf_full is set to 1 after write to TX buffer (PADDR[11:2]==0) + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx_buf_full should be asserted after write to TX buffer") + u_ovl_tx_buf_full + (.clk(PCLK), .reset_n(PRESETn), + .start_event (PSEL & (~PENABLE) & PWRITE & (PADDR[11:2] == 10'h000)), + .test_expr (tx_buf_full) + ); + + // If last tx_state=0 (idle) or 1 (wait for tick), TXD = 1. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 1 when idle or just before data transmission") + u_ovl_txd_state_0_1 + (.clk(PCLK), .reset_n(PRESETn), + .start_event ((tx_state==4'd0)|(tx_state==4'd1)), + .test_expr (TXD==1'b1) + ); + + // If last tx_state=2 (start bit), TXD = 0. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 0 when output start bit") + u_ovl_txd_state_2 + (.clk(PCLK), .reset_n(PRESETn), + .start_event (tx_state==4'd2), + .test_expr (TXD==1'b0) + ); + + // If last tx_state=3-10 (D0 to D7), TXD = anything (tx_shift_buf[0]). + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be same as first bit of shift register during transfer") + u_ovl_txd_state_3_to_10 + (.clk(PCLK), .reset_n(PRESETn), + .start_event ((tx_state>4'd2) & (tx_state<4'd11)), + .test_expr (TXD==ovl_last_tx_shift_buf_0) + ); + + // If last tx_state=11 (stop bit), TXD = 1. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 1 when output stop bit") + u_ovl_txd_state_11 + (.clk(PCLK), .reset_n(PRESETn), + .start_event (tx_state==4'd11), + .test_expr (TXD==1'b1) + ); + + // Duration of tx_state in 2 to 11 must have 16 reg_baud_tick + // (unless high speed test mode has been active) + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of tx_state when in state 2 to state 11 should have 16 ticks") + u_ovl_width_of_tx_state + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((tx_state!=ovl_reg_last_tx_state) & // at state change + (ovl_reg_last_tx_state>4'd1)&(ovl_reg_last_tx_state<4'd12) & // from state 2 to 11 + (ovl_reg_hs_test_mode_triggered==1'b0)), // high speed test mode not triggered + .consequent_expr((ovl_reg_tx_tick_count==8'd15) | (ovl_reg_tx_tick_count==8'd16)) + // count from 0 to 15 (16 ticks) + ); + + + // In high speed test mode, tx_state must change if it is in range of 2 to 11 + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "Duration of tx_state should be 1 cycle if high speed test mode is enabled") + u_ovl_width_of_tx_state_in_high_speed_test_mode + (.clk(PCLK), .reset_n(PRESETn), + .start_event((tx_state>4'd1)&(tx_state<4'd12) & reg_ctrl[6]), + .test_expr (tx_state != ovl_reg_last_tx_state) + ); + + // Duration of rx_state in 1 must have 8 reg_baud_tick + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of rx_state when state 1 should have 8 ticks") + u_ovl_width_of_rx_state_1 + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((rx_state!=ovl_reg_last_rx_state) & // at state change + (ovl_reg_last_rx_state==4'd1)), // last state was state 1 + .consequent_expr((ovl_reg_rx_tick_count==8'd7)|(ovl_reg_rx_tick_count==8'd8)) + // count from 0 to 7 (8 ticks) + ); + + // Duration of rx_state in 2 to 10 must have 16 reg_baud_tick + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of rx_state when in state 2 to state 10 should have 16 ticks") + u_ovl_width_of_rx_state_data + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((rx_state!=ovl_reg_last_rx_state) & // at state change + (ovl_reg_last_rx_state>4'd1)&(ovl_reg_last_rx_state<4'd11)), // from state 2 to 9 + .consequent_expr((ovl_reg_rx_tick_count==8'd15)|(ovl_reg_rx_tick_count==8'd16)) + // count from 0 to 15 (16 ticks) + ); + + // UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0") + u_ovl_uartint_mismatch + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((TXINT | RXINT | TXOVRINT | RXOVRINT) == 1'b0), // No interrupt + .consequent_expr(UARTINT==1'b0) // Combined interrupt = 0 + ); + + // TXINT should be asserted when TX interrupt enabled and transmit buffer is available + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXINT should be triggered when enabled") + u_ovl_txint_enable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (reg_ctrl[0] & reg_ctrl[2] & tx_buf_full & tx_buf_clear), + .test_expr (TXINT == 1'b1) + ); + + // There should be no rising edge of TXINT if transmit is disabled or transmit interrupt is disabled + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXINT should not be triggered when disabled") + u_ovl_txint_disable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (((reg_ctrl[0]==1'b0) | (reg_ctrl[2]==1'b0)) & (TXINT == 1'b0)), + .test_expr (TXINT == 1'b0) + ); + + // if TXINT falling edge, there must has been a write to INTCLEAR register with bit[0]=1 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of TXINT, there must has been a write to INTCLEAR") + u_ovl_txint_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_txint & (~TXINT)), // Falling edge of TXINT + .consequent_expr(ovl_last_psel & ovl_last_pwrite & + (ovl_last_paddr==10'h003) & (ovl_last_pwdata[0]) ) // There must has been a write to INTCLEAR + ); + + // RXINT should be asserted when RX interrupt enabled and a new data is received + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "RXINT should be triggered when enabled") + u_ovl_rxint_enable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (reg_ctrl[3] & (rx_state==9) & (nxt_rx_state==10)), + .test_expr (RXINT == 1'b1) + ); + + // There should be no rising edge of RXINT if receive interrupt is disabled + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "RXINT should not be triggered when disabled") + u_ovl_rxint_disable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((reg_ctrl[3]==1'b0) & (RXINT == 1'b0)), + .test_expr (RXINT == 1'b0) + ); + + // if RXINT falling edge, there must has been a write to INTCLEAR register with bit[1]=1 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_rxint_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_rxint & (~RXINT)), // Falling edge of TXINT + .consequent_expr(ovl_last_psel & ovl_last_pwrite & + (ovl_last_paddr==10'h003) & (ovl_last_pwdata[1]) ) // There must has been a write to INTCLEAR + ); + + // rx_buf_full should rise if rx_state change from 9 to 10 + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx_buf_full should be asserted when a new character is received") + u_ovl_rx_buf_full + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((rx_state==9) & (nxt_rx_state==10)), + .test_expr (rx_buf_full == 1'b1) + ); + + // if rx_buf_full falling edge, there must has been a read to the receive buffer + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a read to receive buffer") + u_ovl_rx_buf_full_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((~rx_buf_full) & ovl_last_rx_buf_full), // Falling edge of rx_buf_full + .consequent_expr(ovl_last_psel & (~ovl_last_pwrite) & + (ovl_last_paddr==10'h000) ) // There must has been a read to rx data + ); + + // TXOVRINT must be 0 if reg_ctrl[4]=0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_txovrint_disable + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(~reg_ctrl[4]), + .consequent_expr(~TXOVRINT) + ); + + // RXOVRINT must be 0 if reg_ctrl[5]=0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_rxovrint_disable + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(~reg_ctrl[5]), + .consequent_expr(~RXOVRINT) + ); + + // if a write take place to TX data buffer and tx_buf_full was 1, reg_tx_overrun will be set + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be asserted when a new character is write to buffer and buffer is already full") + u_ovl_tx_buffer_overrun + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable00 & tx_buf_full & (~tx_buf_clear)), + .test_expr (reg_tx_overrun == 1'b1) + ); + + // if rx_buf_full is high and rx_state change from 9 to 10, reg_rx_overrun will be set + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be asserted when a new character is received and rx buffer is already full") + u_ovl_rx_buffer_overrun + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (rx_buf_full & (~rx_data_read) & (rx_state==9) & (nxt_rx_state==10)), + .test_expr (reg_rx_overrun == 1'b1) + ); + + // if write to INTCLEAR with bit[2]=1, reg_tx_overrun will be cleared, + // Cannot have new overrun at the same time because the APB can only do onething at a time + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be clear when write to INTCLEAR") + u_ovl_tx_buffer_overrun_clear_a + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable0c & (PWDATA[2])), + .test_expr (reg_tx_overrun==1'b0) + ); + + // if write to STATUS with bit[2]=1, reg_tx_overrun will be cleared, + // Cannot have new overrun at the same time because the APB can only do onething at a time + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be clear when write to INTCLEAR") + u_ovl_tx_buffer_overrun_clear_b + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable04 & (PWDATA[2])), + .test_expr (reg_tx_overrun==1'b0) + ); + + // if write to INTCLEAR with bit[3]=1, reg_rx_overrun will be cleared, unless a new overrun take place + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be clear when write to INTCLEAR, unless new overrun") + u_ovl_rx_buffer_overrun_clear_a + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable0c & (PWDATA[3]) & (~(rx_buf_full & (rx_state==9) & (nxt_rx_state==10)))), + .test_expr (reg_rx_overrun==1'b0) + ); + + // If rx buffer is not full, it cannot have new overrun + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be clear when write to INTCLEAR, unless new overrun") + u_ovl_rx_buffer_overrun_when_empty + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((~rx_buf_full) & (reg_rx_overrun==1'b0)), + .test_expr (reg_rx_overrun==1'b0) + ); + + + // Reading of reg_baud_div (worth checking due to two stage read mux) + assert_next + #(`OVL_ERROR, 1, 1, 0, `OVL_ASSERT, + "Reading of baud rate divider value") + u_ovl_read_baud_rate_divide_cfg + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (PSEL & (~PENABLE) & (~PWRITE) & (PADDR[11:2]==10'h004)), + .test_expr (PRDATA=={{12{1'b0}}, reg_baud_div}) + ); + + // Recommended Baud Rate divider value is at least 16 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "UART enabled with baud rate less than 16") + u_ovl_baud_rate_divider_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr(((reg_ctrl[0]) & (reg_ctrl[6]==1'b0) & (reg_baud_div[19:4]=={16{1'b0}}) ) | + ((reg_ctrl[1]) & (reg_baud_div[19:4]=={16{1'b0}}) ) ) + ); + + // Test mode never changes from hi-speed to normal speed unless TX is idle + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "High speed test mode has been changed when TX was not idle") + u_ovl_change_speed_tx_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((tx_state != 4'd00) & (reg_ctrl[6] != ovl_last_reg_ctrl[6])) + ); + +`endif + +endmodule diff --git a/controller/verilog/socshute_ft1248_stream.v b/controller/verilog/socshute_ft1248_stream.v new file mode 100755 index 0000000000000000000000000000000000000000..1030636ae197d099430a22fac96eecd400e0723c --- /dev/null +++ b/controller/verilog/socshute_ft1248_stream.v @@ -0,0 +1,291 @@ +//----------------------------------------------------------------------------- +// SoCShute FTDI FT1248 Interface to AXI-Stream Controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright � 2022, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +module socshute_ft1248_stream #( + parameter integer FT1248_WIDTH = 1, // FTDI Interface 1,2,4 width supported + parameter integer FT1248_CLKON = 1 // FTDI clock always on - else quiet when no access +)( + // IO pad interface - to FT232R configured in 1/2/4/8 mode + output wire ft_clk_o, // SCLK + output wire ft_ssn_o, // SS_N + input wire ft_miso_i, // MISO + output wire [FT1248_WIDTH-1:0] ft_miosio_o, // MIOSIO tristate output when enabled + output wire [FT1248_WIDTH-1:0] ft_miosio_e, // MIOSIO tristate output enable (active hi) + output wire [FT1248_WIDTH-1:0] ft_miosio_z, // MIOSIO tristate output enable (active lo) + input wire [FT1248_WIDTH-1:0] ft_miosio_i, // MIOSIO tristate input + + input wire [7:0] ft_clkdiv, // divider prescaler to ensure SCLK <1MHz + + input wire clk, + input wire resetn, + + // Ports of Axi Master Bus Interface TXD - To ADP Controller + output wire txd_tvalid, + output wire [7:0] txd_tdata, + output wire txd_tlast, + input wire txd_tready, + + // Ports of Axi Slave Bus Interface RXD - To + output wire rxd_tready, + input wire [7:0] rxd_tdata, + input wire rxd_tlast, + input wire rxd_tvalid +); + + //---------------------------------------------- + //-- State Machine encoding + //---------------------------------------------- + +// Explicit FSM state bit assignment +// bit [0] SCLK +// bit [1] MIO_OE +// bit [2] CMD/W +// bit [3] DAT/R +// bit [4] SSEL + + localparam FT_0_IDLE = 5'b00000; + localparam FT_1_IDLE = 5'b00001; + localparam FT_ZCMD_CLKLO = 5'b10100; + localparam FT_CMD_CLKHI = 5'b10111; + localparam FT_CMD_CLKLO = 5'b10110; + localparam FT_ZBT_CLKHI = 5'b10001; + localparam FT_ZBT_CLKLO = 5'b10000; + localparam FT_WD_CLKHI = 5'b11111; + localparam FT_WD_CLKLO = 5'b11110; + localparam FT_ZWD_CLKLO = 5'b11100; + localparam FT_RD_CLKHI = 5'b11001; + localparam FT_RD_CLKLO = 5'b11000; + + reg [4:0] ft_state; + // 9- bit shift register to support 8-bit data + 1 sequence control flag + // write data uses bits[7:0], with bit[8] set to flag length for serialized transfers + // read data uses bits[8:1], with bit[0] set to flag continuation for serialized transfers + reg [8:0] ft_reg; + + //---------------------------------------------- + //-- IO PAD control, parameterized on WIDTH param + //---------------------------------------------- + + wire bwid8 = (FT1248_WIDTH==8); + wire bwid4 = (FT1248_WIDTH==4); + wire bwid2 = (FT1248_WIDTH==2); + wire bwid1 = (FT1248_WIDTH==1); + + wire [7:0] ft_rdmasked; + + generate + if (FT1248_WIDTH == 8) begin + assign ft_rdmasked[7:1] = ft_miosio_i[7:1]; + assign ft_miosio_o[7:1] = ft_reg[7:1]; + assign ft_miosio_e[7:1] = {7{ft_state[1]}}; + assign ft_miosio_z[7:1] = ~{7{ft_state[1]}}; + end + endgenerate + + generate + if (FT1248_WIDTH == 4) begin + assign ft_rdmasked[7:1] = {4'b1111, ft_miosio_i[3:1]}; + assign ft_miosio_o[3:1] = ft_reg[3:1]; + assign ft_miosio_e[3:1] = {3{ft_state[1]}}; + assign ft_miosio_z[3:1] = ~{3{ft_state[1]}}; + end + endgenerate + + generate + if (FT1248_WIDTH == 2) begin + assign ft_rdmasked[7:1] = {6'b111111, ft_miosio_i[1]}; + assign ft_miosio_o[1] = ft_reg[1]; + assign ft_miosio_e[1] = ft_state[1]; + assign ft_miosio_z[1] = ~ft_state[1]; + end + endgenerate + + generate + if (FT1248_WIDTH == 1) begin + assign ft_rdmasked[7:1] = 7'b1111111; + end + endgenerate + + assign ft_rdmasked[0] = ft_miosio_i[0]; + assign ft_miosio_o[0] = ft_reg[0]; + assign ft_miosio_e[0] = ft_state[1]; + assign ft_miosio_z[0] = ~ft_state[1]; + + assign ft_clk_o = ft_state[0]; + assign ft_ssn_o = !ft_state[4]; + + // diagnostic decodes + //wire ft_cmd = !ft_state[3] & ft_state[2]; + //wire ft_dwr = ft_state[3] & ft_state[2]; + //wire ft_drd = ft_state[3] & !ft_state[2]; + + + //---------------------------------------------- + //-- Internal clock prescaler + //---------------------------------------------- + + // clock prescaler, ft_clken enables serial IO engine clocking + reg [7:0] ft_clkcnt_r; + reg ft_clken; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_clkcnt_r <= 0; + ft_clken <= 0; + end + else begin + ft_clken <= (ft_clkcnt_r == ft_clkdiv); + ft_clkcnt_r <= (ft_clkcnt_r == ft_clkdiv) ? 0 : (ft_clkcnt_r +1); + end + end + + //---------------------------------------------- + //-- Internal "synchronizers" (dual stage) + //---------------------------------------------- + // synchronizers for channel ready flags when idle + // (treat these signals as synchronous during transfer sequencing) + reg ft_miso_i_sync; + reg ft_miosio_i0_sync; + reg ft_miso_i_sync_1; + reg ft_miosio_i0_sync_1; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_miso_i_sync_1 <= 1; + ft_miosio_i0_sync_1 <= 1; + ft_miso_i_sync <= 1; + ft_miosio_i0_sync <= 1; + end + else begin + ft_miso_i_sync_1 <= ft_miso_i; + ft_miosio_i0_sync_1 <= ft_miosio_i[0]; + ft_miso_i_sync <= ft_miso_i_sync_1; + ft_miosio_i0_sync <= ft_miosio_i0_sync_1; + end + end + + //---------------------------------------------- + //-- AXI Stream interface handshakes + //---------------------------------------------- + + reg ft_txf; // FTDI Transmit channel Full + reg ft_rxe; // FTDO Receive channel Empty + reg ft_wcyc; // read access committed + reg ft_nak; // check for NAK terminate + + // TX stream delivers valid FT1248 read data transfer + // 8-bit write port with extra top-bit used as valid qualifer + reg [8:0] txdata; + assign txd_tdata = txdata[7:0]; + assign txd_tvalid = txdata[8]; + + // activate if RX channel data and the stream buffer is not full + wire ft_rxreq = !ft_rxe & !txdata[8]; + + + // RX stream handshakes on valid FT1248 write data transfer + reg rxdone; + reg rxrdy; + assign rxd_tready = rxdone; + + // activate if TX channel not full and and the stream buffer data valid + wire ft_txreq = !ft_txf & rxd_tvalid; // & !rxdone; // FTDI TX data ready and rxstream ready + + // FTDI1248 commands + wire [3:0] wcmd = 4'b0000; // write request + wire [3:0] rcmd = 4'b0001; // read request + wire [3:0] fcmd = 4'b0100; // write flush request + //wire [3:0] rcmd = 4'b1000; // read request BE bit-pattern + //wire [3:0] fcmd = 4'b0010; // write flush request BE bit-pattern + // and full FT1248 command bit patterns (using top-bits for shift sequencing) + wire [8:0] wcmdpatt = {2'b11, wcmd[0], wcmd[1], 1'b0, wcmd[2], 1'b0, 1'b0, wcmd[3]}; + wire [8:0] rcmdpatt = {2'b11, rcmd[0], rcmd[1], 1'b0, rcmd[2], 1'b0, 1'b0, rcmd[3]}; + + reg ssn_del; + always @(posedge clk or negedge resetn) + if (!resetn) + ssn_del <= 1'b1; + else if (ft_clken) + ssn_del <= ft_ssn_o; + wire ssn_start = ft_ssn_o & ssn_del; + + // FTDI1248 state machine + + always @(posedge clk or negedge resetn) + if (!resetn) begin + ft_state <= FT_0_IDLE; + ft_reg <= 0; + txdata <= 0; + rxdone <= 0; + ft_wcyc <= 0; + ft_txf <= 1; // ftdi channel TXE# ('1' full) + ft_rxe <= 1; // ftdi channel RXF# ('1' empty) + ft_nak <= 0; + end else begin + ft_txf <= (ft_state==FT_0_IDLE) ? (ft_miosio_i[0] | ft_miosio_i0_sync) : 1'b1; //ft_txf & !( ft_wcyc &(ft_state==FT_ZBT_CLKHI) & ft_miso_i); + ft_rxe <= (ft_state==FT_0_IDLE) ? (ft_miso_i | ft_miso_i_sync) : 1'b1; //ft_rxe & !(!ft_wcyc & (ft_state==FT_ZBT_CLKHI) & ft_miso_i); + txdata[8] <= txdata[8] & !txd_tready; // tx_valid handshake + rxdone <= (ft_clken & (ft_state==FT_ZWD_CLKLO) & !ft_nak) | (rxdone & !rxd_tvalid); // hold until acknowledged + if (ft_clken) + case (ft_state) + FT_0_IDLE: begin // RX req priority + if (ssn_start & ft_rxreq) begin ft_reg <= rcmdpatt; ft_state <= FT_ZCMD_CLKLO; end + else if (ssn_start & ft_txreq) begin ft_reg <= wcmdpatt; ft_state <= FT_ZCMD_CLKLO; ft_wcyc <= 1; end + else ft_state <= (!ft_txf | !ft_rxe | (FT1248_CLKON!=0)) ? FT_1_IDLE : FT_0_IDLE; + end + FT_1_IDLE: + ft_state <= FT_0_IDLE; + FT_ZCMD_CLKLO: + ft_state <= FT_CMD_CLKHI; + FT_CMD_CLKHI: + ft_state <= FT_CMD_CLKLO; + FT_CMD_CLKLO: // 2, 4 or 7 shifts + if (bwid8) begin ft_reg <= FT_ZBT_CLKHI; end + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= (|ft_reg[8:5]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + FT_ZBT_CLKHI: + ft_state <= FT_ZBT_CLKLO; + FT_ZBT_CLKLO: + if (ft_wcyc) begin ft_reg <= {1'b1,rxd_tdata}; ft_state <= FT_WD_CLKHI; end + else begin ft_reg <= 9'b011111111; ft_state <= FT_RD_CLKHI; end + FT_WD_CLKHI: + if (ft_miso_i & ft_reg[8]) begin ft_nak <= 1'b1; ft_state <= FT_ZWD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) ft_state <= (ft_reg[8]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; // special case repeat on write data + else if (bwid4) ft_state <= (|ft_reg[8:5]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else if (bwid2) ft_state <= (|ft_reg[8:3]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else ft_state <= (|ft_reg[8:2]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + FT_WD_CLKLO: + if (bwid8) begin ft_reg <= { 1'b0,ft_reg[7:0]}; ft_state <= FT_WD_CLKHI; end // clear top flag + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= FT_WD_CLKHI; end // shift 4 bits right + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= FT_WD_CLKHI; end // shift 2 bits right + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= FT_WD_CLKHI; end // shift 1 bit right + FT_ZWD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end // terminate without TX handshake + else begin ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end + FT_RD_CLKHI: // capture iodata pins end of CLKHI phase + if (ft_miso_i & (&ft_reg[7:0])) begin ft_nak <= 1'b1; ft_state <= FT_RD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) begin ft_reg <= (ft_reg[0]) ? {ft_rdmasked[7:0],1'b1} : {ft_reg[8:1],1'b0}; ft_state <= FT_RD_CLKLO; end // 8-bit read twice + else if (bwid4) begin ft_reg <= {ft_rdmasked[3:0],ft_reg[8:4]}; ft_state <= FT_RD_CLKLO; end + else if (bwid2) begin ft_reg <= {ft_rdmasked[1:0],ft_reg[8:2]}; ft_state <= FT_RD_CLKLO; end + else begin ft_reg <= {ft_rdmasked[ 0],ft_reg[8:1]}; ft_state <= FT_RD_CLKLO; end + FT_RD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; txdata <= 9'b0; end // terminate without TX handshake + else if (ft_reg[0]) begin ft_state <= FT_RD_CLKHI; ft_reg[0] <= !(bwid8); end // loop until all 8 bits shifted in (or 8-bit read repeated) + else begin ft_state <= FT_0_IDLE; txdata <= {1'b1,ft_reg[8:1]}; end + default: + ft_state <= FT_0_IDLE; + endcase + end + +endmodule diff --git a/socket/verilog/axi_stream_io_v1_0.v b/socket/verilog/axi_stream_io_v1_0.v new file mode 100755 index 0000000000000000000000000000000000000000..0c52be8420c4f63ab7eab0db84cc185a5073bcc6 --- /dev/null +++ b/socket/verilog/axi_stream_io_v1_0.v @@ -0,0 +1,114 @@ + +`timescale 1 ns / 1 ps + + module axi_stream_io_v1_0 # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + + // Parameters of Axi Slave Bus Interface axi + parameter integer C_axi_DATA_WIDTH = 32, + parameter integer C_axi_ADDR_WIDTH = 4, + + // Parameters of Axi Master Bus Interface tx + parameter integer C_tx_TDATA_WIDTH = 8, + parameter integer C_tx_START_COUNT = 3, + + // Parameters of Axi Slave Bus Interface rx + parameter integer C_rx_TDATA_WIDTH = 8 + ) + ( + // Users to add ports here + + // User ports ends + // Do not modify the ports beyond this line + + + // Ports of Axi Slave Bus Interface axi + input wire axi_aclk, + input wire axi_aresetn, + input wire [C_axi_ADDR_WIDTH-1 : 0] axi_awaddr, + input wire [2 : 0] axi_awprot, + input wire axi_awvalid, + output wire axi_awready, + input wire [C_axi_DATA_WIDTH-1 : 0] axi_wdata, + input wire [(C_axi_DATA_WIDTH/8)-1 : 0] axi_wstrb, + input wire axi_wvalid, + output wire axi_wready, + output wire [1 : 0] axi_bresp, + output wire axi_bvalid, + input wire axi_bready, + input wire [C_axi_ADDR_WIDTH-1 : 0] axi_araddr, + input wire [2 : 0] axi_arprot, + input wire axi_arvalid, + output wire axi_arready, + output wire [C_axi_DATA_WIDTH-1 : 0] axi_rdata, + output wire [1 : 0] axi_rresp, + output wire axi_rvalid, + input wire axi_rready, + + output wire interrupt, + // Ports of Axi Master Bus Interface tx + output wire tx_tvalid, + output wire [C_tx_TDATA_WIDTH-1 : 0] tx_tdata, + output wire [(C_tx_TDATA_WIDTH/8)-1 : 0] tx_tstrb, + output wire tx_tlast, + input wire tx_tready, + + // Ports of Axi Slave Bus Interface rx + output wire rx_tready, + input wire [C_rx_TDATA_WIDTH-1 : 0] rx_tdata, + input wire [(C_rx_TDATA_WIDTH/8)-1 : 0] rx_tstrb, + input wire rx_tlast, + input wire rx_tvalid + ); +// Instantiation of Axi Bus Interface axi + iostream_v1_0_axi # ( + .C_S_AXI_DATA_WIDTH(C_axi_DATA_WIDTH), + .C_S_AXI_ADDR_WIDTH(C_axi_ADDR_WIDTH) + ) iostream_v1_0_axi_inst ( + .S_AXI_ACLK(axi_aclk), + .S_AXI_ARESETN(axi_aresetn), + .tx_tvalid(tx_tvalid), + .tx_tdata(tx_tdata), +// output wire [0 : 0] tx_tstrb, +// output wire tx_tlast, + .tx_tready(tx_tready), + .rx_tvalid(rx_tvalid), + .rx_tdata(rx_tdata), +// input wire [0 : 0] tx_tstrb, +// input wire tx_tlast, + .tx_tready(rx_tready), + .interrupt(interrupt), + .S_AXI_AWADDR(axi_awaddr), + .S_AXI_AWPROT(axi_awprot), + .S_AXI_AWVALID(axi_awvalid), + .S_AXI_AWREADY(axi_awready), + .S_AXI_WDATA(axi_wdata), + .S_AXI_WSTRB(axi_wstrb), + .S_AXI_WVALID(axi_wvalid), + .S_AXI_WREADY(axi_wready), + .S_AXI_BRESP(axi_bresp), + .S_AXI_BVALID(axi_bvalid), + .S_AXI_BREADY(axi_bready), + .S_AXI_ARADDR(axi_araddr), + .S_AXI_ARPROT(axi_arprot), + .S_AXI_ARVALID(axi_arvalid), + .S_AXI_ARREADY(axi_arready), + .S_AXI_RDATA(axi_rdata), + .S_AXI_RRESP(axi_rresp), + .S_AXI_RVALID(axi_rvalid), + .S_AXI_RREADY(axi_rready) + ); + +assign tx_tstrb[0:0] = tx_tvalid; +assign tx_tlast = 1'b0; + + // Add user logic here + + // User logic ends + + endmodule diff --git a/socket/verilog/axi_stream_io_v1_0_axi_s.v b/socket/verilog/axi_stream_io_v1_0_axi_s.v new file mode 100755 index 0000000000000000000000000000000000000000..303780efefce184c1f353751c71280794b5348bd --- /dev/null +++ b/socket/verilog/axi_stream_io_v1_0_axi_s.v @@ -0,0 +1,424 @@ + +`timescale 1 ns / 1 ps + + module axi_stream_io_v1_0_axi_s # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + // Width of S_AXI data bus + parameter integer C_S_AXI_DATA_WIDTH = 32, + // Width of S_AXI address bus + parameter integer C_S_AXI_ADDR_WIDTH = 4 + ) + ( + // Users to add ports here + output wire interrupt, + + // Ports of Axi Master Bus Interface tx +// input wire tx_aclk, +// input wire tx_aresetn, + output wire tx_tvalid, + output wire [7 : 0] tx_tdata, +// output wire [0 : 0] tx_tstrb, +// output wire tx_tlast, + input wire tx_tready, + + // Ports of Axi Slave Bus Interface rx +// input wire rx_aclk, +// input wire rx_aresetn, + output wire rx_tready, + input wire [7 : 0] rx_tdata, +// input wire [0 : 0] rx_tstrb, +// input wire rx_tlast, + input wire rx_tvalid, + + // User ports ends + // Do not modify the ports beyond this line + + // Global Clock Signal + input wire S_AXI_ACLK, + // Global Reset Signal. This Signal is Active LOW + input wire S_AXI_ARESETN, + // Write address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + // Write channel Protection type. This signal indicates the + // privilege and security level of the transaction, and whether + // the transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_AWPROT, + // Write address valid. This signal indicates that the master signaling + // valid write address and control information. + input wire S_AXI_AWVALID, + // Write address ready. This signal indicates that the slave is ready + // to accept an address and associated control signals. + output wire S_AXI_AWREADY, + // Write data (issued by master, acceped by Slave) + input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + // Write strobes. This signal indicates which byte lanes hold + // valid data. There is one write strobe bit for each eight + // bits of the write data bus. + input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, + // Write valid. This signal indicates that valid write + // data and strobes are available. + input wire S_AXI_WVALID, + // Write ready. This signal indicates that the slave + // can accept the write data. + output wire S_AXI_WREADY, + // Write response. This signal indicates the status + // of the write transaction. + output wire [1 : 0] S_AXI_BRESP, + // Write response valid. This signal indicates that the channel + // is signaling a valid write response. + output wire S_AXI_BVALID, + // Response ready. This signal indicates that the master + // can accept a write response. + input wire S_AXI_BREADY, + // Read address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + // Protection type. This signal indicates the privilege + // and security level of the transaction, and whether the + // transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_ARPROT, + // Read address valid. This signal indicates that the channel + // is signaling valid read address and control information. + input wire S_AXI_ARVALID, + // Read address ready. This signal indicates that the slave is + // ready to accept an address and associated control signals. + output wire S_AXI_ARREADY, + // Read data (issued by slave) + output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + // Read response. This signal indicates the status of the + // read transfer. + output wire [1 : 0] S_AXI_RRESP, + // Read valid. This signal indicates that the channel is + // signaling the required read data. + output wire S_AXI_RVALID, + // Read ready. This signal indicates that the master can + // accept the read data and response information. + input wire S_AXI_RREADY + ); + + // AXI4LITE signals + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; + reg axi_awready; + reg axi_wready; + reg [1 : 0] axi_bresp; + reg axi_bvalid; + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; + reg axi_arready; + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; + reg [1 : 0] axi_rresp; + reg axi_rvalid; + + // Example-specific design signals + // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH + // ADDR_LSB is used for addressing 32/64 bit registers/memories + // ADDR_LSB = 2 for 32 bits (n downto 2) + // ADDR_LSB = 3 for 64 bits (n downto 3) + localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; + localparam integer OPT_MEM_ADDR_BITS = 1; + + //---------------------------------------------- + //-- Signals for user logic register space example + //------------------------------------------------ + //-- Number of Slave Registers 4 + reg [8:0] tx_reg; // TX data + reg [8:0] rx_reg; // RX data + reg [7:0] ctrl_reg; // ctrl + wire slv_reg_rden; + wire slv_reg_wren; + reg [7:0] reg_data_out; + integer byte_index; + reg aw_en; + + wire tx_req = tx_reg[8]; // request to transmit + wire tx_ack = tx_tready; // acknowledge when stream ready + wire tx_rdy = !tx_reg[8]; + wire rx_req = rx_tvalid; // request to receive + wire rx_ack = !rx_reg[8]; + wire rx_rdy = rx_reg[8]; + + //assign rx_reg[7:0] <= rx_tdata; + + // I/O Connections assignments + + assign interrupt = ctrl_reg[4] & (!tx_req | rx_req); + + // TX stream interface + assign tx_tdata = tx_reg[7:0]; + assign tx_tvalid = tx_req; + + // RX stream interface + assign rx_tready = rx_ack; + + //AXI Slave + assign S_AXI_AWREADY = axi_awready; + assign S_AXI_WREADY = axi_wready; + assign S_AXI_BRESP = axi_bresp; + assign S_AXI_BVALID = axi_bvalid; + assign S_AXI_ARREADY = axi_arready; + assign S_AXI_RDATA = axi_rdata; + assign S_AXI_RRESP = axi_rresp; + assign S_AXI_RVALID = axi_rvalid; + // Implement axi_awready generation + // axi_awready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awready <= 1'b0; + aw_en <= 1'b1; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // slave is ready to accept write address when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_awready <= 1'b1; + aw_en <= 1'b0; + end + else if (S_AXI_BREADY && axi_bvalid) + begin + aw_en <= 1'b1; + axi_awready <= 1'b0; + end + else + begin + axi_awready <= 1'b0; + end + end + end + + // Implement axi_awaddr latching + // This process is used to latch the address when both + // S_AXI_AWVALID and S_AXI_WVALID are valid. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awaddr <= 0; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // Write Address latching + axi_awaddr <= S_AXI_AWADDR; + end + end + end + + // Implement axi_wready generation + // axi_wready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_wready <= 1'b0; + end + else + begin + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en ) + begin + // slave is ready to accept write data when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_wready <= 1'b1; + end + else + begin + axi_wready <= 1'b0; + end + end + end + + // Implement memory mapped register select and write logic generation + // The write data is accepted and written to memory mapped registers when + // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to + // select byte enables of slave registers while writing. + // These registers are cleared when reset (active low) is applied. + // Slave register write enable is asserted when valid address and data are available + // and the slave is ready to accept the write address and write data. + assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + rx_reg <= 0; + else if ((ctrl_reg[1] == 1'b1)) + rx_reg <= 0; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h0)) + rx_reg[8:0] <= {1'b1, S_AXI_WDATA[7:0]}; + else if (slv_reg_rden && (axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h0)) + rx_reg[8] <= 1'b0; + else if (rx_req & rx_ack) // check precedence (rx_req) + rx_reg[8:0] <= {1'b1, rx_tdata[7:0]}; + end + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + tx_reg <= 0; + else if ((ctrl_reg[0] == 1'b1)) + tx_reg <= 0; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h1)) + tx_reg[8:0] <= {1'b1, S_AXI_WDATA[7:0]}; + else if (tx_req & tx_ack) + tx_reg[8] <= 1'b0; + end + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + ctrl_reg <= 8'b00000100; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h3)) + ctrl_reg[7:0] <= S_AXI_WDATA[7:0]; + end + + // Implement write response logic generation + // The write response and response valid signals are asserted by the slave + // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. + // This marks the acceptance of address and indicates the status of + // write transaction. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_bvalid <= 0; + axi_bresp <= 2'b0; + end + else + begin + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) + begin + // indicates a valid write response is available + axi_bvalid <= 1'b1; + axi_bresp <= 2'b0; // 'OKAY' response + end // work error responses in future + else + begin + if (S_AXI_BREADY && axi_bvalid) + //check if bready is asserted while bvalid is high) + //(there is a possibility that bready is always asserted high) + begin + axi_bvalid <= 1'b0; + end + end + end + end + + // Implement axi_arready generation + // axi_arready is asserted for one S_AXI_ACLK clock cycle when + // S_AXI_ARVALID is asserted. axi_awready is + // de-asserted when reset (active low) is asserted. + // The read address is also latched when S_AXI_ARVALID is + // asserted. axi_araddr is reset to zero on reset assertion. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_arready <= 1'b0; + axi_araddr <= 32'b0; + end + else + begin + if (~axi_arready && S_AXI_ARVALID) + begin + // indicates that the slave has acceped the valid read address + axi_arready <= 1'b1; + // Read address latching + axi_araddr <= S_AXI_ARADDR; + end + else + begin + axi_arready <= 1'b0; + end + end + end + + // Implement axi_arvalid generation + // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_ARVALID and axi_arready are asserted. The slave registers + // data are available on the axi_rdata bus at this instance. The + // assertion of axi_rvalid marks the validity of read data on the + // bus and axi_rresp indicates the status of read transaction.axi_rvalid + // is deasserted on reset (active low). axi_rresp and axi_rdata are + // cleared to zero on reset (active low). + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rvalid <= 0; + axi_rresp <= 0; + end + else + begin + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) + begin + // Valid read data is available at the read data bus + axi_rvalid <= 1'b1; + axi_rresp <= 2'b0; // 'OKAY' response + end + else if (axi_rvalid && S_AXI_RREADY) + begin + // Read data is accepted by the master + axi_rvalid <= 1'b0; + end + end + end + + // Implement memory mapped register select and read logic generation + // Slave register read enable is asserted when valid address is available + // and the slave is ready to accept the read address. + assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; + always @(*) + begin + // Address decoding for reading registers + case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 2'h0 : reg_data_out <= rx_reg[7:0]; + 2'h1 : reg_data_out <= tx_reg[7:0]; + 2'h2 : reg_data_out <= {3'b000, ctrl_reg[4], !tx_rdy, tx_rdy, rx_rdy, rx_rdy}; + 2'h3 : reg_data_out <= ctrl_reg; + default : reg_data_out <= 0; + endcase + end + + // Output register or memory read data + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rdata <= 0; + end + else + begin + // When there is a valid read address (S_AXI_ARVALID) with + // acceptance of read address by the slave (axi_arready), + // output the read dada + if (slv_reg_rden) + begin + axi_rdata <= {24'h000000, reg_data_out}; // register read data + end + end + end + + // Add user logic here + + // User logic ends + + endmodule diff --git a/socket/verilog/ft232h_ft1248_x1.v b/socket/verilog/ft232h_ft1248_x1.v new file mode 100644 index 0000000000000000000000000000000000000000..e125ea3a0ca03bce2fccdd816606fb5c2017438c --- /dev/null +++ b/socket/verilog/ft232h_ft1248_x1.v @@ -0,0 +1,157 @@ +//----------------------------------------------------------------------------- +// NanoSoC FT1248 ADP UART file logging +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright � 2022, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Abstract : FT1248 1-bit data off-chip interface (emulate FT232H device) +// and allows cmsdk_uart_capture testbench models to log ADP ip, op streams +//----------------------------------------------------------------------------- + + +module ft232h_ft1248_x1 #( + parameter ADPFILENAME = "adp.cmd", + parameter VERBOSE = 0 +)( + input wire ft_clk_i, // SCLK + input wire ft_ssn_i, // SS_N + output wire ft_miso_o, // MISO + inout wire ft_miosio_io, // MIOSIO tristate output when enabled + + output wire FTDI_CLK2UART_o, // Clock (baud rate) + output wire FTDI_OP2UART_o, // Received data to UART capture + output wire FTDI_IP2UART_o // Transmitted data to UART capture +); + + + //---------------------------------------------- + //-- File I/O + //---------------------------------------------- + + + integer fdcmd; // channel descriptor for cmd file input + integer ch; +`define EOF -1 + + reg ft_rxreq; + wire ft_rxack; + reg [7:0] ft_adpbyte; + + initial + begin + ft_rxreq <= 0; + $timeformat(-9, 0, " ns", 14); + fdcmd= $fopen(ADPFILENAME,"r"); + if (fdcmd == 0) + $write("** FT1248x1 : no command file **\n"); + else begin + ch = $fgetc(fdcmd); + while (ch != `EOF) begin + ft_adpbyte <= (ch & 8'hff); + ft_rxreq <= 1'b1; + while (ft_ssn_i == 1'b0) + @(posedge ft_ssn_i); + @(posedge ft_rxack); + ft_rxreq <=0; + @(negedge ft_rxack); + ch = $fgetc(fdcmd); + end + end + $fclose(fdcmd); + ft_rxreq <= 0; + end + + +//---------------------------------------------- +//-- State Machine +//---------------------------------------------- + +wire ft_miosio_i; +wire ft_miosio_o; +wire ft_miosio_z; + +// tri-state pad control for MIOSIO +assign ft_miosio_io = (ft_miosio_z) ? 1'bz : ft_miosio_o; +// add notinal delay on inout to ensure last "half-bit" on FT1248TXD is sampled before tri-stated +assign #1 ft_miosio_i = ft_miosio_io; + +reg [4:0] ft_state; // 17-state for bit-serial +wire [5:0] ft_nextstate = ft_state + 5'b00001; + +always @(posedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_state <= 5'b11111; + else // loop if multi-data +// ft_state <= (ft_state == 5'b01111) ? 5'b01000 : ft_nextstate; + ft_state <= ft_nextstate; + +// 16: bus turnaround (or bit[5]) +// 0 for CMD3 +// 3 for CMD2 +// 5 for CMD1 +// 6 for CMD0 +// 7 for cmd turnaround +// 8 for data bit0 +// 9 for data bit1 +// 10 for data bit2 +// 11 for data bit3 +// 12 for data bit4 +// 13 for data bit5 +// 14 for data bit6 +// 15 for data bit7 + +// ft_miso_o reflects RXE when deselected +assign ft_miso_o = (ft_ssn_i) ? !ft_rxreq : (ft_state == 5'b00111); + +// capture CMD on falling edge of clock (mid-data) +// - valid sample ready after 7th edge (ready RX or TX data phase functionality) +reg [7:0] ft_cmd; +always @(negedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_cmd <= 8'b00000001; + else // shift in data + ft_cmd <= (!ft_state[3] & !ft_nextstate[3]) ? {ft_cmd[6:0],ft_miosio_i} : ft_cmd; + +wire ft_cmd_valid = ft_cmd[7]; +wire ft_cmd_rxd = ft_cmd[7] & !ft_cmd[6] & !ft_cmd[3] & !ft_cmd[1] & ft_cmd[0]; +wire ft_cmd_txd = ft_cmd[7] & !ft_cmd[6] & !ft_cmd[3] & !ft_cmd[1] & !ft_cmd[0]; + +// tristate enable for miosio (deselected status or serialized data for read command) +wire ft_miosio_e = ft_ssn_i | (ft_cmd_rxd & !ft_state[4] & ft_state[3]); +assign ft_miosio_z = !ft_miosio_e; + +// serial data formatted with start bit for UART capture (on rising uart-clock) +assign FTDI_CLK2UART_o = !ft_clk_i; +// suitable for CMSDK UART capture IO +// inject a start bit low else mark high +assign FTDI_OP2UART_o = (ft_cmd_txd & (ft_state[4:3]) == 2'b01) ? ft_miosio_i : !(ft_cmd_txd & (ft_state == 5'b00111)); +assign FTDI_IP2UART_o = (ft_cmd_rxd & (ft_state[4:3]) == 2'b01) ? ft_miosio_io : !(ft_cmd_rxd & (ft_state == 5'b00111)); + +// capture RXD on falling edge of clock +reg [8:0] ft_rxd; +always @(negedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_rxd <= 9'b111111111; + else if (ft_cmd_txd & !(ft_miosio_i & (&ft_rxd[8:0]))) //only on valid start-bit + ft_rxd <= {ft_miosio_i, ft_rxd[8:1]}; + +// shift TXD on rising edge of clock +reg [8:0] ft_txd; +always @(posedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_txd <= {1'b1,ft_adpbyte}; + else if (ft_rxreq & ft_cmd_rxd & (ft_state[4:3] == 2'b01)) //valid TX shift + ft_txd <= {1'b0,ft_txd[8:1]}; + +assign ft_rxack = (ft_cmd_rxd & (ft_state==5'b01111)); + +// ft_miso_o reflects TXF when deselected (never full for simulation output) +assign ft_miosio_o = (ft_ssn_i) ? 1'b0 : ft_txd[0]; + +endmodule