forked from cores/microwatt
				
			First pass at an external JTAG port
The verilator simulation interface uses the remote_bitbang protocol from openocd. I have a simple implementation for urjtag too. Signed-off-by: Anton Blanchard <anton@linux.ibm.com>caravel-mpw5-20220322
							parent
							
								
									c2577b5446
								
							
						
					
					
						commit
						15bb4aa90a
					
				| @ -0,0 +1,302 @@ | ||||
| -- JTAG to DMI interface, based on the Xilinx version | ||||
| -- | ||||
| -- DMI bus | ||||
| -- | ||||
| --  req : ____/------------\_____ | ||||
| --  addr: xxxx<            >xxxxx, based on the Xilinx version | ||||
| --  dout: xxxx<            >xxxxx | ||||
| --  wr  : xxxx<            >xxxxx | ||||
| --  din : xxxxxxxxxxxx<      >xxx | ||||
| --  ack : ____________/------\___ | ||||
| -- | ||||
| --  * addr/dout set along with req, can be latched on same cycle by slave | ||||
| --  * ack & din remain up until req is dropped by master, the slave must | ||||
| --    provide a stable output on din on reads during that time. | ||||
| --  * req remains low at until at least one sysclk after ack seen down. | ||||
| -- | ||||
| --   JTAG (tck)                    DMI (sys_clk) | ||||
| -- | ||||
| --   * jtag_req = 1 | ||||
| --        (jtag_req_0)             * | ||||
| --          (jtag_req_1) ->        * dmi_req = 1 > | ||||
| --                                 *.../... | ||||
| --                                 * dmi_ack = 1 < | ||||
| --   *                         (dmi_ack_0) | ||||
| --   *                   <-  (dmi_ack_1) | ||||
| --   * jtag_req = 0 (and latch dmi_din) | ||||
| --        (jtag_req_0)             * | ||||
| --          (jtag_req_1) ->        * dmi_req = 0 > | ||||
| --                                 * dmi_ack = 0 < | ||||
| --  *                          (dmi_ack_0) | ||||
| --  *                    <-  (dmi_ack_1) | ||||
| -- | ||||
| --  jtag_req can go back to 1 when jtag_rsp_1 is 0 | ||||
| -- | ||||
| --  Questions/TODO: | ||||
| --    - I use 2 flip fops for sync, is that enough ? | ||||
| --    - I treat the jtag_trst as an async reset, is that necessary ? | ||||
| --    - Dbl check reset situation since we have two different resets | ||||
| --      each only resetting part of the logic... | ||||
| --    - Look at optionally removing the synchronizer on the ack path, | ||||
| --      assuming JTAG is always slow enough that ack will have been | ||||
| --      stable long enough by the time CAPTURE comes in. | ||||
| --    - We could avoid the latched request by not shifting while a | ||||
| --      request is in progress (and force TDO to 1 to return a busy | ||||
| --      status). | ||||
| -- | ||||
| --  WARNING: This isn't the real DMI JTAG protocol (at least not yet). | ||||
| --           a command while busy will be ignored. A response of "11" | ||||
| --           means the previous command is still going, try again. | ||||
| --           As such We don't implement the DMI "error" status, and | ||||
| --           we don't implement DTMCS yet... This may still all change | ||||
| --           but for now it's easier that way as the real DMI protocol | ||||
| --           requires for a command to work properly that enough TCK | ||||
| --           are sent while IDLE and I'm having trouble getting that | ||||
| --           working with UrJtag and the Xilinx BSCAN2 for now. | ||||
|  | ||||
| library ieee; | ||||
| use ieee.std_logic_1164.all; | ||||
| use ieee.math_real.all; | ||||
|  | ||||
| library work; | ||||
| use work.wishbone_types.all; | ||||
|  | ||||
| entity dmi_dtm_jtag is | ||||
|     generic(ABITS : INTEGER:=8; | ||||
| 	    DBITS : INTEGER:=32); | ||||
|  | ||||
|     port(sys_clk	: in std_ulogic; | ||||
| 	 sys_reset	: in std_ulogic; | ||||
| 	 dmi_addr	: out std_ulogic_vector(ABITS - 1 downto 0); | ||||
| 	 dmi_din	: in std_ulogic_vector(DBITS - 1 downto 0); | ||||
| 	 dmi_dout	: out std_ulogic_vector(DBITS - 1 downto 0); | ||||
| 	 dmi_req	: out std_ulogic; | ||||
| 	 dmi_wr		: out std_ulogic; | ||||
| 	 dmi_ack	: in std_ulogic; | ||||
| --	 dmi_err	: in std_ulogic TODO: Add error response | ||||
|          jtag_tck       : in std_ulogic; | ||||
|          jtag_tdi       : in std_ulogic; | ||||
|          jtag_tms       : in std_ulogic; | ||||
| 	 jtag_trst      : in std_ulogic; | ||||
|          jtag_tdo       : out std_ulogic | ||||
| 	 ); | ||||
| end entity dmi_dtm_jtag; | ||||
|  | ||||
| architecture behaviour of dmi_dtm_jtag is | ||||
|  | ||||
|     -- Signals coming out of the JTAG TAP controller | ||||
|     signal capture		: std_ulogic; | ||||
|     signal update		: std_ulogic; | ||||
|     signal sel			: std_ulogic; | ||||
|     signal shift		: std_ulogic; | ||||
|     signal tdi			: std_ulogic; | ||||
|     signal tdo			: std_ulogic; | ||||
|  | ||||
|     -- ** JTAG clock domain ** | ||||
|  | ||||
|     -- Shift register | ||||
|     signal shiftr	: std_ulogic_vector(ABITS + DBITS + 1 downto 0); | ||||
|  | ||||
|     -- Latched request | ||||
|     signal request	: std_ulogic_vector(ABITS + DBITS + 1 downto 0); | ||||
|  | ||||
|     -- A request is present | ||||
|     signal jtag_req	: std_ulogic; | ||||
|  | ||||
|     -- Synchronizer for jtag_rsp (sys clk -> jtag_tck) | ||||
|     signal dmi_ack_0	: std_ulogic; | ||||
|     signal dmi_ack_1	: std_ulogic; | ||||
|  | ||||
|     -- ** sys clock domain ** | ||||
|  | ||||
|     -- Synchronizer for jtag_req (jtag clk -> sys clk) | ||||
|     signal jtag_req_0	: std_ulogic; | ||||
|     signal jtag_req_1	: std_ulogic; | ||||
|  | ||||
|     -- ** combination signals | ||||
|     signal jtag_bsy	: std_ulogic; | ||||
|     signal op_valid	: std_ulogic; | ||||
|     signal rsp_op	: std_ulogic_vector(1 downto 0); | ||||
|  | ||||
|     -- ** Constants ** | ||||
|     constant DMI_REQ_NOP : std_ulogic_vector(1 downto 0) := "00"; | ||||
|     constant DMI_REQ_RD  : std_ulogic_vector(1 downto 0) := "01"; | ||||
|     constant DMI_REQ_WR  : std_ulogic_vector(1 downto 0) := "10"; | ||||
|     constant DMI_RSP_OK  : std_ulogic_vector(1 downto 0) := "00"; | ||||
|     constant DMI_RSP_BSY : std_ulogic_vector(1 downto 0) := "11"; | ||||
|  | ||||
|     attribute ASYNC_REG : string; | ||||
|     attribute ASYNC_REG of jtag_req_0: signal is "TRUE"; | ||||
|     attribute ASYNC_REG of jtag_req_1: signal is "TRUE"; | ||||
|     attribute ASYNC_REG of dmi_ack_0: signal is "TRUE"; | ||||
|     attribute ASYNC_REG of dmi_ack_1: signal is "TRUE"; | ||||
|  | ||||
|     component tap_top port ( | ||||
|         -- JTAG pads | ||||
|         tms_pad_i : in std_ulogic; | ||||
|         tck_pad_i : in std_ulogic; | ||||
|         trst_pad_i : in std_ulogic; | ||||
|         tdi_pad_i : in std_ulogic; | ||||
|         tdo_pad_o : out std_ulogic; | ||||
|         tdo_padoe_o : out std_ulogic; | ||||
|  | ||||
|         -- TAP states | ||||
|         shift_dr_o : out std_ulogic; | ||||
|         pause_dr_o : out std_ulogic; | ||||
|         update_dr_o : out std_ulogic; | ||||
|         capture_dr_o : out std_ulogic; | ||||
|  | ||||
|         -- Select signals for boundary scan or mbist | ||||
|         extest_select_o : out std_ulogic; | ||||
|         sample_preload_select_o : out std_ulogic; | ||||
|         mbist_select_o : out std_ulogic; | ||||
|         debug_select_o : out std_ulogic; | ||||
|  | ||||
|         -- TDO signal that is connected to TDI of sub-modules. | ||||
|         tdo_o : out std_ulogic; | ||||
|  | ||||
|         -- TDI signals from sub-modules | ||||
|         debug_tdi_i : in std_ulogic; | ||||
|         bs_chain_tdi_i : in std_ulogic; | ||||
|         mbist_tdi_i : in std_ulogic | ||||
|         ); | ||||
|     end component; | ||||
|  | ||||
| begin | ||||
|     tap_top0 : tap_top | ||||
| 	port map ( | ||||
| 	    tms_pad_i               => jtag_tms, | ||||
| 	    tck_pad_i               => jtag_tck, | ||||
| 	    trst_pad_i              => jtag_trst, | ||||
| 	    tdi_pad_i               => jtag_tdi, | ||||
| 	    tdo_pad_o               => jtag_tdo, | ||||
| 	    tdo_padoe_o             => open,      -- what to do with this? | ||||
|  | ||||
| 	    shift_dr_o              => shift, | ||||
| 	    pause_dr_o              => open,      -- what to do with this? | ||||
| 	    update_dr_o             => update, | ||||
| 	    capture_dr_o            => capture, | ||||
|  | ||||
| 	    -- connect boundary scan and mbist? | ||||
| 	    extest_select_o         => open, | ||||
| 	    sample_preload_select_o => open, | ||||
| 	    mbist_select_o          => open, | ||||
| 	    debug_select_o          => sel, | ||||
|  | ||||
| 	    tdo_o                   => tdi, | ||||
|             debug_tdi_i             => tdo, | ||||
| 	    bs_chain_tdi_i          => '0', | ||||
|             mbist_tdi_i             => '0' | ||||
| 	    ); | ||||
|  | ||||
|     -- dmi_req synchronization | ||||
|     dmi_req_sync : process(sys_clk) | ||||
|     begin | ||||
| 	-- sys_reset is synchronous | ||||
| 	if rising_edge(sys_clk) then | ||||
| 	    if (sys_reset = '1') then | ||||
| 		jtag_req_0 <= '0'; | ||||
| 		jtag_req_1 <= '0'; | ||||
| 	    else | ||||
| 		jtag_req_0 <= jtag_req; | ||||
| 		jtag_req_1 <= jtag_req_0; | ||||
| 	    end if; | ||||
| 	end if; | ||||
|     end process; | ||||
|     dmi_req <= jtag_req_1; | ||||
|  | ||||
|     -- dmi_ack synchronization | ||||
|     dmi_ack_sync: process(jtag_tck, jtag_trst) | ||||
|     begin | ||||
| 	-- jtag_trst is async (see comments) | ||||
| 	if jtag_trst = '1' then | ||||
| 	    dmi_ack_0 <= '0'; | ||||
| 	    dmi_ack_1 <= '0'; | ||||
| 	elsif rising_edge(jtag_tck) then | ||||
| 	    dmi_ack_0 <= dmi_ack; | ||||
| 	    dmi_ack_1 <= dmi_ack_0; | ||||
| 	end if; | ||||
|     end process; | ||||
|  | ||||
|     -- jtag_bsy indicates whether we can start a new request, we can when | ||||
|     -- we aren't already processing one (jtag_req) and the synchronized ack | ||||
|     -- of the previous one is 0. | ||||
|     -- | ||||
|     jtag_bsy <= jtag_req or dmi_ack_1; | ||||
|  | ||||
|     -- decode request type in shift register | ||||
|     with shiftr(1 downto 0) select op_valid <= | ||||
| 	'1' when DMI_REQ_RD, | ||||
| 	'1' when DMI_REQ_WR, | ||||
| 	'0' when others; | ||||
|  | ||||
|     -- encode response op | ||||
|     rsp_op <= DMI_RSP_BSY when jtag_bsy = '1' else DMI_RSP_OK; | ||||
|  | ||||
|     -- Some DMI out signals are directly driven from the request register | ||||
|     dmi_addr <= request(ABITS + DBITS + 1 downto DBITS + 2); | ||||
|     dmi_dout <= request(DBITS + 1 downto 2); | ||||
|     dmi_wr   <= '1' when request(1 downto 0) = DMI_REQ_WR else '0'; | ||||
|  | ||||
|     -- TDO is wired to shift register bit 0 | ||||
|     tdo <= shiftr(0); | ||||
|  | ||||
|     -- Main state machine. Handles shift registers, request latch and | ||||
|     -- jtag_req latch. Could be split into 3 processes but it's probably | ||||
|     -- not worthwhile. | ||||
|     -- | ||||
|     shifter: process(jtag_tck, jtag_trst, sys_reset) | ||||
|     begin | ||||
| 	if jtag_trst = '1' or sys_reset = '1' then | ||||
| 	    shiftr <= (others => '0'); | ||||
| 	    jtag_req <= '0'; | ||||
| 	    request <= (others => '0'); | ||||
| 	elsif rising_edge(jtag_tck) then | ||||
|  | ||||
| 	    -- Handle jtag "commands" when sel is 1 | ||||
| 	    if sel = '1' then | ||||
| 		-- Shift state, rotate the register | ||||
| 		if shift = '1' then | ||||
| 		    shiftr <= tdi & shiftr(ABITS + DBITS + 1 downto 1); | ||||
| 		end if; | ||||
|  | ||||
| 		-- Update state (trigger) | ||||
| 		-- | ||||
| 		-- Latch the request if we aren't already processing one and | ||||
| 		-- it has a valid command opcode. | ||||
| 		-- | ||||
| 	    	if update = '1' and op_valid = '1' then | ||||
| 		    if jtag_bsy = '0' then | ||||
| 			request <= shiftr; | ||||
| 			jtag_req <= '1'; | ||||
| 		    end if; | ||||
| 		    -- Set the shift register "op" to "busy". This will prevent | ||||
| 		    -- us from re-starting the command on the next update if | ||||
| 		    -- the command completes before that. | ||||
| 		    shiftr(1 downto 0) <= DMI_RSP_BSY; | ||||
| 		end if; | ||||
|  | ||||
| 		-- Request completion. | ||||
| 		-- | ||||
| 		-- Capture the response data for reads and clear request flag. | ||||
| 		-- | ||||
| 		-- Note: We clear req (and thus dmi_req) here which relies on tck | ||||
| 		-- ticking and sel set. This means we are stuck with dmi_req up if | ||||
| 		-- the jtag interface stops. Slaves must be resilient to this. | ||||
| 		-- | ||||
| 		if jtag_req = '1' and dmi_ack_1 = '1' then | ||||
| 		    jtag_req <= '0'; | ||||
| 		    if request(1 downto 0) = DMI_REQ_RD then | ||||
| 			request(DBITS + 1 downto 2) <= dmi_din; | ||||
| 		    end if; | ||||
| 		end if; | ||||
|  | ||||
| 		-- Capture state, grab latch content with updated status | ||||
| 		if capture = '1' then | ||||
| 		    shiftr <= request(ABITS + DBITS + 1 downto 2) & rsp_op; | ||||
| 		end if; | ||||
|  | ||||
| 	    end if; | ||||
| 	end if; | ||||
|     end process; | ||||
| end architecture behaviour; | ||||
| @ -0,0 +1,640 @@ | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
| ////                                                              //// | ||||
| ////  tap_top.v                                                   //// | ||||
| ////                                                              //// | ||||
| ////                                                              //// | ||||
| ////  This file is part of the JTAG Test Access Port (TAP)        //// | ||||
| ////  http://www.opencores.org/projects/jtag/                     //// | ||||
| ////                                                              //// | ||||
| ////  Author(s):                                                  //// | ||||
| ////       Igor Mohor (igorm@opencores.org)                       //// | ||||
| ////                                                              //// | ||||
| ////                                                              //// | ||||
| ////  All additional information is avaliable in the README.txt   //// | ||||
| ////  file.                                                       //// | ||||
| ////                                                              //// | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
| ////                                                              //// | ||||
| //// Copyright (C) 2000 - 2003 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.5  2004/01/18 09:27:39  simons | ||||
| // Blocking non blocking assignmenst fixed. | ||||
| // | ||||
| // Revision 1.4  2004/01/17 17:37:44  mohor | ||||
| // capture_dr_o added to ports. | ||||
| // | ||||
| // Revision 1.3  2004/01/14 13:50:56  mohor | ||||
| // 5 consecutive TMS=1 causes reset of TAP. | ||||
| // | ||||
| // Revision 1.2  2004/01/08 10:29:44  mohor | ||||
| // Control signals for tdo_pad_o mux are changed to negedge. | ||||
| // | ||||
| // Revision 1.1  2003/12/23 14:52:14  mohor | ||||
| // Directory structure changed. New version of TAP. | ||||
| // | ||||
| // Revision 1.10  2003/10/23 18:08:01  mohor | ||||
| // MBIST chain connection fixed. | ||||
| // | ||||
| // Revision 1.9  2003/10/23 16:17:02  mohor | ||||
| // CRC logic changed. | ||||
| // | ||||
| // Revision 1.8  2003/10/21 09:48:31  simons | ||||
| // Mbist support added. | ||||
| // | ||||
| // Revision 1.7  2002/11/06 14:30:10  mohor | ||||
| // Trst active high. Inverted on higher layer. | ||||
| // | ||||
| // Revision 1.6  2002/04/22 12:55:56  mohor | ||||
| // tdo_padoen_o changed to tdo_padoe_o. Signal is active high. | ||||
| // | ||||
| // Revision 1.5  2002/03/26 14:23:38  mohor | ||||
| // Signal tdo_padoe_o changed back to tdo_padoen_o. | ||||
| // | ||||
| // Revision 1.4  2002/03/25 13:16:15  mohor | ||||
| // tdo_padoen_o changed to tdo_padoe_o. Signal was always active high, just | ||||
| // not named correctly. | ||||
| // | ||||
| // Revision 1.3  2002/03/12 14:30:05  mohor | ||||
| // Few outputs for boundary scan chain added. | ||||
| // | ||||
| // Revision 1.2  2002/03/12 10:31:53  mohor | ||||
| // tap_top and dbg_top modules are put into two separate modules. tap_top | ||||
| // contains only tap state machine and related logic. dbg_top contains all | ||||
| // logic necessery for debugging. | ||||
| // | ||||
| // Revision 1.1  2002/03/08 15:28:16  mohor | ||||
| // Structure changed. Hooks for jtag chain added. | ||||
| // | ||||
| // | ||||
| // | ||||
| // | ||||
|  | ||||
| // Top module | ||||
| module tap_top #(parameter | ||||
|                 // 0001             version | ||||
|                 // 0100100101010001 part number (IQ) | ||||
|                 // 00011100001      manufacturer id (flextronics) | ||||
|                 // 1                required by standard | ||||
|                 IDCODE_VALUE = 32'h149511c3, | ||||
|                 IR_LENGTH    = 4) | ||||
|                ( | ||||
|                 // JTAG pads | ||||
|                 tms_pad_i,  | ||||
|                 tck_pad_i,  | ||||
|                 trst_pad_i,  | ||||
|                 tdi_pad_i,  | ||||
|                 tdo_pad_o,  | ||||
|                 tdo_padoe_o, | ||||
|  | ||||
|                 // TAP states | ||||
|                 shift_dr_o, | ||||
|                 pause_dr_o,  | ||||
|                 update_dr_o, | ||||
|                 capture_dr_o, | ||||
|                  | ||||
|                 // Select signals for boundary scan or mbist | ||||
|                 extest_select_o,  | ||||
|                 sample_preload_select_o, | ||||
|                 mbist_select_o, | ||||
|                 debug_select_o, | ||||
|                  | ||||
|                 // TDO signal that is connected to TDI of sub-modules. | ||||
|                 tdo_o,  | ||||
|                  | ||||
|                 // TDI signals from sub-modules | ||||
|                 debug_tdi_i,    // from debug module | ||||
|                 bs_chain_tdi_i, // from Boundary Scan Chain | ||||
|                 mbist_tdi_i     // from Mbist Chain | ||||
|               ); | ||||
|  | ||||
|  | ||||
| // JTAG pins | ||||
| input   tms_pad_i;      // JTAG test mode select pad | ||||
| input   tck_pad_i;      // JTAG test clock pad | ||||
| input   trst_pad_i;     // JTAG test reset pad | ||||
| input   tdi_pad_i;      // JTAG test data input pad | ||||
| output  tdo_pad_o;      // JTAG test data output pad | ||||
| output  tdo_padoe_o;    // Output enable for JTAG test data output pad  | ||||
|  | ||||
| // TAP states | ||||
| output  shift_dr_o; | ||||
| output  pause_dr_o; | ||||
| output  update_dr_o; | ||||
| output  capture_dr_o; | ||||
|  | ||||
| // Select signals for boundary scan or mbist | ||||
| output  extest_select_o; | ||||
| output  sample_preload_select_o; | ||||
| output  mbist_select_o; | ||||
| output  debug_select_o; | ||||
|  | ||||
| // TDO signal that is connected to TDI of sub-modules. | ||||
| output  tdo_o; | ||||
|  | ||||
| // TDI signals from sub-modules | ||||
| input   debug_tdi_i;    // from debug module | ||||
| input   bs_chain_tdi_i; // from Boundary Scan Chain | ||||
| input   mbist_tdi_i;    // from Mbist Chain | ||||
|  | ||||
| //Internal constants | ||||
| localparam EXTEST         = 4'b0000; | ||||
| localparam SAMPLE_PRELOAD = 4'b0001; | ||||
| localparam IDCODE         = 4'b0010; | ||||
| localparam DEBUG          = 4'b1000; | ||||
| localparam MBIST          = 4'b1001; | ||||
| localparam BYPASS         = 4'b1111; | ||||
|  | ||||
| // Registers | ||||
| reg     test_logic_reset; | ||||
| reg     run_test_idle; | ||||
| reg     select_dr_scan; | ||||
| reg     capture_dr; | ||||
| reg     shift_dr; | ||||
| reg     exit1_dr; | ||||
| reg     pause_dr; | ||||
| reg     exit2_dr; | ||||
| reg     update_dr; | ||||
| reg     select_ir_scan; | ||||
| reg     capture_ir; | ||||
| reg     shift_ir, shift_ir_neg; | ||||
| reg     exit1_ir; | ||||
| reg     pause_ir; | ||||
| reg     exit2_ir; | ||||
| reg     update_ir; | ||||
| reg     extest_select; | ||||
| reg     sample_preload_select; | ||||
| reg     idcode_select; | ||||
| reg     mbist_select; | ||||
| reg     debug_select; | ||||
| reg     bypass_select; | ||||
| reg     tdo_pad_o; | ||||
| reg     tdo_padoe_o; | ||||
| reg     tms_q1, tms_q2, tms_q3, tms_q4; | ||||
| wire    tms_reset; | ||||
|  | ||||
| assign tdo_o = tdi_pad_i; | ||||
| assign shift_dr_o = shift_dr; | ||||
| assign pause_dr_o = pause_dr; | ||||
| assign update_dr_o = update_dr; | ||||
| assign capture_dr_o = capture_dr; | ||||
|  | ||||
| assign extest_select_o = extest_select; | ||||
| assign sample_preload_select_o = sample_preload_select; | ||||
| assign mbist_select_o = mbist_select; | ||||
| assign debug_select_o = debug_select; | ||||
|  | ||||
|  | ||||
| always @ (posedge tck_pad_i) | ||||
| begin | ||||
|   tms_q1 <= tms_pad_i; | ||||
|   tms_q2 <= tms_q1; | ||||
|   tms_q3 <= tms_q2; | ||||
|   tms_q4 <= tms_q3; | ||||
| end | ||||
|  | ||||
|  | ||||
| assign tms_reset = tms_q1 & tms_q2 & tms_q3 & tms_q4 & tms_pad_i;    // 5 consecutive TMS=1 causes reset | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   TAP State Machine: Fully JTAG compliant                                       * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
| // test_logic_reset state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     test_logic_reset<= 1'b1; | ||||
|   else if (tms_reset) | ||||
|     test_logic_reset<= 1'b1; | ||||
|   else | ||||
|     begin | ||||
|       if(tms_pad_i & (test_logic_reset | select_ir_scan)) | ||||
|         test_logic_reset<= 1'b1; | ||||
|       else | ||||
|         test_logic_reset<= 1'b0; | ||||
|     end | ||||
| end | ||||
|  | ||||
| // run_test_idle state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     run_test_idle<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     run_test_idle<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & (test_logic_reset | run_test_idle | update_dr | update_ir)) | ||||
|     run_test_idle<= 1'b1; | ||||
|   else | ||||
|     run_test_idle<= 1'b0; | ||||
| end | ||||
|  | ||||
| // select_dr_scan state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     select_dr_scan<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     select_dr_scan<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & (run_test_idle | update_dr | update_ir)) | ||||
|     select_dr_scan<= 1'b1; | ||||
|   else | ||||
|     select_dr_scan<= 1'b0; | ||||
| end | ||||
|  | ||||
| // capture_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     capture_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     capture_dr<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & select_dr_scan) | ||||
|     capture_dr<= 1'b1; | ||||
|   else | ||||
|     capture_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // shift_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     shift_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     shift_dr<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & (capture_dr | shift_dr | exit2_dr)) | ||||
|     shift_dr<= 1'b1; | ||||
|   else | ||||
|     shift_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // exit1_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     exit1_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     exit1_dr<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & (capture_dr | shift_dr)) | ||||
|     exit1_dr<= 1'b1; | ||||
|   else | ||||
|     exit1_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // pause_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     pause_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     pause_dr<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & (exit1_dr | pause_dr)) | ||||
|     pause_dr<= 1'b1; | ||||
|   else | ||||
|     pause_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // exit2_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     exit2_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     exit2_dr<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & pause_dr) | ||||
|     exit2_dr<= 1'b1; | ||||
|   else | ||||
|     exit2_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // update_dr state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     update_dr<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     update_dr<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & (exit1_dr | exit2_dr)) | ||||
|     update_dr<= 1'b1; | ||||
|   else | ||||
|     update_dr<= 1'b0; | ||||
| end | ||||
|  | ||||
| // select_ir_scan state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     select_ir_scan<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     select_ir_scan<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & select_dr_scan) | ||||
|     select_ir_scan<= 1'b1; | ||||
|   else | ||||
|     select_ir_scan<= 1'b0; | ||||
| end | ||||
|  | ||||
| // capture_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     capture_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     capture_ir<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & select_ir_scan) | ||||
|     capture_ir<= 1'b1; | ||||
|   else | ||||
|     capture_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| // shift_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     shift_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     shift_ir<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & (capture_ir | shift_ir | exit2_ir)) | ||||
|     shift_ir<= 1'b1; | ||||
|   else | ||||
|     shift_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| // exit1_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     exit1_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     exit1_ir<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & (capture_ir | shift_ir)) | ||||
|     exit1_ir<= 1'b1; | ||||
|   else | ||||
|     exit1_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| // pause_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     pause_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     pause_ir<= 1'b0; | ||||
|   else | ||||
|   if(~tms_pad_i & (exit1_ir | pause_ir)) | ||||
|     pause_ir<= 1'b1; | ||||
|   else | ||||
|     pause_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| // exit2_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     exit2_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     exit2_ir<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & pause_ir) | ||||
|     exit2_ir<= 1'b1; | ||||
|   else | ||||
|     exit2_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| // update_ir state | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     update_ir<= 1'b0; | ||||
|   else if (tms_reset) | ||||
|     update_ir<= 1'b0; | ||||
|   else | ||||
|   if(tms_pad_i & (exit1_ir | exit2_ir)) | ||||
|     update_ir<= 1'b1; | ||||
|   else | ||||
|     update_ir<= 1'b0; | ||||
| end | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: TAP State Machine                                                        * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   jtag_ir:  JTAG Instruction Register                                           * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
| reg [IR_LENGTH-1:0]  jtag_ir;          // Instruction register | ||||
| reg [IR_LENGTH-1:0]  latched_jtag_ir, latched_jtag_ir_neg; | ||||
| reg                   instruction_tdo; | ||||
|  | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     jtag_ir[IR_LENGTH-1:0] <= {IR_LENGTH{1'b0}}; | ||||
|   else if(capture_ir) | ||||
|     jtag_ir <= 4'b0101;          // This value is fixed for easier fault detection | ||||
|   else if(shift_ir) | ||||
|     jtag_ir[IR_LENGTH-1:0] <= {tdi_pad_i, jtag_ir[IR_LENGTH-1:1]}; | ||||
| end | ||||
|  | ||||
| always @ (negedge tck_pad_i) | ||||
| begin | ||||
|   instruction_tdo <= jtag_ir[0]; | ||||
| end | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: jtag_ir                                                                  * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   idcode logic                                                                  * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
| reg [31:0] idcode_reg; | ||||
| reg        idcode_tdo; | ||||
|  | ||||
| always @ (posedge tck_pad_i) | ||||
| begin | ||||
|   if(idcode_select & shift_dr) | ||||
|     idcode_reg <= {tdi_pad_i, idcode_reg[31:1]}; | ||||
|   else | ||||
|     idcode_reg <= IDCODE_VALUE; | ||||
| end | ||||
|  | ||||
| always @ (negedge tck_pad_i) | ||||
| begin | ||||
|     idcode_tdo <= idcode_reg[0]; | ||||
| end | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: idcode logic                                                             * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   Bypass logic                                                                  * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
| reg  bypassed_tdo; | ||||
| reg  bypass_reg; | ||||
|  | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if (trst_pad_i) | ||||
|     bypass_reg<= 1'b0; | ||||
|   else if(shift_dr) | ||||
|     bypass_reg<= tdi_pad_i; | ||||
| end | ||||
|  | ||||
| always @ (negedge tck_pad_i) | ||||
| begin | ||||
|   bypassed_tdo <= bypass_reg; | ||||
| end | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: Bypass logic                                                             * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   Activating Instructions                                                       * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
| // Updating jtag_ir (Instruction Register) | ||||
| always @ (posedge tck_pad_i or posedge trst_pad_i) | ||||
| begin | ||||
|   if(trst_pad_i) | ||||
|     latched_jtag_ir <= IDCODE;   // IDCODE selected after reset | ||||
|   else if (tms_reset) | ||||
|     latched_jtag_ir <= IDCODE;   // IDCODE selected after reset | ||||
|   else if(update_ir) | ||||
|     latched_jtag_ir <= jtag_ir; | ||||
| end | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: Activating Instructions                                                  * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
| // Updating jtag_ir (Instruction Register) | ||||
| always @ (latched_jtag_ir) | ||||
| begin | ||||
|   extest_select           = 1'b0; | ||||
|   sample_preload_select   = 1'b0; | ||||
|   idcode_select           = 1'b0; | ||||
|   mbist_select            = 1'b0; | ||||
|   debug_select            = 1'b0; | ||||
|   bypass_select           = 1'b0; | ||||
|  | ||||
|   case(latched_jtag_ir)    /* synthesis parallel_case */  | ||||
|     EXTEST:            extest_select           = 1'b1;    // External test | ||||
|     SAMPLE_PRELOAD:    sample_preload_select   = 1'b1;    // Sample preload | ||||
|     IDCODE:            idcode_select           = 1'b1;    // ID Code | ||||
|     MBIST:             mbist_select            = 1'b1;    // Mbist test | ||||
|     DEBUG:             debug_select            = 1'b1;    // Debug | ||||
|     BYPASS:            bypass_select           = 1'b1;    // BYPASS | ||||
|     default:            bypass_select           = 1'b1;    // BYPASS | ||||
|   endcase | ||||
| end | ||||
|  | ||||
|  | ||||
|  | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   Multiplexing TDO data                                                         * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
| always @ (shift_ir_neg or exit1_ir or instruction_tdo or latched_jtag_ir_neg or idcode_tdo or | ||||
|           debug_tdi_i or bs_chain_tdi_i or mbist_tdi_i or  | ||||
|           bypassed_tdo) | ||||
| begin | ||||
|   if(shift_ir_neg) | ||||
|     tdo_pad_o = instruction_tdo; | ||||
|   else | ||||
|     begin | ||||
|       case(latched_jtag_ir_neg)    // synthesis parallel_case | ||||
|         IDCODE:            tdo_pad_o = idcode_tdo;       // Reading ID code | ||||
|         DEBUG:             tdo_pad_o = debug_tdi_i;      // Debug | ||||
|         SAMPLE_PRELOAD:    tdo_pad_o = bs_chain_tdi_i;   // Sampling/Preloading | ||||
|         EXTEST:            tdo_pad_o = bs_chain_tdi_i;   // External test | ||||
|         MBIST:             tdo_pad_o = mbist_tdi_i;      // Mbist test | ||||
|         default:            tdo_pad_o = bypassed_tdo;     // BYPASS instruction | ||||
|       endcase | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| // Tristate control for tdo_pad_o pin | ||||
| always @ (negedge tck_pad_i) | ||||
| begin | ||||
|   tdo_padoe_o <= shift_ir | shift_dr | (pause_dr & debug_select); | ||||
| end | ||||
| /********************************************************************************** | ||||
| *                                                                                 * | ||||
| *   End: Multiplexing TDO data                                                    * | ||||
| *                                                                                 * | ||||
| **********************************************************************************/ | ||||
|  | ||||
|  | ||||
| always @ (negedge tck_pad_i) | ||||
| begin | ||||
|   shift_ir_neg <= shift_ir; | ||||
|   latched_jtag_ir_neg <= latched_jtag_ir; | ||||
| end | ||||
|  | ||||
|  | ||||
| endmodule | ||||
| @ -0,0 +1,196 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdint.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #undef DEBUG | ||||
|  | ||||
| /* XXX Make that some parameter */ | ||||
| #define TCP_PORT	13245 | ||||
|  | ||||
| static int fd = -1; | ||||
| static int cfd = -1; | ||||
|  | ||||
| static void open_socket(void) | ||||
| { | ||||
| 	struct sockaddr_in addr; | ||||
| 	int opt, rc, flags; | ||||
|  | ||||
| 	if (fd >= 0 || fd < -1) | ||||
| 		return; | ||||
|  | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	fd = socket(AF_INET, SOCK_STREAM, 0); | ||||
| 	if (fd < 0) { | ||||
| 		fprintf(stderr, "Failed to open debug socket\r\n"); | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	rc = 0; | ||||
| 	flags = fcntl(fd, F_GETFL); | ||||
| 	if (flags >= 0) | ||||
| 		rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK); | ||||
| 	if (flags < 0 || rc < 0) { | ||||
| 		fprintf(stderr, "Failed to configure debug socket\r\n"); | ||||
| 	} | ||||
|  | ||||
| 	memset(&addr, 0, sizeof(addr)); | ||||
| 	addr.sin_family = AF_INET; | ||||
| 	addr.sin_port = htons(TCP_PORT); | ||||
| 	addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||||
| 	opt = 1; | ||||
| 	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | ||||
| 	rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); | ||||
| 	if (rc < 0) { | ||||
| 		fprintf(stderr, "Failed to bind debug socket\r\n"); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	rc = listen(fd,1); | ||||
| 	if (rc < 0) { | ||||
| 		fprintf(stderr, "Failed to listen to debug socket\r\n"); | ||||
| 		goto fail; | ||||
| 	} | ||||
| #ifdef DEBUG | ||||
| 	fprintf(stdout, "Debug socket ready\r\n"); | ||||
| #endif | ||||
| 	return; | ||||
| fail: | ||||
| 	if (fd >= 0) | ||||
| 		close(fd); | ||||
| 	fd = -2; | ||||
| } | ||||
|  | ||||
| static void check_connection(void) | ||||
| { | ||||
| 	struct sockaddr_in addr; | ||||
| 	socklen_t addr_len = sizeof(addr); | ||||
|  | ||||
| 	cfd = accept(fd, (struct sockaddr *)&addr, &addr_len); | ||||
| 	if (cfd < 0) | ||||
| 		return; | ||||
| #ifdef DEBUG | ||||
| 	fprintf(stdout, "Debug client connected\r\n"); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static bool read_one_byte(char *c) | ||||
| { | ||||
| 	struct pollfd fdset[1]; | ||||
| 	int rc; | ||||
|  | ||||
| 	if (fd == -1) | ||||
| 		open_socket(); | ||||
| 	if (fd < 0) | ||||
| 		return false; | ||||
| 	if (cfd < 0) | ||||
| 		check_connection(); | ||||
| 	if (cfd < 0) | ||||
| 		return false; | ||||
|  | ||||
| 	memset(fdset, 0, sizeof(fdset)); | ||||
| 	fdset[0].fd = cfd; | ||||
| 	fdset[0].events = POLLIN; | ||||
| 	rc = poll(fdset, 1, 0); | ||||
| 	if (rc <= 0) | ||||
| 		return false; | ||||
| 	rc = read(cfd, c, 1); | ||||
| 	if (rc != 1) { | ||||
| #ifdef DEBUG | ||||
| 		fprintf(stdout, "Debug read error, assuming client disconnected !\r\n"); | ||||
| #endif | ||||
| 		close(cfd); | ||||
| 		cfd = -1; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	fprintf(stdout, "Got message: %c\n", *c); | ||||
| #endif | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static void write_one_byte(char c) | ||||
| { | ||||
| 	int rc; | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	fprintf(stdout, "Sending message: %c\r\n", c); | ||||
| #endif | ||||
|  | ||||
| 	rc = write(cfd, &c, 1); | ||||
| 	if (rc != 1) { | ||||
| #ifdef DEBUG | ||||
| 		fprintf(stdout, "JTAG write error, disconnecting\r\n"); | ||||
| #endif | ||||
| 		close(cfd); | ||||
| 		cfd = -1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| struct jtag_in { | ||||
| 	uint8_t tck; | ||||
| 	uint8_t tms; | ||||
| 	uint8_t tdi; | ||||
| 	uint8_t trst; | ||||
| }; | ||||
|  | ||||
| static struct jtag_in jtag_in; | ||||
|  | ||||
| struct jtag_in jtag_one_cycle(uint8_t tdo) | ||||
| { | ||||
| 	char c; | ||||
|  | ||||
| 	if (read_one_byte(&c) == false) | ||||
| 		goto out; | ||||
|  | ||||
| 	// Write request | ||||
| 	if ((c >= '0') && (c <= '7')) { | ||||
| 		uint8_t val = c - '0'; | ||||
|  | ||||
| 		jtag_in.tck = (val >> 2) & 1; | ||||
| 		jtag_in.tms = (val >> 1) & 1; | ||||
| 		jtag_in.tdi = (val >> 0) & 1; | ||||
|  | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	// Reset request | ||||
| 	if ((c >= 'r') && (c <= 'u')) { | ||||
| 		uint8_t val = c - 'r'; | ||||
|  | ||||
| 		jtag_in.trst = (val >> 1) & 1; | ||||
| 	} | ||||
|  | ||||
| 	switch (c) { | ||||
| 		case 'B':	// Blink on | ||||
| 		case 'b':	// Blink off | ||||
| 			goto out; | ||||
|  | ||||
| 		case 'R':	// Read request | ||||
| 			write_one_byte(tdo + '0'); | ||||
| 			goto out; | ||||
|  | ||||
| 		case 'Q':	// Quit request | ||||
| #ifdef DEBUG | ||||
| 			fprintf(stdout, "Disconnecting JTAG\r\n"); | ||||
| #endif | ||||
| 			close(cfd); | ||||
| 			cfd = -1; | ||||
| 			goto out; | ||||
|  | ||||
| 		default: | ||||
| 			fprintf(stderr, "Unknown JTAG command %c\r\n", c); | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	return jtag_in; | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue