//   ==================================================================
//   >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
//   ------------------------------------------------------------------
//   Copyright (c) 2006-2011 by Lattice Semiconductor Corporation
//   ALL RIGHTS RESERVED
//   ------------------------------------------------------------------
//
//   IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM.
//
//   Permission:
//
//      Lattice Semiconductor grants permission to use this code
//      pursuant to the terms of the Lattice Semiconductor Corporation
//      Open Source License Agreement.
//
//   Disclaimer:
//
//      Lattice Semiconductor provides no warranty regarding the use or
//      functionality of this code. It is the user's responsibility to
//      verify the user's design for consistency and functionality through
//      the use of formal verification methods.
//
//   --------------------------------------------------------------------
//
//                  Lattice Semiconductor Corporation
//                  5555 NE Moore Court
//                  Hillsboro, OR 97214
//                  U.S.A
//
//                  TEL: 1-800-Lattice (USA and Canada)
//                         503-286-8001 (other locations)
//
//                  web: http://www.latticesemi.com/
//                  email: techsupport@latticesemi.com
//
//   --------------------------------------------------------------------
//                         FILE DETAILS
// Project          : LatticeMico32
// File             : lm32_jtag.v
// Title            : JTAG interface
// Dependencies     : lm32_include.v
// Version          : 6.1.17
//                  : Initial Release
// Version          : 7.0SP2, 3.0
//                  : No Change
// Version          : 3.1
//                  : No Change
// =============================================================================

`include "lm32_include.v"

`ifdef CFG_JTAG_ENABLED

`define LM32_DP                             3'b000
`define LM32_TX                             3'b001
`define LM32_RX                             3'b010

// LM32 Debug Protocol commands IDs
`define LM32_DP_RNG                         3:0
`define LM32_DP_READ_MEMORY                 4'b0001
`define LM32_DP_WRITE_MEMORY                4'b0010
`define LM32_DP_READ_SEQUENTIAL             4'b0011
`define LM32_DP_WRITE_SEQUENTIAL            4'b0100
`define LM32_DP_WRITE_CSR                   4'b0101
`define LM32_DP_BREAK                       4'b0110
`define LM32_DP_RESET                       4'b0111

// States for FSM
`define LM32_JTAG_STATE_RNG                 3:0
`define LM32_JTAG_STATE_READ_COMMAND        4'h0
`define LM32_JTAG_STATE_READ_BYTE_0         4'h1
`define LM32_JTAG_STATE_READ_BYTE_1         4'h2
`define LM32_JTAG_STATE_READ_BYTE_2         4'h3
`define LM32_JTAG_STATE_READ_BYTE_3         4'h4
`define LM32_JTAG_STATE_READ_BYTE_4         4'h5
`define LM32_JTAG_STATE_PROCESS_COMMAND     4'h6
`define LM32_JTAG_STATE_WAIT_FOR_MEMORY     4'h7
`define LM32_JTAG_STATE_WAIT_FOR_CSR        4'h8

/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////

module lm32_jtag (
    // ----- Inputs -------
    clk_i,
    rst_i,
    jtag_clk,
    jtag_update,
    jtag_reg_q,
    jtag_reg_addr_q,
`ifdef CFG_JTAG_UART_ENABLED
    csr,
    csr_write_enable,
    csr_write_data,
    stall_x,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
    jtag_read_data,
    jtag_access_complete,
`endif
`ifdef CFG_DEBUG_ENABLED
    exception_q_w,
`endif
    // ----- Outputs -------
`ifdef CFG_JTAG_UART_ENABLED
    jtx_csr_read_data,
    jrx_csr_read_data,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
    jtag_csr_write_enable,
    jtag_csr_write_data,
    jtag_csr,
    jtag_read_enable,
    jtag_write_enable,
    jtag_write_data,
    jtag_address,
`endif
`ifdef CFG_DEBUG_ENABLED
    jtag_break,
    jtag_reset,
`endif
    jtag_reg_d,
    jtag_reg_addr_d
    );

/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////

input clk_i;                                            // Clock
input rst_i;                                            // Reset

input jtag_clk;                                         // JTAG clock
input jtag_update;                                      // JTAG data register has been updated
input [`LM32_BYTE_RNG] jtag_reg_q;                      // JTAG data register
input [2:0] jtag_reg_addr_q;                            // JTAG data register

