├── LICENSE.txt ├── README.md ├── psi-file-list.tcl ├── rtl ├── Axis2Jtag │ ├── AxiStreamSelector.vhd │ ├── AxisJtagDebugBridge.vhd │ ├── AxisToJtag.vhd │ ├── AxisToJtagCore.vhd │ ├── AxisToJtagPkg.vhd │ └── JtagSerDesCore.vhd ├── BusIf │ ├── README │ └── Tmem │ │ ├── Axis2TmemFifo.vhd │ │ ├── Tmem2BSCANWrapper.vhd │ │ └── tb │ │ ├── Axis2TmemFifoTb.vhd │ │ └── Axis2TmemLoopbackTb.vhd ├── Jtag2BSCAN │ ├── Jtag2BSCAN.vhd │ ├── README │ └── tb │ │ ├── JTAG_SIM_VIRTEX6.vhd.diff │ │ ├── Jtag2BSCANTb.vhd │ │ ├── Jtag2BSCANTbPkg.vhd │ │ ├── Jtag2BSCANTbPkgBody.vhd │ │ ├── Jtag2BSCANsTb.vhd │ │ └── Tmem2BSCANWrapperTb.vhd ├── JtagTap │ ├── JtagTapFSM.vhd │ ├── JtagTapIR.vhd │ └── README ├── Surf │ ├── AxiStreamPkg.vhd │ ├── StdRtlPkg.vhd │ └── TextUtilPkg.vhd └── sim │ ├── JtagSniffer.py │ ├── README │ ├── dump2pkg.sh │ └── proc.py ├── tb ├── AxiStreamSelectorTb.vhd ├── AxisToJtagCoreTb.vhd ├── AxisToJtagStubTb.vhd ├── AxisToJtagTb.vhd └── JtagSerDesCoreTb.vhd └── xvcSrv ├── src ├── .gitignore ├── jtagDump.cc ├── jtagDump.h ├── makefile ├── mmioHelper.h ├── xvcClient.py ├── xvcConn.cc ├── xvcConn.h ├── xvcDriver.h ├── xvcDrvAxiDbgBridgeIP.cc ├── xvcDrvAxiDbgBridgeIP.h ├── xvcDrvAxisFifo.cc ├── xvcDrvAxisFifo.h ├── xvcDrvAxisTmem.cc ├── xvcDrvAxisTmem.h ├── xvcDrvFoo.cc ├── xvcDrvLoopBack.cc ├── xvcDrvLoopBack.h ├── xvcDrvSerDesTmem.h ├── xvcDrvUdp.cc ├── xvcDrvUdp.h ├── xvcSrv.cc └── xvcSrv.h └── test ├── Makefile ├── makefile ├── test.py └── testData.txt /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2019, The Board of Trustees of the Leland Stanford Junior 3 | University, through SLAC National Accelerator Laboratory (subject to receipt 4 | of any required approvals from the U.S. Dept. of Energy). All rights reserved. 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | (1) Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | (2) Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | (3) Neither the name of the Leland Stanford Junior University, SLAC National 16 | Accelerator Laboratory, U.S. Dept. of Energy nor the names of its 17 | contributors may be used to endorse or promote products derived from this 18 | software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER, THE UNITED STATES GOVERNMENT, 24 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 | OF SUCH DAMAGE. 31 | 32 | You are under no obligation whatsoever to provide any bug fixes, patches, or 33 | upgrades to the features, functionality or performance of the source code 34 | ("Enhancements") to anyone; however, if you choose to make your Enhancements 35 | available either publicly, or directly to SLAC National Accelerator Laboratory, 36 | without imposing a separate written license agreement for such Enhancements, 37 | then you hereby grant the following license: a non-exclusive, royalty-free 38 | perpetual license to install, use, modify, prepare derivative works, incorporate 39 | into other computer software, distribute, and sublicense such Enhancements or 40 | derivative works thereof, in binary and source code form. 41 | 42 | -------------------------------------------------------------------------------- /psi-file-list.tcl: -------------------------------------------------------------------------------- 1 | set xvc_support_fw_files { \ 2 | "rtl/Surf/StdRtlPkg.vhd" \ 3 | "rtl/Surf/AxiStreamPkg.vhd" \ 4 | "rtl/Axis2Jtag/AxisToJtagPkg.vhd" \ 5 | "rtl/Axis2Jtag/JtagSerDesCore.vhd" \ 6 | "rtl/Axis2Jtag/AxiStreamSelector.vhd" \ 7 | "rtl/Axis2Jtag/AxisToJtagCore.vhd" \ 8 | "rtl/Axis2Jtag/AxisToJtag.vhd" \ 9 | "rtl/JtagTap/JtagTapFSM.vhd" \ 10 | "rtl/JtagTap/JtagTapIR.vhd" \ 11 | "rtl/Jtag2BSCAN/Jtag2BSCAN.vhd" \ 12 | "rtl/BusIf/Tmem/Axis2TmemFifo.vhd" \ 13 | "rtl/BusIf/Tmem/Tmem2BSCANWrapper.vhd" \ 14 | } 15 | 16 | set xvc_support_location "[file dirname [info script]]" 17 | 18 | proc xvc_support_add_srcs { pre } { 19 | global xvc_support_fw_files 20 | global xvc_support_location 21 | set xvcSupPath "[file dirname [info script]]" 22 | foreach f $xvc_support_fw_files { 23 | xfile add "$pre$xvc_support_location/$f" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rtl/Axis2Jtag/AxiStreamSelector.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: Select between two input streams under control of a binary signal 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | library ieee; 18 | use ieee.std_logic_1164.all; 19 | 20 | 21 | use work.StdRtlPkg.all; 22 | use work.AxiStreamPkg.all; 23 | 24 | entity AxiStreamSelector is 25 | generic ( 26 | TPD_G : time := 1 ns 27 | ); 28 | port ( 29 | clk : in sl; 30 | rst : in sl; 31 | sel : in sl; 32 | mIb : in AxiStreamMasterArray(1 downto 0); 33 | sIb : out AxiStreamSlaveArray (1 downto 0); 34 | 35 | mOb : out AxiStreamMasterType; 36 | sOb : in AxiStreamSlaveType 37 | ); 38 | end entity AxiStreamSelector; 39 | 40 | architecture AxiStreamSelectorImpl of AxiStreamSelector is 41 | 42 | type RegType is record 43 | streamBuf : AxiStreamMasterType; 44 | end record RegType; 45 | 46 | constant REG_INIT_C : RegType := ( 47 | streamBuf => AXI_STREAM_MASTER_INIT_C 48 | ); 49 | 50 | signal r : RegType := REG_INIT_C; 51 | signal rin : RegType; 52 | signal rdyLoc : sl; 53 | 54 | begin 55 | 56 | rdyLoc <= not r.streamBuf.tValid or sOb.tReady; 57 | 58 | sIb(1).tReady <= rdyLoc when sel = '1' else '0'; 59 | sIb(0).tReady <= rdyLoc when sel = '0' else '0'; 60 | 61 | mOb <= r.streamBuf; 62 | 63 | P_COMB : process(r, rdyLoc, sel, mIb, sOb) 64 | variable v : RegType; 65 | begin 66 | v := r; 67 | 68 | if ( rdyLoc = '1' ) then 69 | if ( sel = '1' ) then 70 | v.streamBuf := mIb(1); 71 | else 72 | v.streamBuf := mIb(0); 73 | end if; 74 | end if; 75 | 76 | rin <= v; 77 | end process P_COMB; 78 | 79 | P_SEQ : process( clk ) 80 | begin 81 | if ( rising_edge( clk ) ) then 82 | if ( rst = '1' ) then 83 | r <= REG_INIT_C after TPD_G; 84 | else 85 | r <= rin after TPD_G; 86 | end if; 87 | end if; 88 | end process P_SEQ; 89 | 90 | end architecture AxiStreamSelectorImpl; 91 | -------------------------------------------------------------------------------- /rtl/Axis2Jtag/AxisJtagDebugBridge.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: AXI Stream Debug Bridge 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | -- Axi Stream to JTAG Protocol 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | 24 | use work.StdRtlPkg.all; 25 | use work.AxiStreamPkg.all; 26 | use work.AxisToJtagPkg.all; 27 | 28 | -- Connect AxisToJtag to a debug bridge IP (convenience wrapper) 29 | entity AxisJtagDebugBridge is 30 | generic ( 31 | TPD_G : time := 1 ns; 32 | AXIS_FREQ_G : real := 0.0; -- Hz (for computing TCK period) 33 | AXIS_WIDTH_G : positive range 4 to 16 := 4; -- bytes 34 | CLK_DIV2_G : positive := 4; -- half-period of TCK in axisClk cycles 35 | MEM_DEPTH_G : natural range 0 to 65535 := 4; -- size of buffer memory (0 for none) 36 | MEM_STYLE_G : string := "auto" -- 'auto', 'block' or 'distributed' 37 | ); 38 | port ( 39 | axisClk : in sl; 40 | axisRst : in sl; 41 | 42 | mAxisReq : in AxiStreamMasterType; 43 | sAxisReq : out AxiStreamSlaveType; 44 | 45 | mAxisTdo : out AxiStreamMasterType; 46 | sAxisTdo : in AxiStreamSlaveType 47 | ); 48 | end entity AxisJtagDebugBridge; 49 | 50 | architecture AxisJtagDebugBridgeImpl of AxisJtagDebugBridge is 51 | 52 | -- IP 53 | -- Must be generated and named DebugBridgeJtag, e.g., with TCL commands: 54 | -- 55 | -- create_ip -name debug_bridge -vendor xilinx.com -library ip -module_name DebugBridgeJtag 56 | -- # C_DEBUG_MODE selects JTAG <-> BSCAN mode 57 | -- set_property -dict [list CONFIG.C_DEBUG_MODE {4}] [get_ips DebugBridgeJtag] 58 | -- 59 | 60 | component DebugBridgeJtag is 61 | port ( 62 | jtag_tdi : in std_logic; 63 | jtag_tdo : out std_logic; 64 | jtag_tms : in std_logic; 65 | jtag_tck : in std_logic 66 | ); 67 | end component DebugBridgeJtag; 68 | 69 | signal tck, tdi, tms, tdo : sl; 70 | 71 | begin 72 | 73 | U_AXIS_JTAG : entity work.AxisToJtag 74 | generic map ( 75 | TPD_G => TPD_G, 76 | AXIS_WIDTH_G => AXIS_WIDTH_G, 77 | AXIS_FREQ_G => AXIS_FREQ_G, 78 | CLK_DIV2_G => CLK_DIV2_G, 79 | MEM_DEPTH_G => MEM_DEPTH_G, 80 | MEM_STYLE_G => MEM_STYLE_G 81 | ) 82 | port map ( 83 | axisClk => axisClk, 84 | axisRst => axisRst, 85 | 86 | mAxisReq => mAxisReq, 87 | sAxisReq => sAxisReq, 88 | 89 | mAxisTdo => mAxisTdo, 90 | sAxisTdo => sAxisTdo, 91 | 92 | tck => tck, 93 | tms => tms, 94 | tdi => tdi, 95 | tdo => tdo 96 | ); 97 | 98 | U_JTAG_BSCAN : component DebugBridgeJtag 99 | port map ( 100 | jtag_tdi => tdi, 101 | jtag_tdo => tdo, 102 | jtag_tms => tms, 103 | jtag_tck => tck 104 | ); 105 | 106 | end architecture AxisJtagDebugBridgeImpl; 107 | 108 | architecture AxisJtagDebugBridgeStub of AxisJtagDebugBridge is 109 | 110 | type StateType is (READY_S, SKIP_S, REPLY_S); 111 | 112 | type RegType is record 113 | state : StateType; 114 | repValid : sl; 115 | repData : slv(31 downto 0); 116 | reqReady : sl; 117 | end record RegType; 118 | 119 | constant REG_INIT_C : RegType := ( 120 | state => READY_S, 121 | repValid => '0', 122 | repData => (others => '0'), 123 | reqReady => '1' 124 | ); 125 | 126 | signal mReply : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; 127 | signal sReq : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; 128 | 129 | signal r : RegType := REG_INIT_C; 130 | signal rin : RegType; 131 | 132 | begin 133 | 134 | sReq.tReady <= r.reqReady; 135 | mReply.tValid <= r.repValid; 136 | mReply.tLast <= '1'; 137 | mReply.tData(31 downto 0) <= r.repData; 138 | 139 | sAxisReq <= sReq; 140 | mAxisTdo <= mReply; 141 | 142 | U_COMB : process(r, mAxisReq, sAxisTdo) is 143 | variable v : RegType; 144 | begin 145 | v := r; 146 | 147 | case (r.state) is 148 | 149 | when READY_S => 150 | if ( mAxisReq.tValid = '1' ) then 151 | v.repData := ( others => '0' ); 152 | if ( getVersion( mAxisReq.tData ) /= PRO_VERSN_C ) then 153 | setVersion( PRO_VERSN_C , v.repData ); 154 | setErr ( ERR_BAD_VERSION_C, v.repData ); 155 | elsif ( getCommand( mAxisReq.tData ) /= CMD_QUERY_C ) then 156 | setErr ( ERR_BAD_COMMAND_C, v.repData ); 157 | else 158 | setErr ( ERR_NOT_PRESENT_C, v.repData ); 159 | end if; 160 | if ( mAxisReq.tLast = '1' ) then 161 | v.reqReady := '0'; 162 | end if; 163 | v.repValid := '1'; 164 | v.state := REPLY_S; 165 | end if; 166 | 167 | when REPLY_S => 168 | if ( (mAxisReq.tValid and mAxisReq.tLast and r.reqReady) = '1' ) then 169 | v.reqReady := '0'; 170 | end if; 171 | if ( sAxisTdo.tReady = '1' ) then 172 | v.repValid := '0'; 173 | if ( v.reqReady = '1' ) then 174 | -- no TLAST seen yet 175 | v.state := SKIP_S; 176 | else 177 | v.reqReady := '1'; 178 | v.state := READY_S; 179 | end if; 180 | end if; 181 | 182 | when SKIP_S => 183 | if ( (mAxisReq.tValid and mAxisReq.tLast) = '1' ) then 184 | v.state := READY_S; 185 | end if; 186 | 187 | end case; 188 | 189 | rin <= v; 190 | 191 | end process U_comb; 192 | 193 | U_SEQ : process( axisClk ) is 194 | begin 195 | if ( rising_edge( axisClk ) ) then 196 | if ( axisRst /= '0' ) then 197 | r <= REG_INIT_C after TPD_G; 198 | else 199 | r <= rin after TPD_G; 200 | end if; 201 | end if; 202 | end process U_seq; 203 | 204 | end architecture AxisJtagDebugBridgeStub; 205 | -------------------------------------------------------------------------------- /rtl/Axis2Jtag/JtagSerDesCore.vhd: -------------------------------------------------------------------------------- 1 | -- Title : JTAG Support 2 | ------------------------------------------------------------------------------- 3 | -- Company : SLAC National Accelerator Laboratory 4 | ------------------------------------------------------------------------------- 5 | -- Description: JTAG serializer/deserializer with parallel word interface 6 | ------------------------------------------------------------------------------- 7 | -- This file is part of 'SLAC Firmware Standard Library'. 8 | -- It is subject to the license terms in the LICENSE.txt file found in the 9 | -- top-level directory of this distribution and at: 10 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 11 | -- No part of 'SLAC Firmware Standard Library', including this file, 12 | -- may be copied, modified, propagated, or distributed except according to 13 | -- the terms contained in the LICENSE.txt file. 14 | ------------------------------------------------------------------------------- 15 | 16 | library ieee; 17 | use ieee.std_logic_1164.all; 18 | 19 | 20 | use work.StdRtlPkg.all; 21 | 22 | -- Serialize a TMS/TDI word pair into JTAG signals and deserialize 23 | -- TDO into a paralle output word. 24 | 25 | entity JtagSerDesCore is 26 | generic ( 27 | TPD_G : time := 1 ns; 28 | WIDTH_G : positive := 32; 29 | CLK_DIV2_G : positive := 8 30 | ); 31 | port ( 32 | clk : in sl; 33 | rst : in sl; 34 | 35 | numBits : in natural range 0 to WIDTH_G - 1; 36 | 37 | dataInTms : in slv(WIDTH_G - 1 downto 0); 38 | dataInTdi : in slv(WIDTH_G - 1 downto 0); 39 | dataInValid : in sl; 40 | dataInReady : out sl; 41 | 42 | dataOut : out slv(WIDTH_G - 1 downto 0); 43 | dataOutValid : out sl; 44 | dataOutReady : in sl; 45 | 46 | tck : out sl; 47 | tck_posedge : out sl; -- may be using as a clock-enable by logic running on 'clk' 48 | tck_negedge : out sl; -- may be using as a clock-enable by logic running on 'clk' 49 | tdi : out sl; 50 | tms : out sl; 51 | tdo : in sl 52 | ); 53 | end entity JtagSerDesCore; 54 | 55 | architecture JtagSerDesCoreImpl of JtagSerDesCore is 56 | 57 | type StateType is (IDLE_S, SHIFT_S, WAI_S); 58 | 59 | type RegType is record 60 | cnt : integer range -1 to WIDTH_G - 1; 61 | div : natural; 62 | tms : slv(WIDTH_G - 1 downto 0 ); 63 | tdi : slv(WIDTH_G - 1 downto 0 ); 64 | tdo : slv(WIDTH_G downto 0 ); 65 | tck : sl; 66 | tck_pos : sl; 67 | tck_neg : sl; 68 | lastBit : boolean; 69 | oValid : sl; 70 | iReady : sl; 71 | state : StateType; 72 | end record RegType; 73 | 74 | constant REG_INIT_C : RegType := ( 75 | cnt => -1, 76 | div => 0, 77 | tms => (others => '0'), 78 | tdi => (others => '0'), 79 | tdo => (others => '0'), 80 | tck => '0', 81 | tck_pos => '0', 82 | tck_neg => '0', 83 | lastBit => false, 84 | oValid => '0', 85 | iReady => '1', 86 | state => IDLE_S 87 | ); 88 | 89 | signal r : RegType := REG_INIT_C; 90 | signal rin : RegType; 91 | 92 | begin 93 | 94 | tck <= r.tck; 95 | tck_posedge <= r.tck_pos; 96 | tck_negedge <= r.tck_neg; 97 | tdi <= r.tdi(0); 98 | tms <= r.tms(0); 99 | 100 | dataOutValid <= r.oValid; 101 | dataInReady <= r.iReady; 102 | dataOut <= r.tdo(WIDTH_G - 1 downto 0); 103 | 104 | P_COMB : process(r, numBits, dataInTms, dataInTdi, dataInValid, dataOutReady, tdo) 105 | variable v : RegType; 106 | begin 107 | v := r; 108 | 109 | v.tck_pos := '0'; 110 | v.tck_neg := '0'; 111 | 112 | case (r.state) is 113 | when IDLE_S => 114 | v.oValid := '0'; 115 | if ( dataInValid /= '0' and r.iReady /= '0' ) then 116 | v.tms := dataInTms; 117 | v.tdi := dataInTdi; 118 | v.iReady := '0'; 119 | v.cnt := numBits; 120 | v.div := CLK_DIV2_G - 1; 121 | v.state := SHIFT_S; 122 | end if; 123 | 124 | when SHIFT_S => 125 | v.iReady := '0'; 126 | v.oValid := '0'; 127 | if ( r.div = 0 ) then 128 | if ( r.tck = '0' ) then 129 | -- about to raise TCK 130 | v.tdo := ( tdo & r.tdo( r.tdo'left downto 1 ) ); 131 | if ( r.lastBit ) then 132 | -- latch last TDO bit 133 | v.lastBit := false; 134 | v.oValid := '1'; 135 | if ( r.cnt >= 0 ) then 136 | -- more words in the pipeline; if receiver is ready 137 | -- then we continue shifting - otherwise we must wait 138 | if ( dataOutReady /= '0' ) then 139 | -- next clock; continue shifting 140 | v.tck := '1'; 141 | v.tck_pos := '1'; 142 | v.div := CLK_DIV2_G - 1; 143 | else 144 | v.state := WAI_S; 145 | end if; 146 | else 147 | -- we are done 148 | if ( dataOutReady /= '0' ) then 149 | v.iReady := '1'; 150 | v.state := IDLE_S; 151 | else 152 | v.state := WAI_S; 153 | end if; 154 | end if; 155 | else 156 | v.tck := '1'; 157 | v.tck_pos := '1'; 158 | v.div := CLK_DIV2_G - 1; 159 | end if; 160 | else 161 | -- falling edge of TCK 162 | v.tms := ( '0' & r.tms(r.tms'left downto 1 ) ); 163 | v.tdi := ( '0' & r.tdi(r.tdi'left downto 1 ) ); 164 | v.cnt := r.cnt - 1; 165 | if ( r.cnt = 0 ) then 166 | if ( dataInValid /= '0' ) then 167 | v.tms := dataInTms; 168 | v.tdi := dataInTdi; 169 | v.cnt := numBits; 170 | v.iReady := '1'; 171 | end if; 172 | v.lastBit := true; 173 | end if; 174 | v.tck := '0'; 175 | v.tck_neg := '1'; 176 | v.div := CLK_DIV2_G - 1; 177 | end if; 178 | else 179 | v.div := r.div - 1; 180 | end if; 181 | 182 | when WAI_S => 183 | if ( dataOutReady /= '0' ) then 184 | v.oValid := '0'; 185 | if ( r.cnt >= 0 ) then 186 | v.tck := '1'; 187 | v.tck_pos := '1'; 188 | v.div := CLK_DIV2_G - 1; 189 | v.state := SHIFT_S; 190 | else 191 | v.iReady := '1'; 192 | v.state := IDLE_S; 193 | end if; 194 | end if; 195 | 196 | end case; 197 | 198 | rin <= v; 199 | 200 | end process P_COMB; 201 | 202 | P_SEQ : process(clk ) 203 | begin 204 | if ( rising_edge( clk ) ) then 205 | if ( rst /= '0' ) then 206 | r <= REG_INIT_C after TPD_G; 207 | else 208 | r <= rin after TPD_G; 209 | end if; 210 | end if; 211 | end process P_SEQ; 212 | 213 | end architecture JtagSerDesCoreImpl; 214 | -------------------------------------------------------------------------------- /rtl/BusIf/README: -------------------------------------------------------------------------------- 1 | Firmware modules that interface AXI-Stream to a memory-mapped bus 2 | should go here. 3 | -------------------------------------------------------------------------------- /rtl/BusIf/Tmem/tb/Axis2TmemLoopbackTb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.StdRtlPkg.all; 6 | use work.AxiStreamPkg.all; 7 | 8 | use work.ifc1210_simu_procedures_pkg.all; 9 | 10 | entity Axis2TmemLoopbackTb is 11 | end entity Axis2TmemLoopbackTb; 12 | 13 | architecture tb of Axis2TmemLoopbackTb is 14 | 15 | signal clk : sl := '0'; 16 | signal rst : sl := '1'; 17 | signal run : boolean := true; 18 | signal cnt : integer := 0; 19 | 20 | constant DEPTH_C : slv := x"2"; 21 | 22 | signal axisPri : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; 23 | signal axisSub : AxiStreamSlaveType; 24 | 25 | signal tmemBusI : tmem_bus_in_t := ( 26 | TMEM_ADD_i => (others => 'X'), 27 | TMEM_DATW_i => (others => 'X'), 28 | TMEM_ENA_i => '0', 29 | TMEM_WE_i => (others => '0'), 30 | TMEM_CS_i => "00" 31 | ); 32 | signal tmemBusO : tmem_bus_out_t; 33 | 34 | signal tmemData : slv(63 downto 0); 35 | 36 | constant axisTstData : Slv32Array := ( 37 | 0 => x"01020304", 38 | 1 => x"abcdef01", 39 | 2 => x"deadbeef" 40 | ); 41 | 42 | constant axisAltData : Slv32Array := ( 43 | 0 => x"ffffffff", 44 | 1 => x"ffffffff", 45 | 2 => x"affecafe" 46 | ); 47 | 48 | 49 | signal rbidx : natural; 50 | 51 | signal irq : std_logic; 52 | 53 | begin 54 | 55 | P_CLK : process is 56 | begin 57 | if ( run ) then 58 | clk <= not clk; 59 | wait for 5 ns; 60 | else 61 | wait; 62 | end if; 63 | end process P_CLK; 64 | 65 | P_CNT : process ( clk ) is 66 | begin 67 | if ( rising_edge( clk ) ) then 68 | cnt <= cnt + 1; 69 | case ( cnt ) is 70 | when 10 => 71 | rst <= '0'; 72 | when others => 73 | end case; 74 | end if; 75 | end process P_CNT; 76 | 77 | P_TEST : process is 78 | variable nvals : natural; 79 | begin 80 | 81 | while ( rst = '1' ) loop 82 | wait until rising_edge( clk ); 83 | end loop; 84 | 85 | wait for 1000 ns; 86 | 87 | -- enable interrupts 88 | 89 | TMEM_BUS_WRITE( "enable output IRQ", 90 | x"00_0008", 91 | x"0F", 92 | x"0000_0000_0004_0000", 93 | 1, 94 | clk, 95 | tmemBusI, 96 | tmemBusO); 97 | 98 | while ( not irq ) loop 99 | wait until rising_edge( clk ); 100 | end loop; 101 | 102 | for i in axisTstData'range loop 103 | TMEM_BUS_WRITE( "writing test values", 104 | x"00_0000", 105 | x"0F", 106 | x"0000_0000" & axisTstData(i), 107 | 1, 108 | clk, 109 | tmemBusI, 110 | tmemBusO); 111 | end loop; 112 | 113 | -- write EOF and enable input IRQ 114 | 115 | TMEM_BUS_WRITE( "writing EOF", 116 | x"00_0008", 117 | x"0F", 118 | x"00000000_00090000", 119 | 1, 120 | clk, 121 | tmemBusI, 122 | tmemBusO); 123 | 124 | while ( not irq ) loop 125 | wait until rising_edge( clk ); 126 | end loop; 127 | 128 | TMEM_BUS_READ( "Status readback", 129 | x"00_0008", 130 | 1, 131 | clk, 132 | tmemData, 133 | tmemBusI, 134 | tmemBusO ); 135 | wait until rising_edge( clk ); 136 | 137 | nvals := to_integer( unsigned( tmemData(15 downto 0) ) ); 138 | 139 | if ( tmemData(31 downto 0) /= x"0" & DEPTH_C & x"08" & slv(to_unsigned(axisTstData'length, 16)) ) then 140 | report "Reading status mismatch" severity failure; 141 | end if; 142 | 143 | 144 | wait until rising_edge( clk ); 145 | 146 | for i in 1 to nvals loop 147 | TMEM_BUS_READ( "reading data", 148 | x"00_0000", 149 | 1, 150 | clk, 151 | tmemData, 152 | tmemBusI, 153 | tmemBusO); 154 | wait until rising_edge( clk ); 155 | if ( tmemData( axisTstData(0)'range ) /= axisTstData(i - 1) ) then 156 | report "readback data mismatch" severity failure; 157 | end if; 158 | end loop; 159 | 160 | if ( irq = '1' ) then 161 | report "IRQ still asserted!" severity failure; 162 | end if; 163 | 164 | report "TEST PASSED"; 165 | 166 | run <= false; 167 | wait; 168 | end process P_TEST; 169 | 170 | U_DUT : entity work.Axis2TmemFifo 171 | port map ( 172 | clk => clk, 173 | rst => rst, 174 | 175 | axisInpPri => axisPri, 176 | axisInpSub => axisSub, 177 | axisOutPri => axisPri, 178 | axisOutSub => axisSub, 179 | 180 | tmemADD => tmemBusI.TMEM_ADD_i, 181 | tmemDATW => tmemBusI.TMEM_DATW_i, 182 | tmemENA => tmemBusI.TMEM_ENA_i, 183 | tmemWE => tmemBusI.TMEM_WE_i, 184 | tmemCS => tmemBusI.TMEM_CS_i, 185 | 186 | tmemDATR => tmemBusO.TMEM_DATR_o, 187 | tmemBUSY => tmemBusO.TMEM_BUSY_o, 188 | tmemPIPE => tmemBusO.TMEM_PIPE_o, 189 | 190 | irq => irq 191 | ); 192 | 193 | end architecture tb; 194 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/Jtag2BSCAN.vhd: -------------------------------------------------------------------------------- 1 | -- Basic Emulation of BSCANE2 for bridging JTAG to xilinx ICON core 2 | 3 | -- Till Straumann, 09/2020. 4 | library ieee; 5 | use ieee.std_logic_1164.all; 6 | use ieee.numeric_std.all; 7 | 8 | entity Jtag2BSCAN is 9 | generic ( 10 | IR_LENGTH_G : natural := 6; 11 | REG_IDCODE_G : std_logic_vector := "001001"; -- must be of IR_LENGTH_G 12 | REG_USERCODE_G : std_logic_vector := "001000"; -- must be of IR_LENGTH_G 13 | REG_USER_G : std_logic_vector := "000010"; -- must be of IR_LENGTH_G 14 | IR_VAL_G : std_logic_vector := "110101"; -- must be of IR_LENGTH_G 15 | IDCODE_VAL_G : std_logic_vector(31 downto 0) := x"22228093"; 16 | USERCODE_VAL_G : std_logic_vector(31 downto 0) := x"ffffffff"; 17 | TCK_IS_CLOCK_G : boolean := true 18 | ); 19 | port ( 20 | clk : in std_logic := '0'; 21 | rst : in std_logic := '0'; 22 | JTCK_POSEDGE : in std_logic := '0'; 23 | JTCK_NEGEDGE : in std_logic := '0'; 24 | 25 | JTCK : in std_logic; 26 | JTMS : in std_logic; 27 | JTDI : in std_logic; 28 | JTDO : out std_logic; 29 | 30 | TDO : in std_logic; 31 | SEL : out std_logic; 32 | DRCK : out std_logic; 33 | CAPTURE : out std_logic; 34 | SHIFT : out std_logic; 35 | UPDATE : out std_logic; 36 | RESET : out std_logic; 37 | TDI : out std_logic; 38 | UPDATE_SEL : out std_logic; 39 | DRCK_SEL : out std_logic 40 | ); 41 | end entity Jtag2BSCAN; 42 | 43 | architecture Impl of Jtag2BSCAN is 44 | 45 | signal testLogicResetLoc : std_logic; 46 | signal scanDRLoc : std_logic; 47 | signal scanIRLoc : std_logic; 48 | signal captureLoc : std_logic; 49 | signal shiftLoc : std_logic; 50 | signal updateLoc : std_logic; 51 | 52 | signal captureIRLoc : std_logic; 53 | signal shiftIRLoc : std_logic; 54 | signal updateIRLoc : std_logic; 55 | signal captureDRLoc : std_logic; 56 | signal shiftDRLoc : std_logic; 57 | signal updateDRLoc : std_logic; 58 | 59 | signal selUSERTap : std_logic; 60 | signal tapTdoLoc : std_logic; 61 | 62 | signal testLogicResetPredict : std_logic; 63 | 64 | type RegType is record 65 | tdo : std_logic; 66 | captureDR : std_logic; 67 | shiftDR : std_logic; 68 | updateDR : std_logic; 69 | selUSER : std_logic; 70 | drckSel : std_logic; 71 | end record RegType; 72 | 73 | constant REG_INIT_C : RegType := ( 74 | tdo => '0', 75 | captureDR => '0', 76 | shiftDR => '0', 77 | updateDR => '0', 78 | selUSER => '0', 79 | drckSel => '0' 80 | ); 81 | 82 | signal r, rin : RegType := REG_INIT_C; 83 | 84 | begin 85 | 86 | U_TapFsm : entity work.JtagTapFSM 87 | generic map ( 88 | TCK_IS_CLOCK_G => TCK_IS_CLOCK_G 89 | ) 90 | port map ( 91 | clk => clk, 92 | rst => rst, 93 | tck_posedge => JTCK_POSEDGE, 94 | tck_negedge => JTCK_NEGEDGE, 95 | tck => JTCK, 96 | tms => JTMS, 97 | tdi => JTDI, 98 | testLogicReset => testLogicResetLoc, 99 | runTestIdle => open, 100 | scanDR => scanDRLoc, 101 | scanIR => scanIRLoc, 102 | selectScan => open, 103 | capture => captureLoc, 104 | shift => shiftLoc, 105 | exit1 => open, 106 | pause => open, 107 | exit2 => open, 108 | update => updateLoc, 109 | nextStateTLR => testLogicResetPredict 110 | ); 111 | 112 | captureIRLoc <= (captureLoc and scanIRLoc); 113 | shiftIRLoc <= (shiftLoc and scanIRLoc); 114 | updateIRLoc <= (updateLoc and scanIRLoc); 115 | 116 | captureDRLoc <= (captureLoc and scanDRLoc); 117 | shiftDRLoc <= (shiftLoc and scanDRLoc); 118 | updateDRLoc <= (updateLoc and scanDRLoc); 119 | 120 | U_JtagTapIR : entity work.JtagTapIR 121 | generic map ( 122 | IR_LENGTH_G => IR_LENGTH_G, 123 | REG_IDCODE_G => REG_IDCODE_G, 124 | REG_USERCODE_G => REG_USERCODE_G, 125 | REG_USER_G => REG_USER_G, 126 | IR_VAL_G => IR_VAL_G, 127 | IDCODE_VAL_G => IDCODE_VAL_G, 128 | USERCODE_VAL_G => USERCODE_VAL_G, 129 | TCK_IS_CLOCK_G => TCK_IS_CLOCK_G 130 | ) 131 | port map ( 132 | clk => clk, 133 | rst => rst, 134 | tck_posedge => JTCK_POSEDGE, 135 | tck_negedge => JTCK_NEGEDGE, 136 | tck => JTCK, 137 | tdi => JTDI, 138 | testLogicReset => testLogicResetLoc, 139 | captureIR => captureIRLoc, 140 | shiftIR => shiftIRLoc, 141 | updateIR => updateIRLoc, 142 | captureDR => captureDRLoc, 143 | shiftDR => shiftDRLoc, 144 | tdo => tapTdoLoc, 145 | selUSER => selUSERTap, 146 | selBYPASS => open 147 | ); 148 | 149 | P_COMB : process (r, tapTdoLoc, selUSERTap, TDO, captureDRLoc, shiftDRLoc, updateDRLoc, shiftIRLoc, updateIRLoc, testLogicResetLoc) is 150 | variable v : RegType; 151 | variable OE : std_logic; 152 | begin 153 | v := r; 154 | OE := shiftDRLoc or shiftIRLoc; 155 | if ( (selUSERTap = '1') and (shiftIRLoc = '0') ) then 156 | v.tdo := TDO; 157 | else 158 | v.tdo := tapTdoLoc; 159 | end if; 160 | 161 | -- BSCANE2 (vhdl -- verilog seems different!) asserts SEL only when USER2 is captured the first time; 162 | -- if captured again (while not changing IR contents in between) then SEL is deasserted! 163 | -- This is most likely a bug in the VHDL simulation code (JTAG_SIM_VIRTEX6) and does not work with ICON. 164 | -- Thus, we stick to asserting selUSER while the IR holds USER2 165 | if ( testLogicResetLoc = '1' ) then 166 | v.selUSER := '0'; 167 | elsif ( updateIRLoc = '1' ) then 168 | v.selUSER := selUSERTap; 169 | end if; 170 | v.tdo := v.tdo or not OE; 171 | v.captureDR := captureDRLoc; 172 | v.shiftDR := shiftDRLoc; 173 | v.updateDR := updateDRLoc; 174 | v.drckSel := (captureDRLoc or shiftDRLoc) and v.selUSER; 175 | rin <= v; 176 | end process P_COMB; 177 | 178 | G_TCK : if ( TCK_IS_CLOCK_G ) generate 179 | signal selUSERLoc : std_logic; 180 | begin 181 | P_SEQ : process ( JTCK ) is 182 | begin 183 | if ( falling_edge( JTCK ) ) then 184 | r <= rin; 185 | end if; 186 | end process P_SEQ; 187 | 188 | -- FIXME: should be able to use a clock buffer but this is not trivial 189 | -- because the muxing signals change on the same clock edges 190 | -- and we don't have a higher-freq. clock available.. 191 | -- 192 | -- IF we had a clock that is trailing TCK by 90deg. then 193 | -- we could generate 194 | -- if ( rising_edge( TCK90deg ) ) then 195 | -- selMux <= (captureDRLoc or shiftDRLoc) and selUSERLoc 196 | -- end if; 197 | -- 198 | -- (polarity of 'selMux' not verified) 199 | -- BUFGMUX( I0 => JTCK, I1 => selUSERLoc, SEL => selMux ); 200 | -- 201 | -- while selUSERLoc changes on negative clock edges it is guaranteed 202 | -- to never switch concurrently with captureDRLoc, shiftDRLoc and thus 203 | -- there is no chance for glitches. 204 | selUSERLoc <= r.selUSER and not testLogicResetLoc; 205 | 206 | DRCK <= (JTCK and r.drckSel ) or (not r.drckSel and selUSERLoc); 207 | SEL <= selUSERLoc; 208 | 209 | -- original BSCANE2 simulation deasserts on the positive clock edge when IR is 210 | -- updated: 211 | -- 212 | -- UPDATE <= r.updateDR and updateDrLoc 213 | -- 214 | -- however, we want to minimize the combinatorial logic here 215 | -- because ICON seems to use UPDATE as a clock and any combinatorial 216 | -- input seems to be treated as a different input clock (which we'd have 217 | -- to constrain...) 218 | UPDATE <= r.updateDR; -- and updateDRLoc; 219 | 220 | 221 | end generate G_TCK; 222 | 223 | G_TCK_CE : if ( not TCK_IS_CLOCK_G ) generate 224 | begin 225 | 226 | P_SEQ : process ( clk ) is 227 | begin 228 | if ( rising_edge( clk ) ) then 229 | if ( rst = '1' ) then 230 | r <= REG_INIT_C; 231 | DRCK <= '0'; 232 | SEL <= '0'; 233 | UPDATE <= '0'; 234 | elsif ( (JTCK_NEGEDGE = '1') or (JTCK_POSEDGE = '1') ) then 235 | if ( (JTCK_NEGEDGE = '1') ) then 236 | r <= rin; 237 | UPDATE <= rin.updateDR; 238 | SEL <= rin.selUSER; 239 | else 240 | UPDATE <= '0'; 241 | end if; 242 | DRCK <= (JTCK and rin.drckSel ) or (not rin.drckSel and rin.selUSER); 243 | if ( testLogicResetPredict = '1' and JTCK_POSEDGE = '1' ) then 244 | SEL <= '0'; 245 | DRCK <= '0'; 246 | end if; 247 | end if; 248 | end if; 249 | end process P_SEQ; 250 | 251 | end generate G_TCK_CE; 252 | 253 | CAPTURE <= r.captureDR; 254 | SHIFT <= r.shiftDR; 255 | RESET <= testLogicResetLoc; 256 | TDI <= JTDI; 257 | JTDO <= r.tdo; 258 | 259 | DRCK_SEL <= r.drckSel; 260 | UPDATE_SEL <= updateDRLoc; 261 | 262 | end architecture Impl; 263 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/README: -------------------------------------------------------------------------------- 1 | The Jtag2BSCAN module can be used under ISE (where no debug 2 | bridge in JTAG -> BSCAN mode is available) to connect an 3 | ICON core to JTAG. Note that you need the JtagTapFSM and JtagTapIR 4 | modules as well. 5 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/tb/JTAG_SIM_VIRTEX6.vhd.diff: -------------------------------------------------------------------------------- 1 | *** JTAG_SIM_VIRTEX6.vhd.orig 2020-10-01 13:29:39.724736485 +0200 2 | --- JTAG_SIM_VIRTEX6.vhd 2020-10-01 13:30:10.388164059 +0200 3 | *************** 4 | *** 641,672 **** 5 | --#################################################################### 6 | prcs_JtagSetGlobalSignals:process(ClkUpdateIR_sig, Tlrst_sig, USER1_sig, USER2_sig, USER3_sig, USER4_sig) 7 | begin 8 | ! if(rising_edge(USER1_sig)) then 9 | JTAG_SEL1_GLBL <= '1'; 10 | JTAG_SEL2_GLBL <= '0'; 11 | JTAG_SEL3_GLBL <= '0'; 12 | JTAG_SEL4_GLBL <= '0'; 13 | ! elsif(rising_edge(USER2_sig)) then 14 | JTAG_SEL1_GLBL <= '0'; 15 | JTAG_SEL2_GLBL <= '1'; 16 | JTAG_SEL3_GLBL <= '0'; 17 | JTAG_SEL4_GLBL <= '0'; 18 | ! elsif(rising_edge(USER3_sig)) then 19 | JTAG_SEL1_GLBL <= '0'; 20 | JTAG_SEL2_GLBL <= '0'; 21 | JTAG_SEL3_GLBL <= '1'; 22 | JTAG_SEL4_GLBL <= '0'; 23 | ! elsif(rising_edge(USER4_sig)) then 24 | JTAG_SEL1_GLBL <= '0'; 25 | JTAG_SEL2_GLBL <= '0'; 26 | JTAG_SEL3_GLBL <= '0'; 27 | JTAG_SEL4_GLBL <= '1'; 28 | ! elsif(rising_edge(ClkUpdateIR_sig)) then 29 | ! JTAG_SEL1_GLBL <= '0'; 30 | ! JTAG_SEL2_GLBL <= '0'; 31 | ! JTAG_SEL3_GLBL <= '0'; 32 | ! JTAG_SEL4_GLBL <= '0'; 33 | ! elsif(rising_edge(Tlrst_sig)) then 34 | JTAG_SEL1_GLBL <= '0'; 35 | JTAG_SEL2_GLBL <= '0'; 36 | JTAG_SEL3_GLBL <= '0'; 37 | --- 641,672 ---- 38 | --#################################################################### 39 | prcs_JtagSetGlobalSignals:process(ClkUpdateIR_sig, Tlrst_sig, USER1_sig, USER2_sig, USER3_sig, USER4_sig) 40 | begin 41 | ! if('1' = (Tlrst_sig)) then 42 | ! JTAG_SEL1_GLBL <= '0'; 43 | ! JTAG_SEL2_GLBL <= '0'; 44 | ! JTAG_SEL3_GLBL <= '0'; 45 | ! JTAG_SEL4_GLBL <= '0'; 46 | ! elsif('1' = (USER1_sig)) then 47 | JTAG_SEL1_GLBL <= '1'; 48 | JTAG_SEL2_GLBL <= '0'; 49 | JTAG_SEL3_GLBL <= '0'; 50 | JTAG_SEL4_GLBL <= '0'; 51 | ! elsif('1' = (USER2_sig)) then 52 | JTAG_SEL1_GLBL <= '0'; 53 | JTAG_SEL2_GLBL <= '1'; 54 | JTAG_SEL3_GLBL <= '0'; 55 | JTAG_SEL4_GLBL <= '0'; 56 | ! elsif('1' = (USER3_sig)) then 57 | JTAG_SEL1_GLBL <= '0'; 58 | JTAG_SEL2_GLBL <= '0'; 59 | JTAG_SEL3_GLBL <= '1'; 60 | JTAG_SEL4_GLBL <= '0'; 61 | ! elsif('1' = (USER4_sig)) then 62 | JTAG_SEL1_GLBL <= '0'; 63 | JTAG_SEL2_GLBL <= '0'; 64 | JTAG_SEL3_GLBL <= '0'; 65 | JTAG_SEL4_GLBL <= '1'; 66 | ! elsif('1' = (ClkUpdateIR_sig)) then 67 | JTAG_SEL1_GLBL <= '0'; 68 | JTAG_SEL2_GLBL <= '0'; 69 | JTAG_SEL3_GLBL <= '0'; 70 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/tb/Jtag2BSCANTb.vhd: -------------------------------------------------------------------------------- 1 | -- JTAG TAP with BSCAN interface (support for external USER register) 2 | -- Emulates a Xilinx BSCANE2 unit while offering fabric JTAG connections 3 | -- (The hard BSCANE2 units require access to the dedicated hardware pins). 4 | -- 5 | -- Till Straumann, 9/2020. (Inspiration from bscan_equiv.v by Patrick Allison) 6 | -- 7 | 8 | library ieee; 9 | use ieee.std_logic_1164.all; 10 | use ieee.numeric_std.all; 11 | 12 | library unisim; 13 | use unisim.vcomponents.all; 14 | 15 | use work.Jtag2BSCANTbPkg.all; 16 | 17 | entity Jtag2BSCANTb is 18 | end entity Jtag2BSCANTb; 19 | 20 | architecture Impl of Jtag2BSCANTb is 21 | 22 | -- constant PART_NAME_C : string := "3s700a"; 23 | -- constant IR_LENGTH_C : natural := 6; 24 | -- constant REG_IDCODE_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "001001"; -- must be of IR_LENGTH_C 25 | -- constant REG_USERCODE_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "001000"; -- must be of IR_LENGTH_C 26 | -- constant REG_USER_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "000010"; -- must be of IR_LENGTH_C 27 | -- constant IR_VAL_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "110101"; -- must be of IR_LENGTH_C 28 | -- constant IDCODE_VAL_C : std_logic_vector(31 downto 0) := x"02228093"; 29 | constant PART_NAME_C : string := "lx130t"; 30 | 31 | constant IR_LENGTH_C : natural := 10; 32 | constant REG_IDCODE_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "1111001001"; -- must be of IR_LENGTH_C 33 | constant REG_USERCODE_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "1111001000"; -- must be of IR_LENGTH_C 34 | constant REG_USER_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "1111000010"; -- must be of IR_LENGTH_C 35 | constant IR_VAL_C : std_logic_vector(IR_LENGTH_C - 1 downto 0) := "1111110001"; -- must be of IR_LENGTH_C bit 5 indicates configured device 36 | constant IDCODE_VAL_C : std_logic_vector(31 downto 0) := x"0424a093"; 37 | constant USERCODE_VAL_C : std_logic_vector(31 downto 0) := x"ffffffff"; 38 | constant USER_VAL_C : std_logic_vector(31 downto 0) := x"affecafe"; 39 | 40 | constant HALFPERIOD : time := 60 ns; 41 | constant SAMPLETIME : time := 10 ns; 42 | 43 | signal jtck : std_logic := '0'; 44 | signal jtms : std_logic := '1'; 45 | signal jtdi : std_logic := 'X'; 46 | signal jtdo : std_logic; 47 | signal jtdocmp : std_logic; 48 | 49 | signal TDO : std_logic := 'X'; 50 | signal SEL : std_logic; 51 | signal DRCK : std_logic; 52 | signal CAPTURE : std_logic; 53 | signal SHIFT : std_logic; 54 | signal UPDATE : std_logic; 55 | signal RESET : std_logic; 56 | signal TDI : std_logic; 57 | signal SEL_CMP : std_logic; 58 | signal DRCK_CMP : std_logic; 59 | signal CAPTURE_CMP : std_logic; 60 | signal SHIFT_CMP : std_logic; 61 | signal UPDATE_CMP : std_logic; 62 | signal RESET_CMP : std_logic; 63 | signal TDI_CMP : std_logic; 64 | signal UPDATE_SEL : std_logic; 65 | signal UPDATE_RAW : std_logic; 66 | 67 | 68 | signal tstDone : boolean := false; 69 | 70 | signal IRegOut : std_logic_vector(IR_LENGTH_C - 1 downto 0); 71 | signal DRegOut : std_logic_vector(31 downto 0); 72 | 73 | signal usr : std_logic_vector(31 downto 0) := (others => 'X'); 74 | 75 | begin 76 | 77 | P_CLK : process is 78 | begin 79 | wait for HALFPERIOD; 80 | jtck <= not jtck; 81 | if ( tstDone ) then 82 | wait; 83 | end if; 84 | end process P_CLK; 85 | 86 | P_USR : process ( DRCK ) is 87 | begin 88 | if ( rising_edge( DRCK ) ) then 89 | if ( CAPTURE = '1' ) then 90 | usr <= USER_VAL_C; 91 | elsif ( SHIFT = '1' ) then 92 | usr <= 'X' & usr(usr'left downto 1); 93 | end if; 94 | end if; 95 | end process P_USR; 96 | 97 | TDO <= usr(0); 98 | 99 | UPDATE <= UPDATE_RAW and UPDATE_SEL; 100 | 101 | B_TST : process is 102 | 103 | procedure setTMSTDI(constant tms_i : std_logic; constant tdi_i : std_logic) is 104 | begin 105 | wait until falling_edge( jtck ); 106 | jtms <= tms_i; 107 | jtdi <= tdi_i; 108 | wait until rising_edge( jtck ); 109 | end procedure setTMSTDI; 110 | 111 | procedure setTMS(constant tms_i : std_logic) is 112 | begin 113 | setTMSTDI(tms_i, 'X'); 114 | end procedure setTMS; 115 | 116 | procedure testLogicReset is 117 | begin 118 | for i in 1 to 5 loop 119 | setTMS('1'); 120 | end loop; 121 | end procedure testLogicReset; 122 | 123 | procedure runTestIdle is 124 | begin 125 | testLogicReset; 126 | setTMS('0'); 127 | end procedure runTestIdle; 128 | 129 | procedure doShift(constant reg_i : std_logic_vector; signal reg_o : inout std_logic_vector) is 130 | variable tmsVal : std_logic; 131 | begin 132 | tmsVal := '0'; 133 | for i in reg_i'right to reg_i'left loop 134 | if ( i = reg_i'left ) then 135 | tmsVal := '1'; 136 | end if; 137 | setTMSTDI(tmsVal, reg_i(i)); 138 | -- reg_o might be wider than reg_i 139 | reg_o(reg_i'left) <= jtdo; 140 | reg_o(reg_i'left - 1 downto 0) <= reg_o(reg_i'left downto 1); 141 | end loop; 142 | end procedure doShift; 143 | 144 | -- assume we start from testRunIdle 145 | procedure scanReg(constant isIR: boolean; constant reg_i : std_logic_vector; signal reg_o : inout std_logic_vector) is 146 | begin 147 | setTMS('1'); -- select DR -> selectIR/Capture 148 | if ( isIR ) then 149 | setTMS('1'); -- selectIR -> capture 150 | end if; 151 | setTMS('0'); -- capture -> scan 152 | setTMS('0'); -- scan -> exit1 153 | doShift(reg_i, reg_o); 154 | setTMS('1'); -- exit1 -> update 155 | setTMS('0'); -- update -> testLogicReset 156 | end procedure scanReg; 157 | 158 | procedure scanIR(constant reg_i : std_logic_vector; signal reg_o : inout std_logic_vector) is 159 | begin 160 | scanReg(true, reg_i, reg_o); 161 | end procedure scanIR; 162 | 163 | procedure scanDR(constant reg_i : std_logic_vector; signal reg_o : inout std_logic_vector) is 164 | begin 165 | scanReg(false, reg_i, reg_o); 166 | end procedure scanDR; 167 | 168 | variable DReg : std_logic_vector(DRegOut'range); 169 | 170 | begin 171 | 172 | for i in 1 to 4 loop 173 | wait until rising_edge( jtck ); 174 | end loop; 175 | 176 | runTestIdle; 177 | 178 | scanIR( REG_IDCODE_C, IRegOut ); 179 | if ( IRegOut /= IR_VAL_C ) then 180 | report "IR READOUT FAILED" severity failure; 181 | end if; 182 | 183 | DReg := (others => '0'); 184 | scanDR( DReg, DRegOut ); 185 | if ( DRegOut /= IDCODE_VAL_C ) then 186 | report "ID READOUT FAILED" severity failure; 187 | end if; 188 | 189 | scanIR( REG_USER_C, IRegOut ); 190 | DReg := (others => '0'); 191 | scanDR( DReg, DRegOut ); 192 | if ( DRegOut /= USER_VAL_C ) then 193 | report "USER REG readout failed" severity failure; 194 | end if; 195 | 196 | scanIR( REG_USERCODE_C, IRegOut ); 197 | DReg := (others => '0'); 198 | scanDR( DReg, DRegOut ); 199 | if ( DRegOut /= USERCODE_VAL_C ) then 200 | report "USERCODE REG readout failed" severity failure; 201 | end if; 202 | 203 | 204 | tstDone <= true; 205 | wait; 206 | end process B_TST; 207 | 208 | B_CMP_P : process is 209 | variable cnt : natural; 210 | begin 211 | cnt := 0; 212 | for i in 1 to 2 loop 213 | wait until rising_edge(jtck); 214 | end loop; 215 | 216 | while ( not tstDone ) loop 217 | wait until jtck'event; 218 | wait for SAMPLETIME; 219 | if ( UPDATE /= UPDATE_CMP ) then 220 | wait until rising_edge(jtck); 221 | report "UPDATE mismatch" severity failure; 222 | end if; 223 | if ( CAPTURE /= CAPTURE_CMP ) then 224 | wait until rising_edge(jtck); 225 | report "CAPTURE mismatch" severity failure; 226 | end if; 227 | if ( SHIFT /= SHIFT_CMP ) then 228 | wait until rising_edge(jtck); 229 | report "SHIFT mismatch" severity failure; 230 | end if; 231 | if ( SEL /= SEL_CMP ) then 232 | wait until rising_edge(jtck); 233 | report "SEL mismatch" severity failure; 234 | end if; 235 | if ( RESET /= RESET_CMP ) then 236 | wait until rising_edge(jtck); 237 | report "RESET mismatch" severity failure; 238 | end if; 239 | if ( TDI /= TDI_CMP ) then 240 | wait until rising_edge(jtck); 241 | report "TDI mismatch" severity failure; 242 | end if; 243 | if ( DRCK /= DRCK_CMP ) then 244 | wait until rising_edge(jtck); 245 | report "DRCK mismatch" severity failure; 246 | end if; 247 | cnt := cnt + 1; 248 | end loop; 249 | 250 | report "Test PASSED; " & natural'image(cnt) & " comparison loops" severity note; 251 | 252 | wait; 253 | end process B_CMP_P; 254 | 255 | U_DUT : entity work.Jtag2BSCAN 256 | generic map ( 257 | IR_LENGTH_G => IR_LENGTH_C, 258 | REG_IDCODE_G => REG_IDCODE_C, 259 | REG_USERCODE_G => REG_USERCODE_C, 260 | REG_USER_G => REG_USER_C, 261 | IR_VAL_G => IR_VAL_C, 262 | IDCODE_VAL_G => IDCODE_VAL_C, 263 | USERCODE_VAL_G => USERCODE_VAL_C 264 | ) 265 | port map ( 266 | JTCK => jtck, 267 | JTMS => jtms, 268 | JTDI => jtdi, 269 | JTDO => jtdo, 270 | 271 | TDO => TDO, 272 | SEL => SEL, 273 | DRCK => DRCK, 274 | CAPTURE => CAPTURE, 275 | SHIFT => SHIFT, 276 | UPDATE => UPDATE_RAW, 277 | UPDATE_SEL => UPDATE_SEL, 278 | RESET => RESET, 279 | TDI => TDI 280 | ); 281 | 282 | U_CMP_TAP : entity work.JTAG_SIM_VIRTEX6 283 | generic map ( 284 | PART_NAME => PART_NAME_C 285 | ) 286 | port map ( 287 | TCK => jtck, 288 | TMS => jtms, 289 | TDI => jtdi, 290 | TDO => jtdocmp 291 | ); 292 | 293 | U_CMP_BSCAN : BSCANE2 294 | port map ( 295 | TDO => TDO, 296 | 297 | SEL => SEL_CMP, 298 | DRCK => DRCK_CMP, 299 | CAPTURE => CAPTURE_CMP, 300 | SHIFT => SHIFT_CMP, 301 | UPDATE => UPDATE_CMP, 302 | RESET => RESET_CMP, 303 | TDI => TDI_CMP, 304 | 305 | RUNTEST => open, 306 | TCK => open, 307 | TMS => open 308 | ); 309 | end architecture Impl; 310 | 311 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/tb/Jtag2BSCANTbPkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package Jtag2BSCANTbPkg is 6 | 7 | constant W_C : natural := 32; 8 | 9 | type TmsTdiType is record 10 | tms : std_logic_vector(W_C - 1 downto 0); 11 | tdi : std_logic_vector(W_C - 1 downto 0); 12 | nbits : natural range 0 to W_C; 13 | end record; 14 | 15 | type TdoType is record 16 | tdo : std_logic_vector(W_C - 1 downto 0); 17 | nbits : natural range 0 to W_C; 18 | end record; 19 | 20 | 21 | type TmsTdiArray is array (natural range <>) of TmsTdiType; 22 | type TdoArray is array (natural range <>) of TdoType; 23 | 24 | constant iSeq : TmsTdiArray; 25 | constant oSeq : TdoArray; 26 | 27 | end package Jtag2BSCANTbPkg; 28 | 29 | 30 | -------------------------------------------------------------------------------- /rtl/Jtag2BSCAN/tb/Tmem2BSCANWrapperTb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.StdRtlPkg.all; 6 | use work.TextUtilPkg.all; 7 | 8 | use work.Jtag2BSCANTbPkg.all; 9 | 10 | use work.ifc1210_simu_procedures_pkg.all; 11 | 12 | entity Tmem2BSCANWrapperTb is 13 | end entity Tmem2BSCANWrapperTb; 14 | 15 | architecture tb of Tmem2BSCANWrapperTb is 16 | 17 | constant DEPTH_C : slv := x"2"; 18 | 19 | constant IR_RB_VAL_C : slv(9 downto 0) := "1111110001"; 20 | 21 | function min(a,b : natural) return natural is 22 | begin 23 | if ( a < b ) then return a; else return b; end if; 24 | end function min; 25 | 26 | constant SEQ_LEN_C : natural := min( iSeq'length, oSeq'length ); 27 | 28 | signal clk : sl := '0'; 29 | signal rst : sl := '1'; 30 | signal run : boolean := true; 31 | signal cnt : integer := 0; 32 | 33 | signal idx : integer; 34 | signal tdocmp : std_logic_vector(31 downto 0); 35 | signal sidx : natural := 0; 36 | signal sbit : natural := 0; 37 | signal TDO : std_logic; 38 | signal jtck : std_logic; 39 | 40 | signal ovecErr : sl := '0'; 41 | signal ovecErrs : natural := 0; 42 | 43 | signal tmemBusI : tmem_bus_in_t := ( 44 | TMEM_ADD_i => (others => 'X'), 45 | TMEM_DATW_i => (others => 'X'), 46 | TMEM_ENA_i => '0', 47 | TMEM_WE_i => (others => '0'), 48 | TMEM_CS_i => "00" 49 | ); 50 | signal tmemBusO : tmem_bus_out_t; 51 | 52 | signal tmemData : slv(63 downto 0); 53 | 54 | constant tstData : Slv32Array := ( 55 | -- TMS 01 1000 0000 0000 1101 1111 56 | -- TDI 00 1111 0010 0100 0000 0000 57 | 0 => x"001800df", 58 | 1 => x"000f2400", 59 | 2 => x"00000115" 60 | ); 61 | 62 | constant altData : Slv32Array := ( 63 | 0 => x"ffffffff", 64 | 1 => x"ffffffff", 65 | 2 => x"affecafe" 66 | ); 67 | 68 | 69 | signal rbidx : natural; 70 | 71 | signal irq : std_logic; 72 | 73 | signal dxbg : std_logic := '0'; 74 | 75 | begin 76 | 77 | P_CLK : process is 78 | begin 79 | if ( run ) then 80 | clk <= not clk; 81 | wait for 5 ns; 82 | else 83 | wait; 84 | end if; 85 | end process P_CLK; 86 | 87 | P_CNT : process ( clk ) is 88 | begin 89 | if ( rising_edge( clk ) ) then 90 | cnt <= cnt + 1; 91 | case ( cnt ) is 92 | when 10 => 93 | rst <= '0'; 94 | when others => 95 | end case; 96 | end if; 97 | end process P_CNT; 98 | 99 | TDO <= 'X' when sidx >= SEQ_LEN_C else oSeq( sidx ).tdo( sbit ); 100 | 101 | P_FEED : process ( jtck ) is 102 | begin 103 | if ( rising_edge( jtck ) and (dxbg = '1') ) then 104 | if ( sbit = oSeq(sidx).nbits - 1 ) then 105 | sbit <= 0; 106 | sidx <= sidx + 1; 107 | else 108 | sbit <= sbit + 1; 109 | end if; 110 | end if; 111 | end process P_FEED; 112 | 113 | P_TEST : process is 114 | variable nvals : natural; 115 | 116 | procedure xact(tms, tdi: std_logic_vector(31 downto 0); numBits : natural; signal rbd : inout std_logic_vector(63 downto 0)) is 117 | variable csr : std_logic_vector(63 downto 0); 118 | begin 119 | 120 | rbd <= x"00000000_00000200"; 121 | 122 | TMEM_BUS_WRITE( "writing test values", 123 | x"00_0010", 124 | x"FF", 125 | tdi & tms, 126 | 1, 127 | clk, 128 | tmemBusI, 129 | tmemBusO); 130 | 131 | csr := x"0000_0000" & x"0002_01" & "000" & std_logic_vector(to_unsigned(numBits - 1, 5)); 132 | 133 | TMEM_BUS_WRITE( "writing test values", 134 | x"00_0018", 135 | x"0F", 136 | csr, 137 | 1, 138 | clk, 139 | tmemBusI, 140 | tmemBusO); 141 | 142 | while ( rbd(9) = '1' ) loop 143 | 144 | TMEM_BUS_READ( "Status readback", 145 | x"00_0018", 146 | 1, 147 | clk, 148 | rbd, 149 | tmemBusI, 150 | tmemBusO ); 151 | wait until rising_edge( clk ); 152 | 153 | end loop; 154 | 155 | print("TDO " & str(tmemData(63 downto 64 - numBits ))); 156 | 157 | end procedure xact; 158 | 159 | begin 160 | 161 | while ( rst = '1' ) loop 162 | wait until rising_edge( clk ); 163 | end loop; 164 | 165 | wait for 1000 ns; 166 | 167 | xact( tms => tstData(0), tdi => tstData(1), numBits => to_integer(unsigned(tstData(2)(4 downto 0)) + 1), rbd => tmemData ); 168 | 169 | if ( tmemData(61 downto 52) /= IR_RB_VAL_C ) then 170 | report "IR content mismatch; got " & str(tmemData(61 downto 52)) severity failure; 171 | end if; 172 | 173 | xact( tms => x"0000_0001", tdi => x"0000_0000", numBits => 3, rbd => tmemData ); 174 | xact( tms => x"8000_0000", tdi => x"0000_0000", numBits => 32, rbd => tmemData ); 175 | 176 | if ( tmemData(63 downto 32) /= x"0424a093" ) then 177 | report "ID mismatch" severity failure; 178 | end if; 179 | -- back to idle 180 | xact( tms => x"8000_0001", tdi => x"0000_0000", numBits => 2, rbd => tmemData ); 181 | 182 | dxbg <= '1'; 183 | 184 | for i in 0 to SEQ_LEN_C - 1 loop 185 | idx <= i; 186 | tdocmp <= oSeq(i).tdo; 187 | xact( tms => iSeq(i).tms, tdi => iSeq(i).tdi, numBits => iSeq(i).nbits, rbd => tmemData ); 188 | if ( tmemData(63 downto 64 - oSeq(i).nbits) /= oSeq(i).tdo(oSeq(i).nbits - 1 downto 0) ) then 189 | ovecErr <= '1'; 190 | ovecErrs <= ovecErrs + 1; 191 | wait until rising_edge( clk ); 192 | ovecErr <= '0'; 193 | end if; 194 | end loop; 195 | 196 | xact( tms => x"0000_00ff", tdi => x"0000_0000", numBits => 8, rbd => tmemData ); 197 | 198 | report "TDO vector mismatches: " & natural'image(ovecErrs); 199 | 200 | report "TEST PASSED"; 201 | 202 | run <= false; 203 | wait; 204 | end process P_TEST; 205 | 206 | U_DUT : entity work.Tmem2BSCANWrapper 207 | generic map ( 208 | USE_AXIS_G => false, 209 | USE_BUFS_G => -1 210 | ) 211 | port map ( 212 | clk => clk, 213 | rst => rst, 214 | 215 | tmemADD => tmemBusI.TMEM_ADD_i, 216 | tmemDATW => tmemBusI.TMEM_DATW_i, 217 | tmemENA => tmemBusI.TMEM_ENA_i, 218 | tmemWE => tmemBusI.TMEM_WE_i, 219 | tmemCS => tmemBusI.TMEM_CS_i, 220 | 221 | tmemDATR => tmemBusO.TMEM_DATR_o, 222 | tmemBUSY => tmemBusO.TMEM_BUSY_o, 223 | tmemPIPE => tmemBusO.TMEM_PIPE_o, 224 | 225 | TDO_IN => TDO, 226 | TDI_OUT => open, 227 | RESET_OUT => open, 228 | SHIFT_OUT => open, 229 | UPDATE_OUT => open, 230 | CAPTURE_OUT => open, 231 | SEL_OUT => open, 232 | DRCK_OUT => open, 233 | 234 | JTCK_OUT => jtck, 235 | 236 | irq => open 237 | ); 238 | 239 | end architecture tb; 240 | -------------------------------------------------------------------------------- /rtl/JtagTap/JtagTapFSM.vhd: -------------------------------------------------------------------------------- 1 | -- JTAG State Machine 2 | 3 | -- Till Straumann, 9/2020. 4 | 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | 9 | -- The current state is flagged on the respective output. 10 | -- During one of the the shifting (sub-)states (selectScan..update) 11 | -- either scanDR or scanIR is asserted. 12 | -- E.g., capture_DR may be detected as 13 | -- 14 | -- capture_DR <= capture and scanDR; 15 | -- 16 | -- The outputs change state on the rising edge of tck. 17 | 18 | entity JtagTapFsm is 19 | generic ( 20 | TCK_IS_CLOCK_G : boolean := true 21 | ); 22 | port ( 23 | clk : in std_logic := '0'; 24 | rst : in std_logic := '0'; 25 | tck_posedge : in std_logic := '0'; 26 | tck_negedge : in std_logic := '0'; 27 | tck : in std_logic; 28 | tms : in std_logic; 29 | tdi : in std_logic; 30 | testLogicReset : out std_logic; 31 | runTestIdle : out std_logic; 32 | scanDR : out std_logic; 33 | scanIR : out std_logic; 34 | selectScan : out std_logic; 35 | capture : out std_logic; 36 | shift : out std_logic; 37 | exit1 : out std_logic; 38 | pause : out std_logic; 39 | exit2 : out std_logic; 40 | update : out std_logic; 41 | nextStateTLR : out std_logic 42 | ); 43 | end entity JtagTapFsm; 44 | 45 | architecture Impl of JtagTapFsm is 46 | 47 | constant TEST_LOGIC_RESET_C : natural := 0; 48 | constant RUN_TEST_IDLE_C : natural := 1; 49 | constant SCAN_DR_C : natural := 2; 50 | constant SCAN_IR_C : natural := 3; 51 | 52 | constant SELECT_SCAN_C : natural := 0; 53 | constant CAPTURE_C : natural := 1; 54 | constant SHIFT_C : natural := 2; 55 | constant EXIT1_C : natural := 3; 56 | constant PAUSE_C : natural := 4; 57 | constant EXIT2_C : natural := 5; 58 | constant UPDATE_C : natural := 6; 59 | 60 | subtype TapPrimaryStateType is std_logic_vector(SCAN_IR_C downto TEST_LOGIC_RESET_C); 61 | subtype TapScanStateType is std_logic_vector(UPDATE_C downto SELECT_SCAN_C ); 62 | 63 | type RegType is record 64 | primaryState : TapPrimaryStateType; 65 | scanSubState : TapScanStateType; 66 | end record; 67 | 68 | constant REG_INIT_C : RegType := ( 69 | primaryState => ( TEST_LOGIC_RESET_C => '1', others => '0' ), 70 | scanSubState => (others => '0' ) 71 | ); 72 | 73 | signal r : RegType := REG_INIT_C; 74 | signal rin : RegType; 75 | 76 | function nextPrimaryState(s : natural range TapPrimaryStateType'range) return TapPrimaryStateType is 77 | variable v : TapPrimaryStateType; 78 | begin 79 | v := (others => '0'); 80 | v(s) := '1'; 81 | return v; 82 | end function nextPrimaryState; 83 | 84 | function nextScanState(s : natural range TapScanStateType'range) return TapScanStateType is 85 | variable v : TapScanStateType; 86 | begin 87 | v := (others => '0'); 88 | v(s) := '1'; 89 | return v; 90 | end function nextScanState; 91 | 92 | function nextScanState return TapScanStateType is 93 | variable v : TapScanStateType; 94 | begin 95 | v := (others => '0'); 96 | return v; 97 | end function nextScanState; 98 | 99 | 100 | begin 101 | 102 | P_COMB : process (r, tms, tdi) is 103 | variable v : RegType; 104 | begin 105 | v := r; 106 | 107 | if ( r.primaryState(TEST_LOGIC_RESET_C) = '1' ) then 108 | if ( tms = '0' ) then 109 | v.primaryState := nextPrimaryState( RUN_TEST_IDLE_C ); 110 | end if; 111 | elsif ( r.primaryState(RUN_TEST_IDLE_C) = '1' ) then 112 | if ( tms = '1' ) then 113 | v.primaryState := nextPrimaryState( SCAN_DR_C ); 114 | v.scanSubState := nextScanState ( SELECT_SCAN_C ); 115 | end if; 116 | elsif ( r.primaryState(SCAN_DR_C) = '1' or r.primaryState(SCAN_IR_C) = '1' ) then 117 | if ( r.scanSubState(SELECT_SCAN_C) = '1' ) then 118 | if ( tms = '1' ) then 119 | if ( r.primaryState(SCAN_DR_C) = '1' ) then 120 | v.primaryState := nextPrimaryState( SCAN_IR_C ); 121 | else 122 | v.primaryState := nextPrimaryState( TEST_LOGIC_RESET_C ); 123 | v.scanSubState := nextScanState; 124 | end if; 125 | else 126 | v.scanSubState := nextScanState( CAPTURE_C ); 127 | end if; 128 | elsif ( r.scanSubState(CAPTURE_C) = '1' ) then 129 | if ( tms = '1' ) then 130 | v.scanSubState := nextScanState( EXIT1_C ); 131 | else 132 | v.scanSubState := nextScanState( SHIFT_C ); 133 | end if; 134 | elsif ( r.scanSubState( SHIFT_C ) = '1' ) then 135 | if ( tms = '1' ) then 136 | v.scanSubState := nextScanState( EXIT1_C ); 137 | end if; 138 | elsif ( r.scanSubState( EXIT1_C ) = '1' ) then 139 | if ( tms = '1' ) then 140 | v.scanSubState := nextScanState( UPDATE_C ); 141 | else 142 | v.scanSubState := nextScanState( PAUSE_C ); 143 | end if; 144 | elsif ( r.scanSubState( PAUSE_C ) = '1' ) then 145 | if ( tms = '1' ) then 146 | v.scanSubState := nextScanState( EXIT2_C ); 147 | end if; 148 | elsif ( r.scanSubState( EXIT2_C ) = '1' ) then 149 | if ( tms = '1' ) then 150 | v.scanSubState := nextScanState( UPDATE_C ); 151 | else 152 | v.scanSubState := nextScanState( SHIFT_C ); 153 | end if; 154 | elsif ( r.scanSubState( UPDATE_C ) = '1' ) then 155 | if ( tms = '1' ) then 156 | v.primaryState := nextPrimaryState( SCAN_DR_C ); 157 | v.scanSubState := nextScanState ( SELECT_SCAN_C ); 158 | else 159 | v.primaryState := nextPrimaryState( RUN_TEST_IDLE_C ); 160 | v.scanSubState := nextScanState; 161 | end if; 162 | else 163 | report "This Scan State Should Never Be Reached" severity failure; 164 | 165 | v.primaryState := nextPrimaryState( TEST_LOGIC_RESET_C ); 166 | v.scanSubState := nextScanState; 167 | end if; 168 | else 169 | report "This Primary State Should Never Be Reached" severity failure; 170 | v.primaryState := nextPrimaryState( TEST_LOGIC_RESET_C ); 171 | v.scanSubState := nextScanState; 172 | end if; 173 | 174 | rin <= v; 175 | end process P_COMB; 176 | 177 | G_TCK : if ( TCK_IS_CLOCK_G ) generate 178 | P_SEQ : process ( tck ) is 179 | begin 180 | if ( rising_edge( tck ) ) then 181 | r <= rin; 182 | end if; 183 | end process P_SEQ; 184 | end generate G_TCK; 185 | 186 | G_TCK_CE : if ( not TCK_IS_CLOCK_G ) generate 187 | P_SEQ : process ( clk ) is 188 | begin 189 | if ( rising_edge( clk ) ) then 190 | if ( rst = '1' ) then 191 | r <= REG_INIT_C; 192 | elsif ( tck_posedge = '1' ) then 193 | r <= rin; 194 | end if; 195 | end if; 196 | end process P_SEQ; 197 | end generate G_TCK_CE; 198 | 199 | testLogicReset <= r.primaryState( TEST_LOGIC_RESET_C ); 200 | runTestIdle <= r.primaryState( RUN_TEST_IDLE_C ); 201 | scanDR <= r.primaryState( SCAN_DR_C ); 202 | scanIR <= r.primaryState( SCAN_IR_C ); 203 | selectScan <= r.scanSubState( SELECT_SCAN_C ); 204 | capture <= r.scanSubState( CAPTURE_C ); 205 | shift <= r.scanSubState( SHIFT_C ); 206 | exit1 <= r.scanSubState( EXIT1_C ); 207 | pause <= r.scanSubState( PAUSE_C ); 208 | exit2 <= r.scanSubState( EXIT2_C ); 209 | update <= r.scanSubState( UPDATE_C ); 210 | nextStateTLR <= rin.primaryState( TEST_LOGIC_RESET_C ); 211 | 212 | end architecture Impl; 213 | -------------------------------------------------------------------------------- /rtl/JtagTap/JtagTapIR.vhd: -------------------------------------------------------------------------------- 1 | -- JTAG TAP controller with support for 2 | -- IDCODE, 3 | -- BYPASS, 4 | -- USERCODE (32-bit data) 5 | -- USER (external data register) 6 | -- instructions. 7 | -- The IR always reads as IR_VAL_G, USERCODE always reads as USERCODE_VAL_G. 8 | 9 | -- Till Straumann, 9/2020. 10 | 11 | library ieee; 12 | use ieee.std_logic_1164.all; 13 | use ieee.numeric_std.all; 14 | 15 | entity JtagTapIR is 16 | generic ( 17 | IR_LENGTH_G : natural := 6; 18 | REG_IDCODE_G : std_logic_vector := "001001"; -- must be of IR_LENGTH_G 19 | REG_USERCODE_G : std_logic_vector := "001000"; -- must be of IR_LENGTH_G 20 | REG_USER_G : std_logic_vector := "000010"; -- must be of IR_LENGTH_G 21 | IR_VAL_G : std_logic_vector := "110101"; -- must be of IR_LENGTH_G 22 | IDCODE_VAL_G : std_logic_vector(31 downto 0) := x"22228093"; 23 | USERCODE_VAL_G : std_logic_vector(31 downto 0) := x"ffffffff"; 24 | TCK_IS_CLOCK_G : boolean := true 25 | ); 26 | port ( 27 | clk : in std_logic := '0'; 28 | rst : in std_logic := '0'; 29 | tck_posedge : in std_logic := '0'; 30 | tck_negedge : in std_logic := '0'; 31 | tck : in std_logic; 32 | tdi : in std_logic; 33 | testLogicReset : in std_logic; -- input from FSM 34 | captureIR : in std_logic; -- input from FSM 35 | shiftIR : in std_logic; -- input from FSM 36 | updateIR : in std_logic; -- input from FSM 37 | captureDR : in std_logic; -- input from FSM 38 | shiftDR : in std_logic; -- input from FSM 39 | tdo : out std_logic; 40 | selUSER : out std_logic; -- USER instruction; changes state on falling edge of TCK 41 | selBYPASS : out std_logic -- BYPASS " " " " " " " " " 42 | ); 43 | end entity JtagTapIR; 44 | 45 | architecture Impl of JtagTapIR is 46 | 47 | function maxl(a,b : std_logic_vector) return natural is 48 | begin 49 | if ( b'length > a'length ) then 50 | return b'length; 51 | else 52 | return a'length; 53 | end if; 54 | end function maxl; 55 | 56 | constant MAX_DR_C : natural := maxl(IDCODE_VAL_G, USERCODE_VAL_G); 57 | 58 | constant REG_BYPASS_C : std_logic_vector(IR_LENGTH_G - 1 downto 0 ) := (others => '1' ); 59 | 60 | type RegNType is record 61 | ir : std_logic_vector(IR_LENGTH_G - 1 downto 0); 62 | selBypass : std_logic; 63 | selUser : std_logic; 64 | end record RegNType; 65 | 66 | constant REG_N_INIT_C : RegNType := ( 67 | ir => REG_IDCODE_G, 68 | selBypass => '0', 69 | selUser => '0' 70 | ); 71 | 72 | type RegPType is record 73 | shift_ir : std_logic_vector(IR_LENGTH_G - 1 downto 0); 74 | shift_dr : std_logic_vector(MAX_DR_C - 1 downto 0); 75 | dr_decoded : boolean; 76 | dr_lst : natural range 0 to MAX_DR_C - 1; 77 | end record RegPType; 78 | 79 | constant REG_P_INIT_C : RegPType := ( 80 | shift_ir => (others => '0'), 81 | shift_dr => (others => '0'), 82 | dr_decoded => true, 83 | dr_lst => 0 84 | ); 85 | 86 | signal rn : RegNType := REG_N_INIT_C; 87 | signal rnin : RegNType; 88 | 89 | signal rp : RegPType := REG_P_INIT_C; 90 | signal rpin : RegPType; 91 | 92 | begin 93 | 94 | P_COMB_N : process ( rn, rp, testLogicReset, updateIR ) is 95 | variable v : RegNType; 96 | begin 97 | v := rn; 98 | if ( testLogicReset = '1' ) then 99 | v := REG_N_INIT_C; 100 | elsif ( updateIR = '1' ) then 101 | v.ir := rp.shift_ir; 102 | end if; 103 | 104 | v.selBypass := '0'; 105 | v.selUser := '0'; 106 | if ( v.ir = REG_BYPASS_C ) then 107 | v.selBypass := '1'; 108 | elsif ( v.ir = REG_USER_G ) then 109 | v.selUser := '1'; 110 | end if; 111 | 112 | rnin <= v; 113 | end process P_COMB_N; 114 | 115 | P_COMB_P : process ( rn, rp, tdi, testLogicReset, captureIR, shiftIR, captureDR, shiftDR ) is 116 | variable v : RegPType; 117 | begin 118 | v := rp; 119 | if ( testLogicReset = '1' ) then 120 | v := REG_P_INIT_C; 121 | elsif ( captureIR = '1' ) then 122 | v.shift_ir := IR_VAL_G; 123 | elsif ( shiftIR = '1' ) then 124 | v.shift_ir := (tdi & rp.shift_ir(rp.shift_ir'left downto 1)); 125 | elsif ( captureDR = '1' ) then 126 | v.dr_decoded := true; 127 | if ( rn.ir = REG_IDCODE_G ) then 128 | v.shift_dr(IDCODE_VAL_G'range) := IDCODE_VAL_G; 129 | v.dr_lst := IDCODE_VAL_G'left; 130 | elsif ( rn.ir = REG_USERCODE_G ) then 131 | v.shift_dr(USERCODE_VAL_G'range) := USERCODE_VAL_G; 132 | v.dr_lst := USERCODE_VAL_G'left; 133 | else -- includes REG_BYPASS_C 134 | if ( rn.ir /= REG_BYPASS_C ) then 135 | v.dr_decoded := false; 136 | end if; 137 | v.shift_dr(0) := '0'; 138 | v.dr_lst := 0; 139 | end if; 140 | elsif ( shiftDR = '1' ) then 141 | v.shift_dr( v.dr_lst ) := tdi; 142 | v.shift_dr( v.dr_lst - 1 downto 0 ) := rp.shift_dr( v.dr_lst downto 1 ); 143 | end if; 144 | 145 | rpin <= v; 146 | end process P_COMB_P; 147 | 148 | G_TCK : if ( TCK_IS_CLOCK_G ) generate 149 | 150 | P_SEQ_N : process ( tck ) is 151 | begin 152 | if ( falling_edge( tck ) ) then 153 | rn <= rnin; 154 | end if; 155 | end process P_SEQ_N; 156 | 157 | P_SEQ_P : process ( tck ) is 158 | begin 159 | if ( rising_edge( tck ) ) then 160 | rp <= rpin; 161 | end if; 162 | end process P_SEQ_P; 163 | 164 | end generate G_TCK; 165 | 166 | G_TCK_CE : if ( not TCK_IS_CLOCK_G ) generate 167 | 168 | P_SEQ_N : process ( clk ) is 169 | begin 170 | if ( rising_edge( clk ) ) then 171 | if ( rst = '1' ) then 172 | rn <= REG_N_INIT_C; 173 | elsif ( tck_negedge = '1' ) then 174 | rn <= rnin; 175 | end if; 176 | end if; 177 | end process P_SEQ_N; 178 | 179 | P_SEQ_P : process ( clk ) is 180 | begin 181 | if ( rising_edge( clk ) ) then 182 | if ( rst = '1' ) then 183 | rp <= REG_P_INIT_C; 184 | elsif ( tck_posedge = '1' ) then 185 | rp <= rpin; 186 | end if; 187 | end if; 188 | end process P_SEQ_P; 189 | 190 | end generate G_TCK_CE; 191 | 192 | -- output signals must still be registered on falling edge by the user 193 | selBYPASS <= rnin.selBypass; 194 | selUSER <= rnin.selUser; 195 | tdo <= rp.shift_ir(0) when shiftIR = '1' else rp.shift_dr(0) when rp.dr_decoded else '1'; 196 | 197 | end architecture Impl; 198 | -------------------------------------------------------------------------------- /rtl/JtagTap/README: -------------------------------------------------------------------------------- 1 | Generic JTAG TAP and IR support 2 | -------------------------------------------------------------------------------- /rtl/sim/JtagSniffer.py: -------------------------------------------------------------------------------- 1 | class TestLogicReset: 2 | def __init__(self,ctx): 3 | self.ctx_=ctx 4 | 5 | def advance(self, tms, tdi): 6 | if ( tms ): 7 | return self 8 | else: 9 | return self.ctx_.RunTestIdle 10 | 11 | class RunTestIdle: 12 | def __init__(self,ctx): 13 | self.ctx_=ctx 14 | 15 | def advance(self, tms, tdi): 16 | if ( tms ): 17 | return self.ctx_.SelectDRScan 18 | else: 19 | return self 20 | 21 | class SelectDRScan: 22 | def __init__(self,ctx): 23 | self.ctx_=ctx 24 | 25 | def advance(self, tms, tdi): 26 | if ( tms ): 27 | return self.ctx_.SelectIRScan 28 | else: 29 | return self.ctx_.CaptureDR 30 | 31 | class CaptureDR: 32 | def __init__(self,ctx): 33 | self.ctx_=ctx 34 | 35 | def advance(self, tms, tdi): 36 | self.ctx_.captureDR() 37 | if ( tms ): 38 | return self.ctx_.Exit1DR 39 | else: 40 | return self.ctx_.ShiftDR 41 | 42 | class ShiftDR: 43 | def __init__(self,ctx): 44 | self.ctx_=ctx 45 | 46 | def advance(self, tms, tdi): 47 | self.ctx_.shiftDR(tdi) 48 | if ( tms ): 49 | return self.ctx_.Exit1DR 50 | else: 51 | return self 52 | 53 | class Exit1DR: 54 | def __init__(self,ctx): 55 | self.ctx_=ctx 56 | 57 | def advance(self, tms, tdi): 58 | if ( tms ): 59 | return self.ctx_.UpdateDR 60 | else: 61 | return self.ctx_.PauseDR 62 | 63 | class PauseDR: 64 | def __init__(self,ctx): 65 | self.ctx_=ctx 66 | 67 | def advance(self, tms, tdi): 68 | if ( tms ): 69 | return self.ctx_.Exit2DR 70 | else: 71 | return self 72 | 73 | class Exit2DR: 74 | def __init__(self,ctx): 75 | self.ctx_=ctx 76 | 77 | def advance(self, tms, tdi): 78 | if ( tms ): 79 | return self.ctx_.UpdateDR 80 | else: 81 | return self.ctx_.ShiftDR 82 | 83 | class UpdateDR: 84 | def __init__(self,ctx): 85 | self.ctx_=ctx 86 | 87 | def advance(self, tms, tdi): 88 | self.ctx_.updateDR() 89 | if ( tms ): 90 | return self.ctx_.SelectDRScan 91 | else: 92 | return self.ctx_.RunTestIdle 93 | 94 | class SelectIRScan: 95 | def __init__(self,ctx): 96 | self.ctx_=ctx 97 | 98 | def advance(self, tms, tdi): 99 | if ( tms ): 100 | return self.ctx_.TestLogicReset 101 | else: 102 | return self.ctx_.CaptureIR 103 | 104 | class CaptureIR: 105 | def __init__(self,ctx): 106 | self.ctx_=ctx 107 | 108 | def advance(self, tms, tdi): 109 | self.ctx_.captureIR() 110 | if ( tms ): 111 | return self.ctx_.Exit1IR 112 | else: 113 | return self.ctx_.ShiftIR 114 | 115 | class ShiftIR: 116 | def __init__(self,ctx): 117 | self.ctx_=ctx 118 | 119 | def advance(self, tms, tdi): 120 | self.ctx_.shiftIR(tdi) 121 | if ( tms ): 122 | return self.ctx_.Exit1IR 123 | else: 124 | return self 125 | 126 | class Exit1IR: 127 | def __init__(self,ctx): 128 | self.ctx_=ctx 129 | 130 | def advance(self, tms, tdi): 131 | if ( tms ): 132 | return self.ctx_.UpdateIR 133 | else: 134 | return self.ctx_.PauseIR 135 | 136 | class PauseIR: 137 | def __init__(self,ctx): 138 | self.ctx_=ctx 139 | 140 | def advance(self, tms, tdi): 141 | if ( tms ): 142 | return self.ctx_.Exit2IR 143 | else: 144 | return self 145 | 146 | class Exit2IR: 147 | def __init__(self,ctx): 148 | self.ctx_=ctx 149 | 150 | def advance(self, tms, tdi): 151 | if ( tms ): 152 | return self.ctx_.UpdateIR 153 | else: 154 | return self.ctx_.ShiftIR 155 | 156 | class UpdateIR: 157 | def __init__(self,ctx): 158 | self.ctx_=ctx 159 | 160 | def advance(self, tms, tdi): 161 | self.ctx_.updateIR() 162 | if ( tms ): 163 | return self.ctx_.SelectDRScan 164 | else: 165 | return self.ctx_.RunTestIdle 166 | 167 | 168 | class JtagShiftReg: 169 | def __init__(self, LIM=0): 170 | self.reg_ = 0 171 | self.len_ = 0 172 | self.shr_ = 0 173 | self.shl_ = 0 174 | self.msk_ = 1 175 | self.lim_ = LIM 176 | 177 | def capture(self): 178 | self.shr_ = 0 179 | self.shl_ = 0 180 | self.msk_ = 1 181 | 182 | def shift(self, tdi): 183 | if ( tdi ): 184 | self.shr_ |= self.msk_ 185 | self.shl_ += 1 186 | self.msk_ <<= 1 187 | 188 | def update(self): 189 | if (self.lim_ > 0 and self.shl_ != self.lim_ ): 190 | raise RuntimeError("Bad DATA? Register length mismatch") 191 | self.reg_ = self.shr_ 192 | self.len_ = self.shl_ 193 | 194 | def getLength(self): 195 | return self.len_ 196 | 197 | def getData(self): 198 | return self.reg_ 199 | 200 | class JtagSniffer: 201 | 202 | def __init__(self, IR_USER=0x3c2, IR_LEN=10): 203 | self.TestLogicReset=TestLogicReset(self) 204 | self.RunTestIdle=RunTestIdle(self) 205 | self.SelectDRScan=SelectDRScan(self) 206 | self.CaptureDR=CaptureDR(self) 207 | self.ShiftDR=ShiftDR(self) 208 | self.Exit1DR=Exit1DR(self) 209 | self.PauseDR=PauseDR(self) 210 | self.Exit2DR=Exit2DR(self) 211 | self.UpdateDR=UpdateDR(self) 212 | self.SelectIRScan=SelectIRScan(self) 213 | self.CaptureIR=CaptureIR(self) 214 | self.ShiftIR=ShiftIR(self) 215 | self.Exit1IR=Exit1IR(self) 216 | self.PauseIR=PauseIR(self) 217 | self.Exit2IR=Exit2IR(self) 218 | self.UpdateIR=UpdateIR(self) 219 | 220 | self.IR_USR_ = IR_USER 221 | self.IR_ULN_ = IR_LEN 222 | self.state_ = self.TestLogicReset 223 | self.IR_ = ~IR_USER 224 | self.IR_SHR_ = 0 225 | self_IR_LEN_ = 0 226 | 227 | self.DR_ = 0 228 | self.DR_SHR_ = 0 229 | self.DR_LEN_ = 0 230 | 231 | self.DR = JtagShiftReg() 232 | self.IR = JtagShiftReg(LIM=IR_LEN) 233 | 234 | def advance(self, tms, tdi): 235 | self.state_ = self.state_.advance(tms, tdi) 236 | 237 | def isUSER(self): 238 | return self.IR.getData() == self.IR_USR_ 239 | 240 | def captureIR(self): 241 | self.IR.capture() 242 | 243 | def captureDR(self): 244 | if (self.isUSER()): 245 | self.DR.capture() 246 | 247 | def shiftIR(self, tdi): 248 | self.IR.shift(tdi) 249 | 250 | def shiftDR(self, tdi): 251 | if (self.isUSER()): 252 | self.DR.shift(tdi) 253 | 254 | def updateIR(self): 255 | self.IR.update() 256 | #print("New IR: 0x{:x}".format(self.IR.getData())) 257 | 258 | def updateDR(self): 259 | if (self.isUSER()): 260 | self.DR.update() 261 | print("New DR[{}]: {:x}".format(self.DR.getLength(),self.DR.getData())) 262 | 263 | 264 | def processVecs(self, tms, tdi, nbits): 265 | for i in range(nbits): 266 | self.advance( not not (tms & 1), not not (tdi & 1) ) 267 | tms >>= 1 268 | tdi >>= 1 269 | -------------------------------------------------------------------------------- /rtl/sim/README: -------------------------------------------------------------------------------- 1 | This directory contains scripts that are useful 2 | for simulation/debugging. 3 | 4 | They can process logged output from 'xvcSrc' to 5 | generate test vectors. 6 | -------------------------------------------------------------------------------- /rtl/sim/dump2pkg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Convert a log obtained from xvcSrv -vv to a VHDL 4 | # package body (declaration in 5 | # Jtag2Bscan/tb/Jtag2BSCANTbPkg.vhd 6 | # ) for simulations. 7 | if [ $# -lt 1 ] ; then 8 | echo "Need input file name arg" 9 | exit 1 10 | fi 11 | ofnam="Jtag2BSCANTbPkgBody.vhd" 12 | rm -i "$ofnam" 13 | echo 'package body Jtag2BSCANTbPkg is' >> "$ofnam" 14 | echo ' constant iSeq : TmsTdiArray := (' >> "$ofnam" 15 | grep TMS $1 >> "$ofnam" 16 | # append a sentinel (avoid having to eliminate trailing ',') 17 | # --> simulation code must skip last element. 18 | echo '( TMS => x"0000001f", TDI => x"00000000", nbits => 5 )' >> "$ofnam" 19 | echo ' );' >> "$ofnam" 20 | echo ' constant oSeq : TdoArray := (' >> "$ofnam" 21 | grep TDO $1 >> "$ofnam" 22 | # append a sentinel (avoid having to eliminate trailing ',') 23 | # --> simulation code must skip last element. 24 | echo '( TDO => x"00000000", nbits => 5 )' >> "$ofnam" 25 | echo ' );' >> "$ofnam" 26 | echo 'end package body Jtag2BSCANTbPkg;' >> "$ofnam" 27 | -------------------------------------------------------------------------------- /rtl/sim/proc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import re 3 | import sys 4 | import JtagSniffer 5 | 6 | if ( len(sys.argv) < 2 ): 7 | print("Need filename arg") 8 | sys.exit(1) 9 | 10 | f=sys.argv[1] 11 | 12 | patt=re.compile('^BSCN') 13 | 14 | msk_tck_o = (1<<16) 15 | msk_tms_o = (1<<17) 16 | msk_tdi_o = (1<<18) 17 | msk_tdo_i = (1<<19) 18 | msk_tck_rb = (1<<20) 19 | msk_tms_rb = (1<<21) 20 | msk_tdi_rb = (1<<22) 21 | msk_bscn_tdo = (1<<23) 22 | msk_bscn_sel = (1<<24) 23 | msk_bscn_dck = (1<<25) 24 | msk_bscn_upd = (1<<26) 25 | msk_bscn_shf = (1<<27) 26 | msk_bscn_rst = (1<<28) 27 | msk_bscn_tdi = (1<<29) 28 | msk_bscn_cap = (1<<30) 29 | 30 | def pval(v, endmark='\n'): 31 | print("SE({:d}) CK({:d}) CA({:d}) DI({:d}) DO({:d}) BO({:d}) SH({:d}) UP({:d}) DK({:d}) TI({:d})".format( 32 | not not (v & msk_bscn_sel), 33 | not not (v & msk_tck_rb ), 34 | not not (v & msk_bscn_cap), 35 | not not (v & msk_bscn_tdi), 36 | not not (v & msk_tdo_i ), 37 | not not (v & msk_bscn_tdo), 38 | not not (v & msk_bscn_shf), 39 | not not (v & msk_bscn_upd), 40 | not not (v & msk_bscn_dck), 41 | not not (v & msk_tdi_o ) 42 | ), end=endmark) 43 | 44 | def process_file(f, cb, cl): 45 | lno = 1 46 | for l in open(f): 47 | l = l.rstrip('\n') 48 | if ( None != patt.match(l) ): 49 | v = int(l.split()[1],0) 50 | cb(v, lno, l, cl) 51 | lno += 1 52 | 53 | def check_tck_tms_tdi_readback(val, lineNo, line, closure): 54 | if ( ((val >> 16) & 0x7) != ((val>>20) & 0x7) ): 55 | pval( val ) 56 | raise RuntimeError("TMS/TDI/TCK Readback Mismatch: line #{} {}".format(lineNo, line)) 57 | if ( (not not (val & msk_bscn_tdi)) != (not not (val & msk_tdi_o)) ): 58 | pval( val ) 59 | raise RuntimeError("BSCN_TDI readback mismatch: line #{} {}".format(lineNo, line)) 60 | if ( (lineNo > 1) and ((closure[0] & msk_tck_rb) == (val & msk_tck_rb)) ): 61 | raise RuntimeError("TCK does not toggle (line #{})".format(lineNo)) 62 | closure[0] = val 63 | 64 | def filter_sel(val, lineNo, line, closure): 65 | if ( (val & msk_bscn_sel) != 0 ): 66 | # print preceding non-SEL value 67 | if (closure[0] == 0): 68 | pval(closure[1]) 69 | pval(val) 70 | closure[0]=1 71 | else: 72 | if (closure[0]!=0): 73 | pval(val) 74 | closure[0]=0 75 | closure[1]=val 76 | 77 | def filter_upd_and_sel(val, lineNo, line, closure): 78 | if ( (val & (msk_bscn_sel | msk_bscn_upd)) == (msk_bscn_sel | msk_bscn_upd) ): 79 | print(line) 80 | 81 | def print_all(val, lineNo, line, closure): 82 | pval(val) 83 | 84 | def sig_posedge(prev, val, msk = msk_tck_rb): 85 | return ( ((prev & msk) == 0) and ((val & msk) != 0) ) 86 | 87 | def filter_bscan_irregular_tdo_change(val, lineNo, line, closure): 88 | prev = closure[0] 89 | closure[0] = val 90 | if ((prev & msk_bscn_tdo) != (val & msk_bscn_tdo)): 91 | if ( ((prev & msk_tck_rb) != 0) or ((val & msk_tck_rb) == 0) ): 92 | msg = "Irregular TDO #line {}".format(lineNo) 93 | pval(prev) 94 | pval(val) 95 | if (lineNo > 1): 96 | raise RuntimeError(msg) 97 | print("Warning: {}".format(msg)) 98 | 99 | def filter_upd_shf_cap_overlap(val, lineNo, line, closure): 100 | bits = 0 101 | if ( (val & msk_bscn_cap) != 0): 102 | bits += 1 103 | if ( (val & msk_bscn_shf) != 0): 104 | bits += 1 105 | if ( (val & msk_bscn_upd) != 0): 106 | bits += 1 107 | if ( bits > 1 ): 108 | msg = "CAP/SHF/UPD overlap detected @#{}".format(lineNo) 109 | pval( val ) 110 | raise RuntimeError(msg) 111 | 112 | process_file(f, check_tck_tms_tdi_readback, [0,0]) 113 | process_file(f, filter_bscan_irregular_tdo_change, [0,0]) 114 | process_file(f, filter_upd_shf_cap_overlap, [0,0]) 115 | print("Elementary Checks PASSES") 116 | 117 | def track_user_data_from_jtag(val, lineNo, line, closure): 118 | scanner = closure[1] 119 | pval = closure[0] 120 | if ( sig_posedge(pval, val, msk_tck_o) ): 121 | scanner.advance( not not (val & msk_tms_o), not not (val & msk_tdi_o) ) 122 | closure[0] = val 123 | 124 | def track_user_data_from_bscn(val, lineNo, line, closure): 125 | shr = closure[1] 126 | pval = closure[0] 127 | closure[0] = val 128 | if ( sig_posedge( pval, val, msk_bscn_dck) ): 129 | if ( (val & msk_bscn_cap) != 0 ): 130 | print("CAP") 131 | shr.capture() 132 | if ( (val & msk_bscn_shf) != 0 ): 133 | shr.shift( not not (val & msk_bscn_tdi) ) 134 | if ( (val & msk_bscn_upd) != 0 ): 135 | print("New DR [{}]: {:x}".format(shr.getLength(), shr.getData())) 136 | 137 | class VhdlPkgConverter: 138 | def __init__(self): 139 | self.lim_ = 32 140 | self.vec_ = [] 141 | self.clear() 142 | 143 | def clear(self): 144 | self.len_ = 0 145 | self.msk_ = 1 146 | self.tms_ = 0 147 | self.tdi_ = 0 148 | self.tdo_ = 0 149 | 150 | def push(self): 151 | if ( self.len_ > 0 ): 152 | self.vec_.append( {"TMS": self.tms_, "TDI": self.tdi_, "TDO": self.tdo_, "LEN": self.len_} ) 153 | self.clear() 154 | 155 | def dump(self, feil=None): 156 | self.push() 157 | print("package body Jtag2BSCANTbPkg is", file=feil) 158 | print(" constant iSeq : TmsTdiArray := (", file=feil) 159 | w = int((self.lim_ + 3)/4) 160 | for r in self.vec_: 161 | print("( TMS => x\"{:0{}x}\", TDI => x\"{:0{}x}\", nbits => {:d} ),".format(r["TMS"], w, r["TDI"], w, r["LEN"]), file=feil) 162 | # sentinel 163 | print("( TMS => x\"{:0{}x}\", TDI => x\"{:0{}x}\", nbits => {:d} )".format(0,w,0,w,0), file=feil) 164 | print(");", file=feil) 165 | print(" constant oSeq : TdoArray := (", file=feil) 166 | for r in self.vec_: 167 | print("( TDO => x\"{:0{}x}\", nbits => {:d} ),".format(r["TDO"], w, r["LEN"]), file=feil) 168 | # sentinel 169 | print("( TDO => x\"{:0{}x}\", nbits => {:d} )".format(0, w, 0), file=feil) 170 | print(");", file=feil) 171 | print("end package body Jtag2BSCANTbPkg;", file=feil) 172 | 173 | def append(self, tms, tdi, tdo): 174 | if ( tms ): 175 | self.tms_ |= self.msk_ 176 | if ( tdi ): 177 | self.tdi_ |= self.msk_ 178 | if ( tdo ): 179 | self.tdo_ |= self.msk_ 180 | self.msk_ <<= 1 181 | self.len_ += 1 182 | if (self.len_ >= self.lim_): 183 | self.push() 184 | 185 | def filter_vhdl_pkg(val, lineNo, line, closure): 186 | cvt = closure[1] 187 | cvt.append( not not (val & msk_tms_o), not not (val & msk_tdi_o), not not (val & msk_tdo_i) ) 188 | 189 | def gen_vhdl_pkg(fnam = "Jtag2BSCANTbPkgBody.vhd"): 190 | feil = open(fnam, "w") 191 | 192 | cvt = VhdlPkgConverter() 193 | process_file(f, filter_vhdl_pkg, [0, cvt]) 194 | cvt.dump( feil ) 195 | feil.close() 196 | 197 | #process_file(f, track_user_data_from_jtag, [0,JtagSniffer.JtagSniffer()]) 198 | #process_file(f, track_user_data_from_bscn, [0,JtagSniffer.JtagShiftReg()]) 199 | #process_file(f, filter_sel, [0,0]) 200 | #process_file(f, print_all, None) 201 | gen_vhdl_pkg() 202 | -------------------------------------------------------------------------------- /tb/AxiStreamSelectorTb.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: Simulation Test bench for AxisStreamSelector 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | library ieee; 18 | use ieee.std_logic_1164.all; 19 | 20 | 21 | use work.StdRtlPkg.all; 22 | use work.AxiStreamPkg.all; 23 | 24 | entity AxiStreamSelectorTb is 25 | end entity AxiStreamSelectorTb; 26 | 27 | architecture AxiStreamSelectorTbImpl of AxiStreamSelectorTb is 28 | 29 | constant DW_C : positive := 8; 30 | 31 | constant TPD_G : time := 0 ns; 32 | 33 | signal clk : sl := '0'; 34 | signal rst : sl := '0'; 35 | signal run : boolean := true; 36 | 37 | -- r, sel, v1 v0, d1, d0 38 | type TestMType is record 39 | v : sl; 40 | d : slv(DW_C - 1 downto 0); 41 | end record TestMType; 42 | 43 | type TestSType is record 44 | r : sl; 45 | end record TestSType; 46 | 47 | type TestMArray is array (natural range <>) of TestMType; 48 | 49 | signal testVec1 : TestMArray(0 to 9 ) := ( 50 | 0 => ( '0', X"A0" ), 51 | 1 => ( '1', X"A1" ), 52 | 2 => ( '1', X"A2" ), 53 | 3 => ( '0', X"A3" ), 54 | 4 => ( '1', X"A4" ), 55 | 5 => ( '1', X"A5" ), 56 | 6 => ( '1', X"A6" ), 57 | 7 => ( '0', X"A7" ), 58 | 8 => ( '0', X"A8" ), 59 | 9 => ( '0', X"A9" ) 60 | ); 61 | 62 | signal testVec2 : TestMArray(0 to 6 ) := ( 63 | 0 => ( '0', X"B0" ), 64 | 1 => ( '0', X"B1" ), 65 | 2 => ( '1', X"B2" ), 66 | 3 => ( '0', X"B3" ), 67 | 4 => ( '1', X"B4" ), 68 | 5 => ( '1', X"B5" ), 69 | 6 => ( '1', X"B6" ) 70 | ); 71 | 72 | 73 | signal mTx : AxiStreamMasterArray(1 downto 0) := ( 74 | others => AXI_STREAM_MASTER_INIT_C 75 | ); 76 | 77 | signal sTx : AxiStreamSlaveArray (1 downto 0); 78 | 79 | signal sRx : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; 80 | signal mRx : AxiStreamMasterType; 81 | 82 | signal sel : sl := '0'; 83 | 84 | signal stage : natural := 0; 85 | 86 | signal t1d : slv(DW_C - 1 downto 0); 87 | signal t0d : slv(DW_C - 1 downto 0); 88 | signal rd : slv(DW_C - 1 downto 0); 89 | 90 | signal t1v : sl := '0'; 91 | signal t0v : sl := '0'; 92 | signal rr : sl := '0'; 93 | 94 | begin 95 | 96 | mTx(0).tValid <= t0v; 97 | mTx(1).tValid <= t1v; 98 | 99 | mTx(0).tData(DW_C - 1 downto 0) <= t0d; 100 | mTx(1).tData(DW_C - 1 downto 0) <= t1d; 101 | 102 | rd <= mRx.tData(DW_C - 1 downto 0); 103 | sRx.tReady <= rr; 104 | 105 | P_CLK : process 106 | begin 107 | if ( run ) then 108 | clk <= not clk; 109 | wait for 50 ns; 110 | else 111 | wait; 112 | end if; 113 | end process P_CLK; 114 | 115 | P_TST : process( clk ) 116 | variable nstage : natural; 117 | 118 | impure function xferTx(idx : natural range 0 to 1) return boolean is 119 | begin 120 | return mTx(idx).tValid = '1' and sTx(idx).tReady = '1'; 121 | end function xferTx; 122 | 123 | impure function xferRx return boolean is 124 | begin 125 | return mRx.tValid = '1' and sRx.tReady = '1'; 126 | end function xferRx; 127 | 128 | procedure assertNoXfer is 129 | begin 130 | assert not xferTx(0) severity failure; 131 | assert not xferTx(1) severity failure; 132 | assert not xferRx severity failure; 133 | end procedure assertNoXfer; 134 | 135 | begin 136 | if ( rising_edge( clk ) ) then 137 | nstage := stage + 1; 138 | if ( stage < 3 ) then 139 | elsif ( stage = 3 ) then 140 | rst <= '0'; 141 | elsif ( stage = 4 ) then 142 | -- drive not-selected valid first 143 | t1v <= '1'; 144 | t1d <= X"B0"; 145 | t0d <= X"A0"; 146 | assertNoXfer; 147 | elsif ( stage = 5 ) then 148 | rr <= '1'; 149 | assertNoXfer; 150 | elsif ( stage = 6 ) then 151 | assertNoXfer; 152 | elsif ( stage = 7 ) then 153 | sel <= '1'; 154 | assertNoXfer; 155 | elsif ( stage = 8 ) then 156 | assert not xferTx(0) severity failure; 157 | assert xferTx(1) severity failure; 158 | assert not xferRx severity failure; 159 | t1d <= X"B1"; 160 | elsif ( stage = 9 ) then 161 | assert not xferTx(0) severity failure; 162 | assert xferTx(1) severity failure; 163 | assert xferRx severity failure; 164 | assert rd = X"B0" severity failure; 165 | sel <= '0'; 166 | elsif ( stage = 10) then 167 | assert not xferTx(0) severity failure; 168 | assert not xferTx(1) severity failure; 169 | assert xferRx severity failure; 170 | assert rd = X"B1" severity failure; 171 | rr <= '0'; 172 | t1v <= '1'; 173 | t0v <= '1'; 174 | t1d <= x"B2"; 175 | t0d <= x"A2"; 176 | elsif ( stage = 11 ) then 177 | assert xferTx(0) severity failure; 178 | assert not xferTx(1) severity failure; 179 | assert not xferRx severity failure; 180 | rr <= '1'; 181 | sel <= '1'; 182 | elsif ( stage = 12 ) then 183 | assert not xferTx(0) severity failure; 184 | assert xferTx(1) severity failure; 185 | assert xferRx severity failure; 186 | assert rd = x"A2"; 187 | t1d <= x"B3"; 188 | rr <= '0'; 189 | elsif ( stage = 13 ) then 190 | assert not xferTx(0) severity failure; 191 | assert not xferTx(1) severity failure; 192 | assert not xferRx severity failure; 193 | rr <= '1'; 194 | elsif ( stage = 14 ) then 195 | assert not xferTx(0) severity failure; 196 | assert xferTx(1) severity failure; 197 | assert xferRx severity failure; 198 | assert rd = x"B2"; 199 | t1v <= '0'; 200 | elsif ( stage = 14 ) then 201 | assert not xferTx(0) severity failure; 202 | assert not xferTx(1) severity failure; 203 | assert xferRx severity failure; 204 | assert rd = x"B3"; 205 | elsif ( stage = 14 ) then 206 | assertNoXfer; 207 | else 208 | run <= false; 209 | report "Test PASSED"; 210 | end if; 211 | stage <= nstage after TPD_G; 212 | end if; 213 | end process P_TST; 214 | 215 | U_DUT : entity work.AxiStreamSelector 216 | generic map ( 217 | TPD_G => TPD_G 218 | ) 219 | port map ( 220 | clk => clk, 221 | rst => rst, 222 | sel => sel, 223 | mIb => mTx, 224 | sIb => sTx, 225 | mOb => mRx, 226 | sOb => sRx 227 | ); 228 | 229 | end architecture AxiStreamSelectorTbImpl; 230 | 231 | -------------------------------------------------------------------------------- /tb/AxisToJtagCoreTb.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: Simulation Test bench for AxisToJtagCore 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | library ieee; 18 | use ieee.std_logic_1164.all; 19 | use ieee.numeric_std.all; 20 | 21 | 22 | use work.StdRtlPkg.all; 23 | use work.AxiStreamPkg.all; 24 | 25 | entity AxisToJtagCoreTb is 26 | end entity AxisToJtagCoreTb; 27 | 28 | architecture AxisToJtagCoreTbImpl of AxisToJtagCoreTb is 29 | 30 | constant W_C : positive := 2; 31 | constant WB_C : positive := 8*W_C; 32 | 33 | type WordArray is array (natural range <>) of slv(WB_C - 1 downto 0); 34 | 35 | signal clk : sl := '0'; 36 | signal rst : sl := '1'; 37 | signal rsttx : sl := '1'; 38 | 39 | signal run : boolean := true; 40 | 41 | signal tdi : sl; 42 | signal tdo : sl; 43 | signal tck : sl; 44 | 45 | signal mAxisTdi : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; 46 | signal sAxisTdi : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; 47 | 48 | signal mAxisTdo : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; 49 | signal sAxisTdo : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; 50 | 51 | signal stage : natural := 0; 52 | 53 | signal res : WordArray(0 to 4); 54 | signal ridx : natural := 0; 55 | signal tidx : natural := 0; 56 | 57 | signal tvGate : boolean := true; 58 | signal rrGate : boolean := true; 59 | 60 | signal rxDon : boolean := false; 61 | 62 | signal del : slv(31 downto 0) := (others => '0'); 63 | 64 | signal txData : WordArray(0 to 6) := ( 65 | x"0021", 66 | x"0000", 67 | x"dead", 68 | x"0000", 69 | x"3210", 70 | x"0000", 71 | x"0002" 72 | ); 73 | 74 | begin 75 | 76 | tdo <= tdi; 77 | 78 | mAxisTdi.tData(WB_C - 1 downto 0) <= txData(tidx) when (tidx <= txData'right) else (others => 'X'); 79 | mAxisTdi.tKeep(W_C - 1 downto 0) <= (others => '1'); 80 | mAxisTdi.tLast <= ite( tidx = txData'right, '1', '0' ); 81 | 82 | mAxisTdi.tValid <= '1' when (tidx <= txData'right and tvGate) else '0'; 83 | sAxisTdo.tReady <= '1' when (ridx <= res'right and not rxDon and rrGate) else '0'; 84 | 85 | process 86 | begin 87 | if ( run ) then 88 | clk <= not clk; 89 | wait for 5 ns; 90 | else 91 | wait; 92 | end if; 93 | end process; 94 | 95 | P_TX : process (clk ) 96 | begin 97 | if ( rising_edge( clk ) ) then 98 | if ( (rst or rsttx) /= '0' ) then 99 | tidx <= 0; 100 | else 101 | if ( (mAxisTdi.tValid and sAxisTdi.tReady) = '1' ) then 102 | tidx <= tidx + 1; 103 | end if; 104 | end if; 105 | del <= slv(unsigned(del) + 1 ); 106 | end if; 107 | end process P_TX; 108 | 109 | P_RX : process (clk) 110 | variable x : slv(WB_C - 1 downto 0 ); 111 | begin 112 | if ( rising_edge( clk ) ) then 113 | if ( (rst or rsttx) /= '0' ) then 114 | ridx <= 0; 115 | rxDon <= false; 116 | elsif ( (mAxisTdo.tValid and sAxisTdo.tReady) = '1' ) then 117 | x := mAxisTdo.tData( WB_C - 1 downto 0 ); 118 | assert x = txData(2*ridx + 2) severity failure; 119 | res(ridx) <= x; 120 | if ( mAxisTdo.tLast = '0' ) then 121 | ridx <= ridx + 1; 122 | else 123 | rxDon <= true; 124 | end if; 125 | end if; 126 | end if; 127 | end process P_RX; 128 | 129 | P_RST : process( clk ) 130 | begin 131 | if ( rising_edge( clk ) ) then 132 | if ( stage < 3 ) then 133 | stage <= stage + 1; 134 | elsif (stage = 3 ) then 135 | rst <= '0'; 136 | rsttx <= '0'; 137 | stage <= stage + 1; 138 | elsif (stage = 4 ) then 139 | if ( rxDon ) then 140 | stage <= stage + 1; 141 | rrGate <= false; 142 | rsttx <= '1'; 143 | stage <= stage + 1; 144 | end if; 145 | elsif (stage = 5 ) then 146 | rsttx <= '0'; 147 | stage <= stage + 1; 148 | elsif (stage = 6 ) then 149 | if ( rxDon ) then 150 | stage <= stage + 1; 151 | rrGate <= true; 152 | tvGate <= false; 153 | rsttx <= '1'; 154 | end if; 155 | if ( rrGate ) then 156 | rrGate <= false; 157 | elsif del(7 downto 0) = "10000010" then 158 | rrGate <= true; 159 | end if; 160 | elsif (stage = 7 ) then 161 | rsttx <= '0'; 162 | stage <= stage + 1; 163 | elsif (stage = 8 ) then 164 | if ( rxDon ) then 165 | stage <= stage + 1; 166 | end if; 167 | if ( tvGate ) then 168 | tvGate <= false; 169 | elsif del(7 downto 0) = "10000010" then 170 | tvGate <= true; 171 | end if; 172 | else 173 | run <= false; 174 | end if; 175 | end if; 176 | end process P_RST; 177 | 178 | U_DUT : entity work.AxisToJtagCore 179 | generic map ( 180 | AXIS_WIDTH_G => W_C, 181 | CLK_DIV2_G => 2 182 | ) 183 | port map ( 184 | axisClk => clk, 185 | axisRst => rst, 186 | mAxisTmsTdi => mAxisTdi, 187 | sAxisTmsTdi => sAxisTdi, 188 | mAxisTdo => mAxisTdo, 189 | sAxisTdo => sAxisTdo, 190 | 191 | tck => tck, 192 | tdi => tdi, 193 | tdo => tdo, 194 | tms => open 195 | ); 196 | 197 | end architecture AxisToJtagCoreTbImpl; 198 | 199 | -------------------------------------------------------------------------------- /tb/AxisToJtagStubTb.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: Simulation Test bench for AxisToJtagStub 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | library ieee; 18 | use ieee.std_logic_1164.all; 19 | use ieee.numeric_std.all; 20 | 21 | 22 | use work.StdRtlPkg.all; 23 | use work.AxiStreamPkg.all; 24 | use work.AxisToJtagPkg.all; 25 | 26 | entity AxisToJtagStubTb is 27 | end entity AxisToJtagStubTb; 28 | 29 | architecture AxisToJtagStubTbImpl of AxisToJtagStubTb is 30 | 31 | signal clk : sl := '0'; 32 | signal rst : sl := '1'; 33 | 34 | signal mAxisReq : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; 35 | signal mAxisRep : AxiStreamMasterType; 36 | signal sAxisReq : AxiStreamSlaveType; 37 | signal sAxisRep : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; 38 | 39 | signal run : boolean := true; 40 | 41 | signal ini : natural := 0; 42 | 43 | signal rxs : natural := 0; 44 | 45 | begin 46 | process 47 | begin 48 | if ( run ) then 49 | clk <= not clk; 50 | wait for 5 ns; 51 | else 52 | wait; 53 | end if; 54 | end process; 55 | 56 | U_TX : process(clk) is 57 | variable stage : natural; 58 | begin 59 | if ( rising_edge(clk) ) then 60 | 61 | stage := ini + 1; 62 | 63 | case (stage) is 64 | when 0 | 1 | 2 | 3 => 65 | when 4 => rst <= '0'; 66 | when 5 => 67 | when 6 => 68 | mAxisReq.tData(31 downto 0) <= (others => '0'); 69 | mAxisReq.tValid <= '1'; 70 | mAxisReq.tLast <= '1'; 71 | when 7 => 72 | if ( sAxisReq.tReady = '0' ) then 73 | stage := ini; 74 | else 75 | mAxisReq.tValid <= '0'; 76 | end if; when 8 => when 9 => 77 | mAxisReq.tData(31 downto 0) <= (others => '1'); 78 | mAxisReq.tValid <= '1'; 79 | mAxisReq.tLast <= '0'; 80 | if ( sAxisReq.tReady = '0' ) then 81 | stage := ini; 82 | end if; 83 | when 10 => 84 | if ( sAxisReq.tReady = '0' ) then 85 | stage := ini; 86 | end if; 87 | when 11 => 88 | if ( sAxisReq.tReady = '0' ) then 89 | stage := ini; 90 | else 91 | mAxisReq.tLast <= '1'; 92 | end if; 93 | when 12 => 94 | if ( sAxisReq.tReady = '0' ) then 95 | stage := ini; 96 | else 97 | mAxisReq.tValid <= '0'; 98 | end if; 99 | when others => 100 | end case; 101 | 102 | ini <= stage; 103 | end if; 104 | end process U_TX; 105 | 106 | U_RX : process(clk) is 107 | variable stage : natural; 108 | begin 109 | if ( rising_edge(clk) ) then 110 | stage := rxs + 1; 111 | 112 | case (rxs) is 113 | when 0 => 114 | sAxisRep.tReady <= '1'; 115 | when 1 => 116 | if ( mAxisRep.tValid = '0' ) then 117 | stage := rxs; 118 | else 119 | assert ( mAxisRep.tLast = '1' ) 120 | report "Reply without TLAST" severity failure; 121 | assert ( getCommand( mAxisRep.tData ) = CMD_ERROR_C ) 122 | report "Expected ERROR" severity failure; 123 | assert ( getLen( mAxisRep.tData ) = ERR_NOT_PRESENT_C ) 124 | report "Unexpected error code" severity failure; 125 | sAxisRep.tReady <= '0'; 126 | end if; 127 | 128 | when 2 => 129 | sAxisRep.tReady <= '1'; 130 | 131 | when 3 => 132 | 133 | if ( mAxisRep.tValid = '0' ) then 134 | stage := rxs; 135 | else 136 | assert ( mAxisRep.tLast = '1' ) 137 | report "Reply without TLAST" severity failure; 138 | assert ( getCommand( mAxisRep.tData ) = CMD_ERROR_C ) 139 | report "Expected ERROR" severity failure; 140 | assert ( getLen( mAxisRep.tData ) = ERR_BAD_VERSION_C ) 141 | report "Unexpected error code" severity failure; 142 | assert ( getVersion( mAxisRep.tData ) = PRO_VERSN_C ) 143 | report "Bad version in reply" severity failure; 144 | sAxisRep.tReady <= '0'; 145 | end if; 146 | 147 | when 4 => 148 | 149 | when others => 150 | run <= false; 151 | report "TEST PASSED"; 152 | end case; 153 | 154 | rxs <= stage; 155 | end if; 156 | end process U_RX; 157 | 158 | U_dut : entity work.AxisJtagDebugBridge(AxisJtagDebugBridgeStub) 159 | port map ( 160 | axisClk => clk, 161 | axisRst => rst, 162 | 163 | mAxisReq => mAxisReq, 164 | sAxisReq => sAxisReq, 165 | 166 | mAxisTdo => mAxisRep, 167 | sAxisTdo => sAxisRep 168 | ); 169 | 170 | end architecture AxisToJtagStubTbImpl; 171 | -------------------------------------------------------------------------------- /tb/JtagSerDesCoreTb.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Title : JTAG Support 3 | ------------------------------------------------------------------------------- 4 | -- Company : SLAC National Accelerator Laboratory 5 | ------------------------------------------------------------------------------- 6 | -- Description: Simulation Test bench for JtagSerDesCore 7 | ------------------------------------------------------------------------------- 8 | -- This file is part of 'SLAC Firmware Standard Library'. 9 | -- It is subject to the license terms in the LICENSE.txt file found in the 10 | -- top-level directory of this distribution and at: 11 | -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | -- No part of 'SLAC Firmware Standard Library', including this file, 13 | -- may be copied, modified, propagated, or distributed except according to 14 | -- the terms contained in the LICENSE.txt file. 15 | ------------------------------------------------------------------------------- 16 | 17 | library ieee; 18 | use ieee.std_logic_1164.all; 19 | use ieee.numeric_std.all; 20 | 21 | 22 | use work.StdRtlPkg.all; 23 | 24 | entity JtagSerDesCoreTb is 25 | end entity JtagSerDesCoreTb; 26 | 27 | architecture JtagSerDesCoreTbImpl of JtagSerDesCoreTb is 28 | constant W_C : positive := 4; 29 | constant D_C : positive := 2; 30 | 31 | type TestVecArray is array (natural range 0 to 15) of natural range 0 to 15; 32 | 33 | signal tck : sl; 34 | signal clk : sl := '0'; 35 | signal rst : sl := '1'; 36 | signal tdi : sl; 37 | signal tdo : sl; 38 | signal tms : sl; 39 | 40 | signal diTdi : slv(W_C-1 downto 0); 41 | signal doTdo : slv(W_C-1 downto 0); 42 | 43 | signal nBits : natural range 0 to W_C - 1; 44 | 45 | signal diV : sl := '0'; 46 | signal diR : sl; 47 | signal doV : sl; 48 | signal doR : sl := '0'; 49 | 50 | signal run : boolean := true; 51 | 52 | signal step : integer := 0; 53 | 54 | signal idxi : natural range 0 to 15; 55 | signal idxo : natural range 0 to 15; 56 | 57 | signal testVec : TestVecArray := ( 58 | 4,6,3,11,7,8,1,9,2,12,0,14,5,13,15,10 59 | ); 60 | 61 | begin 62 | 63 | process 64 | begin 65 | if ( run ) then 66 | clk <= not clk; 67 | wait for 5 ns; 68 | else 69 | wait; 70 | end if; 71 | end process; 72 | 73 | tdo <= tdi; 74 | 75 | process (clk) 76 | begin 77 | if ( rising_edge(clk) ) then 78 | if ( step < 4 ) then 79 | if ( step = 2 ) then 80 | rst <= '0'; 81 | end if; 82 | step <= step + 1; 83 | elsif ( step = 4 ) then 84 | nBits <= 3; 85 | doR <= '1'; 86 | diTdi <= "0101"; 87 | diV <= '1'; 88 | step <= 5; 89 | elsif ( step = 5 ) then 90 | if ( diV = '1' and diR = '1' ) then 91 | diV <= '0'; 92 | step <= 6; 93 | end if; 94 | elsif ( step = 6 ) then 95 | if ( doV = '1' and doR = '1' ) then 96 | doR <= '0'; 97 | step <= 7; 98 | assert unsigned(doTdo) = 5 severity failure; 99 | end if; 100 | elsif ( step = 7 ) then 101 | step <= step + 1; 102 | -- back-to-back with no wait 103 | elsif ( step = 8 ) then 104 | diTdi <= "1010"; 105 | diV <= '1'; 106 | doR <= '1'; 107 | step <= step+1; 108 | elsif ( step = 9 ) then 109 | if ( diV = '1' and diR = '1' ) then 110 | diTdi <= "0011"; 111 | step <= step+1; 112 | end if; 113 | elsif ( step = 10 ) then 114 | if ( diV = '1' and diR = '1' ) then 115 | diV <= '0'; 116 | end if; 117 | if ( doV = '1' and doR = '1' ) then 118 | assert doTdo = "1010" severity failure; 119 | step <= step+1; 120 | end if; 121 | elsif ( step = 11 ) then 122 | if ( doV = '1' and doR = '1' ) then 123 | doR <= '0'; 124 | assert doTdo = "0011" severity failure; 125 | step <= step+1; 126 | end if; 127 | -- back-to-back with wait 128 | elsif ( step = 12 ) then 129 | diTdi <= "0110"; 130 | diV <= '1'; 131 | doR <= '0'; 132 | step <= step+1; 133 | elsif ( step = 13 ) then 134 | if ( diV = '1' and diR = '1' ) then 135 | diTdi <= "1111"; 136 | nBits <= 0; 137 | step <= step + 1; 138 | end if; 139 | elsif ( step = 14 ) then 140 | 141 | if ( diV = '1' and diR = '1' ) then 142 | diV <= '0'; 143 | end if; 144 | 145 | if ( doV = '1' ) then 146 | step <= step+1; 147 | end if; 148 | elsif ( step = 15 ) then 149 | doR <= '1'; 150 | step <= step + 1; 151 | elsif ( step = 16 ) then 152 | if ( doV = '1' and doR = '1' ) then 153 | assert doTdo = "0110" severity failure; 154 | step <= step+1; 155 | end if; 156 | elsif ( step = 17 ) then 157 | if ( doV = '1' and doR = '1' ) then 158 | doR <= '0'; 159 | assert doTdo(3) = '1' severity failure; 160 | step <= step+1; 161 | end if; 162 | elsif ( step = 18 ) then 163 | idxo <= 0; 164 | idxi <= 0; 165 | diTdi <= toSlv(testVec(0), W_C); 166 | diV <= '1'; 167 | doR <= '1'; 168 | nBits <= 3; 169 | step <= step + 1; 170 | elsif ( step = 19 ) then 171 | if ( diV = '1' and diR = '1' ) then 172 | if ( idxi = 15 ) then 173 | diV <= '0'; 174 | else 175 | diTdi <= toSlv(testVec(idxi + 1), W_C); 176 | idxi <= idxi + 1; 177 | end if; 178 | end if; 179 | if ( doV = '1' and doR = '1' ) then 180 | assert testVec(idxo) = unsigned(doTdo) severity failure; 181 | if ( idxo = 15 ) then 182 | doR <= '0'; 183 | step <= step+1; 184 | else 185 | idxo <= idxo + 1; 186 | end if; 187 | end if; 188 | elsif ( step = 20 ) then 189 | idxo <= 0; 190 | idxi <= 0; 191 | diTdi <= toSlv(testVec(0), W_C); 192 | diV <= '1'; 193 | doR <= '1'; 194 | nBits <= 1; 195 | step <= step + 1; 196 | elsif ( step = 21 ) then 197 | if ( diV = '1' and diR = '1' ) then 198 | if ( idxi = 15 ) then 199 | diV <= '0'; 200 | else 201 | diTdi <= toSlv(testVec(idxi + 1), W_C); 202 | idxi <= idxi + 1; 203 | end if; 204 | end if; 205 | if ( doV = '1' and doR = '1' ) then 206 | assert toSlv(testVec(idxo), W_C)(1 downto 0) = doTdo(3 downto 2) severity failure; 207 | if ( idxo = 15 ) then 208 | doR <= '0'; 209 | step <= step+1; 210 | else 211 | idxo <= idxo + 1; 212 | end if; 213 | end if; 214 | else 215 | run <= false; 216 | end if; 217 | end if; 218 | end process; 219 | 220 | 221 | U_DUT : entity work.JtagSerDesCore 222 | generic map ( 223 | WIDTH_G => W_C, 224 | CLK_DIV2_G => D_C 225 | ) 226 | port map ( 227 | clk => clk, 228 | rst => rst, 229 | 230 | numBits => nBits, 231 | dataInTms => (others => '0'), 232 | dataInTdi => diTdi, 233 | dataInValid => diV, 234 | dataInReady => diR, 235 | 236 | dataOut => doTdo, 237 | dataOutValid => doV, 238 | dataOutReady => doR, 239 | 240 | tck => tck, 241 | tdi => tdi, 242 | tms => tms, 243 | tdo => tdo 244 | ); 245 | end architecture JtagSerDesCoreTbImpl; 246 | -------------------------------------------------------------------------------- /xvcSrv/src/.gitignore: -------------------------------------------------------------------------------- 1 | defs.local.mk 2 | rules.local.mk 3 | -------------------------------------------------------------------------------- /xvcSrv/src/jtagDump.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | JtagRegType::JtagRegType() 6 | : bitpos_(0) 7 | { 8 | v_.push_back(0ULL); 9 | } 10 | 11 | void 12 | JtagRegType::clear() 13 | { 14 | v_.clear(); 15 | v_.push_back(0ULL); 16 | bitpos_ = 0; 17 | } 18 | 19 | unsigned 20 | JtagRegType::getNumBits() const 21 | { 22 | return (v_.size() - 1) * 8 * sizeof(VType::value_type) + bitpos_; 23 | } 24 | 25 | void 26 | JtagRegType::print(FILE *f) const 27 | { 28 | VType::const_reverse_iterator it = v_.rbegin(); 29 | fprintf(f, "0x"); 30 | if ( bitpos_ > 0 ) { 31 | fprintf(f,"%llx",(unsigned long long) *it); 32 | } 33 | while ( ++it != v_.rend() ) { 34 | fprintf(f,"%016llx", (unsigned long long) *it); 35 | } 36 | } 37 | 38 | void 39 | JtagRegType::addBit(int b) 40 | { 41 | if ( b ) { 42 | v_.back() |= (1<= 8*sizeof(VType::value_type) ) { 46 | bitpos_ = 0; 47 | v_.push_back( 0ULL ); 48 | } 49 | } 50 | 51 | void 52 | JtagState_TestLogicReset::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 53 | { 54 | if ( ! tms ) { 55 | context->changeState( &context->state_RunTestIdle_ ); 56 | } 57 | } 58 | 59 | void 60 | JtagState_RunTestIdle::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 61 | { 62 | if ( tms ) { 63 | context->changeState( &context->state_SelectDRScan_ ); 64 | } 65 | } 66 | 67 | void 68 | JtagState_SelectDRScan::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 69 | { 70 | if ( tms ) { 71 | context->changeState( &context->state_SelectIRScan_ ); 72 | } else { 73 | context->changeState( &context->state_CaptureDR_ ); 74 | } 75 | } 76 | 77 | void 78 | JtagState_CaptureDR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 79 | { 80 | context->clearDR(); 81 | if ( tms ) { 82 | context->changeState( &context->state_Exit1DR_ ); 83 | } else { 84 | context->changeState( &context->state_ShiftDR_ ); 85 | } 86 | } 87 | 88 | void 89 | JtagState_ShiftDR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 90 | { 91 | context->shiftDR( tdo, tdi ); 92 | if ( tms ) { 93 | context->changeState( &context->state_Exit1DR_ ); 94 | } 95 | } 96 | 97 | void 98 | JtagState_Exit1DR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 99 | { 100 | if ( tms ) { 101 | context->changeState( &context->state_UpdateDR_ ); 102 | } else { 103 | context->changeState( &context->state_PauseDR_ ); 104 | } 105 | } 106 | 107 | void 108 | JtagState_PauseDR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 109 | { 110 | if ( tms ) { 111 | context->changeState( &context->state_Exit2DR_ ); 112 | } 113 | } 114 | 115 | void 116 | JtagState_Exit2DR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 117 | { 118 | if ( tms ) { 119 | context->changeState( &context->state_UpdateDR_ ); 120 | } else { 121 | context->changeState( &context->state_ShiftDR_ ); 122 | } 123 | } 124 | 125 | void 126 | JtagState_UpdateDR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 127 | { 128 | unsigned bits = context->getDRLen(); 129 | fprintf(stderr, "%s: DR[IR = ", getName()); 130 | context->getIRo()->print( stderr ); 131 | fprintf(stderr, "], nbits: %u\n", bits); 132 | fprintf(stderr, " sent: "); context->getDRo()->print( stderr ); fprintf(stderr,"\n"); 133 | fprintf(stderr, " rcvd: "); context->getDRi()->print( stderr ); fprintf(stderr,"\n"); 134 | if ( tms ) { 135 | context->changeState( &context->state_SelectDRScan_ ); 136 | } else { 137 | context->changeState( &context->state_RunTestIdle_ ); 138 | } 139 | } 140 | 141 | void 142 | JtagState_SelectIRScan::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 143 | { 144 | if ( tms ) { 145 | context->changeState( &context->state_TestLogicReset_ ); 146 | } else { 147 | context->changeState( &context->state_CaptureIR_ ); 148 | } 149 | } 150 | 151 | void 152 | JtagState_CaptureIR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 153 | { 154 | context->clearIR(); 155 | if ( tms ) { 156 | context->changeState( &context->state_Exit1IR_ ); 157 | } else { 158 | context->changeState( &context->state_ShiftIR_ ); 159 | } 160 | } 161 | 162 | void 163 | JtagState_ShiftIR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 164 | { 165 | context->shiftIR( tdo, tdi ); 166 | if ( tms ) { 167 | context->changeState( &context->state_Exit1IR_ ); 168 | } 169 | } 170 | 171 | void 172 | JtagState_Exit1IR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 173 | { 174 | if ( tms ) { 175 | context->changeState( &context->state_UpdateIR_ ); 176 | } else { 177 | context->changeState( &context->state_PauseIR_ ); 178 | } 179 | } 180 | 181 | void 182 | JtagState_PauseIR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 183 | { 184 | if ( tms ) { 185 | context->changeState( &context->state_Exit2IR_ ); 186 | } 187 | } 188 | 189 | void 190 | JtagState_Exit2IR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 191 | { 192 | if ( tms ) { 193 | context->changeState( &context->state_UpdateIR_ ); 194 | } else { 195 | context->changeState( &context->state_ShiftIR_ ); 196 | } 197 | } 198 | 199 | void 200 | JtagState_UpdateIR::advance(JtagDumpCtx *context, int tms, int tdo, int tdi) 201 | { 202 | unsigned bits = context->getIRLen(); 203 | fprintf(stderr, "%s: IR sent: ", getName()); 204 | context->getIRo()->print( stderr ); 205 | fprintf(stderr, ", recv: "); 206 | context->getIRi()->print( stderr ); 207 | fprintf(stderr, " (nbits: %u)\n", bits); 208 | if ( tms ) { 209 | context->changeState( &context->state_SelectDRScan_ ); 210 | } else { 211 | context->changeState( &context->state_RunTestIdle_ ); 212 | } 213 | } 214 | 215 | JtagDumpCtx::JtagDumpCtx() 216 | { 217 | state_ = &state_TestLogicReset_; 218 | } 219 | 220 | void 221 | JtagDumpCtx::clearDR() 222 | { 223 | dri_.clear(); 224 | dro_.clear(); 225 | } 226 | 227 | void 228 | JtagDumpCtx::clearIR() 229 | { 230 | iri_.clear(); 231 | iro_.clear(); 232 | } 233 | 234 | unsigned 235 | JtagDumpCtx::getDRLen() 236 | { 237 | return dri_.getNumBits(); 238 | } 239 | 240 | unsigned 241 | JtagDumpCtx::getIRLen() 242 | { 243 | return iri_.getNumBits(); 244 | } 245 | 246 | void 247 | JtagDumpCtx::shiftDR(int tdo, int tdi) 248 | { 249 | dro_.addBit( tdo ); 250 | dri_.addBit( tdi ); 251 | } 252 | 253 | void 254 | JtagDumpCtx::shiftIR(int tdo, int tdi) 255 | { 256 | iro_.addBit( tdo ); 257 | iri_.addBit( tdi ); 258 | } 259 | 260 | const JtagRegType * 261 | JtagDumpCtx::getDRi() 262 | { 263 | return &dri_; 264 | } 265 | 266 | const JtagRegType * 267 | JtagDumpCtx::getDRo() 268 | { 269 | return &dro_; 270 | } 271 | 272 | const JtagRegType * 273 | JtagDumpCtx::getIRi() 274 | { 275 | return &iri_; 276 | } 277 | 278 | const JtagRegType * 279 | JtagDumpCtx::getIRo() 280 | { 281 | return &iro_; 282 | } 283 | 284 | void 285 | JtagDumpCtx::changeState(JtagState *newState) 286 | { 287 | #ifdef DEBUG 288 | if ( (state_ != newState) ) { 289 | fprintf(stderr, "Entering %s\n", newState->getName()); 290 | } 291 | #endif 292 | state_ = newState; 293 | } 294 | 295 | void 296 | JtagDumpCtx::advance(int tms, int tdo, int tdi) 297 | { 298 | #if 0 299 | fprintf(stderr, "A(%d)\n", !!tms); 300 | #endif 301 | state_->advance(this, tms, tdo, tdi); 302 | } 303 | 304 | unsigned 305 | JtagDumpCtx::processBuf(int nbits, unsigned char *tmsb, unsigned char *tdob, unsigned char *tdib, const JtagState *until) 306 | { 307 | unsigned n,m; 308 | 309 | while ( nbits > 0 ) { 310 | n = 1 << ( nbits < 8 ? nbits : 8 ); 311 | for ( m = 1; m < n; m <<= 1 ) { 312 | if ( until && ( *state_ == *until ) ) { 313 | return nbits; 314 | } 315 | advance( ((*tmsb) & m), ((*tdob) & m), ((*tdib) & m) ); 316 | nbits--; 317 | } 318 | 319 | tmsb++; 320 | tdob++; 321 | tdib++; 322 | } 323 | return 0; 324 | } 325 | -------------------------------------------------------------------------------- /xvcSrv/src/jtagDump.h: -------------------------------------------------------------------------------- 1 | #ifndef JTAG_DUMP_H 2 | #define JTAG_DUMP_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class JtagRegType { 9 | private: 10 | int bitpos_; 11 | 12 | typedef std::vector VType; 13 | 14 | VType v_; 15 | 16 | public: 17 | JtagRegType(); 18 | 19 | void addBit(int i); 20 | 21 | unsigned getNumBits() const; 22 | 23 | void clear(); 24 | 25 | void print(FILE *f) const; 26 | }; 27 | 28 | class JtagDumpCtx; 29 | 30 | class JtagState { 31 | public: 32 | virtual const char *getName() const = 0; 33 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi) = 0; 34 | 35 | virtual int operator==(const JtagState &other) const 36 | { 37 | return this->getName() == other.getName(); 38 | } 39 | }; 40 | 41 | class JtagState_TestLogicReset : public JtagState { 42 | public: 43 | virtual const char *getName() const 44 | { 45 | return "TestLogicReset"; 46 | } 47 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 48 | }; 49 | 50 | class JtagState_RunTestIdle : public JtagState { 51 | public: 52 | virtual const char *getName() const 53 | { 54 | return "RunTestIdle"; 55 | } 56 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 57 | }; 58 | 59 | class JtagState_SelectDRScan : public JtagState { 60 | public: 61 | virtual const char *getName() const 62 | { 63 | return "SelectDRScan"; 64 | } 65 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 66 | }; 67 | 68 | class JtagState_CaptureDR : public JtagState { 69 | public: 70 | virtual const char *getName() const 71 | { 72 | return "CaptureDR"; 73 | } 74 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 75 | }; 76 | 77 | class JtagState_ShiftDR : public JtagState { 78 | public: 79 | virtual const char *getName() const 80 | { 81 | return "ShiftDR"; 82 | } 83 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 84 | }; 85 | 86 | class JtagState_Exit1DR : public JtagState { 87 | public: 88 | virtual const char *getName() const 89 | { 90 | return "Exit1DR"; 91 | } 92 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 93 | }; 94 | 95 | class JtagState_PauseDR : public JtagState { 96 | public: 97 | virtual const char *getName() const 98 | { 99 | return "PauseDR"; 100 | } 101 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 102 | }; 103 | 104 | class JtagState_Exit2DR : public JtagState { 105 | public: 106 | virtual const char *getName() const 107 | { 108 | return "Exit2DR"; 109 | } 110 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 111 | }; 112 | 113 | class JtagState_UpdateDR : public JtagState { 114 | public: 115 | virtual const char *getName() const 116 | { 117 | return "UpdateDR"; 118 | } 119 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 120 | }; 121 | 122 | class JtagState_SelectIRScan : public JtagState { 123 | public: 124 | virtual const char *getName() const 125 | { 126 | return "SelectIRScan"; 127 | } 128 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 129 | }; 130 | 131 | class JtagState_CaptureIR : public JtagState { 132 | public: 133 | virtual const char *getName() const 134 | { 135 | return "CaptureIR"; 136 | } 137 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 138 | }; 139 | 140 | class JtagState_ShiftIR : public JtagState { 141 | public: 142 | virtual const char *getName() const 143 | { 144 | return "ShiftIR"; 145 | } 146 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 147 | }; 148 | 149 | class JtagState_Exit1IR : public JtagState { 150 | public: 151 | virtual const char *getName() const 152 | { 153 | return "Exit1IR"; 154 | } 155 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 156 | 157 | }; 158 | 159 | class JtagState_PauseIR : public JtagState { 160 | public: 161 | virtual const char *getName() const 162 | { 163 | return "PauseIR"; 164 | } 165 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 166 | }; 167 | 168 | class JtagState_Exit2IR : public JtagState { 169 | public: 170 | virtual const char *getName() const 171 | { 172 | return "Exit2IR"; 173 | } 174 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 175 | }; 176 | 177 | class JtagState_UpdateIR : public JtagState { 178 | public: 179 | virtual const char *getName() const 180 | { 181 | return "UpdateIR"; 182 | } 183 | virtual void advance(JtagDumpCtx *context, int tms, int tdo, int tdi); 184 | }; 185 | 186 | 187 | class JtagDumpCtx { 188 | private: 189 | unsigned irl_, drl_; 190 | JtagRegType iri_,dri_; 191 | JtagRegType iro_,dro_; 192 | JtagState *state_; 193 | 194 | public: 195 | JtagDumpCtx(); 196 | 197 | JtagState_TestLogicReset state_TestLogicReset_; 198 | JtagState_RunTestIdle state_RunTestIdle_; 199 | JtagState_SelectDRScan state_SelectDRScan_; 200 | JtagState_CaptureDR state_CaptureDR_; 201 | JtagState_ShiftDR state_ShiftDR_; 202 | JtagState_Exit1DR state_Exit1DR_; 203 | JtagState_PauseDR state_PauseDR_; 204 | JtagState_Exit2DR state_Exit2DR_; 205 | JtagState_UpdateDR state_UpdateDR_; 206 | JtagState_SelectIRScan state_SelectIRScan_; 207 | JtagState_CaptureIR state_CaptureIR_; 208 | JtagState_ShiftIR state_ShiftIR_; 209 | JtagState_Exit1IR state_Exit1IR_; 210 | JtagState_PauseIR state_PauseIR_; 211 | JtagState_Exit2IR state_Exit2IR_; 212 | JtagState_UpdateIR state_UpdateIR_; 213 | 214 | void clearDR(); 215 | void clearIR(); 216 | void shiftDR(int tdo, int tdi); 217 | void shiftIR(int tdo, int tdi); 218 | const JtagRegType *getDRi(); 219 | const JtagRegType *getIRi(); 220 | const JtagRegType *getDRo(); 221 | const JtagRegType *getIRo(); 222 | 223 | unsigned getDRLen(); 224 | unsigned getIRLen(); 225 | 226 | void changeState(JtagState *newState); 227 | 228 | void advance(int tms, int tdo, int tdi); 229 | 230 | unsigned processBuf(int nbits, unsigned char *tmsb, unsigned char *tdob, unsigned char *tdib, const JtagState *until = 0); 231 | 232 | const JtagState *getCurrentState() { return state_; } 233 | }; 234 | 235 | #endif 236 | 237 | -------------------------------------------------------------------------------- /xvcSrv/src/makefile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Title : JTAG Support 3 | #----------------------------------------------------------------------------- 4 | # File : makefile 5 | # Author : Till Straumann 6 | # Company : SLAC National Accelerator Laboratory 7 | # Created : 2017-12-05 8 | # Last update: 2017-12-05 9 | # Platform : 10 | # Standard : VHDL'93/02 11 | #----------------------------------------------------------------------------- 12 | # Description: 13 | #----------------------------------------------------------------------------- 14 | # This file is part of 'SLAC Firmware Standard Library'. 15 | # It is subject to the license terms in the LICENSE.txt file found in the 16 | # top-level directory of this distribution and at: 17 | # https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 18 | # No part of 'SLAC Firmware Standard Library', including this file, 19 | # may be copied, modified, propagated, or distributed except according to 20 | # the terms contained in the LICENSE.txt file. 21 | #----------------------------------------------------------------------------- 22 | 23 | # If you want to cross-compile this program define 24 | # the path to the cross-tools either here or on the 25 | # command line 26 | # 27 | # CROSS=/path/to/arm-linux- 28 | CROSS= 29 | USR_CPPFLAGS= 30 | 31 | #CROSS=/opt/eldk-5.2/powerpc-e500v2/sysroots/i686-eldk-linux/usr/bin/ppce500v2-linux-gnuspe/powerpc-e500v2- 32 | #TOSCAINC=-I/afs/psi.ch/user/s/straumann_t/epics/modules/tosca/toscaApi/include/ 33 | #TOSCALIB=-L/afs/psi.ch/user/s/straumann_t/epics/modules/tosca/toscaApi/ -Wl,-Bstatic -ltoscaApi -Wl,-Bdynamic 34 | TMEM_DRIVER_BUILTIN=YES 35 | 36 | # 37 | # so that $(CROSS)$(CXX) points to a valid cross compiler 38 | # 39 | DRIVERS += drvAxilFifo.so drvAxiDbgBridgeIP.so 40 | 41 | OBJS=xvcSrv.o xvcDrvLoopBack.o xvcConn.o xvcDrvUdp.o jtagDump.o 42 | 43 | VERSION_INFO:='"$(shell git describe --always)"' 44 | 45 | CPPFLAGS+=-DXVC_SRV_VERSION=$(VERSION_INFO) 46 | CPPFLAGS+=$(USR_CPPFLAGS) 47 | 48 | 49 | DRVOBJS = 50 | 51 | ifneq ($(TOSCALIB),) 52 | ifneq ($(TMEM_DRIVER_BUILTIN),YES) 53 | DRIVERS += drvTmemFifo.so 54 | else 55 | CPPFLAGS+=-DDEFAULTDRVNAME='"tmem"' 56 | DRVOBJS += xvcDrvAxisTmem.o 57 | endif 58 | endif 59 | 60 | -include defs.local.mk 61 | 62 | TARGETS=xvcSrv $(DRIVERS) 63 | 64 | all: $(TARGETS) 65 | 66 | $(OBJS): xvcDriver.h xvcSrv.h 67 | 68 | xvcSrv: $(OBJS) $(DRVOBJS) 69 | $(CROSS)$(CXX) -o $@ $^ -ldl -Wl,--export-dynamic $(TOSCALIB) -lm -lpthread -lrt 70 | 71 | $(OBJS) $(DRVOBJS): %.o: %.cc 72 | $(CROSS)$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $< -I. $(TOSCAINC) -O2 -c 73 | 74 | drvAxilFifo.so: xvcDrvAxisFifo.cc xvcDriver.h xvcDrvAxisFifo.h 75 | $(CROSS)$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -fPIC -I. -O2 -o $@ $< 76 | 77 | drvAxiDbgBridgeIP.so: xvcDrvAxiDbgBridgeIP.cc xvcDriver.h xvcDrvAxiDbgBridgeIP.h 78 | $(CROSS)$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -fPIC -I. -O2 -o $@ $< 79 | 80 | drvTmemFifo.so: xvcDrvAxisTmem.cc xvcDrvAxisTmem.h xvcDriver.h 81 | $(CROSS)$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -fPIC -I. $(TOSCAINC) -O2 -o $@ $< $(TOSCALIB) -lrt 82 | 83 | 84 | xvcDrvAxisTmem.o: xvcDrvAxisTmem.cc xvcDrvAxisTmem.h xvcDriver.h 85 | 86 | clean: 87 | $(RM) xvcSrv $(DRIVERS) $(OBJS) $(DRVOBJS) 88 | 89 | -include rules.local.mk 90 | -------------------------------------------------------------------------------- /xvcSrv/src/mmioHelper.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | 18 | #ifndef MMIO_HELPER_H 19 | #define MMIO_HELPER_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | class CStrObj { 29 | public: 30 | char *s_; 31 | CStrObj(const char *s) 32 | : s_( strdup(s) ) 33 | { 34 | } 35 | 36 | ~CStrObj() 37 | { 38 | free(s_); 39 | } 40 | }; 41 | 42 | template class MemMap { 43 | private: 44 | volatile void *mapBas_; 45 | unsigned long mapSiz_; 46 | volatile T *devMem_; 47 | int fd_; 48 | public: 49 | MemMap(const char *devnam, unsigned long siz = 1); 50 | 51 | // default implementations; if the system requires 52 | // special ordering instructions and/or byte-swapping 53 | // etc. then they should override 54 | virtual T rd(unsigned index) 55 | { 56 | return devMem_[index]; 57 | } 58 | 59 | virtual int fd() 60 | { 61 | return fd_; 62 | } 63 | 64 | virtual void wr(unsigned index, T val) 65 | { 66 | devMem_[index] = val; 67 | } 68 | 69 | virtual ~MemMap(); 70 | }; 71 | 72 | 73 | template 74 | MemMap::MemMap(const char *devnam, unsigned long siz) 75 | { 76 | unsigned long pgsz; 77 | CStrObj arg(devnam); 78 | char *col,*end; 79 | unsigned long off = 0; 80 | unsigned long mapOff; 81 | 82 | if ( (col = strchr(arg.s_, ':')) ) { 83 | *(col++) = 0; 84 | if ( *col ) { 85 | off = strtoul(col, &end, 0); 86 | if ( end == col || *end ) { 87 | throw std::runtime_error("MemMap Invalid name; expected [:]"); 88 | } 89 | } 90 | } 91 | 92 | if ( (fd_ = open( arg.s_, O_RDWR )) < 0 ) { 93 | throw SysErr("Unable to open FIFO device file"); 94 | } 95 | pgsz = sysconf( _SC_PAGE_SIZE ); 96 | 97 | mapOff = off & (pgsz - 1); 98 | 99 | mapSiz_ = (mapOff + siz + pgsz - 1) / pgsz; 100 | mapSiz_ *= pgsz; 101 | 102 | 103 | mapBas_ = (volatile void*)mmap( 104 | NULL, 105 | mapSiz_, 106 | PROT_READ | PROT_WRITE, 107 | MAP_SHARED, 108 | fd_, 109 | off - mapOff 110 | ); 111 | 112 | if ( mapBas_ == MAP_FAILED ) { 113 | close( fd_ ); 114 | throw SysErr("Unable to mmap device"); 115 | } 116 | devMem_ = (volatile T*)((char*)mapBas_ + mapOff); 117 | } 118 | 119 | template 120 | MemMap::~MemMap() 121 | { 122 | close( fd_ ); 123 | munmap( (void*)mapBas_, mapSiz_ ); 124 | } 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcClient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import socket 3 | import math 4 | 5 | # XVC Client to drive JTAG on a remote TAP 6 | 7 | class ConnectionClosedError(RuntimeError): 8 | def __init__(self, msg): 9 | super().__init__( msg ) 10 | 11 | # Create client providing a connected socket. 12 | # You can use the XvcClientMgr to do that... 13 | # 14 | # Methods starting with an underscore are 15 | # considered 'private' 16 | class XvcClient: 17 | def __init__(self, sock): 18 | self.sock_ = sock 19 | self.maxv_ = None 20 | self.maxv_ = self.getMaxVectorBits() 21 | self.iLen_ = None 22 | self.iLen_ = self.getIRLength() 23 | 24 | def _send(self, buf): 25 | l = len(buf) 26 | p = 0 27 | while l > 0: 28 | g = self.sock_.send(buf[p:]) 29 | p += g; 30 | l -= g; 31 | 32 | def _recv(self, minl, maxl=0): 33 | if 0 == maxl: 34 | maxl = minl 35 | l = 0 36 | b = bytearray() 37 | while l < minl: 38 | g = self.sock_.recv(maxl - l) 39 | if 0 == len(g): 40 | raise ConnectionClosedError("Connection is dead") 41 | l += len(g) 42 | b += g 43 | return b 44 | 45 | # Get the server info string 46 | def getinfo(self): 47 | self._send( bytearray('getinfo:', encoding='ascii') ) 48 | return self._recv(10,100).decode('ascii') 49 | 50 | # Get max. bit-vector length supported 51 | # by the server 52 | def getMaxVectorBits(self): 53 | if not self.maxv_ is None: 54 | return self.maxv_ 55 | info = self.getinfo() 56 | info = info.split(':') 57 | return int(info[1]) 58 | 59 | # Send raw vectors -- low-level routine 60 | def sendVecs(self, tms, tdi, nbits): 61 | if nbits > self.maxv_: 62 | raise RuntimeError("Vectors larger than {} not supported".format(self.maxv_)) 63 | nbytes = int( (nbits + 7 ) / 8 ) 64 | tmsbuf = tms.to_bytes(nbytes, 'little') 65 | tdibuf = tdi.to_bytes(nbytes, 'little') 66 | nbuf = nbits.to_bytes(4, 'little') 67 | obuf = bytearray('shift:','ascii') + nbuf + tmsbuf + tdibuf 68 | self._send(obuf) 69 | ibuf = self._recv(nbytes, nbytes) 70 | return int.from_bytes(ibuf, 'little', signed=False) 71 | 72 | # Bring into TestLogicReset, then TestRunIdle 73 | def resetToIdle(self): 74 | l = 6 75 | self.sendVecs(0b011111,0,l) 76 | 77 | # Select for IR scan 78 | # ASSUMPTION: TAP is in TestRunIdle state when you call this 79 | def selIR(self): 80 | self.sendVecs(0b0011,0,4) 81 | 82 | # Select for DR scan 83 | # ASSUMPTION: TAP is in TestRunIdle state when you call this 84 | def selDR(self): 85 | self.sendVecs(0b001,0,3) 86 | 87 | # Shift DR or IR; if 'update' is 88 | # - False: 89 | # Tap is left in shiftDR/shiftIR state when 90 | # 'shift' returns (useful for inspecting tdo and further 91 | # shifting). 92 | # - True: 93 | # DR/IR is updated after shifting and the TAP 94 | # is driven into TestRunIdle state 95 | # ASSUMPTION: TAP is in shiftDR or shirtIR state when you call this 96 | def shift(self, regin, reglen, update=True): 97 | tms = 0 98 | tdolen = reglen 99 | if update: 100 | tms |= 3<<(reglen - 1) 101 | reglen += 2 # prepended 0b01 102 | tdo = self.sendVecs(tms, regin, reglen) 103 | if update: 104 | tdo &= (1< 18 | 19 | #include 20 | #include 21 | 22 | XvcConn::XvcConn( int sd, JtagDriver *drv, unsigned long maxVecLen ) 23 | : drv_ ( drv ), 24 | ld_ ( sd ), 25 | maxVecLen_ ( maxVecLen ), 26 | supVecLen_ ( 0 ) 27 | { 28 | socklen_t sz = sizeof(peer_); 29 | 30 | // RAII for the sd_ 31 | if ( (sd_ = ::accept(ld_, (struct sockaddr*)&peer_, &sz) ) < 0 ) { 32 | throw SysErr("Unable to accept connection"); 33 | } 34 | } 35 | 36 | XvcConn::~XvcConn() 37 | { 38 | ::close( sd_ ); 39 | } 40 | 41 | ssize_t 42 | XvcConn::read(void *buf, size_t l) 43 | { 44 | fd_set fds; 45 | int nfds = (sd_ > ld_ ? sd_ : ld_) + 1; 46 | int got; 47 | 48 | do { 49 | FD_ZERO( &fds ); 50 | FD_SET( sd_, &fds ); 51 | FD_SET( ld_, &fds ); 52 | 53 | 54 | if ( (got = select( nfds, &fds, 0, 0, 0 )) < 0 ) { 55 | throw SysErr("select failed"); 56 | } 57 | 58 | if ( FD_ISSET(ld_, &fds) ) { 59 | struct sockaddr_in peer; 60 | socklen_t asiz = sizeof(peer); 61 | int newsd = ::accept( ld_ , (struct sockaddr*)&peer, &asiz ); 62 | printf("Activity on LSD\n"); 63 | if ( newsd >= 0 ) { 64 | ::close( newsd ); 65 | fprintf(stderr, "WARNING: a new client (%s:%hu) tried to connect; I just closed this connection\n", inet_ntoa( peer.sin_addr ), ntohs( peer.sin_port ) ); 66 | fprintf(stderr, " XVC supports only a single client!\n"); 67 | } 68 | } 69 | 70 | } while ( ! FD_ISSET(sd_, &fds) ); 71 | 72 | return ::read(sd_, buf, l); 73 | } 74 | 75 | // fill rx buffer to 'n' octets 76 | void 77 | XvcConn::fill(unsigned long n) 78 | { 79 | uint8_t *p = rp_ + rl_; 80 | int got; 81 | unsigned long k = n; 82 | 83 | if ( n <= rl_ ) 84 | return; 85 | 86 | k -= rl_; 87 | while ( k > 0 ) { 88 | got = read( p, k ); 89 | if ( got <= 0 ) { 90 | throw SysErr("Unable to read from socket"); 91 | } 92 | k -= got; 93 | p += got; 94 | } 95 | rl_ = n; 96 | } 97 | 98 | // mark 'n' octets as 'consumed' 99 | void 100 | XvcConn::bump(unsigned long n) 101 | { 102 | rp_ += n; 103 | rl_ -= n; 104 | if ( rl_ == 0 ) { 105 | rp_ = &rxb_[0]; 106 | } 107 | } 108 | 109 | void 110 | XvcConn::allocBufs() 111 | { 112 | unsigned long tgtVecLen; 113 | unsigned long overhead = 128; //headers and such; 114 | 115 | // Determine the vector size supported by the target 116 | tgtVecLen = drv_->query(); 117 | 118 | if ( 0 == tgtVecLen ) { 119 | // target can stream 120 | tgtVecLen = maxVecLen_; 121 | } 122 | 123 | // What can the driver support? 124 | supVecLen_ = drv_->getMaxVectorSize(); 125 | 126 | if ( supVecLen_ == 0 ) { 127 | // supports any size 128 | supVecLen_ = tgtVecLen; 129 | } else if ( tgtVecLen < supVecLen_ ) { 130 | supVecLen_ = tgtVecLen; 131 | } 132 | 133 | chunk_ = (2*maxVecLen_ + overhead); 134 | 135 | rxb_.resize( 2*chunk_ ); 136 | txb_.resize( maxVecLen_ + overhead ); 137 | 138 | rp_ = &rxb_[0]; 139 | rl_ = 0; 140 | tl_ = 0; 141 | } 142 | 143 | void 144 | XvcConn::flush() 145 | { 146 | int put; 147 | uint8_t *p = &txb_[0]; 148 | 149 | while ( tl_ > 0 ) { 150 | put = write( sd_, p, tl_ ); 151 | if ( put <= 0 ) { 152 | throw SysErr("Unable to send from socket"); 153 | } 154 | p += put; 155 | tl_ -= put; 156 | } 157 | } 158 | 159 | void 160 | XvcConn::run() 161 | { 162 | 163 | int got; 164 | uint32_t bits, bitsLeft, bitsSent; 165 | unsigned long bytes; 166 | unsigned long vecLen; 167 | unsigned long off; 168 | 169 | 170 | allocBufs(); 171 | 172 | // XVC protocol is synchronous / not pipelined :-( 173 | // use TCP_NODELAY to make sure our messages (many of which 174 | // are small) are sent ASAP 175 | got = 1; 176 | if ( setsockopt( sd_, IPPROTO_TCP, TCP_NODELAY, &got, sizeof(got) ) ) { 177 | throw SysErr("Unable to set TCP_NODELAY"); 178 | } 179 | 180 | while ( 1 ) { 181 | 182 | // read stuff; 183 | 184 | got = read( rp_, chunk_ ); 185 | if ( got <= 0 ) { 186 | throw SysErr("Unable to read from socket"); 187 | } 188 | 189 | rl_ = got; 190 | 191 | do { 192 | 193 | fill( 2 ); 194 | 195 | if ( 0 == ::memcmp( rp_, "ge", 2 ) ) { 196 | fill( 8 ); 197 | 198 | drv_->query(); // informs the driver that there is a new connection 199 | 200 | tl_ = sprintf( (char*)&txb_[0], "xvcServer_v1.0:%ld\n", maxVecLen_ ); 201 | 202 | bump( 8 ); 203 | } else 204 | if ( 0 == ::memcmp( rp_, "se", 2 ) ) { 205 | uint32_t requestedPeriod; 206 | uint32_t newPeriod; 207 | 208 | fill( 11 ); 209 | 210 | requestedPeriod = (rp_[10] << 24) | (rp_[9] << 16) | (rp_[8] << 8) | rp_[7]; 211 | 212 | newPeriod = drv_->setPeriodNs( requestedPeriod ); 213 | 214 | for ( unsigned u = 0; u < sizeof(newPeriod); u++ ) { 215 | txb_[u] = (uint8_t)newPeriod; 216 | newPeriod = newPeriod >> 8; 217 | } 218 | 219 | tl_ = 4; 220 | 221 | bump( 11 ); 222 | } else 223 | if ( 0 == ::memcmp( rp_, "sh", 2 ) ) { 224 | fill( 10 ); 225 | 226 | bits = 0; 227 | for ( got = 9; got >=6; got-- ) { 228 | bits = (bits<<8) | rp_[got]; 229 | } 230 | bytes = (bits + 7)/8; 231 | if ( bytes > maxVecLen_ ) { 232 | throw ProtoErr("Requested bit vector length too big"); 233 | } 234 | bump( 10 ); 235 | fill( 2*bytes ); 236 | 237 | vecLen = bytes > supVecLen_ ? supVecLen_ : bytes; 238 | 239 | // break into chunks the driver can handle; due to the xvc layout we can't efficiently 240 | // start working on a chunk while still waiting for more data to come in (well - we could 241 | // but had to have the full TDI vector plus a chunk of the TMS vector in. Thus, we don't 242 | // bother...). 243 | for ( off = 0, bitsLeft = bits; bitsLeft > 0; bitsLeft -= bitsSent, off += vecLen ) { 244 | 245 | bitsSent = 8*vecLen; 246 | if ( bitsLeft < bitsSent ) { 247 | bitsSent = bitsLeft; 248 | } 249 | 250 | drv_->sendVectors( bitsSent, rp_ + off, rp_ + bytes + off, &txb_[0] + off ); 251 | } 252 | tl_ = bytes; 253 | 254 | bump( 2*bytes ); 255 | } else { 256 | throw ProtoErr("unsupported message received"); 257 | } 258 | 259 | flush(); 260 | 261 | /* Repeat until all the characters from the first chunk are exhausted 262 | * (most likely the chunk just contained a vector shift message) and 263 | * it is exhausted during the first iteration. If for some reason it is 264 | * not then we use the spill-over area for a second iteration which 265 | * should then terminate this while loop. 266 | */ 267 | } while ( rl_ > 0 ); 268 | 269 | } 270 | 271 | } 272 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcConn.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef XVC_CONNECTION_H 18 | #define XVC_CONNECTION_H 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | // Class managing a XVC tcp connection 26 | 27 | class XvcConn { 28 | JtagDriver *drv_; 29 | int sd_; 30 | int ld_; 31 | struct sockaddr_in peer_; 32 | // just use vectors to back raw memory; DONT use 'size/resize' 33 | // (unfortunately 'resize' fills elements beyond the current 'size' 34 | // with zeroes) 35 | vector rxb_; 36 | uint8_t *rp_; 37 | unsigned long rl_; 38 | unsigned long tl_; 39 | 40 | vector txb_; 41 | unsigned long maxVecLen_; 42 | unsigned long supVecLen_; 43 | unsigned long chunk_; 44 | 45 | public: 46 | XvcConn( int sd, JtagDriver *drv, unsigned long maxVecLen_ = 32768 ); 47 | 48 | // fill rx buffer to 'n' octets (from TCP connection) 49 | virtual void fill(unsigned long n); 50 | 51 | // send tx buffer to TCP connection 52 | virtual void flush(); 53 | 54 | // delegate to read but while blocking make sure to 55 | // reject attempts by other clients to connect by accepting 56 | // and closing extra connections 57 | virtual ssize_t read(void *buf, size_t l); 58 | 59 | // discard 'n' octets from rx buffer (mark as consumed) 60 | virtual void bump(unsigned long n); 61 | 62 | // (re)allocated buffers 63 | virtual void allocBufs(); 64 | 65 | virtual void run(); 66 | 67 | virtual ~XvcConn(); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDriver.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef XVC_TRANSPORT_DRIVER_H 18 | #define XVC_TRANSPORT_DRIVER_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using std::vector; 31 | 32 | class JtagDumpCtx; 33 | 34 | // Abstract JTAG driver -- in most cases you'd want to 35 | // subclass JtagDriverAxisToJtag if you want to support 36 | // a new transport. 37 | class JtagDriver { 38 | protected: 39 | unsigned debug_; 40 | // occasionally drop a packet for testing (when enabled) 41 | unsigned drop_; 42 | bool drEn_; 43 | JtagDumpCtx *snif_; 44 | 45 | public: 46 | JtagDriver(int argc, char *const argv[], unsigned debug); 47 | 48 | // set/get debug level 49 | void setDebug(unsigned debug); 50 | unsigned getDebug(); 51 | 52 | bool getSniff(); 53 | 54 | void setTestMode(unsigned flags); 55 | 56 | virtual void init() 57 | = 0; 58 | 59 | // XVC query support; return the size of max. supported JTAG vector in bytes 60 | // if 0 then no the target does not have memory and if 61 | // there is reliable transport there is no limit to vector 62 | // length. 63 | virtual unsigned long 64 | query() 65 | = 0; 66 | 67 | // Max. vector size (in bytes) this driver supports - may be different 68 | // from what the target supports and the minimum will be used... 69 | // Note that this is a single vector (the message the driver 70 | // must handle typically contains two vectors and a header, so 71 | // the driver must consider this when computing the max. supported 72 | // vector size) 73 | virtual unsigned long 74 | getMaxVectorSize() 75 | = 0; 76 | 77 | // XVC -- setting to 0 merely retrieves 78 | virtual uint32_t 79 | setPeriodNs(uint32_t newPeriod) 80 | = 0; 81 | 82 | // send tms and tdi vectors of length numBits (each) and receive tdo 83 | // little-endian (first send/received at lowest offset) 84 | virtual void 85 | sendVectors( 86 | unsigned long numBits, 87 | uint8_t *tms, 88 | uint8_t *tdi, 89 | uint8_t *tdo) 90 | = 0; 91 | 92 | virtual void 93 | dumpInfo(FILE *f = stdout) = 0; 94 | 95 | virtual ~JtagDriver(); 96 | 97 | static void usage(); // to be implemented by subclass 98 | 99 | static bool needTargetArg() // to be overridden by subclass 100 | { 101 | return true; 102 | }; 103 | }; 104 | 105 | // Simple driver registry (only a single loadable driver is remembered) 106 | // 107 | // Each driver must instantiate a registrar object: 108 | // 109 | // static DriverRegistrar r; 110 | // 111 | 112 | class DriverRegistry { 113 | public: 114 | typedef JtagDriver * (*Factory)(int argc, char *const argv[], const char *); 115 | typedef void (*Usage)(); 116 | 117 | private: 118 | typedef struct { 119 | const char * name_; 120 | Factory creator_; 121 | Usage helper_; 122 | bool needTargetArg_; 123 | } RegEntry; 124 | 125 | vector entries_; 126 | 127 | DriverRegistry(); 128 | ~DriverRegistry(); 129 | 130 | static DriverRegistry *getP(bool creat); 131 | 132 | RegEntry *find(const char *drvnam); 133 | 134 | public: 135 | JtagDriver *create(const char *drvnam, int argc, char *const argv[], const char *arg); 136 | 137 | void registerFactory(const char * const name, Factory f, Usage h, bool needTargetArg); 138 | 139 | void usage(const char *drvnam); 140 | 141 | void printRegisteredDrivers(FILE *f, const char *fmt); 142 | 143 | bool has(const char *drvnam); 144 | 145 | static DriverRegistry * 146 | get(); 147 | 148 | static DriverRegistry * 149 | init(); 150 | }; 151 | 152 | template class DriverRegistrar { 153 | private: 154 | static JtagDriver *createP(int argc, char * const argv[], const char *arg) 155 | { 156 | return new T(argc, argv, arg); 157 | } 158 | 159 | public: 160 | 161 | DriverRegistrar(const char * const nm) 162 | { 163 | // avoid registring statically linked drivers 164 | // (prior to init() being executed) 165 | DriverRegistry *r = DriverRegistry::get(); 166 | if ( r ) { 167 | r->registerFactory( nm, createP, T::usage, T::needTargetArg() ); 168 | } 169 | } 170 | }; 171 | 172 | 173 | // Exceptions 174 | 175 | // library/syscall errors (yielding and 'errno' -- which is converted to a message) 176 | class SysErr : public std::runtime_error { 177 | public: 178 | SysErr(const char *prefix); 179 | }; 180 | 181 | // Protocol error 182 | class ProtoErr : public std::runtime_error { 183 | public: 184 | ProtoErr(const char *msg); 185 | }; 186 | 187 | // Timeout 188 | class TimeoutErr : public std::runtime_error { 189 | public: 190 | TimeoutErr(const char *detail = ""); 191 | }; 192 | 193 | 194 | // Driver for the AxisToJtag FW module; a transport-level 195 | // driver must derive from this and implement 196 | // 197 | // - 'xfer()'. 198 | // - 'getMaxVectorSize()' 199 | // 200 | // If the driver is to be run-time loaded (compiled separately) 201 | // then it must register itself: 202 | // 203 | // static DriverRegistrar r; 204 | // 205 | // 'getMaxVectorSize()' must return the max. size of a single 206 | // JTAG vector (in bytes) the driver can support. Note that the 207 | // max. *message* size is bigger - it comprises two vectors and 208 | // a header word (depends on the word size the target FW was 209 | // built for). 210 | // E.g., A UDP transport might want to limit to less than the 211 | // ethernet MTU. See xvcDrvUdp.cc for an example... 212 | // 213 | // 'xfer()' must transmit the (opaque) message in 'txb' of size 214 | // 'txBytes' (which is guaranteed to be at most 215 | // 216 | // 2*maxVectorSize() + getWordSize() 217 | // 218 | // The method must then receive the reply from the target 219 | // and: 220 | // - store the first 'hsize' bytes into 'hbuf'. If less than 221 | // 'hsize' were received then 'xfer' must throw and exception. 222 | // - store the remainder of the message up to at most 'size' 223 | // bytes into 'rbuf'. 224 | // - return the number of actual bytes stored in 'rbuf'. 225 | // 226 | // If a timeout occurs then 'xfer' must throw a TimeoutErr(). 227 | // 228 | class JtagDriverAxisToJtag : public JtagDriver { 229 | protected: 230 | typedef uint32_t Header; 231 | typedef uint8_t Xid; 232 | 233 | static const Xid XID_ANY = 0; 234 | 235 | private: 236 | unsigned wordSize_; 237 | unsigned memDepth_; 238 | 239 | vector txBuf_; 240 | vector hdBuf_; 241 | 242 | unsigned bufSz_; 243 | unsigned retry_; 244 | 245 | Xid xid_; 246 | 247 | uint32_t periodNs_; 248 | 249 | Header newXid(); 250 | 251 | Header mkQuery(); 252 | Header mkShift(unsigned len); 253 | 254 | protected: 255 | 256 | virtual void setHdr(uint8_t *buf, Header hdr); 257 | 258 | static Header getHdr(uint8_t *buf); 259 | 260 | static uint32_t getw32(uint8_t *buf); 261 | static void setw32(uint8_t *buf, uint32_t w, unsigned l = sizeof(uint32_t)); 262 | 263 | 264 | static const Header PVER0 = 0x00000000; 265 | static const Header PVERS = PVER0; 266 | static const Header CMD_Q = 0x00000000; 267 | static const Header CMD_S = 0x10000000; 268 | static const Header CMD_E = 0x20000000; 269 | 270 | static const Header VRS_MASK = 0xc0000000; 271 | static const Header CMD_MASK = 0x30000000; 272 | static const unsigned ERR_SHIFT = 0; 273 | static const Header ERR_MASK = 0x000000ff; 274 | 275 | static const unsigned XID_SHIFT = 20; 276 | static const unsigned LEN_SHIFT = 0; 277 | static const Header LEN_MASK = 0x000fffff; 278 | 279 | static const unsigned ERR_BAD_VERSION = 1; 280 | static const unsigned ERR_BAD_COMMAND = 2; 281 | static const unsigned ERR_TRUNCATED = 3; 282 | static const unsigned ERR_NOT_PRESENT = 4; 283 | 284 | static Xid getXid(Header x); 285 | static uint32_t getCmd(Header x); 286 | static unsigned getErr(Header x); 287 | static unsigned long getLen(Header x); 288 | static Header getVrs(Header x); 289 | 290 | static Header mkQueryReply 291 | ( 292 | Header protoVers, 293 | unsigned wordSize, 294 | unsigned memDepth, 295 | uint32_t periodNs 296 | ); 297 | 298 | // returns error message or NULL (unknown error) 299 | static const char *getMsg(unsigned error); 300 | 301 | 302 | // extract from message header 303 | static unsigned wordSize(Header reply); 304 | static unsigned memDepth(Header reply); 305 | static uint32_t cvtPerNs(Header reply); 306 | 307 | static uint32_t encPerNs(uint32_t); 308 | 309 | static int isLE() 310 | { 311 | static const union { uint8_t c[2]; uint16_t s; } u = { s: 1 }; 312 | return !!u.c[0]; 313 | } 314 | 315 | static const uint32_t UNKNOWN_PERIOD = 0; 316 | 317 | static double REF_FREQ_HZ() 318 | { 319 | return 200.0E6; 320 | } 321 | 322 | // obtain (current/cached) parameters; these may 323 | // depend on values provided by the transport-level driver 324 | virtual unsigned getWordSize(); 325 | virtual unsigned getMemDepth(); 326 | virtual uint32_t getPeriodNs(); 327 | 328 | public: 329 | 330 | JtagDriverAxisToJtag( int argc, char *const argv[], unsigned debug = 0 ); 331 | 332 | // initialization after full construction 333 | virtual void 334 | init(); 335 | 336 | // virtual method to be implemented by transport-level driver; 337 | // transmit txBytes from TX buffer (txb) and receive 'hsize' header 338 | // bytes into hdbuf and up to 'size' bytes into rxb. 339 | // RETURNS: number of payload bytes (w/o header). 340 | virtual int 341 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) = 0; 342 | 343 | // Transfer with retry/timeout. 344 | // 'txBytes' are transmitted from the TX buffer 'txb'. 345 | // The message header is received into '*phdr', payload (of up to 'sizeBytes') into 'rxb'. 346 | // 347 | virtual int 348 | xferRel( uint8_t *txb, unsigned txBytes, Header *phdr, uint8_t *rxb, unsigned sizeBytes ); 349 | 350 | // XVC query ("getinfo") 351 | virtual unsigned long 352 | query(); 353 | 354 | virtual uint32_t 355 | setPeriodNs(uint32_t newPeriod); 356 | 357 | // XVC send vectors ("shift") 358 | virtual void sendVectors(unsigned long bits, uint8_t *tms, uint8_t *tdi, uint8_t *tdo); 359 | 360 | virtual void dumpInfo(FILE *f); 361 | 362 | static void usage(); 363 | }; 364 | 365 | // RAII socket helper 366 | class SockSd { 367 | private: 368 | int sd_; 369 | 370 | SockSd(const SockSd&); 371 | SockSd & operator=(const SockSd&); 372 | 373 | public: 374 | // 'stream': SOCK_STREAM vs SOCK_DGRAM 375 | SockSd(bool stream); 376 | 377 | virtual int getSd(); 378 | 379 | virtual ~SockSd(); 380 | }; 381 | 382 | #endif 383 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvAxiDbgBridgeIP.cc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : PSI 5 | //----------------------------------------------------------------------------- 6 | // Description: Driver for Vivado's AXI Debug Bridge IP 7 | //----------------------------------------------------------------------------- 8 | 9 | #include 10 | #include 11 | 12 | JtagDriverZynqAxiDbgBridgeIP::JtagDriverZynqAxiDbgBridgeIP(int argc, char *const argv[], const char *devnam) 13 | : JtagDriverAxisToJtag( argc, argv ), 14 | map_ ( devnam, MAP_SIZE ), 15 | doSleep_ ( false ), 16 | measure_ ( 100 ), 17 | maxPollDelayUs_ ( 0 ) 18 | { 19 | unsigned long maxBytes = 1024; /* arbitrary; could support an option to change this */ 20 | int opt; 21 | 22 | while ( (opt = getopt(argc, argv, "M:")) > 0 ) { 23 | switch ( opt ) { 24 | case 'M': 25 | if ( 1 != sscanf(optarg, "%li", &maxBytes) ) { 26 | fprintf( stderr,"Error: Unable to scan value for option -%c\n", opt); 27 | throw std::runtime_error("Invalid scan driver option value"); 28 | } 29 | break; 30 | default: 31 | fprintf( stderr,"Unknown driver option -%c\n", opt ); 32 | throw std::runtime_error("Unknown driver option"); 33 | } 34 | } 35 | 36 | reset(); 37 | 38 | wrdSiz_ = 4; 39 | maxVec_ = maxBytes; 40 | } 41 | 42 | JtagDriverZynqAxiDbgBridgeIP::~JtagDriverZynqAxiDbgBridgeIP() 43 | { 44 | } 45 | 46 | void 47 | JtagDriverZynqAxiDbgBridgeIP::o32(unsigned idx, uint32_t v) 48 | { 49 | if ( getDebug() > 2 ) { 50 | fprintf(stderr, "r[%d]:=0x%08x\n", idx, v); 51 | } 52 | map_.wr(idx, v); 53 | } 54 | 55 | uint32_t 56 | JtagDriverZynqAxiDbgBridgeIP::i32(unsigned idx) 57 | { 58 | uint32_t v = map_.rd(idx); 59 | if ( getDebug() > 2 ) { 60 | fprintf(stderr, "r[%d]=>0x%08x\n", idx, v); 61 | } 62 | return v; 63 | } 64 | 65 | void 66 | JtagDriverZynqAxiDbgBridgeIP::wait() 67 | { 68 | if ( doSleep_ ) { 69 | nanosleep( &pollTime_, 0 ); 70 | } 71 | } 72 | 73 | void 74 | JtagDriverZynqAxiDbgBridgeIP::reset() 75 | { 76 | } 77 | 78 | void 79 | JtagDriverZynqAxiDbgBridgeIP::init() 80 | { 81 | reset(); 82 | JtagDriverAxisToJtag::init(); 83 | // have now the target word size -- verify: 84 | if ( getWordSize() != wrdSiz_ ) { 85 | throw std::runtime_error("ERROR: firmware misconfigured -- AXI-IP word size /= JTAG stream word size"); 86 | } 87 | } 88 | 89 | unsigned long 90 | JtagDriverZynqAxiDbgBridgeIP::getMaxVectorSize() 91 | { 92 | return maxVec_; 93 | } 94 | 95 | int 96 | JtagDriverZynqAxiDbgBridgeIP::xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) 97 | { 98 | Header hdr; 99 | unsigned nbits, l, lb; 100 | uint8_t *pi, *po; 101 | int min; 102 | uint32_t w; 103 | unsigned nbytes; 104 | unsigned nwords; 105 | unsigned wsz = hsize; 106 | 107 | struct timespec then, now; 108 | 109 | /* This firmware does not expect a stream in our usual format, so we must handle the header here */ 110 | pi = txb; 111 | po = rxb; 112 | 113 | /* Header is in little-endian format */ 114 | hdr = getHdr( txb ); 115 | pi += wsz; 116 | 117 | if ( getVrs(hdr) != PVER0 ) { 118 | throw std::runtime_error("AxiDbgBridgeIP driver: xfer() found unexpected version"); 119 | } 120 | 121 | if ( hsize != sizeof(uint32_t) ) { 122 | throw std::runtime_error("AxiDbgBridgeIP driver: xfer() found unexpected header size"); 123 | } 124 | 125 | switch ( getCmd(hdr) ) { 126 | case CMD_S: /* normal/main case */ 127 | break; 128 | 129 | case CMD_Q: 130 | hdr = mkQueryReply( PVER0, sizeof(uint32_t), 0, UNKNOWN_PERIOD ); 131 | setHdr( hdbuf, hdr ); po += sizeof(hdr); 132 | return sizeof(uint32_t); 133 | 134 | default: 135 | throw std::runtime_error("AxiDbgBridgeIP driver: xfer() found unexpected command"); 136 | } 137 | 138 | if ( wsz != sizeof(w) ) { 139 | throw std::runtime_error("AXI-DebugBridge IP only supports word-lengths of 4"); 140 | } 141 | 142 | nbits = getLen( hdr ); 143 | nbytes = (nbits + 7)/8; 144 | nwords = (nbytes + wsz - 1)/wsz; 145 | 146 | if ( txBytes < nwords * 2 * wsz ) { 147 | throw std::runtime_error("AXI-DebugBridge IP: not enough input data"); 148 | } 149 | 150 | if ( size < nbytes ) { 151 | throw std::runtime_error("AXI-DebugBridge IP: output buffer too small"); 152 | } 153 | 154 | setHdr( hdbuf, hdr ); 155 | 156 | 157 | lb = sizeof(w); 158 | l = 8*lb; 159 | o32( LENGTH_IDX, l); 160 | 161 | while ( nbits > 0 ) { 162 | 163 | w = getw32( pi ); pi += sizeof(w); 164 | o32( TMSVEC_IDX, w ); 165 | w = getw32( pi ); pi += sizeof(w); 166 | o32( TDIVEC_IDX, w ); 167 | if (nbits < 8*sizeof(w)) { 168 | l = nbits; 169 | o32( LENGTH_IDX, l ); 170 | lb = (l + 7)/8; 171 | } 172 | w = i32( CSR_IDX ); 173 | w |= CSR_RUN; 174 | o32( CSR_IDX, w ); 175 | 176 | if ( measure_ ) { 177 | doSleep_ = false; 178 | clock_gettime( CLOCK_MONOTONIC, &then ); 179 | } 180 | 181 | while ( i32(CSR_IDX) & CSR_RUN ) { 182 | wait(); 183 | } 184 | 185 | w = i32( TDOVEC_IDX ); 186 | setw32( po, w, lb ); po += lb; 187 | 188 | if ( measure_ ) { 189 | unsigned long diffNs, diffUs; 190 | clock_gettime( CLOCK_MONOTONIC, &now ); 191 | diffNs = (now.tv_sec - then.tv_sec ) * 1000000000UL; 192 | diffNs += (now.tv_nsec - then.tv_nsec); 193 | if ( diffNs >= MIN_SLEEP_NS ) { 194 | pollTime_.tv_sec = 0; 195 | pollTime_.tv_nsec = diffNs; 196 | measure_ = 0; 197 | doSleep_ = true; 198 | } else { 199 | measure_--; 200 | } 201 | diffUs = diffNs/1000UL; 202 | if ( diffUs > maxPollDelayUs_ ) { 203 | maxPollDelayUs_ = diffUs; 204 | if ( getDebug() ) { 205 | printf("axiDebugBridgeIP Driver max poll delay %lu us so far...\n", maxPollDelayUs_); 206 | } 207 | } 208 | } 209 | 210 | nbits -= l; 211 | } 212 | 213 | return nbytes; 214 | } 215 | 216 | void 217 | JtagDriverZynqAxiDbgBridgeIP::usage() 218 | { 219 | printf(" Axi-Debug Bridge IP Fifo Driver options: (none)\n"); 220 | } 221 | 222 | static DriverRegistrar r("axiDbgBridgeIP"); 223 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvAxiDbgBridgeIP.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Company : PSI 3 | //----------------------------------------------------------------------------- 4 | // Description: Driver for Vivado's AXI Debug Bridge IP 5 | //----------------------------------------------------------------------------- 6 | 7 | #ifndef JTAG_DRIVER_ZYNQ_AXI_DEBUG_BRIDGE_H 8 | #define JTAG_DRIVER_ZYNQ_AXI_DEBUG_BRIDGE_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class JtagDriverZynqAxiDbgBridgeIP : public JtagDriverAxisToJtag { 15 | 16 | private: 17 | static const int LENGTH_IDX = 0; 18 | static const int TMSVEC_IDX = 1; 19 | static const int TDIVEC_IDX = 2; 20 | static const int TDOVEC_IDX = 3; 21 | static const int CSR_IDX = 4; 22 | static const uint32_t CSR_RUN = 0x00000001; 23 | static const int MAP_SIZE = 0x14; 24 | 25 | MemMap map_; 26 | 27 | unsigned long maxVec_; 28 | unsigned wrdSiz_; 29 | 30 | static const unsigned long MIN_SLEEP_NS = 20UL*1000UL*1000UL; 31 | struct timespec pollTime_; 32 | bool doSleep_; 33 | unsigned measure_; 34 | unsigned long maxPollDelayUs_; 35 | 36 | public: 37 | 38 | // I/O 39 | virtual void o32(unsigned idx, uint32_t v); 40 | virtual uint32_t i32(unsigned idx); 41 | 42 | virtual void reset(); 43 | 44 | virtual void wait(); 45 | 46 | JtagDriverZynqAxiDbgBridgeIP(int argc, char *const argv[], const char *devnam); 47 | virtual void 48 | init(); 49 | 50 | virtual unsigned long 51 | getMaxVectorSize(); 52 | 53 | virtual int 54 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 55 | 56 | virtual ~JtagDriverZynqAxiDbgBridgeIP(); 57 | 58 | static void usage(); 59 | }; 60 | 61 | extern "C" JtagDriver *drvCreate(const char *target); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvAxisFifo.cc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #include 18 | #include 19 | 20 | JtagDriverZynqFifo::JtagDriverZynqFifo(int argc, char *const argv[], const char *devnam) 21 | : JtagDriverAxisToJtag( argc, argv ), 22 | map_ ( devnam ), 23 | useIrq_( true ) 24 | { 25 | uint32_t sizVal; 26 | unsigned long maxBytes; 27 | unsigned long maxWords; 28 | int opt; 29 | 30 | while ( (opt = getopt(argc, argv, "i")) > 0 ) { 31 | switch ( opt ) { 32 | case 'i': useIrq_ = false; printf("Interrupts disabled\n"); break; 33 | default: 34 | fprintf( stderr,"Unknown driver option -%c\n", opt ); 35 | throw std::runtime_error("Unknown driver option"); 36 | } 37 | } 38 | 39 | reset(); 40 | 41 | sizVal = i32( TX_SIZ_IDX ); 42 | 43 | wrdSiz_ = (sizVal >> 24); 44 | 45 | // this fifo must have one empty slot always. 46 | maxWords = (sizVal & 0x00ffffff) - 1; 47 | 48 | // one header word; two vectors must fit 49 | maxBytes = (maxWords - 1) * wrdSiz_; 50 | 51 | maxVec_ = maxBytes/2; 52 | } 53 | 54 | JtagDriverZynqFifo::~JtagDriverZynqFifo() 55 | { 56 | } 57 | 58 | void 59 | JtagDriverZynqFifo::o32(unsigned idx, uint32_t v) 60 | { 61 | if ( getDebug() > 2 ) { 62 | fprintf(stderr, "r[%d]:=0x%08x\n", idx, v); 63 | } 64 | map_.wr(idx, v); 65 | } 66 | 67 | uint32_t 68 | JtagDriverZynqFifo::i32(unsigned idx) 69 | { 70 | uint32_t v = map_.rd(idx); 71 | if ( getDebug() > 2 ) { 72 | fprintf(stderr, "r[%d]=>0x%08x\n", idx, v); 73 | } 74 | return v; 75 | } 76 | 77 | uint32_t 78 | JtagDriverZynqFifo::wait() 79 | { 80 | uint32_t evs = 0; 81 | if ( useIrq_ ) { 82 | evs = 1; 83 | if ( sizeof(evs) != write( map_.fd(), &evs, sizeof(evs) ) ) { 84 | throw SysErr("Unable to write to IRQ descriptor"); 85 | } 86 | if ( sizeof(evs) != read( map_.fd(), &evs, sizeof(evs) ) ) { 87 | throw SysErr("Unable to read from IRQ descriptor"); 88 | } 89 | } // else busy wait 90 | return evs; 91 | } 92 | 93 | void 94 | JtagDriverZynqFifo::reset() 95 | { 96 | int set = 0; 97 | 98 | o32( RX_RST_IDX, RST_MAGIC ); 99 | o32( TX_RST_IDX, RST_MAGIC ); 100 | if ( useIrq_ ) { 101 | o32( RX_IEN_IDX, (1< r("zynqAxis"); 222 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvAxisFifo.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef JTAG_DRIVER_ZYNQ_FIFO_H 18 | #define JTAG_DRIVER_ZYNQ_FIFO_H 19 | 20 | #include 21 | #include 22 | 23 | class JtagDriverZynqFifo : public JtagDriverAxisToJtag { 24 | private: 25 | static const int TX_STA_IDX = 0; 26 | static const int TX_IEN_IDX = 1; 27 | static const int TX_RST_IDX = 2; 28 | static const uint32_t RST_MAGIC = 0xa5; 29 | static const int TX_OCC_IDX = 3; 30 | static const int TX_DAT_IDX = 4; 31 | static const int TX_END_IDX = 5; 32 | static const int TX_SIZ_IDX = 6; 33 | static const int RX_STA_IDX = 8; 34 | static const int RX_IEN_IDX = 9; 35 | static const int RX_RST_IDX = 10; 36 | static const int RX_OCC_IDX = 11; 37 | static const int RX_DAT_IDX = 12; 38 | static const int RX_CNT_IDX = 13; 39 | static const int RX_SIZ_IDX = 14; 40 | 41 | static const int RX_RDY_SHF = 5; 42 | static const int RX_RST_SHF = 0; 43 | static const int TX_RST_SHF = 0; 44 | 45 | MemMap map_; 46 | 47 | unsigned long maxVec_; 48 | unsigned wrdSiz_; 49 | bool useIrq_; 50 | 51 | public: 52 | 53 | // I/O 54 | virtual void o32(unsigned idx, uint32_t v); 55 | virtual uint32_t i32(unsigned idx); 56 | 57 | virtual void reset(); 58 | 59 | virtual uint32_t wait(); 60 | 61 | JtagDriverZynqFifo(int argc, char *const argv[], const char *devnam); 62 | 63 | virtual void 64 | init(); 65 | 66 | virtual unsigned long 67 | getMaxVectorSize(); 68 | 69 | virtual int 70 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 71 | 72 | virtual ~JtagDriverZynqFifo(); 73 | 74 | static void usage(); 75 | }; 76 | 77 | extern "C" JtagDriver *drvCreate(const char *target); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvAxisTmem.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // File : xvcDrvAxisFifo.h 5 | // Author : Till Straumann 6 | // Company : SLAC National Accelerator Laboratory 7 | // Created : 2017-12-05 8 | // Last update: 2017-12-05 9 | // Platform : 10 | // Standard : VHDL'93/02 11 | //----------------------------------------------------------------------------- 12 | // Description: 13 | //----------------------------------------------------------------------------- 14 | // This file is part of 'SLAC Firmware Standard Library'. 15 | // It is subject to the license terms in the LICENSE.txt file found in the 16 | // top-level directory of this distribution and at: 17 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 18 | // No part of 'SLAC Firmware Standard Library', including this file, 19 | // may be copied, modified, propagated, or distributed except according to 20 | // the terms contained in the LICENSE.txt file. 21 | //----------------------------------------------------------------------------- 22 | 23 | #ifndef JTAG_DRIVER_TMEM_FIFO_H 24 | #define JTAG_DRIVER_TMEM_FIFO_H 25 | 26 | #include 27 | #include 28 | 29 | class JtagDriverTmemFifo : public JtagDriverAxisToJtag { 30 | private: 31 | static const int FIFO_DAT_IDX = 0; 32 | static const int FIFO_MAGIC_IDX = 1; // reading this will ALSO read the FIFO 33 | // (use only during detection)! 34 | static const int FIFO_CSR_IDX = 2; 35 | static const uint32_t FIFO_CSR_RST = (1<<23); 36 | static const uint32_t FIFO_CSR_EOFO = (1<<16); 37 | static const uint32_t FIFO_CSR_EMPI = (1<<17); 38 | static const uint32_t FIFO_CSR_IENO = (1<<18); 39 | static const uint32_t FIFO_CSR_IENI = (1<<19); 40 | static const uint32_t FIFO_CSR_NWRDS = 0; 41 | static const uint32_t FIFO_CSR_NWRDM = 0xffff; 42 | static const uint32_t FIFO_CSR_MAXWS = 24; 43 | static const uint32_t FIFO_CSR_MAXWM = 0x0f000000; 44 | static const uint32_t FIFO_CSR_VERSM = 0xf0000000; 45 | static const uint32_t FIFO_CSR_VERSS = 28; 46 | 47 | static const uint32_t VERSION_0 = 0; 48 | static const uint32_t VERSION_1 = 1; 49 | static const uint32_t MAGIC = 0x6666aaaa; 50 | 51 | static const int SDES_TMS_IDX = 4; 52 | static const int SDES_TDI_IDX = 5; 53 | static const int SDES_CSR_IDX = 6; 54 | static const int SDES_TDO_IDX = 7; 55 | 56 | static const uint32_t SDES_CSR_RUN = 0x00000100; 57 | static const uint32_t SDES_CSR_BSY = 0x00000200; 58 | static const uint32_t SDES_CSR_LENS = 0; 59 | 60 | static const uint32_t SDES_CSR_LRMSK = 0x00000fff; 61 | static const uint32_t SDES_CSR_BBMSK = 0x000f0000; 62 | 63 | static const uint32_t SDES_CSR_BB_TCK = 0x00010000; 64 | static const uint32_t SDES_CSR_BB_TMS = 0x00020000; 65 | static const uint32_t SDES_CSR_BB_TDI = 0x00040000; 66 | static const uint32_t SDES_CSR_BB_TDO = 0x00080000; 67 | static const uint32_t SDES_CSR_BB_ENA = 0x80000000; 68 | 69 | unsigned toscaSpace_; 70 | unsigned long toscaBase_; 71 | 72 | unsigned long maxVec_; 73 | unsigned wrdSiz_; 74 | int irqFd_ ; 75 | 76 | 77 | bool bitBang_; 78 | bool useSdes_; 79 | unsigned logBscn_; 80 | 81 | static const unsigned long MIN_SLEEP_NS = 20UL*1000UL*1000UL; 82 | 83 | struct timespec pollTime_; 84 | bool doSleep_; 85 | unsigned measure_; 86 | unsigned long maxPollDelayUs_; 87 | unsigned version_; 88 | 89 | public: 90 | 91 | // I/O 92 | virtual void o32(unsigned idx, uint32_t v); 93 | virtual uint32_t i32(unsigned idx); 94 | 95 | virtual void reset(); 96 | 97 | virtual uint32_t wait(); 98 | 99 | JtagDriverTmemFifo(int argc, char *const argv[], const char *devnam); 100 | 101 | virtual void 102 | init(); 103 | 104 | virtual unsigned long 105 | getMaxVectorSize(); 106 | 107 | virtual int 108 | xferFifo( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 109 | 110 | virtual int 111 | xferSdes( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 112 | 113 | virtual int 114 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 115 | 116 | virtual uint32_t 117 | xfer32bb(uint32_t tms, uint32_t tdi, unsigned nbits); 118 | 119 | virtual void 120 | bbsleep(); 121 | 122 | virtual uint32_t 123 | xfer32sdes(uint32_t tms, uint32_t tdi, unsigned nbits, struct timespec *); 124 | 125 | 126 | virtual ~JtagDriverTmemFifo(); 127 | 128 | static void usage(); 129 | 130 | }; 131 | 132 | extern "C" JtagDriver *drvCreate(const char *target); 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvFoo.cc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #include 18 | 19 | // Skeleton for xvcSrv communication driver 20 | 21 | class JtagDriverFoo : public JtagDriverAxisToJtag { 22 | public: 23 | JtagDriverFoo(int argc, char *const argv[], const char *devnam) 24 | : JtagDriverAxisToJtag(argc, argv) 25 | { 26 | } 27 | 28 | // This is the core method; send/receive a packet to the firmware 29 | // driver we support. Return then number of bytes transferred. 30 | virtual int 31 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) 32 | { 33 | return 0; 34 | } 35 | 36 | // return max. TMS/TDI/TDO vector size (in bits) this driver can handle 37 | // (size of a single vector, e.g., TMS) 38 | virtual unsigned long getMaxVectorSize() { return 0; } 39 | 40 | virtual ~JtagDriverFoo() {} 41 | 42 | // print usage info 43 | static void usage() { printf("FOO driver\n"); } 44 | 45 | // override default if your drive does not need a '-t ' option 46 | // to identify a target. Avoids the main program from flagging an error. 47 | // static bool needTargetArg() { return false; } 48 | }; 49 | 50 | // Register, so -D can find this driver 51 | static DriverRegistrar r("foo"); 52 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvLoopBack.cc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #include 18 | #include 19 | 20 | JtagDriverLoopBack::JtagDriverLoopBack(int argc, char *const argv[], const char *fnam) 21 | : JtagDriverAxisToJtag(argc, argv ), 22 | skip_ ( 0 == fnam || 0 == *fnam ), 23 | line_ ( 1 ), 24 | tdoOnly_( false ) 25 | { 26 | if ( fnam && *fnam ) { 27 | if ( ! (f_ = fopen(fnam, "r")) ) { 28 | throw SysErr(fnam); 29 | } 30 | if ( strstr(fnam, "TdoOnly") ) { 31 | // for tests where be change the packet structure 32 | // from the test file (e.g., when we break large 33 | // vectors) the length fields are no longer valid 34 | // and TDO gets interspersed with TDI/TMS. 35 | // For such a test we want a file that contains 36 | // just TDO bits so we can play them back. 37 | // The python script checks correctness of the result... 38 | tdoOnly_ = true; 39 | } 40 | } 41 | } 42 | 43 | JtagDriverLoopBack::~JtagDriverLoopBack() 44 | { 45 | if ( f_ ) { 46 | fclose( f_ ); 47 | } 48 | } 49 | 50 | 51 | bool 52 | JtagDriverLoopBack::rdl(char *buf, size_t bufsz) 53 | { 54 | if ( !skip_ && 0 == fgets( buf, bufsz, f_ ) ) { 55 | fprintf(stderr,"EOF on playback file\n"); 56 | skip_ = true; 57 | } 58 | return !skip_; 59 | } 60 | 61 | unsigned long 62 | JtagDriverLoopBack::check(unsigned long val, const char *fmt, bool rdOnly) 63 | { 64 | char cbuf[512]; 65 | unsigned long cmp = 0; 66 | 67 | if ( rdl( cbuf, sizeof(cbuf) ) ) { 68 | if ( 1 != sscanf(cbuf, fmt, &cmp) ) { 69 | snprintf(cbuf, sizeof(cbuf), "Unable to scan (format %s; line %ld)", fmt, line_); 70 | throw std::runtime_error(cbuf); 71 | } 72 | if ( ! rdOnly && cmp != val ) { 73 | snprintf(cbuf, sizeof(cbuf), "value mismatch -- got 0x%lx; expected 0x%lx (@line %ld)", val, cmp, line_); 74 | throw std::runtime_error(cbuf); 75 | } 76 | line_++; 77 | } 78 | return cmp; 79 | } 80 | 81 | unsigned long 82 | JtagDriverLoopBack::getMaxVectorSize() 83 | { 84 | return 0; // allow any 85 | } 86 | 87 | void 88 | JtagDriverLoopBack::checkTDI(unsigned long val) 89 | { 90 | if ( ! tdoOnly_ ) { 91 | check(val, "TDI : %li"); 92 | } 93 | } 94 | 95 | void 96 | JtagDriverLoopBack::checkTMS(unsigned long val) 97 | { 98 | if ( ! tdoOnly_ ) { 99 | check(val, "TMS : %li"); 100 | } 101 | } 102 | 103 | void 104 | JtagDriverLoopBack::checkLEN(unsigned long val) 105 | { 106 | if ( ! tdoOnly_ ) { 107 | check(val, "LENBITS: %li"); 108 | } 109 | } 110 | 111 | unsigned long 112 | JtagDriverLoopBack::getTDO() 113 | { 114 | return check(0, "TDO : %li", true); 115 | } 116 | 117 | unsigned long 118 | JtagDriverLoopBack::getValLE(uint8_t *buf, unsigned wsz) 119 | { 120 | unsigned long rval = 0; 121 | while ( wsz > 0 ) { 122 | wsz--; 123 | rval = (rval << 8) | buf[wsz]; 124 | } 125 | return rval; 126 | } 127 | 128 | void 129 | JtagDriverLoopBack::setValLE(unsigned long val, uint8_t *buf, unsigned wsz) 130 | { 131 | while ( wsz > 0 ) { 132 | *buf++ = val; 133 | val >>= 8; 134 | wsz--; 135 | } 136 | } 137 | 138 | unsigned 139 | JtagDriverLoopBack::emulWordSize() 140 | { 141 | return 4; 142 | } 143 | 144 | unsigned 145 | JtagDriverLoopBack::emulMemDepth() 146 | { 147 | return 0; // no memory = reliable channel required! 148 | } 149 | 150 | 151 | int 152 | JtagDriverLoopBack::xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) 153 | { 154 | unsigned i,j; 155 | int rval = 0; 156 | uint32_t cmd; 157 | unsigned long bits; 158 | unsigned bytes; 159 | unsigned rem; 160 | unsigned wbytes; 161 | const unsigned wsz = emulWordSize(); 162 | const unsigned dpt = emulMemDepth(); 163 | char cbuf[1024]; 164 | 165 | if ( txBytes < 4 ) 166 | return 0; 167 | 168 | i = 0; 169 | uint32_t h = (((((txb[i+3]<<8)|txb[i+2])<<8)|txb[i+1])<<8)|txb[i+0]; 170 | 171 | if ( getVrs(h) != PVER0 ) { 172 | h = (h & ~(CMD_MASK | LEN_MASK)) | (CMD_E | 2 ); 173 | } else { 174 | switch ( (cmd = getCmd( h )) ) { 175 | case CMD_Q: 176 | h |= ((dpt & 0xfffff) << 4 ) | (wsz-1); 177 | if ( getDebug() > 1 ) { 178 | fprintf(stderr, "QUERY \n"); 179 | } 180 | if ( f_ ) { 181 | fseek( f_, 0, SEEK_SET ); 182 | skip_ = false; 183 | } 184 | break; 185 | 186 | case CMD_S: 187 | if ( getDebug() > 1 ) { 188 | fprintf(stderr, "SHIFT\n"); 189 | } 190 | bits = getLen( h ); 191 | 192 | checkLEN( bits ); 193 | 194 | bytes = (bits + 7 )/8; 195 | wbytes = (bytes/wsz)*wsz; 196 | if ( txBytes < wsz + 2*bytes ) { 197 | fprintf(stderr,"txBytes: %d, word-size %d, vector-size %d\n", txBytes, wsz, bytes); 198 | throw std::runtime_error("Not enough TX bytes??"); 199 | } 200 | 201 | for ( j = i = 0; i < 2*wbytes; i += 2*wsz, j += wsz ) { 202 | checkTMS( getValLE( &txb[wsz + i], wsz ) ); 203 | checkTDI( getValLE( &txb[wsz + wsz + i], wsz ) ); 204 | if ( skip_ ) { 205 | // loop TDI back 206 | memcpy( &rxb[j], &txb[wsz + wsz + i], wsz ); 207 | } 208 | } 209 | 210 | if ( (rem = (bytes - wbytes)) ) { 211 | checkTMS( getValLE( &txb[wsz + i], rem ) ); 212 | checkTDI( getValLE( &txb[wsz + wsz + i], rem ) ); 213 | if ( skip_ ) { 214 | // loop TDI back 215 | memcpy( &rxb[j], &txb[wsz + wsz + i], rem ); 216 | } 217 | } 218 | 219 | if ( ! skip_ ) { 220 | for ( i = 0; i < bytes; i+=wsz ) { 221 | unsigned l = bytes - i; 222 | if ( l > 4 ) 223 | l = 4; 224 | setValLE( getTDO(), &rxb[i], l ); 225 | } 226 | } 227 | 228 | rval = bytes; 229 | break; 230 | 231 | default: 232 | h = (h & ~(CMD_MASK | LEN_MASK)) | (CMD_E | 1 ); 233 | break; 234 | } 235 | } 236 | 237 | memcpy(hdbuf, &h, 4); 238 | return rval; 239 | } 240 | 241 | UdpLoopBack::UdpLoopBack(const char *fnam, unsigned port) 242 | : JtagDriverLoopBack( 0, 0, fnam ), 243 | sock_( false ), 244 | tsiz_( -1 ) 245 | { 246 | struct sockaddr_in a; 247 | int yes = 1; 248 | 249 | rbuf_.reserve(1500); 250 | tbuf_.reserve(1500); 251 | 252 | a.sin_family = AF_INET; 253 | a.sin_addr.s_addr = INADDR_ANY; 254 | a.sin_port = htons( port ); 255 | 256 | if ( ::setsockopt( sock_.getSd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes) ) ) { 257 | throw SysErr("setsockopt(SO_REUSEADDR) failed"); 258 | } 259 | 260 | 261 | if ( ::bind( sock_.getSd(), (struct sockaddr*)&a, sizeof(a) ) ) { 262 | throw SysErr("Unable to bind Stream socket to local address"); 263 | } 264 | 265 | } 266 | 267 | UdpLoopBack::~UdpLoopBack() 268 | { 269 | } 270 | 271 | int 272 | UdpLoopBack::xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) 273 | { 274 | Header txh = getHdr( txb ); 275 | Header rxh = getHdr( hdbuf ); 276 | 277 | int got; 278 | bool isNewShift = false; 279 | 280 | switch ( getCmd(txh) ) { 281 | case CMD_Q: 282 | // assume a new connection 283 | tsiz_ = -1; 284 | break; 285 | 286 | case CMD_S: 287 | if ( getXid( txh ) == getXid( rxh ) ) { 288 | // retry! 289 | if ( tsiz_ < 0 ) { 290 | throw std::runtime_error("ERROR: UdpLoopBack - attempted retry but have no valid message!"); 291 | } 292 | // resend what we have 293 | return tsiz_; 294 | } 295 | isNewShift = true; 296 | break; 297 | 298 | default: 299 | break; 300 | } 301 | 302 | got = JtagDriverLoopBack::xfer( txb, txBytes, hdbuf, hsize, rxb, size ); 303 | 304 | if ( isNewShift ) { 305 | tsiz_ = got; 306 | } 307 | 308 | return got; 309 | } 310 | 311 | unsigned 312 | UdpLoopBack::emulMemDepth() 313 | { 314 | // limit to ethernet MTU; 2 vectors plus header must fit... 315 | return 1450/2/emulWordSize() - 1; 316 | } 317 | 318 | void 319 | UdpLoopBack::run() 320 | { 321 | int got, pld; 322 | struct sockaddr sa; 323 | socklen_t sl; 324 | 325 | while ( 1 ) { 326 | sl = sizeof(sa); 327 | if ( (got = recvfrom( sock_.getSd(), &rbuf_[0], rbuf_.capacity(), 0, &sa, &sl )) < 0 ) { 328 | throw SysErr("UdpLoopBack: unable to read from socket!"); 329 | } 330 | if ( got < 4 ) { 331 | throw ProtoErr("UdpLoopBack: got no header!"); 332 | } 333 | if ( drEn_ && ( (++drop_ & 0xff) == 0 ) ) { 334 | fprintf(stderr, "Drop\n"); 335 | continue; 336 | } 337 | pld = xfer( &rbuf_[0], got, &tbuf_[0], 4, &tbuf_[4], tbuf_.capacity() - 4 ); 338 | if ( sendto( sock_.getSd(), &tbuf_[0], pld + 4, 0, &sa, sl ) < 0 ) { 339 | throw SysErr("UdpLoopBack: unable to send from socket"); 340 | } 341 | } 342 | } 343 | 344 | static DriverRegistrar r("loopback"); 345 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvLoopBack.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef JTAG_DRIVER_LOOP_BACK_H 18 | #define JTAG_DRIVER_LOOP_BACK_H 19 | 20 | #include 21 | 22 | // The loopback driver is used for testing; it loops TDI back to TDO; 23 | // Optionally, it can be initialized with a file-name. 24 | // The file is expected to contain text describing JTAG vectors of the format 25 | // file: record {, record} 26 | // record: bitlen_line, tms_line, tdi_line, tdo_line {, tms_line, tdi_line, tdo_line } 27 | // 28 | // bitlen_line: "LENBITS: ", number_in_ascii 29 | // tms_line : "TMS : ", 32bit_hexnum_in_ascii 30 | // tdi_line : "TDI : ", 32bit_hexnum_in_ascii 31 | // tdo_line : "TDO : ", 32bit_hexnum_in_ascii 32 | // 33 | class JtagDriverLoopBack : public JtagDriverAxisToJtag { 34 | private: 35 | FILE *f_; 36 | bool skip_; 37 | bool tdoOnly_; 38 | unsigned long line_; 39 | public: 40 | 41 | JtagDriverLoopBack(int argc, char *const argv[], const char *fnam = 0); 42 | 43 | virtual ~JtagDriverLoopBack(); 44 | 45 | virtual unsigned emulWordSize(); 46 | virtual unsigned emulMemDepth(); 47 | 48 | virtual bool rdl(char *buf, size_t bufsz); 49 | 50 | virtual unsigned long check(unsigned long val, const char *fmt, bool rdOnly = false); 51 | 52 | virtual void checkTDI(unsigned long val); 53 | 54 | virtual void checkTMS(unsigned long val); 55 | 56 | virtual void checkLEN(unsigned long val); 57 | 58 | virtual unsigned long getTDO(); 59 | 60 | virtual unsigned long getValLE(uint8_t *buf, unsigned wsz); 61 | 62 | virtual void setValLE(unsigned long val, uint8_t *buf, unsigned wsz); 63 | 64 | virtual unsigned long 65 | getMaxVectorSize(); 66 | 67 | // main transfer method 68 | virtual int 69 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 70 | }; 71 | 72 | // mimick the 'far' end of UDP, i.e., a FW server 73 | class UdpLoopBack : public JtagDriverLoopBack { 74 | private: 75 | SockSd sock_; 76 | vector rbuf_; 77 | vector tbuf_; 78 | int tsiz_; 79 | 80 | public: 81 | UdpLoopBack( const char *fnam, unsigned port = 2543 ); 82 | 83 | virtual int 84 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 85 | 86 | virtual unsigned 87 | emulMemDepth(); 88 | 89 | void run(); 90 | 91 | virtual ~UdpLoopBack(); 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvSerDesTmem.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Company : PSI 3 | //----------------------------------------------------------------------------- 4 | // Description: Driver for raw register-mapped JtagSerDes (w/o fifo; for debugging) 5 | //----------------------------------------------------------------------------- 6 | 7 | #ifndef JTAG_DRIVER_SERDES_TMEM_H 8 | #define JTAG_DRIVER_SERDES_TMEM_H 9 | 10 | #include 11 | #include 12 | 13 | class JtagDriverSerDesTmem : public JtagDriverAxisToJtag { 14 | 15 | private: 16 | static const int FIFO_DAT_IDX = 0; 17 | static const int FIFO_MAGIC_IDX = 1; 18 | static const int FIFO_CSR_IDX = 2; 19 | static const int SDES_TMS_IDX = 4; 20 | static const int SDES_TDI_IDX = 5; 21 | static const int SDES_CSR_IDX = 6; 22 | static const int SDES_TDO_IDX = 7; 23 | 24 | static const uint32_t FIFO_CSR_VERSM = 0xf0000000; 25 | static const uint32_t FIFO_CSR_VERSS = 28; 26 | 27 | static const uint32_t SUPPORTED_VERS = 0; 28 | static const uint32_t MAGIC = 0x6666aaaa; 29 | 30 | 31 | static const uint32_t SDES_CSR_RUN = 0x00000100; 32 | static const uint32_t SDES_CSR_BSY = 0x00000200; 33 | static const uint32_t SDES_CSR_LENS = 0; 34 | 35 | static const uint32_t SDES_CSR_LRMSK = 0x00000fff; 36 | static const uint32_t SDES_CSR_BBMSK = 0x000f0000; 37 | 38 | static const uint32_t SDES_CSR_BB_TCK = 0x00010000; 39 | static const uint32_t SDES_CSR_BB_TMS = 0x00020000; 40 | static const uint32_t SDES_CSR_BB_TDI = 0x00040000; 41 | static const uint32_t SDES_CSR_BB_TDO = 0x00080000; 42 | static const uint32_t SDES_CSR_BB_ENA = 0x80000000; 43 | 44 | unsigned long maxVec_; 45 | unsigned wrdSiz_; 46 | 47 | unsigned toscaSpace_; 48 | unsigned long toscaBase_; 49 | bool bitBang_; 50 | unsigned debug_; 51 | 52 | static const unsigned long MIN_SLEEP_NS = 20UL*1000UL*1000UL; 53 | struct timespec pollTime_; 54 | bool doSleep_; 55 | unsigned measure_; 56 | unsigned long maxPollDelayUs_; 57 | 58 | public: 59 | 60 | // I/O 61 | virtual void o32(unsigned idx, uint32_t v); 62 | virtual uint32_t i32(unsigned idx); 63 | 64 | virtual void reset(); 65 | 66 | virtual void wait(); 67 | 68 | JtagDriverSerDesTmem(int argc, char *const argv[], const char *devnam); 69 | virtual void 70 | init(); 71 | 72 | virtual unsigned long 73 | getMaxVectorSize(); 74 | 75 | virtual int 76 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 77 | 78 | virtual uint32_t 79 | xfer32bb(uint32_t tms, uint32_t tdi, unsigned nbits); 80 | 81 | virtual void 82 | bbsleep(); 83 | 84 | virtual uint32_t 85 | xfer32sdes(uint32_t tms, uint32_t tdi, unsigned nbits, struct timespec *); 86 | 87 | virtual ~JtagDriverSerDesTmem(); 88 | 89 | static void usage(); 90 | }; 91 | 92 | extern "C" JtagDriver *drvCreate(const char *target); 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvUdp.cc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | static const char *DFLT_PORT="2542"; 24 | 25 | static const unsigned MAXL = 256; 26 | 27 | JtagDriverUdp::JtagDriverUdp(int argc, char *const argv[], const char *target) 28 | : JtagDriverAxisToJtag( argc, argv ), 29 | sock_ ( false ), 30 | timeoutMs_ ( 500 ), 31 | mtu_ ( 1450 ) // ethernet mtu minus MAC/IP/UDP addresses 32 | { 33 | struct addrinfo hint, *res; 34 | const char *col, *prtnam; 35 | char buf[MAXL]; 36 | unsigned l; 37 | int stat, opt; 38 | unsigned mtu; 39 | unsigned *i_p; 40 | socklen_t slen; 41 | bool userMtu = false; 42 | bool frag = false; 43 | 44 | while ( (opt = getopt(argc, argv, "m:f")) > 0 ) { 45 | 46 | i_p = 0; 47 | 48 | switch ( opt ) { 49 | case 'm': 50 | i_p = &mtu_; 51 | userMtu = true; 52 | break; 53 | 54 | case 'f': 55 | frag = true; 56 | break; 57 | 58 | default: 59 | fprintf(stderr,"Unknown driver option -%c\n", opt); 60 | throw std::runtime_error("Unknown driver option"); 61 | } 62 | 63 | if ( i_p ) { 64 | if ( 1 != sscanf(optarg,"%i", i_p) ) { 65 | fprintf(stderr,"Unable to scan argument to option -%c\n", opt); 66 | throw std::runtime_error("Unable to scan option argument"); 67 | } 68 | } 69 | } 70 | 71 | if ( (col = strchr(target, ':')) ) { 72 | 73 | l = col - target; 74 | 75 | if ( l+1 > sizeof(buf) ) { 76 | snprintf(buf, sizeof(buf), "Internal error - not supporting target string lengths > %d", MAXL); 77 | throw std::runtime_error( buf ); 78 | } 79 | 80 | strncpy(buf, target, l); 81 | buf[l] = 0; 82 | 83 | target = buf; 84 | prtnam = col + 1; 85 | 86 | } else { 87 | prtnam = DFLT_PORT; 88 | } 89 | 90 | hint.ai_family = AF_INET; 91 | hint.ai_socktype = SOCK_DGRAM; 92 | hint.ai_protocol = IPPROTO_UDP; 93 | hint.ai_flags = AI_NUMERICSERV; 94 | 95 | if ( ( stat = getaddrinfo( target, prtnam, &hint, &res ) ) ) { 96 | // doesn't use errno 97 | snprintf(buf, sizeof(buf), "getaddrinfo for '%s' failed: %s", target, gai_strerror( stat ) ); 98 | throw std::runtime_error( buf ); 99 | } else { 100 | stat = connect( sock_.getSd(), res->ai_addr, res->ai_addrlen ); 101 | freeaddrinfo( res ); 102 | 103 | if ( stat ) { 104 | throw SysErr("Unable to connect UDP socket"); 105 | } 106 | } 107 | 108 | // find current MTU 109 | slen = sizeof(mtu); 110 | stat = getsockopt( sock_.getSd(), IPPROTO_IP, IP_MTU, &mtu, &slen ); 111 | if ( stat ) { 112 | fprintf(stderr,"Warning: Unable to estimate MTU (getsockopt(IP_MTU) failed: %s) -- using %d\n", strerror(errno), mtu_); 113 | } else { 114 | if ( mtu < mtu_ ) { 115 | fprintf(stderr,"Warning: requested MTU limit (%d) > IP_MTU; clipping to %d octets\n", mtu_, mtu); 116 | mtu_ = mtu; 117 | } else if ( ! userMtu ) { 118 | // allow MTU to be increased only if not defined by the user 119 | mtu_ = mtu; 120 | } 121 | } 122 | 123 | if ( ! frag ) { 124 | opt = IP_PMTUDISC_DO; // this forces the DF (dont-fragment) flag 125 | stat = setsockopt( sock_.getSd(), IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt) ); 126 | if ( stat ) { 127 | throw SysErr("Unable to set IP_MTU_DISCOVER to IP_PMTUDISC_DO (enforce DF)"); 128 | } 129 | } 130 | 131 | poll_[0].fd = sock_.getSd(); 132 | poll_[0].events = POLLIN; 133 | } 134 | 135 | JtagDriverUdp::~JtagDriverUdp() 136 | { 137 | } 138 | 139 | 140 | void 141 | JtagDriverUdp::init() 142 | { 143 | JtagDriverAxisToJtag::init(); 144 | if ( getMemDepth() == 0 ) { 145 | fprintf(stderr,"WARNING: target does not appear to have memory support.\n"); 146 | fprintf(stderr," Reliable communication impossible!\n"); 147 | } 148 | } 149 | 150 | unsigned long 151 | JtagDriverUdp::getMaxVectorSize() 152 | { 153 | // MTU lim; 2*vector size + header must fit! 154 | unsigned long mtuLim = (mtu_ - getWordSize()) / 2; 155 | 156 | return mtuLim; 157 | } 158 | 159 | int 160 | JtagDriverUdp::xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ) 161 | { 162 | int got; 163 | 164 | if ( write( poll_[0].fd, txb, txBytes ) < 0 ) { 165 | if ( EMSGSIZE == errno ) { 166 | fprintf(stderr, "UDP message size too large; would require fragmentation!\n"); 167 | fprintf(stderr, "Try to reduce using the driver option -- -m .\n"); 168 | } 169 | throw SysErr("JtagDriverUdp: unable to send"); 170 | } 171 | 172 | poll_[0].revents = 0; 173 | 174 | got = poll( poll_, sizeof(poll_)/sizeof(poll_[0]), timeoutMs_ /* ms */ ); 175 | 176 | if ( got < 0 ) { 177 | throw SysErr("JtagDriverUdp: poll failed"); 178 | } 179 | 180 | if ( got == 0 ) { 181 | throw TimeoutErr(); 182 | } 183 | 184 | if ( poll_[0].revents & (POLLERR | POLLNVAL) ) { 185 | throw std::runtime_error("JtagDriverUdp -- internal error; poll has POLLERR or POLLNVAL set"); 186 | } 187 | 188 | if ( ! (poll_[0].revents & POLLIN) ) { 189 | throw std::runtime_error("JtagDriverUdp -- poll with no data?"); 190 | } 191 | 192 | 193 | iovs_[0].iov_base = hdbuf; 194 | iovs_[0].iov_len = hsize; 195 | iovs_[1].iov_base = rxb; 196 | iovs_[1].iov_len = size; 197 | 198 | got = readv( poll_[0].fd, iovs_, sizeof(iovs_)/sizeof(iovs_[0]) ); 199 | 200 | if ( debug_ > 1 ) { 201 | fprintf(stderr, "HSIZE %d, SIZE %d, got %d\n", hsize ,size, got ); 202 | } 203 | 204 | if ( got < 0 ) { 205 | throw SysErr("JtagDriverUdp -- recvmsg failed"); 206 | } 207 | 208 | got -= hsize; 209 | 210 | if ( got < 0 ) { 211 | throw ProtoErr("JtagDriverUdp -- not enough header data received"); 212 | } 213 | 214 | return got; 215 | } 216 | 217 | void 218 | JtagDriverUdp::usage() 219 | { 220 | printf(" UDP Driver options: [-m ]\n"); 221 | printf(" -m : Set MTU limit for UDP datagrams (must not be fragmented!)\n"); 222 | printf(" -f : Enable IP fragmentation - note that FW does probably not support this!\n"); 223 | } 224 | 225 | static DriverRegistrar r("udp"); 226 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcDrvUdp.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef JTAG_DRIVER_UDP_H 18 | #define JTAG_DRIVER_UDP_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | class JtagDriverUdp : public JtagDriverAxisToJtag { 25 | private: 26 | SockSd sock_; 27 | 28 | struct pollfd poll_[1]; 29 | 30 | int timeoutMs_; 31 | 32 | struct msghdr msgh_; 33 | struct iovec iovs_[2]; 34 | 35 | unsigned mtu_; 36 | public: 37 | 38 | JtagDriverUdp(int argc, char *const argv[], const char *target); 39 | 40 | virtual void 41 | init(); 42 | 43 | virtual unsigned long 44 | getMaxVectorSize(); 45 | 46 | virtual int 47 | xfer( uint8_t *txb, unsigned txBytes, uint8_t *hdbuf, unsigned hsize, uint8_t *rxb, unsigned size ); 48 | 49 | virtual ~JtagDriverUdp(); 50 | 51 | static void usage(); 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /xvcSrv/src/xvcSrv.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Title : JTAG Support 3 | //----------------------------------------------------------------------------- 4 | // Company : SLAC National Accelerator Laboratory 5 | //----------------------------------------------------------------------------- 6 | // Description: 7 | //----------------------------------------------------------------------------- 8 | // This file is part of 'SLAC Firmware Standard Library'. 9 | // It is subject to the license terms in the LICENSE.txt file found in the 10 | // top-level directory of this distribution and at: 11 | // https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | // No part of 'SLAC Firmware Standard Library', including this file, 13 | // may be copied, modified, propagated, or distributed except according to 14 | // the terms contained in the LICENSE.txt file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef XVC_SRV_H 18 | #define XVC_SRV_H 19 | 20 | #include 21 | 22 | // XVC Server (top) class 23 | class XvcServer { 24 | private: 25 | SockSd sock_; 26 | JtagDriver *drv_; 27 | unsigned debug_; 28 | unsigned maxMsgSize_; 29 | bool once_; 30 | 31 | public: 32 | XvcServer( 33 | uint16_t port, 34 | JtagDriver *drv, 35 | unsigned debug=0, 36 | unsigned maxMsgSize = 32768, 37 | bool once = false 38 | ); 39 | 40 | virtual void run(); 41 | 42 | virtual ~XvcServer() 43 | { 44 | }; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /xvcSrv/test/Makefile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Title : JTAG Support 3 | #----------------------------------------------------------------------------- 4 | # Company : SLAC National Accelerator Laboratory 5 | #----------------------------------------------------------------------------- 6 | # Description: 7 | #----------------------------------------------------------------------------- 8 | # This file is part of 'SLAC Firmware Standard Library'. 9 | # It is subject to the license terms in the LICENSE.txt file found in the 10 | # top-level directory of this distribution and at: 11 | # https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 12 | # No part of 'SLAC Firmware Standard Library', including this file, 13 | # may be copied, modified, propagated, or distributed except according to 14 | # the terms contained in the LICENSE.txt file. 15 | #----------------------------------------------------------------------------- 16 | 17 | all: test 18 | 19 | testDataTdoOnly.txt: testData.txt 20 | $(RM) $@ 21 | grep TDO $^ > $@ 22 | 23 | clean: 24 | $(RM) testDataTdoOnly.txt 25 | 26 | test: ../src/xvcSrv test.py testDataTdoOnly.txt 27 | sh -c "(../src/xvcSrv -D udpLoopback -o -t testDataTdoOnly.txt & sleep 1 ; python3 test.py -k)" 28 | 29 | ../src/xvcSrv: 30 | @$(error "You need to build the xvcSrv executable in the ../src/ directory first!") 31 | -------------------------------------------------------------------------------- /xvcSrv/test/makefile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Title : JTAG Support 3 | #----------------------------------------------------------------------------- 4 | # File : makefile 5 | # Author : Till Straumann 6 | # Company : SLAC National Accelerator Laboratory 7 | # Created : 2017-12-05 8 | # Last update: 2017-12-05 9 | # Platform : 10 | # Standard : VHDL'93/02 11 | #----------------------------------------------------------------------------- 12 | # Description: 13 | #----------------------------------------------------------------------------- 14 | # This file is part of 'SLAC Firmware Standard Library'. 15 | # It is subject to the license terms in the LICENSE.txt file found in the 16 | # top-level directory of this distribution and at: 17 | # https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 18 | # No part of 'SLAC Firmware Standard Library', including this file, 19 | # may be copied, modified, propagated, or distributed except according to 20 | # the terms contained in the LICENSE.txt file. 21 | #----------------------------------------------------------------------------- 22 | 23 | all: test 24 | 25 | testDataTdoOnly.txt: testData.txt 26 | $(RM) $@ 27 | grep TDO $^ > $@ 28 | 29 | clean: 30 | $(RM) testDataTdoOnly.txt 31 | 32 | test: ../src/xvcSrv test.py testDataTdoOnly.txt 33 | sh -c "(../src/xvcSrv -D udpLoopback -o -t testDataTdoOnly.txt & sleep 1 ; python3 test.py -k)" 34 | 35 | ../src/xvcSrv: 36 | @$(error "You need to build the xvcSrv executable in the ../src/ directory first!") 37 | -------------------------------------------------------------------------------- /xvcSrv/test/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | #----------------------------------------------------------------------------- 3 | # This file is part of 'SLAC Firmware Standard Library'. 4 | # It is subject to the license terms in the LICENSE.txt file found in the 5 | # top-level directory of this distribution and at: 6 | # https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 7 | # No part of 'SLAC Firmware Standard Library', including this file, 8 | # may be copied, modified, propagated, or distributed except according to 9 | # the terms contained in the LICENSE.txt file. 10 | #----------------------------------------------------------------------------- 11 | 12 | # Test driver. See 'makefile' for how this is normally invoked 13 | 14 | import re 15 | import io 16 | import sys 17 | import os 18 | import array 19 | import getopt 20 | from socket import *; 21 | 22 | def query(): 23 | with socket(AF_INET,SOCK_STREAM) as sd: 24 | sd.connect(("localhost",2542)) 25 | sd.send(bytearray('getinfo:','ascii')) 26 | return sd.recv(1000) 27 | 28 | 29 | def ser(a, wrds, byts): 30 | for w in wrds: 31 | if byts > 4: 32 | n = 4 33 | else: 34 | n = byts 35 | for i in range(0,n): 36 | a.append( w % 256 ) 37 | w = int(w / 256) 38 | byts = byts - 4 39 | 40 | def mkvecs(f): 41 | patt = re.compile('^(r[[]4]:=)(.*)$',re.MULTILINE) 42 | with io.open(f,'r') as fd: 43 | fnd = patt.findall( fd.read(1000) ) 44 | bits = (int(fnd[0][1],16) % 0x100000) + 1; 45 | byts = int((bits + 7)/8) 46 | wrds = [ int(x[1],16) for x in fnd[1:] ] 47 | vec = bytearray() 48 | ser(vec, [bits], 4) 49 | ser(vec, wrds[0::2], byts) 50 | ser(vec, wrds[1::2], byts) 51 | return vec 52 | 53 | def sendfil(f): 54 | vecs = mkvecs(f) 55 | with socket(AF_INET,SOCK_STREAM) as sd: 56 | sd.connect(("localhost",2542)) 57 | sd.send(bytearray('shift:','ascii')) 58 | sd.send(vecs) 59 | return sd.recv(1000) 60 | 61 | def playfile(f): 62 | with socket(AF_INET,SOCK_STREAM) as sd: 63 | with io.open(f,'r') as rd: 64 | sd.connect(("localhost",2542)) 65 | lenbits = re.compile("(^LENBITS:[ ]*)([0-9]+)[ ]*$") 66 | tdi = re.compile("(^TDI[ ]*[:][ ]*)([^ ]+)[ ]*$") 67 | tms = re.compile("(^TMS[ ]*[:][ ]*)([^ ]+)[ ]*$") 68 | tdo = re.compile("(^TDO[ ]*[:][ ]*)([^ ]+)[ ]*$") 69 | m = None 70 | while True: 71 | while None == m: 72 | l = rd.readline() 73 | if l == None or len(l) == 0: 74 | print("EOF -- Test PASSED") 75 | return; 76 | print("checking: ", l) 77 | m = lenbits.match(l) 78 | print("Got {} bits".format( m.group(2) )) 79 | bits = int(m.group(2)) 80 | byts = int((bits + 7)/8) 81 | wrds = int((byts + 3)/4) 82 | arri = list() 83 | for i in range(0,wrds): 84 | l = rd.readline() 85 | if None == l: 86 | raise RuntimeError("Premature EOF") 87 | m = tms.match(l) 88 | if None == m: 89 | print(l) 90 | raise RuntimeError("EXPECTED TMS") 91 | arri.append( int( m.group(2), 16 ) ) 92 | l = rd.readline() 93 | if None == l: 94 | raise RuntimeError("Premature EOF") 95 | m = tdi.match(l) 96 | if None == m: 97 | raise RuntimeError("EXPECTED TDI") 98 | arri.append( int( m.group(2), 16 ) ) 99 | arro = list() 100 | for i in range(0,wrds): 101 | l = rd.readline() 102 | if None == l: 103 | raise RuntimeError("Premature EOF") 104 | m = tdo.match(l) 105 | if None == m: 106 | print(l) 107 | raise RuntimeError("EXPECTED TMS") 108 | arro.append( int( m.group(2), 16 ) ) 109 | vec=bytearray() 110 | ser(vec, [bits], 4) 111 | ser(vec, arri[0::2], byts) 112 | ser(vec, arri[1::2], byts) 113 | sd.send(bytearray('shift:','ascii')) 114 | sd.send(vec) 115 | tmp=bytearray() 116 | ser(tmp, arro, byts) 117 | got=sd.recv(2000) 118 | if ( got != tmp ): 119 | if (len(got) != len(tmp)): 120 | print("Length mismatch: got {} exp {}".format(len(got), len(tmp))) 121 | raise RuntimeError("TDO MISMATCH") 122 | m = None 123 | 124 | 125 | if __name__ == "__main__": 126 | (opts, args) = getopt.getopt(sys.argv[1:], "k") 127 | dokill = False 128 | for (o, a) in opts: 129 | if o == '-k': 130 | dokill = True; 131 | try: 132 | playfile('testData.txt') 133 | except: 134 | if dokill: 135 | os.kill( os.getpgid(0), 15 ) 136 | raise 137 | --------------------------------------------------------------------------------