URL
https://opencores.org/ocsvn/dbg_interface/dbg_interface/trunk
Subversion Repositories dbg_interface
[/] [dbg_interface/] [tags/] [rel_21/] [rtl/] [verilog/] [dbg_cpu.v] - Rev 158
Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////// //// //// //// dbg_cpu.v //// //// //// //// //// //// This file is part of the SoC/OpenRISC Development Interface //// //// http://www.opencores.org/projects/DebugInterface/ //// //// //// //// Author(s): //// //// Igor Mohor (igorm@opencores.org) //// //// //// //// //// //// All additional information is avaliable in the README.txt //// //// file. //// //// //// ////////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000 - 2004 Authors //// //// //// //// This source file may be used and distributed without //// //// restriction provided that this copyright statement is not //// //// removed from the file and that any derivative work contains //// //// the original copyright notice and the associated disclaimer. //// //// //// //// This source file is free software; you can redistribute it //// //// and/or modify it under the terms of the GNU Lesser General //// //// Public License as published by the Free Software Foundation; //// //// either version 2.1 of the License, or (at your option) any //// //// later version. //// //// //// //// This source is distributed in the hope that it will be //// //// useful, but WITHOUT ANY WARRANTY; without even the implied //// //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// //// PURPOSE. See the GNU Lesser General Public License for more //// //// details. //// //// //// //// You should have received a copy of the GNU Lesser General //// //// Public License along with this source; if not, download it //// //// from http://www.opencores.org/lgpl.shtml //// //// //// ////////////////////////////////////////////////////////////////////// // // CVS Revision History // // $Log: not supported by cvs2svn $ // Revision 1.6 2004/01/22 13:58:53 mohor // Port signals are all set to zero after reset. // // Revision 1.5 2004/01/19 07:32:41 simons // Reset values width added because of FV, a good sentence changed because some tools can not handle it. // // Revision 1.4 2004/01/17 18:38:11 mohor // cpu_tall_o is set with cpu_stb_o or register. // // Revision 1.3 2004/01/17 18:01:24 mohor // New version. // // Revision 1.2 2004/01/17 17:01:14 mohor // Almost finished. // // Revision 1.1 2004/01/16 14:53:31 mohor // *** empty log message *** // // // // synopsys translate_off `include "timescale.v" // synopsys translate_on `include "dbg_cpu_defines.v" // Top module module dbg_cpu( // JTAG signals tck_i, tdi_i, tdo_o, // TAP states shift_dr_i, pause_dr_i, update_dr_i, cpu_ce_i, crc_match_i, crc_en_o, shift_crc_o, rst_i, // CPU signals cpu_clk_i, cpu_addr_o, cpu_data_i, cpu_data_o, cpu_bp_i, cpu_stall_o, cpu_stall_all_o, cpu_stb_o, cpu_sel_o, // Not synchronized cpu_we_o, cpu_ack_i, cpu_rst_o ); // JTAG signals input tck_i; input tdi_i; output tdo_o; // TAP states input shift_dr_i; input pause_dr_i; input update_dr_i; input cpu_ce_i; input crc_match_i; output crc_en_o; output shift_crc_o; input rst_i; // CPU signals input cpu_clk_i; output [31:0] cpu_addr_o; input [31:0] cpu_data_i; output [31:0] cpu_data_o; input cpu_bp_i; output cpu_stall_o; output cpu_stall_all_o; output cpu_stb_o; output [`CPU_NUM -1:0] cpu_sel_o; output cpu_we_o; input cpu_ack_i; output cpu_rst_o; reg tdo_o; wire cmd_cnt_en; reg [1:0] cmd_cnt; wire cmd_cnt_end; reg cmd_cnt_end_q; wire addr_cnt_en; reg [5:0] addr_cnt; reg [5:0] addr_cnt_limit; wire addr_cnt_end; wire crc_cnt_en; reg [5:0] crc_cnt; wire crc_cnt_end; reg crc_cnt_end_q; wire data_cnt_en; reg [5:0] data_cnt; reg [5:0] data_cnt_limit; wire data_cnt_end; reg data_cnt_end_q; wire status_cnt_end; reg status_cnt1, status_cnt2, status_cnt3, status_cnt4; reg [3:0] status; reg crc_match_reg; wire enable; reg read_cycle_reg; reg read_cycle_reg_q; reg read_cycle_cpu; reg read_cycle_cpu_q; reg write_cycle_reg; reg write_cycle_cpu; wire read_cycle; wire write_cycle; reg [31:0] dr; wire [7:0] reg_data_out; wire dr_read_reg; wire dr_write_reg; wire dr_read_cpu8; wire dr_read_cpu32; wire dr_write_cpu8; wire dr_write_cpu32; wire dr_go; reg dr_read_reg_latched; reg dr_write_reg_latched; reg dr_read_cpu8_latched; reg dr_read_cpu32_latched; reg dr_write_cpu8_latched; reg dr_write_cpu32_latched; reg dr_go_latched; reg cmd_read_reg; reg cmd_read_cpu; reg cmd_write_reg; reg cmd_write_cpu; reg cycle_32_bit; reg reg_access; reg [31:0] adr; reg cpu_ack_sync; reg cpu_ack_tck; reg cpu_ack_tck_q; reg cpu_stb; reg cpu_stb_sync; reg cpu_stb_o; wire cpu_stall_tmp; wire go_prelim; wire crc_cnt_31; assign enable = cpu_ce_i & shift_dr_i; assign crc_en_o = enable & crc_cnt_end & (~status_cnt_end); assign shift_crc_o = enable & status_cnt_end; // Signals dbg module to shift out the CRC assign cmd_cnt_en = enable & (~cmd_cnt_end); // Command counter always @ (posedge tck_i or posedge rst_i) begin if (rst_i) cmd_cnt <= #1 2'h0; else if (update_dr_i) cmd_cnt <= #1 2'h0; else if (cmd_cnt_en) cmd_cnt <= #1 cmd_cnt + 1'b1; end assign addr_cnt_en = enable & cmd_cnt_end & (~addr_cnt_end); // Address/length counter always @ (posedge tck_i or posedge rst_i) begin if (rst_i) addr_cnt <= #1 6'h0; else if (update_dr_i) addr_cnt <= #1 6'h0; else if (addr_cnt_en) addr_cnt <= #1 addr_cnt + 1'b1; end assign data_cnt_en = enable & (~data_cnt_end) & (cmd_cnt_end & write_cycle | crc_cnt_end & read_cycle); // Data counter always @ (posedge tck_i or posedge rst_i) begin if (rst_i) data_cnt <= #1 6'h0; else if (update_dr_i) data_cnt <= #1 6'h0; else if (data_cnt_en) data_cnt <= #1 data_cnt + 1'b1; end assign crc_cnt_en = enable & (~crc_cnt_end) & (cmd_cnt_end & addr_cnt_end & (~write_cycle) | (data_cnt_end & write_cycle)); // crc counter always @ (posedge tck_i or posedge rst_i) begin if (rst_i) crc_cnt <= #1 6'h0; else if(crc_cnt_en) crc_cnt <= #1 crc_cnt + 1'b1; else if (update_dr_i) crc_cnt <= #1 6'h0; end // Upper limit. Address/length counter counts until this value is reached always @ (posedge tck_i or posedge rst_i) begin if (rst_i) addr_cnt_limit = 6'd0; else if (cmd_cnt == 2'h2) begin if ((~dr[0]) & (~tdi_i)) // (current command is WB_STATUS or WB_GO) addr_cnt_limit = 6'd0; else // (current command is WB_WRITEx or WB_READx) addr_cnt_limit = 6'd32; end end assign cmd_cnt_end = cmd_cnt == 2'h3; assign addr_cnt_end = addr_cnt == addr_cnt_limit; assign crc_cnt_end = crc_cnt == 6'd32; assign crc_cnt_31 = crc_cnt == 6'd31; assign data_cnt_end = (data_cnt == data_cnt_limit); always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin crc_cnt_end_q <= #1 1'b0; cmd_cnt_end_q <= #1 1'b0; data_cnt_end_q <= #1 1'b0; end else begin crc_cnt_end_q <= #1 crc_cnt_end; cmd_cnt_end_q <= #1 cmd_cnt_end; data_cnt_end_q <= #1 data_cnt_end; end end // Status counter is made of 4 serialy connected registers always @ (posedge tck_i or posedge rst_i) begin if (rst_i) status_cnt1 <= #1 1'b0; else if (update_dr_i) status_cnt1 <= #1 1'b0; else if (data_cnt_end & read_cycle | crc_cnt_end & (~read_cycle) ) status_cnt1 <= #1 1'b1; end always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin status_cnt2 <= #1 1'b0; status_cnt3 <= #1 1'b0; status_cnt4 <= #1 1'b0; end else if (update_dr_i) begin status_cnt2 <= #1 1'b0; status_cnt3 <= #1 1'b0; status_cnt4 <= #1 1'b0; end else begin status_cnt2 <= #1 status_cnt1; status_cnt3 <= #1 status_cnt2; status_cnt4 <= #1 status_cnt3; end end assign status_cnt_end = status_cnt4; // Latching address always @ (posedge tck_i or posedge rst_i) begin if (rst_i) adr <= #1 32'h0; else if(crc_cnt_end & (~crc_cnt_end_q) & crc_match_i & (~dr_go_latched)) adr <= #1 dr[31:0]; end assign cpu_addr_o = adr; // Shift register for shifting in and out the data always @ (posedge tck_i or posedge rst_i) begin if (rst_i) dr <= #1 32'h0; else if (reg_access) dr[31:24] <= #1 reg_data_out; else if (cpu_ack_tck & (~cpu_ack_tck_q) & read_cycle_cpu) begin if (cycle_32_bit) dr[31:0] <= #1 cpu_data_i; else dr[31:24] <= #1 cpu_data_i[7:0]; end else if (enable & ((~addr_cnt_end) | (~cmd_cnt_end) | ((~data_cnt_end) & write_cycle) | (crc_cnt_end & (~data_cnt_end) & read_cycle))) begin dr <= #1 {dr[30:0], tdi_i}; end end assign dr_read_reg = dr[2:0] == `CPU_READ_REG; assign dr_write_reg = dr[2:0] == `CPU_WRITE_REG; assign dr_read_cpu8 = dr[2:0] == `CPU_READ8; assign dr_read_cpu32 = dr[2:0] == `CPU_READ32; assign dr_write_cpu8 = dr[2:0] == `CPU_WRITE8; assign dr_write_cpu32 = dr[2:0] == `CPU_WRITE32; assign dr_go = dr[2:0] == `CPU_GO; // Latching instruction always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin dr_read_reg_latched <= #1 1'b0; dr_read_cpu8_latched <= #1 1'b0; dr_read_cpu32_latched <= #1 1'b0; dr_write_reg_latched <= #1 1'b0; dr_write_cpu8_latched <= #1 1'b0; dr_write_cpu32_latched <= #1 1'b0; dr_go_latched <= #1 1'b0; end else if (update_dr_i) begin dr_read_reg_latched <= #1 1'b0; dr_read_cpu8_latched <= #1 1'b0; dr_read_cpu32_latched <= #1 1'b0; dr_write_reg_latched <= #1 1'b0; dr_write_cpu8_latched <= #1 1'b0; dr_write_cpu32_latched <= #1 1'b0; dr_go_latched <= #1 1'b0; end else if (cmd_cnt_end & (~cmd_cnt_end_q)) begin dr_read_reg_latched <= #1 dr_read_reg; dr_read_cpu8_latched <= #1 dr_read_cpu8; dr_read_cpu32_latched <= #1 dr_read_cpu32; dr_write_reg_latched <= #1 dr_write_reg; dr_write_cpu8_latched <= #1 dr_write_cpu8; dr_write_cpu32_latched <= #1 dr_write_cpu32; dr_go_latched <= #1 dr_go; end end // Latching instruction always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin cmd_read_reg <= #1 1'b0; cmd_read_cpu <= #1 1'b0; cmd_write_reg <= #1 1'b0; cmd_write_cpu <= #1 1'b0; cycle_32_bit <= #1 1'b0; end else if(crc_cnt_end & (~crc_cnt_end_q) & crc_match_i) begin cmd_read_reg <= #1 dr_read_reg_latched; cmd_read_cpu <= #1 dr_read_cpu8_latched | dr_read_cpu32_latched; cmd_write_reg <= #1 dr_write_reg_latched; cmd_write_cpu <= #1 dr_write_cpu8_latched | dr_write_cpu32_latched; cycle_32_bit <= #1 dr_read_cpu32_latched | dr_write_cpu32_latched; end end // Upper limit. Data counter counts until this value is reached. always @ (posedge tck_i or posedge rst_i) begin if (rst_i) data_cnt_limit <= #1 6'h0; else if(crc_cnt_end & (~crc_cnt_end_q) & crc_match_i & (~dr_go_latched)) begin if (dr_read_cpu32_latched | dr_write_cpu32_latched) data_cnt_limit <= #1 6'd32; else data_cnt_limit <= #1 6'd8; end end assign go_prelim = (cmd_cnt == 2'h2) & dr[1] & (~dr[0]) & (~tdi_i); always @ (posedge tck_i or posedge rst_i) begin if (rst_i) read_cycle_reg <= #1 1'b0; else if (update_dr_i) read_cycle_reg <= #1 1'b0; else if (cmd_read_reg & go_prelim) read_cycle_reg <= #1 1'b1; end always @ (posedge tck_i or posedge rst_i) begin if (rst_i) read_cycle_cpu <= #1 1'b0; else if (update_dr_i) read_cycle_cpu <= #1 1'b0; else if (cmd_read_cpu & go_prelim) read_cycle_cpu <= #1 1'b1; end always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin read_cycle_reg_q <= #1 1'b0; read_cycle_cpu_q <= #1 1'b0; end else begin read_cycle_reg_q <= #1 read_cycle_reg; read_cycle_cpu_q <= #1 read_cycle_cpu; end end always @ (posedge tck_i or posedge rst_i) begin if (rst_i) write_cycle_reg <= #1 1'b0; else if (update_dr_i) write_cycle_reg <= #1 1'b0; else if (cmd_write_reg & go_prelim) write_cycle_reg <= #1 1'b1; end always @ (posedge tck_i or posedge rst_i) begin if (rst_i) write_cycle_cpu <= #1 1'b0; else if (update_dr_i) write_cycle_cpu <= #1 1'b0; else if (cmd_write_cpu & go_prelim) write_cycle_cpu <= #1 1'b1; end assign read_cycle = read_cycle_reg | read_cycle_cpu; assign write_cycle = write_cycle_reg | write_cycle_cpu; // Start register access cycle always @ (posedge tck_i or posedge rst_i) begin if (rst_i) reg_access <= #1 1'b0; else if (write_cycle_reg & data_cnt_end & (~data_cnt_end_q) | read_cycle_reg & (~read_cycle_reg_q)) reg_access <= #1 1'b1; else reg_access <= #1 1'b0; end // Connecting dbg_cpu_registers dbg_cpu_registers i_dbg_cpu_registers ( .data_i (dr[7:0]), .data_o (reg_data_out), .addr_i (adr[1:0]), .we_i (write_cycle_reg), .en_i (reg_access), .clk_i (tck_i), .bp_i (cpu_bp_i), .rst_i (rst_i), .cpu_clk_i (cpu_clk_i), .cpu_stall_o (cpu_stall_tmp), .cpu_stall_all_o (cpu_stall_all_o), .cpu_sel_o (cpu_sel_o), .cpu_rst_o (cpu_rst_o) ); assign cpu_we_o = write_cycle_cpu; assign cpu_data_o = dr[31:0]; assign cpu_stall_o = cpu_stb_o | cpu_stall_tmp; // Synchronizing ack signal from cpu always @ (posedge tck_i or posedge rst_i) begin if (rst_i) begin cpu_ack_sync <= #1 1'b0; cpu_ack_tck <= #1 1'b0; cpu_ack_tck_q <= #1 1'b0; end else begin cpu_ack_sync <= #1 cpu_ack_i; cpu_ack_tck <= #1 cpu_ack_sync; cpu_ack_tck_q <= #1 cpu_ack_tck; end end // Start cpu access cycle always @ (posedge tck_i or posedge rst_i) begin if (rst_i) cpu_stb <= #1 1'b0; else if (update_dr_i | cpu_ack_tck) cpu_stb <= #1 1'b0; else if (write_cycle_cpu & data_cnt_end & (~data_cnt_end_q) | read_cycle_cpu & (~read_cycle_cpu_q)) cpu_stb <= #1 1'b1; end // Synchronizing cpu_stb to cpu_clk_i clock always @ (posedge cpu_clk_i or posedge rst_i) begin if (rst_i) begin cpu_stb_sync <= #1 1'b0; cpu_stb_o <= #1 1'b0; end else begin cpu_stb_sync <= #1 cpu_stb; cpu_stb_o <= #1 cpu_stb_sync; end end // Latching crc always @ (posedge tck_i or posedge rst_i) begin if (rst_i) crc_match_reg <= #1 1'b0; else if(crc_cnt_end & (~crc_cnt_end_q)) crc_match_reg <= #1 crc_match_i; end // Status register always @ (posedge tck_i or posedge rst_i) begin if (rst_i) status <= #1 4'h0; else if(crc_cnt_end & (~crc_cnt_end_q) & (~read_cycle)) status <= #1 {crc_match_i, 1'b0, 1'b1, 1'b0}; else if (data_cnt_end & (~data_cnt_end_q) & read_cycle) status <= #1 {crc_match_reg, 1'b0, 1'b1, 1'b0}; else if (shift_dr_i & (~status_cnt_end)) status <= #1 {status[0], status[3:1]}; end // Following status is shifted out: // 1. bit: 1 if crc is OK, else 0 // 2. bit: 1'b0 // 3. bit: 1'b1 // 4. bit: 1'b0 // TDO multiplexer always @ (crc_cnt_end or crc_cnt_end_q or crc_match_i or data_cnt_end or data_cnt_end_q or read_cycle or crc_match_reg or status or dr) begin if (crc_cnt_end & (~crc_cnt_end_q) & (~(read_cycle))) begin tdo_o = crc_match_i; end else if (read_cycle & crc_cnt_end & (~data_cnt_end)) begin tdo_o = dr[31]; end else if (read_cycle & data_cnt_end & (~data_cnt_end_q)) // cmd is already updated begin tdo_o = crc_match_reg; end else if (crc_cnt_end) begin tdo_o = status[0]; end else begin tdo_o = 1'b0; end end endmodule