`ifdef CFG_JTAG_UART_ENABLED
input [`LM32_CSR_RNG] csr;                              // CSR to write
input csr_write_enable;                                 // CSR write enable
input [`LM32_WORD_RNG] csr_write_data;                  // Data to write to specified CSR
input stall_x;                                          // Stall instruction in X stage
`endif
`ifdef CFG_HW_DEBUG_ENABLED
input [`LM32_BYTE_RNG] jtag_read_data;                  // Data read from requested address
input jtag_access_complete;                             // Memory access if complete
`endif
`ifdef CFG_DEBUG_ENABLED
input exception_q_w;                                    // Indicates an exception has occured in W stage
`endif

/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////

`ifdef CFG_JTAG_UART_ENABLED
output [`LM32_WORD_RNG] jtx_csr_read_data;              // Value of JTX CSR for rcsr instructions
wire   [`LM32_WORD_RNG] jtx_csr_read_data;
output [`LM32_WORD_RNG] jrx_csr_read_data;              // Value of JRX CSR for rcsr instructions
wire   [`LM32_WORD_RNG] jrx_csr_read_data;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
output jtag_csr_write_enable;                           // CSR write enable
reg    jtag_csr_write_enable;
output [`LM32_WORD_RNG] jtag_csr_write_data;            // Data to write to specified CSR
wire   [`LM32_WORD_RNG] jtag_csr_write_data;
output [`LM32_CSR_RNG] jtag_csr;                        // CSR to write
wire   [`LM32_CSR_RNG] jtag_csr;
output jtag_read_enable;                                // Memory read enable
reg    jtag_read_enable;
output jtag_write_enable;                               // Memory write enable
reg    jtag_write_enable;
output [`LM32_BYTE_RNG] jtag_write_data;                // Data to write to specified address
wire   [`LM32_BYTE_RNG] jtag_write_data;
output [`LM32_WORD_RNG] jtag_address;                   // Memory read/write address
wire   [`LM32_WORD_RNG] jtag_address;
`endif
`ifdef CFG_DEBUG_ENABLED
output jtag_break;                                      // Request to raise a breakpoint exception
reg    jtag_break;
output jtag_reset;                                      // Request to raise a reset exception
reg    jtag_reset;
`endif
output [`LM32_BYTE_RNG] jtag_reg_d;
reg    [`LM32_BYTE_RNG] jtag_reg_d;
output [2:0] jtag_reg_addr_d;
wire   [2:0] jtag_reg_addr_d;

/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////

reg rx_toggle;                          // Clock-domain crossing registers
reg rx_toggle_r;                        // Registered version of rx_toggle
reg rx_toggle_r_r;                      // Registered version of rx_toggle_r
reg rx_toggle_r_r_r;                    // Registered version of rx_toggle_r_r

reg [`LM32_BYTE_RNG] rx_byte;
reg [2:0] rx_addr;

