From 79f6144deddfc770b40ecedc6f3957ec2a3c342e Mon Sep 17 00:00:00 2001 From: Neel Date: Sat, 21 Jul 2018 16:13:49 +0530 Subject: [PATCH] add jtag interface --- src/bsv/bsv_lib/jtagdefines.bsv | 19 ++ src/bsv/bsv_lib/jtagdtm_new.bsv | 337 ++++++++++++++++++++++++++++++++ 2 files changed, 356 insertions(+) create mode 100644 src/bsv/bsv_lib/jtagdefines.bsv create mode 100644 src/bsv/bsv_lib/jtagdtm_new.bsv diff --git a/src/bsv/bsv_lib/jtagdefines.bsv b/src/bsv/bsv_lib/jtagdefines.bsv new file mode 100644 index 0000000..83b1daf --- /dev/null +++ b/src/bsv/bsv_lib/jtagdefines.bsv @@ -0,0 +1,19 @@ +`define EXTEST 'h00 +`define IDCODE 'h01 +`define SAMPLE_PRELOAD 'h02 +`define SCANMODE_TE 'h03 +`define SCAN1 'h04 +`define SCAN2 'h05 +`define SCAN3 'h06 +`define SCAN4 'h07 +`define SCAN5 'h08 +`define SCANALL 'h12 +`define SCANEN 'h13 +`define FULLSCANEN 'h14 +`define DEBUG 'h0A +`define MBIST 'h09 +`define BYPASS 'h1f +`define DTMCONTROL 'h10 +`define DMIACCESS 'h11 +//`define IDCODEVALUE 32'h10e31913 +`define IDCODEVALUE 32'h100039D3 diff --git a/src/bsv/bsv_lib/jtagdtm_new.bsv b/src/bsv/bsv_lib/jtagdtm_new.bsv new file mode 100644 index 0000000..ae22304 --- /dev/null +++ b/src/bsv/bsv_lib/jtagdtm_new.bsv @@ -0,0 +1,337 @@ +/* +Copyright (c) 2013, IIT Madras +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +*/ +package jtagdtm_new; +/*====== Package imports ======= */ + import ConcatReg::*; + import FIFO::*; + import FIFOF::*; + import SpecialFIFOs::*; +/*======= Project imports ===== */ + `include "jtagdefines.bsv" + import defined_types::*; +/*============================== */ + +interface Ifc_jtagdtm; + /*======== JTAG input pins ===== */ + (*always_enabled,always_ready*) + method Action tms_i(Bit#(1) tms); + (*always_enabled,always_ready*) + method Action tdi_i(Bit#(1) tdi); + (*always_enabled,always_ready*) + method Action tck_i(Bit#(1) tck); + (*always_enabled,always_ready*) + method Action trst_i(Bit#(1) trst); + /*==== inputs from Sub-modules === */ + method Action debug_tdi_i(Bit#(1) debug_tdi); + method Action bs_chain_i(Bit#(1) bs_chain); + /*======= JTAG Output Pins ====== */ + (*always_enabled,always_ready*) + method Bit#(1) tdo; + method Bit#(1) tdo_oe; + /*======== TAP States ============= */ + method Bit#(1) shift_dr; + method Bit#(1) pause_dr; + method Bit#(1) update_dr; + method Bit#(1) capture_dr; + /*=========== Output for BS Chain ==== */ + method Bit#(1) extest_select; + method Bit#(1) sample_preload_select; + method Bit#(1) debug_select; + method Bit#(1) debug_tdo; + /*================================ */ + method Action response_from_dm(Bit#(34) responsedm); + method ActionValue#(Bit#(40)) request_to_dm; + +endinterface + + function Reg#(t) readOnlyReg(t r); + return (interface Reg; + method t _read = r; + method Action _write(t x) = noAction; + endinterface); + endfunction + function Reg#(Bit#(1)) condwriteSideEffect(Reg#(Bit#(1)) r, Action a); + return (interface Reg; + method Bit#(1) _read = r._read; + method Action _write(Bit#(1) x); + r._write(x); + if(x==1) + a; + endmethod + endinterface); + endfunction + + + +typedef enum {TestLogicReset = 4'h0, RunTestIdle = 4'h1, SelectDRScan = 4'h2, + CaptureDR = 4'h3, ShiftDR = 4'h4, Exit1DR = 4'h5, + PauseDR = 4'h6, Exit2DR = 4'h7, UpdateDR = 4'h8, + SelectIRScan = 4'h9, CaptureIR = 4'ha, ShiftIR = 4'hb, + Exit1IR = 4'hc, PauseIR = 4'hd, Exit2IR = 4'he, + UpdateIR = 4'hf } TapStates deriving(Bits,Eq,FShow); + + (*synthesize*) + module mkjtagdtm(Ifc_jtagdtm); + Reg#(Bit#(1)) prv_clk <-mkReg(0); + PulseWire posedge_clk <-mkPulseWire(); + PulseWire negedge_clk <-mkPulseWire(); + /*========= FIFOs to communicate with the DM==== */ + FIFOF#(Bit#(40)) request_to_DM <-mkUGFIFOF1(); + FIFOF#(Bit#(34)) response_from_DM <-mkUGFIFOF1(); + /*================================================ */ + + /*=== Wires to capture the input pins === */ + Wire#(Bit#(1)) wr_tms<-mkDWire(0); + Wire#(Bit#(1)) wr_tdi<-mkDWire(0); + Wire#(Bool) wr_trst<-mkDWire(False); + Wire#(Bit#(1)) wr_debug_tdi<-mkDWire(0); + Wire#(Bit#(1)) wr_bs_chain_tdi<-mkDWire(0); + /*======================================== */ + + Reg#(TapStates) tapstate<-mkRegA(TestLogicReset); + Reg#(Bit#(5)) instruction_shiftreg<-mkRegA(0); + Reg#(Bit#(5)) instruction<-mkRegA(`IDCODE); // clock this by the inverted clock + Reg#(Bit#(1)) bypass_sr<-mkRegA(0); + Reg#(Bit#(32)) idcode_sr<-mkRegA(`IDCODEVALUE); + + Wire#(Bool) wr_dmihardreset_generated<-mkDWire(False); + Reg#(Bit#(1)) rg_dmihardreset<-mkRegA(0); + Reg#(Bit#(1)) dmihardreset=condwriteSideEffect(rg_dmihardreset,wr_dmihardreset_generated._write(True)); + Wire#(Bool) wr_dmireset_generated<-mkDWire(False); + Reg#(Bit#(1)) rg_dmireset<-mkRegA(0); + Reg#(Bit#(1)) dmireset=condwriteSideEffect(rg_dmireset,wr_dmireset_generated._write(True)); + Reg#(Bit#(3)) idle=readOnlyReg(3'd7); + Reg#(Bit#(2)) dmistat<-mkRegA(0); + Reg#(Bit#(6)) abits =readOnlyReg(6'd6); + Reg#(Bit#(4)) version = readOnlyReg('d1); + Reg#(Bit#(32)) dtmcontrol=concatReg8(readOnlyReg(14'd0), + dmihardreset,dmireset,readOnlyReg(1'd0), + idle,dmistat,abits,version); + Reg#(Bit#(32)) dtmcontrol_shiftreg<-mkRegA({17'd0,3'd2,2'd0,6'd6,4'd1}); + + Reg#(Bit#(40)) dmiaccess_shiftreg[2]<-mkCReg(2,'d0); + Reg#(Bit#(2)) response_status<-mkReg(0); + Reg#(Bool) rg_dmibusy<-mkRegA(False); + + + Bit#(1) bypass_sel = instruction == `BYPASS?1:0; + Bit#(1) idcode_sel = instruction == `IDCODE?1:0; + Bit#(1) dbg_sel = instruction == `DEBUG?1:0; + Bit#(1) dtmcontrol_sel = instruction == `DTMCONTROL?1:0; + Bit#(1) dmi_sel = instruction == `DMIACCESS?1:0; + + Bit#(1) instruction_tdo=instruction_shiftreg[0]; + Bit#(1) bypass_tdo=bypass_sr; + Bit#(1) idcode_tdo=idcode_sr[0]; + Bit#(1) dtmcontrol_tdo=dtmcontrol_shiftreg[0]; + Bit#(1) dmiaccess_tdo=dmiaccess_shiftreg[0][0]; + + Reg#(Bit#(1)) rg_tdo<-mkRegA(0); + + /*== This rule implements the TAPs STATE MACHINE====== */ + `ifdef verbose + rule just_display; + $display($time,"\tTAPSTATE: ",fshow(tapstate),"\tINSTRUCTION: %h",instruction_shiftreg, " DMIACCESS: %h",dmiaccess_shiftreg[1]); + endrule + `endif + + rule reset_tap(wr_trst); + tapstate<=TestLogicReset; + instruction<=`IDCODE; + instruction_shiftreg<=0; + dtmcontrol<=0; + rg_dmibusy<=False; + dmiaccess_shiftreg[1]<=0; + dtmcontrol_shiftreg<=({17'd0,3'd2,2'd0,6'd6,4'd1}); + idcode_sr<=`IDCODEVALUE; + bypass_sr<=0; + endrule + rule tap_state_machine(posedge_clk && !wr_trst); + case(tapstate) + TestLogicReset: if(wr_tms==0) tapstate<=RunTestIdle; + RunTestIdle : if(wr_tms==1) tapstate <= SelectDRScan; + SelectDRScan : if(wr_tms==1) tapstate <= SelectIRScan; + else tapstate <= CaptureDR; + CaptureDR : if(wr_tms==0) tapstate <= ShiftDR; + else tapstate <= Exit1DR; + ShiftDR : if(wr_tms==1) tapstate <= Exit1DR; + Exit1DR : if(wr_tms==0) tapstate <= PauseDR; + else tapstate <= UpdateDR; + PauseDR : if(wr_tms==1) tapstate <= Exit2DR; + Exit2DR : if(wr_tms==1) tapstate <= UpdateDR; + else tapstate <= ShiftDR; + UpdateDR : if(wr_tms==1) tapstate <= SelectDRScan; + else tapstate <= RunTestIdle; + SelectIRScan : if(wr_tms==1) tapstate <= TestLogicReset; + else tapstate <= CaptureIR; + CaptureIR : if(wr_tms==0) tapstate <= ShiftIR; + else tapstate <= Exit1IR; + ShiftIR : if(wr_tms==1) tapstate <= Exit1IR; + Exit1IR : if(wr_tms==0) tapstate <= PauseIR; + else tapstate <= UpdateIR; + PauseIR : if(wr_tms==1) tapstate <= Exit2IR; + Exit2IR : if(wr_tms==1) tapstate <= UpdateIR; + else tapstate <= ShiftIR; + UpdateIR : if(wr_tms==1) tapstate <= SelectDRScan; + else tapstate <= RunTestIdle; + default : tapstate <= TestLogicReset; + endcase + endrule + + rule dmireset_generated(wr_dmireset_generated && !wr_trst); + dmiaccess_shiftreg[1][1:0]<='d0; + response_status<=0; + endrule + rule dmihardreset_generated(wr_dmihardreset_generated && !wr_trst); + request_to_DM.deq; + response_from_DM.deq; + rg_dmibusy<=False; + endrule + + /*======= perform dtmcontrol shifts ======== */ + rule shift_dtm(posedge_clk && !wr_trst); + case(tapstate) + TestLogicReset: dtmcontrol<={17'd0,idle,2'b0,abits,version}; + CaptureDR: if(dtmcontrol_sel==1) dtmcontrol_shiftreg<=dtmcontrol; + ShiftDR: if(dtmcontrol_sel==1) dtmcontrol_shiftreg<={wr_tdi,dtmcontrol_shiftreg[31:1]}; + UpdateDR: if(dtmcontrol_sel==1) dtmcontrol<=dtmcontrol_shiftreg; + endcase + endrule + /*========================================== */ + /*======= perform dmiaccess shifts ======== */ + rule shift_dmiaccess(posedge_clk && !wr_dmihardreset_generated && !wr_trst && !wr_dmireset_generated); + case(tapstate) + TestLogicReset: dmiaccess_shiftreg[0]<='d0; + CaptureDR: if(dmi_sel==1) + if(response_from_DM.notEmpty)begin + let x=response_from_DM.first[33:0]; + $display($time,"\tDTM: Getting response: data %h op: %h",x[33:2],x[1:0]); + x[1:0]=x[1:0]|response_status;// keeping the lower 2 bits sticky + dmiaccess_shiftreg[0][33:0]<=x; + response_status<=x[1:0]; + response_from_DM.deq; + $display($time,"\tDTM: New DMIACCESS value: %h",x); + rg_dmibusy<=False; + end + ShiftDR: if(dmi_sel==1) dmiaccess_shiftreg[0]<={wr_tdi,dmiaccess_shiftreg[0][39:1]}; + UpdateDR: if(dmi_sel==1) + if(request_to_DM.notFull && dmiaccess_shiftreg[0][1:0]!=0 && rg_dmibusy==False)begin + request_to_DM.enq(dmiaccess_shiftreg[0]); + rg_dmibusy<=True; + $display($time,"\tDTM: Sending request to Debug: %h",dmiaccess_shiftreg[0]); + end + else if(rg_dmibusy) begin + response_from_DM.enq('d3); + end + endcase + endrule + /*========================================== */ + + /*== perform instruction register shifts === */ + rule shift_reg(posedge_clk && !wr_trst); + case(tapstate) + CaptureIR: instruction_shiftreg<='b10101; + ShiftIR : instruction_shiftreg<= {wr_tdi,instruction_shiftreg[4:1]}; + endcase + endrule + rule transfer_instruction_on_nedge(negedge_clk && !wr_trst); // TODO negedge here + case(tapstate) + TestLogicReset :instruction<=`IDCODE; + UpdateIR :instruction<=instruction_shiftreg; + endcase + endrule + + /*==== Bypass Section === */ + rule bypass_logic(posedge_clk && !wr_trst); + case(tapstate) + TestLogicReset: bypass_sr<=1'b0; + CaptureDR : if(bypass_sel==1) bypass_sr<=1'b0; + ShiftDR : if(bypass_sel==1) bypass_sr<=wr_tdi; + endcase + endrule + + /*======= IDCODE section === */ + rule idcode_logic(posedge_clk && !wr_trst); + case(tapstate) + TestLogicReset:idcode_sr<=`IDCODEVALUE; + CaptureDR: if(idcode_sel==1) idcode_sr<=`IDCODEVALUE; + ShiftDR : if(idcode_sel==1) idcode_sr<={wr_tdi,idcode_sr[31:1]}; + endcase + endrule + + rule generate_tdo_outputpin(negedge_clk && !wr_trst); + if(tapstate==ShiftIR) + rg_tdo<=instruction_tdo; + else + case(instruction) + `IDCODE: rg_tdo<=idcode_tdo; + `DEBUG : rg_tdo<=wr_debug_tdi; + `EXTEST: rg_tdo<=wr_bs_chain_tdi; + `SAMPLE_PRELOAD: rg_tdo<=wr_bs_chain_tdi; + `BYPASS: rg_tdo<=bypass_tdo; + `DTMCONTROL: rg_tdo<=dtmcontrol_tdo; + `DMIACCESS: rg_tdo<=dmiaccess_tdo; + default: rg_tdo<=bypass_tdo; + endcase + endrule + + /*======== JTAG input pins ===== */ + method Action tms_i(Bit#(1) tms); + wr_tms<=tms; + endmethod + method Action tdi_i(Bit#(1) tdi); + wr_tdi<=tdi; + endmethod + method Action tck_i(Bit#(1) tck); + prv_clk<=tck; + if(prv_clk==0 && tck==1) + posedge_clk.send; + else if(prv_clk==1 && tck==0) + negedge_clk.send; + endmethod + method Action trst_i(Bit#(1) trst); + wr_trst<=unpack(trst); + endmethod + /*============================= */ + method Action debug_tdi_i(Bit#(1) debug_tdi); + wr_debug_tdi<=debug_tdi; + endmethod + method Action bs_chain_i(Bit#(1) bs_chain); + wr_bs_chain_tdi<=bs_chain; + endmethod + /*======== TAP States ============= */ + method shift_dr=tapstate==ShiftDR?1:0; + method pause_dr=tapstate==PauseDR?1:0; + method update_dr=tapstate==UpdateDR?1:0; + method capture_dr=tapstate==CaptureDR?1:0; + /*=================================== */ + /*=========== Output for BS Chain ==== */ + method extest_select =instruction==`EXTEST?1:0; + method sample_preload_select =instruction==`SAMPLE_PRELOAD?1:0; + method debug_select =instruction==`DEBUG?1:0; + /*================================ */ + /*======= JTAG Output Pins ====== */ + method tdo = rg_tdo; + method debug_tdo = wr_tdi; + method Bit#(1) tdo_oe = ((tapstate == ShiftIR) || (tapstate == ShiftDR))?1:0; + method Action response_from_dm(Bit#(34) responsedm) if(response_from_DM.notFull); + response_from_DM.enq(responsedm); + endmethod + method ActionValue#(Bit#(40)) request_to_dm if(request_to_DM.notEmpty); + request_to_DM.deq; + return request_to_DM.first; + endmethod + endmodule + +endpackage -- 2.30.2