├── .gitignore ├── sim ├── ghdl.sh ├── wave_config.gtkw └── cjtag_bridge_tb.vhd ├── LICENSE ├── README.md └── rtl └── cjtag_bridge.vhd /.gitignore: -------------------------------------------------------------------------------- 1 | sim/*.cf 2 | sim/*.ghw 3 | sim/*.vcd 4 | -------------------------------------------------------------------------------- /sim/ghdl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # Analyse sources 6 | ghdl -a ../rtl/cjtag_bridge.vhd 7 | ghdl -a cjtag_bridge_tb.vhd 8 | 9 | # Elaborate top entity 10 | ghdl -e cjtag_bridge_tb 11 | 12 | # Run simulation 13 | ghdl -e cjtag_bridge_tb 14 | ghdl -r cjtag_bridge_tb --stop-time=1ms --wave=cjtag_bridge.ghw 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Stephan Nolting 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :electric_plug: Compact-JTAG to 4-Wire JTAG Bridge 2 | 3 | [![license](https://img.shields.io/github/license/stnolting/cjtag_bridge)](https://github.com/stnolting/cjtag_bridge/blob/main/LICENSE) 4 | 5 | * [Top Entity](#Top-Entity) 6 | * [Simulation](#Simulation) 7 | * [Hardware Utilization](#Hardware-Utilization) 8 | * [Resources](#Resources) 9 | 10 | This bridge implements a simple converter to connect _compact JTAG_ (cJTAG) probes to IEEE 1149.1 4-wire JTAG device. 11 | cJTAG only uses two wires: a uni-directional clock generated by the probe (TCKC) and a bi-directional data signal (TMSC). 12 | 13 | :information_source: This bridge only supports the **OScan1** cJTAG format yet. 14 | 15 | :warning: **This project is still _work-in-progress_**. 16 | 17 | 18 | ## Top Entity 19 | 20 | The top entity is [`rtl/cjtag_bridge.vhd`](https://github.com/stnolting/cjtag_bridge/blob/main/rtl/cjtag_bridge.vhd): 21 | 22 | ```vhdl 23 | entity cjtag_bridge is 24 | port ( 25 | -- global control -- 26 | clk_i : in std_ulogic; -- main clock 27 | rstn_i : in std_ulogic; -- main reset, async, low-active 28 | -- cJTAG (from debug probe) -- 29 | tckc_i : in std_ulogic; -- tap clock 30 | tmsc_i : in std_ulogic; -- tap data input 31 | tmsc_o : out std_ulogic; -- tap data output 32 | tmsc_oe_o : out std_ulogic; -- tap data output enable (tri-state driver) 33 | -- JTAG (to device) -- 34 | tck_o : out std_ulogic; -- tap clock 35 | tdi_o : out std_ulogic; -- tap data input 36 | tdo_i : in std_ulogic; -- tap data output 37 | tms_o : out std_ulogic -- tap mode select 38 | ); 39 | end cjtag_bridge; 40 | ``` 41 | 42 | :information_source: The cJTAG clock frequency (TCKC signal) must not exceed 1/5 of the main clock (`clk_i` signal) frequency. 43 | 44 | :information_source: All 4-wire JTAG signals are expected to be sync to `clk_i` (same clock domain). 45 | 46 | :information_source: The debug signals `db_*` are intended for testing/development only. 47 | 48 | ### Hardware Requirements 49 | 50 | The bridge requires a module-external tri-state driver for the off-chip TMSC signal (`tmsc`), which handles the module's 51 | `tmsc_i`, `tmsc_o` and `tmsc_oe_o` signals: 52 | 53 | ```vhdl 54 | -- TMSC tri-state driver -- 55 | tmsc <= tmsc_o when (tmsc_oe_o = '1') else 'Z'; 56 | tmsc_i <= tmsc; 57 | ``` 58 | 59 | :warning: Better add a "panic resistor" into the bi-directional TMSC line - just to be safe. 60 | 61 | 62 | ## Simulation 63 | 64 | The projects provides a very simple testbench to test the basic IO functions 65 | ([`sim/cjtag_bridge_tb.vhd`](https://github.com/stnolting/cjtag_bridge/blob/main/sim/cjtag_bridge_tb.vhd)). 66 | It can be simulated by GHDL via the provided script: 67 | 68 | ``` 69 | cjtag_bridge/sim$ sh ghdl.sh 70 | ``` 71 | 72 | The simulation will run for 1ms using a 100MHz clock. The waveform data is stored to `sim/cjtag_bridge.ghw` 73 | so it can be viewed using _gtkwave_: 74 | 75 | ``` 76 | cjtag_bridge/sim$ gtkwave cjtag_bridge.ghw 77 | ``` 78 | 79 | A pre-defined waveform configuration file is also provided: `sim/wave_config.gtkw` 80 | 81 | 82 | ## Hardware Utilization 83 | 84 | :construction: TODO :construction: 85 | 86 | 87 | ## Resources 88 | 89 | * [MIPS® cJTAG Adapter User’s Manual](https://s3-eu-west-1.amazonaws.com/downloads-mips/mips-documentation/login-required/mips_cjtag_adapter_users_manual.pdf) 90 | * [https://sudonull.com/post/106128-We-disassemble-the-2-wire-JTAG-protocol](https://sudonull.com/post/106128-We-disassemble-the-2-wire-JTAG-protocol) 91 | * [https://wiki.segger.com/J-Link_cJTAG_specifics](https://wiki.segger.com/J-Link_cJTAG_specifics) 92 | -------------------------------------------------------------------------------- /sim/wave_config.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sun Dec 19 20:00:06 2021 4 | [*] 5 | [dumpfile] "/mnt/n/Projects/cjtag_bridge/sim/cjtag_bridge.ghw" 6 | [dumpfile_mtime] "Sun Dec 19 19:57:56 2021" 7 | [dumpfile_size] 702784 8 | [savefile] "/mnt/n/Projects/cjtag_bridge/sim/wave_config.gtkw" 9 | [timestart] 8004000000 10 | [size] 1366 745 11 | [pos] -1 -1 12 | *-30.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] top. 14 | [treeopen] top.cjtag_bridge_tb. 15 | [treeopen] top.cjtag_bridge_tb.cjtag_bridge_inst. 16 | [treeopen] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync. 17 | [treeopen] top.cjtag_bridge_tb.cjtag_bridge_inst.reset. 18 | [treeopen] top.cjtag_bridge_tb.cjtag_bridge_inst.status. 19 | [sst_width] 192 20 | [signals_width] 132 21 | [sst_expanded] 1 22 | [sst_vpaned_height] 209 23 | @200 24 | -cJTAG 25 | @28 26 | top.cjtag_bridge_tb.cjtag_bridge_inst.tckc_i 27 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_i 28 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_o 29 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_oe_o 30 | @200 31 | -JTAG 32 | @29 33 | top.cjtag_bridge_tb.cjtag_bridge_inst.tck_o 34 | @28 35 | top.cjtag_bridge_tb.cjtag_bridge_inst.tms_o 36 | top.cjtag_bridge_tb.cjtag_bridge_inst.tdi_o 37 | top.cjtag_bridge_tb.cjtag_bridge_inst.tdo_i 38 | @200 39 | -Global 40 | @28 41 | top.cjtag_bridge_tb.cjtag_bridge_inst.rstn_i 42 | top.cjtag_bridge_tb.cjtag_bridge_inst.clk_i 43 | @200 44 | -IO SYNC 45 | @28 46 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[2] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[1] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[0] 47 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[2] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[1] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[0] 48 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_falling 49 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_rising 50 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_falling 51 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_rising 52 | @200 53 | -RESET 54 | @28 55 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[2] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[1] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[0] 56 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[1:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[1] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[0] 57 | top.cjtag_bridge_tb.cjtag_bridge_inst.reset.fire 58 | @200 59 | -STATUS 60 | @22 61 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[11:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[11] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[10] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[9] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[8] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[7] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[6] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[5] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[4] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[3] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[2] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[1] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[0] 62 | @28 63 | top.cjtag_bridge_tb.cjtag_bridge_inst.status.online 64 | @200 65 | -CTRL 66 | @420 67 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.state 68 | @28 69 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tms 70 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tdi 71 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tck 72 | @200 73 | -cJTAG 74 | @28 75 | top.cjtag_bridge_tb.cjtag_bridge_inst.tckc_i 76 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_i 77 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_o 78 | top.cjtag_bridge_tb.cjtag_bridge_inst.tmsc_oe_o 79 | @200 80 | -JTAG 81 | @28 82 | top.cjtag_bridge_tb.cjtag_bridge_inst.tck_o 83 | top.cjtag_bridge_tb.cjtag_bridge_inst.tms_o 84 | top.cjtag_bridge_tb.cjtag_bridge_inst.tdi_o 85 | top.cjtag_bridge_tb.cjtag_bridge_inst.tdo_i 86 | @200 87 | -Global 88 | @28 89 | top.cjtag_bridge_tb.cjtag_bridge_inst.rstn_i 90 | top.cjtag_bridge_tb.cjtag_bridge_inst.clk_i 91 | @200 92 | -IO SYNC 93 | @28 94 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[2] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[1] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_ff[0] 95 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[2] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[1] top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_ff[0] 96 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_falling 97 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tmsc_rising 98 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_falling 99 | top.cjtag_bridge_tb.cjtag_bridge_inst.io_sync.tckc_rising 100 | @200 101 | -RESET 102 | @28 103 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[2:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[2] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[1] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.cnt[0] 104 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[1:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[1] top.cjtag_bridge_tb.cjtag_bridge_inst.reset.sreg[0] 105 | top.cjtag_bridge_tb.cjtag_bridge_inst.reset.fire 106 | @200 107 | -STATUS 108 | @22 109 | #{top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[11:0]} top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[11] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[10] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[9] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[8] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[7] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[6] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[5] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[4] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[3] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[2] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[1] top.cjtag_bridge_tb.cjtag_bridge_inst.status.sreg[0] 110 | @28 111 | top.cjtag_bridge_tb.cjtag_bridge_inst.status.online 112 | @200 113 | -CTRL 114 | @421 115 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.state 116 | @28 117 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tms 118 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tdi 119 | top.cjtag_bridge_tb.cjtag_bridge_inst.ctrl.tck 120 | [pattern_trace] 1 121 | [pattern_trace] 0 122 | -------------------------------------------------------------------------------- /sim/cjtag_bridge_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity cjtag_bridge_tb is 6 | end cjtag_bridge_tb; 7 | 8 | architecture cjtag_bridge_tb_rtl of cjtag_bridge_tb is 9 | 10 | -- output bits on TMSC -- 11 | procedure WriteEscapeSeq(cycles : natural) is 12 | begin 13 | for i in 0 to cycles-1 loop 14 | 15 | end loop; 16 | end procedure; 17 | 18 | -- dut -- 19 | component cjtag_bridge 20 | port ( 21 | -- global control -- 22 | clk_i : in std_ulogic; 23 | rstn_i : in std_ulogic; 24 | -- cJTAG -- 25 | tckc_i : in std_ulogic; 26 | tmsc_i : in std_ulogic; 27 | tmsc_o : out std_ulogic; 28 | tmsc_oe_o : out std_ulogic; 29 | -- JTAG -- 30 | tck_o : out std_ulogic; 31 | tdi_o : out std_ulogic; 32 | tdo_i : in std_ulogic; 33 | tms_o : out std_ulogic; 34 | -- Debugging (for testing only) -- 35 | db_tck_rising_o : out std_ulogic; 36 | db_tck_falling_o : out std_ulogic 37 | ); 38 | end component; 39 | 40 | -- generators -- 41 | signal clk_gen, rstn_gen : std_ulogic := '0'; 42 | 43 | -- cJTAG interface -- 44 | type cjtag_t is record 45 | tckc : std_ulogic; 46 | tmsc : std_ulogic; 47 | tmsc_rd : std_ulogic; 48 | end record; 49 | signal cjtag : cjtag_t; 50 | 51 | begin 52 | 53 | -- Generators ----------------------------------------------------------------------------- 54 | -- ------------------------------------------------------------------------------------------- 55 | clk_gen <= not clk_gen after 10 ns; 56 | rstn_gen <= '0', '1' after 60 ns; 57 | 58 | 59 | -- Device-under-Test ---------------------------------------------------------------------- 60 | -- ------------------------------------------------------------------------------------------- 61 | cjtag_bridge_inst: cjtag_bridge 62 | port map ( 63 | -- global control -- 64 | clk_i => clk_gen, 65 | rstn_i => rstn_gen, 66 | -- cJTAG -- 67 | tckc_i => cjtag.tckc, 68 | tmsc_i => cjtag.tmsc, 69 | tmsc_o => cjtag.tmsc_rd, 70 | tmsc_oe_o => open, 71 | -- JTAG -- 72 | tck_o => open, 73 | tdi_o => open, 74 | tdo_i => '0', 75 | tms_o => open, 76 | -- Debugging (for testing only) -- 77 | db_tck_rising_o => open, 78 | db_tck_falling_o => open 79 | ); 80 | 81 | 82 | -- Stimulus ------------------------------------------------------------------------------- 83 | -- ------------------------------------------------------------------------------------------- 84 | stimulus: process 85 | begin 86 | cjtag.tckc <= '0'; 87 | cjtag.tmsc <= '0'; 88 | wait for 200 ns; 89 | 90 | -- WriteEscapeSeq(10); -- 91 | -- protocol reset: 10 TMSC edges while TCKC is kept high -- 92 | cjtag.tckc <= '1'; 93 | cjtag.tmsc <= '0'; 94 | wait for 100 ns; 95 | for i in 0 to 9 loop 96 | cjtag.tmsc <= not cjtag.tmsc; 97 | wait for 100 ns; 98 | end loop; 99 | 100 | -- WriteTMS(0xFFFFFFFF, xx); -- 101 | -- send >= 22 dummy clocks to reset 4-wire JTAG -- 102 | cjtag.tmsc <= '1'; 103 | wait for 100 ns; 104 | for i in 0 to 22*2 loop 105 | cjtag.tckc <= not cjtag.tckc; 106 | wait for 100 ns; 107 | end loop; 108 | 109 | -- WriteTMS(0x00, 1); -- 110 | -- TAP reset -- 111 | cjtag.tckc <= '0'; 112 | cjtag.tmsc <= '0'; 113 | wait for 100 ns; 114 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 115 | wait for 100 ns; 116 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 117 | wait for 100 ns; 118 | 119 | -- WriteEscapeSeq(7); -- 120 | -- escape sequence selection -- 121 | cjtag.tckc <= '1'; 122 | cjtag.tmsc <= '0'; 123 | wait for 100 ns; 124 | for i in 0 to 6 loop 125 | cjtag.tmsc <= not cjtag.tmsc; 126 | wait for 100 ns; 127 | end loop; 128 | 129 | -- WriteTMS(0x0C, 4); -- 130 | -- write 4-bit OAC -- 131 | cjtag.tckc <= '0'; 132 | cjtag.tmsc <= '0'; 133 | wait for 100 ns; 134 | 135 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 136 | wait for 100 ns; 137 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 138 | wait for 100 ns; 139 | 140 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 141 | wait for 100 ns; 142 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 143 | wait for 100 ns; 144 | 145 | cjtag.tckc <= '1'; cjtag.tmsc <= '1'; 146 | wait for 100 ns; 147 | cjtag.tckc <= '0'; cjtag.tmsc <= '1'; 148 | wait for 100 ns; 149 | 150 | cjtag.tckc <= '1'; cjtag.tmsc <= '1'; 151 | wait for 100 ns; 152 | cjtag.tckc <= '0'; cjtag.tmsc <= '1'; 153 | wait for 100 ns; 154 | 155 | -- WriteTMS(0x08, 4); -- 156 | -- write 4-bit EC -- 157 | cjtag.tckc <= '0'; 158 | cjtag.tmsc <= '0'; 159 | wait for 100 ns; 160 | 161 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 162 | wait for 100 ns; 163 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 164 | wait for 100 ns; 165 | 166 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 167 | wait for 100 ns; 168 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 169 | wait for 100 ns; 170 | 171 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 172 | wait for 100 ns; 173 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 174 | wait for 100 ns; 175 | 176 | cjtag.tckc <= '1'; cjtag.tmsc <= '1'; 177 | wait for 100 ns; 178 | cjtag.tckc <= '0'; cjtag.tmsc <= '1'; 179 | wait for 100 ns; 180 | 181 | -- WriteTMS(0x00, 4); -- 182 | -- write 4-bit CP -- 183 | cjtag.tckc <= '0'; 184 | cjtag.tmsc <= '0'; 185 | wait for 100 ns; 186 | 187 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 188 | wait for 100 ns; 189 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 190 | wait for 100 ns; 191 | 192 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 193 | wait for 100 ns; 194 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 195 | wait for 100 ns; 196 | 197 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 198 | wait for 100 ns; 199 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 200 | wait for 100 ns; 201 | 202 | cjtag.tckc <= '1'; cjtag.tmsc <= '0'; 203 | wait for 100 ns; 204 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 205 | wait for 100 ns; 206 | 207 | wait for 200 ns; 208 | 209 | -- JTAG transmission -- 210 | -- TDI=1, TMS=1 211 | cjtag.tmsc <= '0'; 212 | wait for 100 ns; 213 | cjtag.tckc <= '1'; 214 | wait for 100 ns; 215 | cjtag.tckc <= '0'; cjtag.tmsc <= '1'; 216 | wait for 100 ns; 217 | cjtag.tckc <= '1'; 218 | wait for 100 ns; 219 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 220 | wait for 100 ns; 221 | cjtag.tckc <= '1'; 222 | wait for 100 ns; 223 | cjtag.tckc <= '0'; 224 | wait for 100 ns; 225 | 226 | -- JTAG transmission -- 227 | -- TDI=0, TMS=0 228 | cjtag.tmsc <= '1'; 229 | wait for 100 ns; 230 | cjtag.tckc <= '1'; 231 | wait for 100 ns; 232 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 233 | wait for 100 ns; 234 | cjtag.tckc <= '1'; 235 | wait for 100 ns; 236 | cjtag.tckc <= '0'; cjtag.tmsc <= '0'; 237 | wait for 100 ns; 238 | cjtag.tckc <= '1'; 239 | wait for 100 ns; 240 | cjtag.tckc <= '0'; 241 | wait for 100 ns; 242 | 243 | 244 | wait; 245 | end process stimulus; 246 | 247 | 248 | end cjtag_bridge_tb_rtl; 249 | -------------------------------------------------------------------------------- /rtl/cjtag_bridge.vhd: -------------------------------------------------------------------------------- 1 | -- ################################################################################################# 2 | -- # <> cJTAG to 4-Wire JTAG Bridge # 3 | -- # ********************************************************************************************* # 4 | -- # Converts a debugger probe's compact JTAG (cJTAG) port into a 4-wire IEEE 1149.1 JTAG port. # 5 | -- # This bridge only supports "OScan1" cJTAG format. # 6 | -- # # 7 | -- # IMPORTANT # 8 | -- # * TCKC (tckc_i) input frequency must not exceed 1/5 of clk_i frequency # 9 | -- # * all 4-wire JTAG signals are expected to be sync to clk_i # 10 | -- # ********************************************************************************************* # 11 | -- # BSD 3-Clause License # 12 | -- # # 13 | -- # Copyright (c) 2021, Stephan Nolting. All rights reserved. # 14 | -- # # 15 | -- # Redistribution and use in source and binary forms, with or without modification, are # 16 | -- # permitted provided that the following conditions are met: # 17 | -- # # 18 | -- # 1. Redistributions of source code must retain the above copyright notice, this list of # 19 | -- # conditions and the following disclaimer. # 20 | -- # # 21 | -- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # 22 | -- # conditions and the following disclaimer in the documentation and/or other materials # 23 | -- # provided with the distribution. # 24 | -- # # 25 | -- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # 26 | -- # endorse or promote products derived from this software without specific prior written # 27 | -- # permission. # 28 | -- # # 29 | -- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # 30 | -- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # 31 | -- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # 32 | -- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # 33 | -- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # 34 | -- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # 35 | -- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # 36 | -- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # 37 | -- # OF THE POSSIBILITY OF SUCH DAMAGE. # 38 | -- # ********************************************************************************************* # 39 | -- # https://github.com/stnolting/cjtag_bridge (c) Stephan Nolting # 40 | -- ################################################################################################# 41 | 42 | library ieee; 43 | use ieee.std_logic_1164.all; 44 | use ieee.numeric_std.all; 45 | 46 | entity cjtag_bridge is 47 | port ( 48 | -- global control -- 49 | clk_i : in std_ulogic; -- main clock 50 | rstn_i : in std_ulogic; -- main reset, async, low-active 51 | -- cJTAG (from debug probe) -- 52 | tckc_i : in std_ulogic; -- tap clock 53 | tmsc_i : in std_ulogic; -- tap data input 54 | tmsc_o : out std_ulogic; -- tap data output 55 | tmsc_oe_o : out std_ulogic; -- tap data output enable (tri-state driver) 56 | -- JTAG (to device) -- 57 | tck_o : out std_ulogic; -- tap clock 58 | tdi_o : out std_ulogic; -- tap data input 59 | tdo_i : in std_ulogic; -- tap data output 60 | tms_o : out std_ulogic; -- tap mode select 61 | -- Debugging (for testing only) -- 62 | db_tck_rising_o : out std_ulogic; 63 | db_tck_falling_o : out std_ulogic 64 | ); 65 | end cjtag_bridge; 66 | 67 | architecture cjtag_bridge_rtl of cjtag_bridge is 68 | 69 | -- activation sequence commands -- 70 | -- NOTE: these are bit-reversed as the LSB is sent first!! -- 71 | constant cmd_oac_c : std_ulogic_vector(3 downto 0) := "0011"; -- online activation code 72 | constant cmd_ec_c : std_ulogic_vector(3 downto 0) := "0001"; -- extension code 73 | constant cmd_cp_c : std_ulogic_vector(3 downto 0) := "0000"; -- check packet 74 | 75 | -- I/O synchronization -- 76 | type io_sync_t is record 77 | tckc_ff : std_ulogic_vector(2 downto 0); 78 | tmsc_ff : std_ulogic_vector(2 downto 0); 79 | -- 80 | tckc_rising : std_ulogic; 81 | tckc_falling : std_ulogic; 82 | tmsc_rising : std_ulogic; 83 | tmsc_falling : std_ulogic; 84 | end record; 85 | signal io_sync : io_sync_t; 86 | 87 | -- reset -- 88 | type reset_t is record 89 | cnt : std_ulogic_vector(2 downto 0); 90 | sreg : std_ulogic_vector(1 downto 0); 91 | fire : std_ulogic; 92 | end record; 93 | signal reset : reset_t; 94 | 95 | -- status -- 96 | type status_t is record 97 | online : std_ulogic; 98 | sreg : std_ulogic_vector(11 downto 0); 99 | end record; 100 | signal status : status_t; 101 | 102 | -- control fsm -- 103 | type ctrl_state_t is (S_NTDI, S_TMS, S_TDO); 104 | type ctrl_t is record 105 | state : ctrl_state_t; 106 | tck : std_ulogic; 107 | tdi : std_ulogic; 108 | tms : std_ulogic; 109 | end record; 110 | signal ctrl : ctrl_t; 111 | 112 | -- debugging signals -- 113 | type debug_t is record 114 | tck_sync : std_ulogic_vector(1 downto 0); 115 | end record; 116 | signal debug : debug_t; 117 | 118 | begin 119 | 120 | -- cJTAG Input Signal Synchronizer -------------------------------------------------------- 121 | -- ------------------------------------------------------------------------------------------- 122 | input_synchronizer: process(clk_i) 123 | begin 124 | if rising_edge(clk_i) then 125 | io_sync.tckc_ff <= io_sync.tckc_ff(1 downto 0) & tckc_i; 126 | io_sync.tmsc_ff <= io_sync.tmsc_ff(1 downto 0) & tmsc_i; 127 | end if; 128 | end process input_synchronizer; 129 | 130 | -- clock -- 131 | io_sync.tckc_rising <= '1' when (io_sync.tckc_ff(2 downto 1) = "01") else '0'; 132 | io_sync.tckc_falling <= '1' when (io_sync.tckc_ff(2 downto 1) = "10") else '0'; 133 | 134 | -- data -- 135 | io_sync.tmsc_rising <= '1' when (io_sync.tmsc_ff(2 downto 1) = "01") else '0'; 136 | io_sync.tmsc_falling <= '1' when (io_sync.tmsc_ff(2 downto 1) = "10") else '0'; 137 | 138 | 139 | -- Reset Controller ----------------------------------------------------------------------- 140 | -- ------------------------------------------------------------------------------------------- 141 | bridge_reset: process(rstn_i, clk_i) 142 | begin 143 | if (rstn_i = '0') then 144 | reset.cnt <= (others => '0'); 145 | reset.sreg <= "01"; -- internal reset after bitstream upload 146 | elsif rising_edge(clk_i) then 147 | -- edge counter -- 148 | if (io_sync.tckc_rising = '1') or (io_sync.tckc_falling = '1') then -- reset on any TCKC edge 149 | reset.cnt <= (others => '0'); 150 | elsif (reset.cnt /= "111") and -- saturate 151 | ((io_sync.tmsc_rising = '1') or (io_sync.tmsc_falling = '1')) then -- increment on any TMSC edge 152 | reset.cnt <= std_ulogic_vector(unsigned(reset.cnt) + 1); 153 | end if; 154 | -- reset edge detector -- 155 | reset.sreg(1) <= reset.sreg(0); 156 | if (reset.cnt = "111") then 157 | reset.sreg(0) <= '1'; 158 | else 159 | reset.sreg(0) <= '0'; 160 | end if; 161 | end if; 162 | end process bridge_reset; 163 | 164 | -- fire reset *once* -- 165 | reset.fire <= '1' when (reset.sreg = "01") else '0'; 166 | 167 | 168 | -- Bridge Activation Control -------------------------------------------------------------- 169 | -- ------------------------------------------------------------------------------------------- 170 | bridge_status: process(rstn_i, clk_i) 171 | begin 172 | if (rstn_i = '0') then 173 | status.online <= '0'; 174 | status.sreg <= (others => '0'); 175 | elsif rising_edge(clk_i) then 176 | if (reset.fire = '1') then -- sync reset 177 | status.online <= '0'; 178 | status.sreg <= (others => '0'); 179 | elsif (status.online = '0') then 180 | if (io_sync.tckc_rising = '1') then 181 | status.sreg <= status.sreg(status.sreg'left-1 downto 0) & io_sync.tmsc_ff(1); -- data is transmitted LSB-first 182 | end if; 183 | if (status.sreg(11 downto 08) = cmd_oac_c) and -- check activation code 184 | (status.sreg(07 downto 04) = cmd_ec_c) and 185 | (status.sreg(03 downto 00) = cmd_cp_c) and 186 | (io_sync.tckc_falling = '1') then 187 | status.online <= '1'; 188 | end if; 189 | end if; 190 | end if; 191 | end process bridge_status; 192 | 193 | 194 | -- Bridge Transmission Control ------------------------------------------------------------ 195 | -- ------------------------------------------------------------------------------------------- 196 | bridge_control: process(rstn_i, clk_i) 197 | begin 198 | if (rstn_i = '0') then 199 | ctrl.state <= S_NTDI; 200 | ctrl.tck <= '0'; 201 | ctrl.tdi <= '0'; 202 | ctrl.tms <= '0'; 203 | elsif rising_edge(clk_i) then 204 | if (status.online = '0') then -- reset while offline 205 | ctrl.state <= S_NTDI; 206 | ctrl.tck <= '0'; 207 | ctrl.tdi <= '0'; 208 | ctrl.tms <= '0'; 209 | else 210 | -- fsm -- 211 | case ctrl.state is 212 | 213 | when S_NTDI => -- sample inverse TDI and clear clock 214 | if (io_sync.tckc_rising = '1') then 215 | ctrl.tdi <= not io_sync.tmsc_ff(1); 216 | end if; 217 | if (io_sync.tckc_falling = '1') then 218 | ctrl.state <= S_TMS; 219 | end if; 220 | 221 | when S_TMS => -- sample TMS 222 | if (io_sync.tckc_rising = '1') then 223 | ctrl.tms <= io_sync.tmsc_ff(1); 224 | end if; 225 | if (io_sync.tckc_falling = '1') then 226 | ctrl.state <= S_TDO; 227 | end if; 228 | 229 | when S_TDO => -- output TDO and set clock 230 | if (io_sync.tckc_falling = '1') then 231 | ctrl.state <= S_NTDI; 232 | end if; 233 | 234 | when others => 235 | ctrl.state <= S_NTDI; 236 | end case; 237 | 238 | -- JTAG clock control -- 239 | if (ctrl.state = S_TDO) then 240 | if (io_sync.tckc_rising = '1') then 241 | ctrl.tck <= '1'; 242 | elsif (io_sync.tckc_falling = '1') then 243 | ctrl.tck <= '0'; 244 | end if; 245 | end if; 246 | end if; 247 | end if; 248 | end process bridge_control; 249 | 250 | -- IO control -- 251 | tck_o <= io_sync.tckc_ff(1) when (status.online = '0') else ctrl.tck; 252 | tms_o <= io_sync.tmsc_ff(1) when (status.online = '0') else ctrl.tms; 253 | tdi_o <= '0' when (status.online = '0') else ctrl.tdi; 254 | 255 | -- tri-state control -- 256 | tmsc_o <= tdo_i; -- FIXME: synchronize tdo_i? 257 | tmsc_oe_o <= '1' when (ctrl.state = S_TDO) else '0'; 258 | 259 | 260 | -- Debugging Stuff ------------------------------------------------------------------------ 261 | -- ------------------------------------------------------------------------------------------- 262 | debug_control: process(rstn_i, clk_i) 263 | begin 264 | if (rstn_i = '0') then 265 | debug.tck_sync <= (others => '0'); 266 | elsif rising_edge(clk_i) then 267 | debug.tck_sync(1) <= debug.tck_sync(0); 268 | if (status.online = '0') then 269 | debug.tck_sync(0) <= io_sync.tckc_ff(1); 270 | else 271 | debug.tck_sync(0) <= ctrl.tck; 272 | end if; 273 | end if; 274 | end process debug_control; 275 | 276 | -- edge detector -- 277 | db_tck_rising_o <= '1' when (debug.tck_sync = "01") else '0'; 278 | db_tck_falling_o <= '1' when (debug.tck_sync = "10") else '0'; 279 | 280 | 281 | end cjtag_bridge_rtl; 282 | --------------------------------------------------------------------------------