`ifdef CFG_JTAG_UART_ENABLED
reg [`LM32_BYTE_RNG] uart_tx_byte;      // UART TX data
reg uart_tx_valid;                      // TX data is valid
reg [`LM32_BYTE_RNG] uart_rx_byte;      // UART RX data
reg uart_rx_valid;                      // RX data is valid
`endif

reg [`LM32_DP_RNG] command;             // The last received command
`ifdef CFG_HW_DEBUG_ENABLED
reg [`LM32_BYTE_RNG] jtag_byte_0;       // Registers to hold command paramaters
reg [`LM32_BYTE_RNG] jtag_byte_1;
reg [`LM32_BYTE_RNG] jtag_byte_2;
reg [`LM32_BYTE_RNG] jtag_byte_3;
reg [`LM32_BYTE_RNG] jtag_byte_4;
reg processing;                         // Indicates if we're still processing a memory read/write
`endif

reg [`LM32_JTAG_STATE_RNG] state;       // Current state of FSM

/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////

`ifdef CFG_HW_DEBUG_ENABLED
assign jtag_csr_write_data = {jtag_byte_0, jtag_byte_1, jtag_byte_2, jtag_byte_3};
assign jtag_csr = jtag_byte_4[`LM32_CSR_RNG];
assign jtag_address = {jtag_byte_0, jtag_byte_1, jtag_byte_2, jtag_byte_3};
assign jtag_write_data = jtag_byte_4;
`endif

// Generate status flags for reading via the JTAG interface
`ifdef CFG_JTAG_UART_ENABLED
assign jtag_reg_addr_d[1:0] = {uart_rx_valid, uart_tx_valid};
`else
assign jtag_reg_addr_d[1:0] = 2'b00;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
assign jtag_reg_addr_d[2] = processing;
`else
assign jtag_reg_addr_d[2] = 1'b0;
`endif

`ifdef CFG_JTAG_UART_ENABLED
assign jtx_csr_read_data = {{`LM32_WORD_WIDTH-9{1'b0}}, uart_tx_valid, 8'h00};
assign jrx_csr_read_data = {{`LM32_WORD_WIDTH-9{1'b0}}, uart_rx_valid, uart_rx_byte};
`endif

/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////

// Toggle a flag when a JTAG write occurs

always @(negedge jtag_update `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
  rx_toggle <= 1'b0;
else
  rx_toggle <= ~rx_toggle;
end

always @(*)
begin
    rx_byte = jtag_reg_q;
    rx_addr = jtag_reg_addr_q;
end

// Clock domain crossing from JTAG clock domain to CPU clock domain
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
    begin
        rx_toggle_r <= 1'b0;
        rx_toggle_r_r <= 1'b0;
        rx_toggle_r_r_r <= 1'b0;
    end
    else
    begin
        rx_toggle_r <= rx_toggle;
        rx_toggle_r_r <= rx_toggle_r;
        rx_toggle_r_r_r <= rx_toggle_r_r;
    end
end

// LM32 debug protocol state machine
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
    begin
        state <= `LM32_JTAG_STATE_READ_COMMAND;
        command <= 4'b0000;
        jtag_reg_d <= 8'h00;
`ifdef CFG_HW_DEBUG_ENABLED
        processing <= `FALSE;
        jtag_csr_write_enable <= `FALSE;
        jtag_read_enable <= `FALSE;
        jtag_write_enable <= `FALSE;
`endif
`ifdef CFG_DEBUG_ENABLED
        jtag_break <= `FALSE;
        jtag_reset <= `FALSE;
`endif
`ifdef CFG_JTAG_UART_ENABLED
        uart_tx_byte <= 8'h00;
        uart_tx_valid <= `FALSE;
        uart_rx_byte <= 8'h00;
        uart_rx_valid <= `FALSE;
`endif
    end
    else
    begin
`ifdef CFG_JTAG_UART_ENABLED
        if ((csr_write_enable == `TRUE) && (stall_x == `FALSE))
        begin
            case (csr)
            `LM32_CSR_JTX:
            begin
                // Set flag indicating data is available
                uart_tx_byte <= csr_write_data[`LM32_BYTE_0_RNG];
                uart_tx_valid <= `TRUE;
            end
            `LM32_CSR_JRX:
            begin
                // Clear flag indidicating data has been received
                uart_rx_valid <= `FALSE;
            end
            endcase
        end
`endif
`ifdef CFG_DEBUG_ENABLED
        // When an exception has occured, clear the requests
        if (exception_q_w == `TRUE)
        begin
            jtag_break <= `FALSE;
            jtag_reset <= `FALSE;
        end
`endif
        case (state)
        `LM32_JTAG_STATE_READ_COMMAND:
        begin
            // Wait for rx register to toggle which indicates new data is available
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                command <= rx_byte[7:4];
                case (rx_addr)
`ifdef CFG_DEBUG_ENABLED
                `LM32_DP:
                begin
                    case (rx_byte[7:4])
`ifdef CFG_HW_DEBUG_ENABLED
                    `LM32_DP_READ_MEMORY:
                        state <= `LM32_JTAG_STATE_READ_BYTE_0;
                    `LM32_DP_READ_SEQUENTIAL:
                    begin
                        {jtag_byte_2, jtag_byte_3} <= {jtag_byte_2, jtag_byte_3} + 1'b1;
                        state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
                    end
                    `LM32_DP_WRITE_MEMORY:
                        state <= `LM32_JTAG_STATE_READ_BYTE_0;
                    `LM32_DP_WRITE_SEQUENTIAL:
                    begin
                        {jtag_byte_2, jtag_byte_3} <= {jtag_byte_2, jtag_byte_3} + 1'b1;
                        state <= 5;
                    end
                    `LM32_DP_WRITE_CSR:
                        state <= `LM32_JTAG_STATE_READ_BYTE_0;
`endif
                    `LM32_DP_BREAK:
                    begin
`ifdef CFG_JTAG_UART_ENABLED
                        uart_rx_valid <= `FALSE;
                        uart_tx_valid <= `FALSE;
`endif
                        jtag_break <= `TRUE;
                    end
                    `LM32_DP_RESET:
                    begin
`ifdef CFG_JTAG_UART_ENABLED
                        uart_rx_valid <= `FALSE;
                        uart_tx_valid <= `FALSE;
`endif
                        jtag_reset <= `TRUE;
                    end
                    endcase
                end
`endif
`ifdef CFG_JTAG_UART_ENABLED
                `LM32_TX:
                begin
                    uart_rx_byte <= rx_byte;
                    uart_rx_valid <= `TRUE;
                end
                `LM32_RX:
                begin
                    jtag_reg_d <= uart_tx_byte;
                    uart_tx_valid <= `FALSE;
                end
`endif
                default:
                    ;
                endcase
            end
        end
`ifdef CFG_HW_DEBUG_ENABLED
        `LM32_JTAG_STATE_READ_BYTE_0:
        begin
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                jtag_byte_0 <= rx_byte;
                state <= `LM32_JTAG_STATE_READ_BYTE_1;
            end
        end
        `LM32_JTAG_STATE_READ_BYTE_1:
        begin
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                jtag_byte_1 <= rx_byte;
                state <= `LM32_JTAG_STATE_READ_BYTE_2;
            end
        end
        `LM32_JTAG_STATE_READ_BYTE_2:
        begin
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                jtag_byte_2 <= rx_byte;
                state <= `LM32_JTAG_STATE_READ_BYTE_3;
            end
        end
        `LM32_JTAG_STATE_READ_BYTE_3:
        begin
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                jtag_byte_3 <= rx_byte;
                if (command == `LM32_DP_READ_MEMORY)
                    state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
                else
                    state <= `LM32_JTAG_STATE_READ_BYTE_4;
            end
        end
        `LM32_JTAG_STATE_READ_BYTE_4:
        begin
            if (rx_toggle_r_r != rx_toggle_r_r_r)
            begin
                jtag_byte_4 <= rx_byte;
                state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
            end
        end
        `LM32_JTAG_STATE_PROCESS_COMMAND:
        begin
            case (command)
            `LM32_DP_READ_MEMORY,
            `LM32_DP_READ_SEQUENTIAL:
            begin
                jtag_read_enable <= `TRUE;
                processing <= `TRUE;
                state <= `LM32_JTAG_STATE_WAIT_FOR_MEMORY;
            end
            `LM32_DP_WRITE_MEMORY,
            `LM32_DP_WRITE_SEQUENTIAL:
            begin
                jtag_write_enable <= `TRUE;
                processing <= `TRUE;
                state <= `LM32_JTAG_STATE_WAIT_FOR_MEMORY;
            end
            `LM32_DP_WRITE_CSR:
            begin
                jtag_csr_write_enable <= `TRUE;
                processing <= `TRUE;
                state <= `LM32_JTAG_STATE_WAIT_FOR_CSR;
            end
            endcase
        end
        `LM32_JTAG_STATE_WAIT_FOR_MEMORY:
        begin
            if (jtag_access_complete == `TRUE)
            begin
                jtag_read_enable <= `FALSE;
                jtag_reg_d <= jtag_read_data;
                jtag_write_enable <= `FALSE;
                processing <= `FALSE;
                state <= `LM32_JTAG_STATE_READ_COMMAND;
            end
        end
        `LM32_JTAG_STATE_WAIT_FOR_CSR:
        begin
            jtag_csr_write_enable <= `FALSE;
            processing <= `FALSE;
            state <= `LM32_JTAG_STATE_READ_COMMAND;
        end
`endif
        endcase
    end
end

endmodule

`endif
