Skip to content
Snippets Groups Projects
Select Git revision
  • db793c4587f94028b4fcaaafb42b9f654784ce22
  • master default
2 results

README.md

Blame
  • To learn more about this project, read the wiki.
    ADPmanager.v 35.84 KiB
    //-----------------------------------------------------------------------------
    // soclabs 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
    `begin_keywords "1364-2001"
    
    module ADPmanager // AHB initiator interface
       #(parameter PROMPT_CHAR          = "]"
        )
                ( 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     COM_RXE_i,
        input  wire [ 7:0] COMRX_TDATA_i,
        input  wire        COMRX_TVALID_i,
        output wire        COMRX_TREADY_o,
    //    input  wire     COM_TXF_i,
        output wire [ 7:0] COMTX_TDATA_o,
        output wire        COMTX_TVALID_o,
        input  wire        COMTX_TREADY_i,
    // STDIO interface
    //    input  wire     STDOUT_RXE_i,
        input  wire [ 7:0] STDRX_TDATA_i,
        input  wire        STDRX_TVALID_i,
        output wire        STDRX_TREADY_o,
    //    input  wire     STDIN_TXF_i
        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'h50c1ab03;
    `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 [63:0] FNBuild_param64_hexdigit;
    input [63:0] param64;
    input [7:0] char8;
    case (char8[7:0])
    "\t":FNBuild_param64_hexdigit = 64'b0; // tab starts new (zeroed) param64
    " ": FNBuild_param64_hexdigit = 64'b0; // space starts new (zeroed) param64
    "x": FNBuild_param64_hexdigit = 64'b0; // hex prefix starts new (zeroed) param64
    "X": FNBuild_param64_hexdigit = 64'b0; // hex prefix starts new (zeroed) param64
    "0": FNBuild_param64_hexdigit = {param64[59:0],4'b0000};
    "1": FNBuild_param64_hexdigit = {param64[59:0],4'b0001};
    "2": FNBuild_param64_hexdigit = {param64[59:0],4'b0010};
    "3": FNBuild_param64_hexdigit = {param64[59:0],4'b0011};
    "4": FNBuild_param64_hexdigit = {param64[59:0],4'b0100};
    "5": FNBuild_param64_hexdigit = {param64[59:0],4'b0101};
    "6": FNBuild_param64_hexdigit = {param64[59:0],4'b0110};
    "7": FNBuild_param64_hexdigit = {param64[59:0],4'b0111};
    "8": FNBuild_param64_hexdigit = {param64[59:0],4'b1000};
    "9": FNBuild_param64_hexdigit = {param64[59:0],4'b1001};
    "A": FNBuild_param64_hexdigit = {param64[59:0],4'b1010};
    "B": FNBuild_param64_hexdigit = {param64[59:0],4'b1011};
    "C": FNBuild_param64_hexdigit = {param64[59:0],4'b1100};
    "D": FNBuild_param64_hexdigit = {param64[59:0],4'b1101};
    "E": FNBuild_param64_hexdigit = {param64[59:0],4'b1110};
    "F": FNBuild_param64_hexdigit = {param64[59:0],4'b1111};
    "a": FNBuild_param64_hexdigit = {param64[59:0],4'b1010};
    "b": FNBuild_param64_hexdigit = {param64[59:0],4'b1011};
    "c": FNBuild_param64_hexdigit = {param64[59:0],4'b1100};
    "d": FNBuild_param64_hexdigit = {param64[59:0],4'b1101};
    "e": FNBuild_param64_hexdigit = {param64[59:0],4'b1110};
    "f": FNBuild_param64_hexdigit = {param64[59:0],4'b1111};
    default: FNBuild_param64_hexdigit = param64; // EOL etc returns param64 unchanged
    endcase
    endfunction
    
    function [63:0] FNBuild_param64_byte;
    input [63:0] param64;
    input [7:0] byte;
      FNBuild_param64_byte = {byte[7:0], param64[63:08]};
    endfunction
    
    function [31:0] FNBuild_param32_hexdigit;
    input [31:0] param32;
    input [7:0] char8;
    case (char8[7:0])
    "\t":FNBuild_param32_hexdigit = 32'b0; // tab starts new (zeroed) param32
    " ": FNBuild_param32_hexdigit = 32'b0; // space starts new (zeroed) param32
    "x": FNBuild_param32_hexdigit = 32'b0; // hex prefix starts new (zeroed) param32
    "X": FNBuild_param32_hexdigit = 32'b0; // hex prefix starts new (zeroed) param32
    "0": FNBuild_param32_hexdigit = {param32[27:0],4'b0000};
    "1": FNBuild_param32_hexdigit = {param32[27:0],4'b0001};
    "2": FNBuild_param32_hexdigit = {param32[27:0],4'b0010};
    "3": FNBuild_param32_hexdigit = {param32[27:0],4'b0011};
    "4": FNBuild_param32_hexdigit = {param32[27:0],4'b0100};
    "5": FNBuild_param32_hexdigit = {param32[27:0],4'b0101};
    "6": FNBuild_param32_hexdigit = {param32[27:0],4'b0110};
    "7": FNBuild_param32_hexdigit = {param32[27:0],4'b0111};
    "8": FNBuild_param32_hexdigit = {param32[27:0],4'b1000};
    "9": FNBuild_param32_hexdigit = {param32[27:0],4'b1001};
    "A": FNBuild_param32_hexdigit = {param32[27:0],4'b1010};
    "B": FNBuild_param32_hexdigit = {param32[27:0],4'b1011};
    "C": FNBuild_param32_hexdigit = {param32[27:0],4'b1100};
    "D": FNBuild_param32_hexdigit = {param32[27:0],4'b1101};
    "E": FNBuild_param32_hexdigit = {param32[27:0],4'b1110};
    "F": FNBuild_param32_hexdigit = {param32[27:0],4'b1111};
    "a": FNBuild_param32_hexdigit = {param32[27:0],4'b1010};
    "b": FNBuild_param32_hexdigit = {param32[27:0],4'b1011};
    "c": FNBuild_param32_hexdigit = {param32[27:0],4'b1100};
    "d": FNBuild_param32_hexdigit = {param32[27:0],4'b1101};
    "e": FNBuild_param32_hexdigit = {param32[27:0],4'b1110};
    "f": FNBuild_param32_hexdigit = {param32[27:0],4'b1111};
    default: FNBuild_param32_hexdigit = param32; // EOL etc returns param32 unchanged
    endcase
    endfunction
    
    function [31:0] FNBuild_param32_byte;
    input [31:0] param32;
    input [7:0] byte;
      FNBuild_param32_byte = {byte[7:0], param32[31:08]};
    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_UREADB0 = 6'b100011 ;
    localparam    ADP_UREADB1 = 6'b100100 ;
    localparam    ADP_UREADB2 = 6'b100101 ;
    localparam    ADP_UREADB3 = 6'b100110 ;
    localparam     ADP_UWRITE = 6'b100111 ;
    localparam       ADP_POLL = 6'b101000 ;
    localparam      ADP_POLL1 = 6'b101001 ;
    localparam      ADP_POLL2 = 6'b101010 ;
    localparam      ADP_FCTRL = 6'b101011 ;
    localparam     ADP_FWRITE = 6'b101100 ;
    localparam    ADP_ECHOCMD = 6'b101101 ;
    localparam    ADP_ECHOBUS = 6'b101110 ;
    localparam    ADP_UNKNOWN = 6'b101111 ;
    reg  [5:0] adp_state   ;
    `else
    // one-hot encoded explicitly
    localparam   ADP_WRITEHEX = 48'b000000000000000000000000000000000000000000000001 ; // = 6'b000000
    localparam  ADP_WRITEHEXS = 48'b000000000000000000000000000000000000000000000010 ; // = 6'b000001
    localparam  ADP_WRITEHEX9 = 48'b000000000000000000000000000000000000000000000100 ; // = 6'b000010
    localparam  ADP_WRITEHEX8 = 48'b000000000000000000000000000000000000000000001000 ; // = 6'b000011
    localparam  ADP_WRITEHEX7 = 48'b000000000000000000000000000000000000000000010000 ; // = 6'b000100
    localparam  ADP_WRITEHEX6 = 48'b000000000000000000000000000000000000000000100000 ; // = 6'b000101
    localparam  ADP_WRITEHEX5 = 48'b000000000000000000000000000000000000000001000000 ; // = 6'b000110
    localparam  ADP_WRITEHEX4 = 48'b000000000000000000000000000000000000000010000000 ; // = 6'b000111
    localparam  ADP_WRITEHEX3 = 48'b000000000000000000000000000000000000000100000000 ; // = 6'b001000
    localparam  ADP_WRITEHEX2 = 48'b000000000000000000000000000000000000001000000000 ; // = 6'b001001
    localparam  ADP_WRITEHEX1 = 48'b000000000000000000000000000000000000010000000000 ; // = 6'b001010
    localparam  ADP_WRITEHEX0 = 48'b000000000000000000000000000000000000100000000000 ; // = 6'b001011
    localparam    ADP_LINEACK = 48'b000000000000000000000000000000000001000000000000 ; // = 6'b001100
    localparam   ADP_LINEACK2 = 48'b000000000000000000000000000000000010000000000000 ; // = 6'b001101
    localparam     ADP_PROMPT = 48'b000000000000000000000000000000000100000000000000 ; // = 6'b001110
    localparam      ADP_IOCHK = 48'b000000000000000000000000000000001000000000000000 ; // = 6'b001111
    localparam     ADP_STDOUT = 48'b000000000000000000000000000000010000000000000000 ; // = 6'b010000
    localparam    ADP_STDOUT1 = 48'b000000000000000000000000000000100000000000000000 ; // = 6'b010001
    localparam    ADP_STDOUT2 = 48'b000000000000000000000000000001000000000000000000 ; // = 6'b010010
    localparam    ADP_STDOUT3 = 48'b000000000000000000000000000010000000000000000000 ; // = 6'b010011
    localparam      ADP_RXCMD = 48'b000000000000000000000000000100000000000000000000 ; // = 6'b010100
    localparam    ADP_RXPARAM = 48'b000000000000000000000000001000000000000000000000 ; // = 6'b010101
    localparam     ADP_ACTION = 48'b000000000000000000000000010000000000000000000000 ; // = 6'b010110
    localparam     ADP_SYSCTL = 48'b000000000000000000000000100000000000000000000000 ; // = 6'b010111
    localparam       ADP_READ = 48'b000000000000000000000001000000000000000000000000 ; // = 6'b011000
    localparam     ADP_SYSCHK = 48'b000000000000000000000010000000000000000000000000 ; // = 6'b011001
    localparam      ADP_STDIN = 48'b000000000000000000000100000000000000000000000000 ; // = 6'b011010
    localparam      ADP_WRITE = 48'b000000000000000000001000000000000000000000000000 ; // = 6'b011011
    localparam       ADP_EXIT = 48'b000000000000000000010000000000000000000000000000 ; // = 6'b011100
    localparam      STD_IOCHK = 48'b000000000000000000100000000000000000000000000000 ; // = 6'b011101
    localparam       STD_RXD1 = 48'b000000000000000001000000000000000000000000000000 ; // = 6'b011110
    localparam       STD_RXD2 = 48'b000000000000000010000000000000000000000000000000 ; // = 6'b011111
    localparam       STD_TXD1 = 48'b000000000000000100000000000000000000000000000000 ; // = 6'b100000
    localparam       STD_TXD2 = 48'b000000000000001000000000000000000000000000000000 ; // = 6'b100001
    localparam      ADP_UCTRL = 48'b000000000000010000000000000000000000000000000000 ; // = 6'b100010
    localparam    ADP_UREADB0 = 48'b000000000000100000000000000000000000000000000000 ; // = 6'b100011
    localparam    ADP_UREADB1 = 48'b000000000001000000000000000000000000000000000000 ; // = 6'b100100
    localparam    ADP_UREADB2 = 48'b000000000010000000000000000000000000000000000000 ; // = 6'b100101
    localparam    ADP_UREADB3 = 48'b000000000100000000000000000000000000000000000000 ; // = 6'b100110
    localparam     ADP_UWRITE = 48'b000000001000000000000000000000000000000000000000 ; // = 6'b100111
    localparam       ADP_POLL = 48'b000000010000000000000000000000000000000000000000 ; // = 6'b101000
    localparam      ADP_POLL1 = 48'b000000100000000000000000000000000000000000000000 ; // = 6'b101001
    localparam      ADP_POLL2 = 48'b000001000000000000000000000000000000000000000000 ; // = 6'b101010
    localparam      ADP_FCTRL = 48'b000010000000000000000000000000000000000000000000 ; // = 6'b101011
    localparam     ADP_FWRITE = 48'b000100000000000000000000000000000000000000000000 ; // = 6'b101100
    localparam    ADP_ECHOCMD = 48'b001000000000000000000000000000000000000000000000 ; // = 6'b101101
    localparam    ADP_ECHOBUS = 48'b010000000000000000000000000000000000000000000000 ; // = 6'b101110
    localparam    ADP_UNKNOWN = 48'b100000000000000000000000000000000000000000000000 ; // = 6'b101111
    reg [47: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 [32:0] adp_param   ;
    reg [31:0] adp_addr    ;
    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);
    
    assign HADDR32_o     =  adp_addr;
    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, 2'b10};
    assign HTRANS2_o     = {ahb_aphase,1'b0}; // non-seq
    assign HWDATA32_o    =  adp_bus_data;
    assign HWRITE_o      =  adp_bus_write;
    
    
    `ifndef ADPBASIC
    reg  [31: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] byte;
      begin com_tx_req<= 1; com_tx_byte <= byte; 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_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 + 4 : 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_ACTION; end // no command, skip param
               else begin adp_cmd <= com_rx_byte; adp_param <= 33'h1_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; end // parameter complete on EOL
    `else
                begin adp_state <= ADP_ACTION; end // parameter complete on EOL
    `endif
               else
                 begin adp_param <= {1'b0,FNBuild_param32_hexdigit(adp_param[31: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[32] == 1'b1) adp_param <= {1'b0, adp_addr}; else adp_addr <= adp_param[31:0];
                 adp_state <= ADP_ECHOCMD; end
             else if (FNvalid_cmd(adp_cmd) == CMD_C) begin
               if (adp_param[32]) // 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_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_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[32] == 1'b1) adp_param <= {1'b0,adp_mask}; else adp_mask <= adp_param[31:0];
                 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[32] == 1'b1) adp_param <= {1'b0,adp_val}; else adp_val <= adp_param[31:0];
                 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 <= 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_state <= ADP_UREADB0; end  // read next 4 bytes
           ADP_UREADB0: // read raw binary byte 0
             if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[ 7: 0] <= com_rx_byte; adp_state <= ADP_UREADB1; end
             else com_rx_ack <= 1;  // extend stream request if not ready
           ADP_UREADB1: // read raw binary byte 1
             if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[15: 8] <= com_rx_byte; adp_state <= ADP_UREADB2; end
             else com_rx_ack <= 1;  // extend stream request if not ready
           ADP_UREADB2: // read raw binary byte 2
             if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[23:16] <= com_rx_byte; adp_state <= ADP_UREADB3; end
             else com_rx_ack <= 1;  // extend stream request if not ready
           ADP_UREADB3: // read raw binary byte 3
             if (com_rx_done)
               begin adp_bus_data[31:24] <= 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_UREADB0; 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) == 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_bus_data <= adp_val; 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) begin adp_state <= ADP_WRITEHEX8; 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
    
    `end_keywords
    
    ////AHBLITE_ADPMASTER instancing
    //ADPmaster
    //   #(.PROMPT_CHAR     ("]"))
    // ADPmaster(
    //  .HCLK        (ahb_hclk      ),
    //  .HRESETn     (ahb_hrestn    ),
    //  .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     ),
    
    //  .COMRX_TREADY_o(com_rx_tready),
    //  .COMRX_TDATA_i(com_rx_tdata),
    //  .COMRX_TVALID_i(com_rx_tvalid),
    //  .STDRX_TREADY_o(std_rx_tready),
    //  .STDRX_TDATA_i(std_rx_tdata),
    //  .STDRX_TVALID_i(std_rx_tvalid),
    //  .COMTX_TVALID_o(com_tx_tvalid),
    //  .COMTX_TDATA_o(com_tx_tdata),
    //  .COMTX_TREADY_i(com_tx_tready),
    //  .STDTX_TVALID_o(std_tx_tvalid),
    //  .STDTX_TDATA_o(std_tx_tdata),
    //  .STDTX_TREADY_i(std_tx_tready)
    
    //  );