/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: JtagTesterModel.java * Written by Jonathan Gainsley, Sun Microsystems. * * Copyright (c) 2007 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.simulation.test; import java.util.Random; public class JtagTesterModel extends BypassJtagTester { private final String tck; private final String tms; private final String trstb; private final String tdi; private final String tdob; // IR instructions private static final String SHIFT_IR = "1100"; private static final String SHIFT_DR = "100"; private static final String CAPTURE_DR = "10"; private static final String IDLE = "110"; private static final boolean DEBUG = true; JtagTesterModel(SimulationModel nm, String tck, String tms, String trstb, String tdi, String tdob) { super(nm); this.tck = tck; this.tms = tms; this.trstb = trstb; this.tdi = tdi; this.tdob = tdob; configure((float)nm.getVdd(), 100000); // 100MHz } public void reset() { if (model.isBypassScanning()) { // just leave the controller in reset mode model.setNodeState(trstb, 0); model.setNodeState(tck, 0); model.setNodeState(tms, 1); model.setNodeState(tdi, 0); model.waitNS(delay); } else { // set the controller in reset state model.setNodeState(trstb, 0); model.setNodeState(tck, 0); model.setNodeState(tms, 1); model.setNodeState(tdi, 0); model.waitNS(delay); // set the controller in idle state model.setNodeState(trstb, 1); model.setNodeState(tms, 0); cycle_tck(1); } if (DEBUG) System.out.println("Finished resetting JtagTester"); } public void tms_reset() { reset(); } void shift(ChainNode chain, boolean readEnable, boolean writeEnable, int irBadSeverity) { if (isBypassScanning()) { doBypassScanning(chain, readEnable, writeEnable); return; } // create the instruction String instruction = NetscanGeneric.getInstructionRegister(chain, readEnable, writeEnable); task_load_instruction(instruction); // Add an extra bit for any jtag controller in bypass mode MyTreeNode root = chain.getParentChip().getParent(); int numPrebits = 0; int numPostbits = 0; boolean foundChain = false; for (int i=0; i<root.getChildCount(); i++) { MyTreeNode child = root.getChildAt(i); if (child instanceof ChipNode) { ChipNode chip = (ChipNode)child; if (chip == chain.getParentChip()) { foundChain = true; continue; } if (foundChain) numPostbits++; else numPrebits++; } } // Construct, and optionally report, the bit sequence to write BitVector scanInBits = NetscanGeneric.padBitVector(chain.getInBits(), numPrebits, numPostbits); // get data to send. String inbits = scanInBits.getState(); String outbits = task_scan_data(inbits); // remove extra bits from scanned out data BitVector scanOutBits = new BitVector(outbits.substring(numPrebits, outbits.length()-numPostbits), "outbits"); // invert if specified to account for inverting output if (isScanOutInverted()) { scanOutBits.flip(0, scanOutBits.getNumBits()); } chain.getOutBits().put(0, scanOutBits); if (writeEnable) { // check that data was written correctly BitVector bitsToCheck = new BitVector(chain.getInBits().getNumBits(), "bitsToCheck"); bitsToCheck.set(0, chain.getInBits().getNumBits(), true); checkDataNets(chain, 0, bitsToCheck); checkDataNets(chain, 1, bitsToCheck); } } // ================================================================ private void cycle_tck(int times) { for (int i=0; i<times; i++) { model.waitNS(delay); model.setNodeState(tck, 1); model.waitNS(delay); model.setNodeState(tck, 0); } } // Steer the tap controller to the specified state private void task_goto(String IR) { int [] arr = stringToIntArray(IR); for (int i=0; i<arr.length; i++) { model.setNodeState(tms, arr[i]); model.waitNS(1); cycle_tck(1); } } // Steers the tap controller to the specified state, // but retrieves the last bit of scanned out data private int task_goto_send_tdo(String IR) { int [] arr = stringToIntArray(IR); boolean sendLastBit = true; int out = -1; for (int i=0; i<arr.length; i++) { model.setNodeState(tms, arr[i]); if (sendLastBit) { sendLastBit = false; model.waitNS(delay+1); model.setNodeState(tck, 1); out = model.getNodeState(tdob); model.waitNS(delay); model.setNodeState(tck, 0); } else { model.waitNS(1); cycle_tck(1); } } return out; } // forces tap controller to idle state regardless of current state private void task_go_idle() { model.setNodeState(tms, 1); cycle_tck(5); model.setNodeState(tms, 0); cycle_tck(1); } void task_load_instruction(String opcode) { // Note that we scan in from the end of the string to the front of the string int [] arr = stringToIntArray(reverse(opcode)); System.out.print(" Loading instruction "+opcode+"."); System.out.flush(); task_goto(SHIFT_IR); model.setNodeState(tdi, arr[0]); System.out.print("."); System.out.flush(); for (int i=1; i<arr.length; i++) { cycle_tck(1); model.setNodeState(tdi, arr[i]); System.out.print("."); System.out.flush(); } task_goto(IDLE); System.out.println("...done."); } // scan data in and scan data out. Note that data scanned in // starts with the end of the string, not the beginning, and // so some reversal is necessary String task_scan_data(String data) { task_goto(SHIFT_DR); // Note that we scan in from the end of the string to the front of the string data = reverse(data); int [] arr = stringToIntArray(data); StringBuffer buf = new StringBuffer(); System.out.println(" Scanning in (reversed): "+data); System.out.print (" Scanning out (reversed): "); int i; for (i=0; i<arr.length-1; i++) { model.setNodeState(tdi, arr[i]); model.waitNS(0.5*delay); model.setNodeState(tck, 1); model.waitNS(0.5*delay); int n = model.getNodeState(tdob); String s = String.valueOf(n); if (n < 0) s = "X"; buf.append(s); System.out.print(s); System.out.flush(); model.waitNS(0.5*delay); model.setNodeState(tck, 0); model.waitNS(0.5*delay); } // scan in last bit model.setNodeState(tdi, arr[arr.length-1]); model.waitNS(delay); int ret = task_goto_send_tdo(IDLE); String s = String.valueOf(ret); if (ret < 0) s = "X"; buf.append(s); System.out.println(s+"...done"); System.out.flush(); String outbits = reverse(buf.toString()); outbits = outbits.replace('X', '0'); return outbits; } // =================================================================== private static String reverse(String str) { StringBuffer buf = new StringBuffer(); for (int i=str.length()-1; i>=0; i--) { buf.append(str.charAt(i)); } //System.out.println("Reversed: "+str+" --> "+buf.toString()); return buf.toString(); } private static int [] stringToIntArray(String str) { int [] arr = new int[str.length()]; for (int i=0; i<str.length(); i++) { if (str.charAt(i) == '1') arr[i] = 1; else if (str.charAt(i) == '0') arr[i] = 0; else { System.out.println("Warning: Unknown char in string, setting to 0: "+str.charAt(i)); arr[i] = 0; } } return arr; } /** Unit Test * This test requires the file loco_core.hsp in your working dir * */ public static void main(String args[]) { NanosimModel nm = new NanosimModel(); JtagTesterModel tester = (JtagTesterModel)nm.createJtagTester("TCK", "TMS", "TRSTb", "TDI", "TDOb"); nm.start("nanosim", "loco_core.hsp", 0); // test private methods separately tester.task_load_instruction("11000101"); tester.task_scan_data("1000100010001111"); //tester.task_go_idle(); tester.task_load_instruction("11001100"); tester.task_scan_data("100010001000111101011100011"); tester.task_scan_data("100010001000111101011100011"); tester.task_scan_data("100010001000111101011100011"); tester.task_scan_data("100010001000111101011100011"); // test public methods which use private methods if (true) { ChipNode cn = new ChipNode("test", 8, "none"); ChainNode testNode = new ChainNode("testNode", "1001", 156, "node for unit test"); cn.addChild(testNode); Random rand = new Random(309402934); for (int i=0; i<testNode.getInBits().getNumBits(); i++) { testNode.getInBits().set(i, rand.nextBoolean()); } System.out.println("Note that data shifted out is inverted sense of data shifted in,"); System.out.println(" unless it goes through one of our inverting output pads first."); System.out.println("Unit Test: Shifting in: "+testNode.getInBits().getState()); tester.shift(testNode, true, true, 0); System.out.println("Unit Test: Shifted out: "+testNode.getOutBits().getState()); // We sent to a chain that had no elements, so scan in == scan out. boolean match = true; for (int i=0; i<testNode.getInBits().getNumBits(); i++) { if (testNode.getInBits().get(i) != !testNode.getOutBits().get(i)) { match = false; break; } } if (!match) { System.out.println("Unit Test Error: scan data in should match scan data out when chain is looped back."); } else { System.out.println("Unit Test OK."); } } tester.model.finish(); } }