The In-Circuit Debugger Survial Guide
1F00 1170 bcf 0x70,0x2
1F01 1903 btfsc STATUS,ZERO
1F02 1570 bsf 0x70,0x2 ; Copy Zero Bit
1F03 1370 bcf 0x70,0x6
1F04 1B03 btfsc STATUS,RP1
1F05 1770 bsf 0x70,0x6 ; Copy RP1 Bit
1F06 12F0 bcf 0x70,0x5
1F07 1A83 btfsc STATUS,RP0
1F08 16F0 bsf 0x70,0x5 ; Copy RP0 Bit
1F09 1703 bsf STATUS,RP1
1F0A 1683 bsf STATUS,RP0 ; Select Bank 3
1F0B 00ED movwf 0x6D ; Copy Working Register to 0x6D
1F0C 3064 movlw 0x64
1F0D 05F0 andwf 0x70 ; Clear Bits we have not worried about yet
; !(RP1, RP2 & Zero)
1F0E 0803 movf STATUS,W
1F0F 399B andlw 0x9B ; Exclude Bits we have already read (RP1, RP2 & Zero)
1F10 04F0 iorwf 0x70 ; Or Result together (XOR?)
1F11 0804 movf FSR,W ; Indirect Data Memory Address Pointer
1F12 00EE movwf 0x6E ; Store Temporarly at 0x6E
1F13 080A movf PCLATH,W ; Store Temporarly at 0x6F
1F14 00EF movwf 0x6F
1F15 301F movlw 0x1F
1F16 008A movwf PCLATH ; Set Upper Location
1F17 080E movf 0xE,W ; Reserved
1F18 00EB movwf 0x6B ; Store Temporarly a 0x6B
1F19 1703 bsf STATUS,RP1
1F1A 1683 bsf STATUS,RP0 ; Select Bank 3
1F1B 30E0 movlw 0xE0 ; 0x60
1F1C 05EC andwf 0x6C
1F1D 1706 bsf TRISB,0x6 ; Set Clock Input
1F1E 1386 bcf TRISB,0x7 ; Set Data Output
1F1F 1283 bcf STATUS,RP0 ; Select Bank 2
1F20 1386 bcf PORTB,0x7 ; Clear Data
1F21 1683 bsf STATUS,RP0 ; Select Bank 3
1F22 0AEC Loop incf 0x6C ;
1F23 1D6C btfss 0x6C,0x2 ; Skip if Set
1F24 2F22 goto 0x1F22 (Loop); loop until bit 2 is set
1F25 116C bcf 0x6C,0x2 ; Clear Bit 2
1F26 1283 bcf STATUS,RP0 ; Select Bank 2 -> Access to Ports
1F27 0064 HitoLo clrwdt
1F28 1B06 btfsc PORTB,0x6(CLOCK) ; Loop until High to Low Transition
1F29 2F27 goto 0x1F27 (HitoLo)
1F2A 0064 LotoHi clrwdt
1F2B 1F06 btfss PORTB,0x6(CLOCK) ; Loop until low to high Transition
1F2C 2F2A goto 0x1F2A (LotoHi)
1F2D 1786 bsf PORTB,0x7 (DATA) ; Set Data Bit High
1F2E 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F2F 0AEC incf 0x6C
1F30 1DEC btfss 0x6C,0x3
1F31 2F2F goto 0x1F2F
1F32 11EC bcf 0x6C,0x3 ; Clear Bit 3
1F33 1283 bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F34 1386 bcf PORTB,0x7 (DATA) ; Clear Data
1F35 0064 clrwdt
1F36 1B06 btfsc PORTB,0x6 (CLOCK) ; Loop until High to Low Transition
1F37 2F35 goto 0x1F35
1F38 0064 clrwdt
1F39 1F06 btfss PORTB,0x6 (CLOCK) ; Loop until low to high Transition
1F3A 2F38 goto 0x1F38
1F3B 1003 bcf STATUS,CARRY ; Clear Carry
1F3C 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F3D 1BEC btfsc 0x6C,0x7 ; Copy Bit 7 of 6C
1F3E 1403 bsf STATUS,CARRY
1F3F 1283 bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F40 1386 bcf PORTB,0x7 (DATA) ; Clear Data
1F41 1C03 btfss STATUS,CARRY ; Copy Bit 7 to Data
1F42 1786 bsf PORTB,0x7 (DATA)
1F43 1B06 btfsc PORTB,0x6 (CLOCK) ; Loop until High to Low Transition
1F44 2F43 goto 0x1F43
1F45 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F46 1786 bsf TRISB,0x7 (DATA) ; Make DATA Input
1F47 0064 clrwdt
1F48 0AEC incf 0x6C
1F49 1283 bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F4A 1003 bcf STATUS,CARRY
1F4B 1B86 btfsc PORTB,0x7 (DATA) ; Read Data
1F4C 1403 bsf STATUS,CARRY
1F4D 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F4E 13EC bcf 0x6C,0x7 ; Store 6C
1F4F 1803 btfsc STATUS,CARRY
1F50 17EC bsf 0x6C,0x7
1F51 1283 loop bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F52 0064 clrwdt
1F53 1F06 btfss PORTB,0x6 (CLOCK) ; Loop until low to high Transition
1F54 2F52 goto 0x1F52
1F55 1386 bcf PORTB,0x7 (DATA)
1F56 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F57 1386 bcf PORTB,0x7 (DATA)
1F58 1003 bcf STATUS,CARRY
1F59 1B6B btfsc 0x6B,0x6
1F5A 1403 bsf STATUS,CARRY
1F5B 1283 bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F5C 1386 bcf PORTB,0x7 (DATA)
1F5D 1803 btfsc STATUS,CARRY
1F5E 1786 bsf PORTB,0x7 (DATA)
1F5F 0064 clrwdt
1F60 1B06 btfsc PORTB,0x6 (CLOCK) ; Loop until High to Low Transition
1F61 2F5F goto 0x1F5F
1F62 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F63 1786 bsf TRISB,0x7 (DATA) ; Make Data an Input!
1F64 1003 bcf STATUS,CARRY
1F65 0D8F rlf 0x0F
1F66 0DEB rlf 0x6B
1F67 0AEC incf 0x6C
1F68 1283 bcf STATUS,RP0 ; Select BANK 2 -> Access to Ports
1F69 1003 bcf STATUS,CARRY
1F6A 1B86 btfsc PORTB,0x7 (DATA) ; read data
1F6B 1403 bsf STATUS,CARRY
1F6C 1683 bsf STATUS,RP0 ; Select BANK 3 -> Access to Debug Registers
1F6D 1803 btfsc STATUS,CARRY
1F6E 140F bsf 0xF,0x0 (Reserved)
1F6F 1E6C btfss 0x6C,0x4
1F70 2F51 goto 0x1F51
1F71 1FEC btfss 0x6C,0x7
1F72 2F84 goto 0x1F84
1F73 086B movf 0x6B,W ; Restore Registers
1F74 008E movwf 0xE (Reserved)
1F75 086F movf 0x6F,W
1F76 008A movwf PCLATH
1F77 086E movf 0x6E,W
1F78 0084 movwf FSR
1F79 0870 movf 0x70,W
1F7A 0083 movwf STATUS
1F7B 1683 bsf STATUS,RP0
1F7C 1703 bsf STATUS,RP1 ; BANK SELECT 3
1F7D 0EED swapf 0x6D
1F7E 0E6D swapf 0x6D,W
1F7F 1F70 btfss 0x70,0x6
1F80 1303 bcf STATUS,RP1
1F81 1EF0 btfss 0x70,0x5
1F82 1283 bcf STATUS,RP0
1F83 0008 return ; Pop of stack?
1F84 0E6B swapf 0x6B,W
1F85 3907 andlw 0x7 ; 8 Possible Combinations of High Nibble
1F86 0782 addwf PCL
1F87 2FAE goto 0x1FAE
1F88 2FB2 goto 0x1FB2
1F89 2FB0 goto 0x1FB0
1F8A 2FB4 goto 0x1FB4
1F8B 2F9A goto 0x1F9A
1F8C 2FA6 goto 0x1FA6
1F8D 2F8F goto 0x1F8F
1F8E 2FA1 goto 0x1FA1
1F8F 086B movf 0x6B,W
1F90 3907 andlw 0x7 ; 8 Possible Combinations of Low Nibble
1F91 0782 addwf PCL
1F92 2FB6 goto 0x1FB6
1F93 2FBC goto 0x1FBC
1F94 2FB9 goto 0x1FB9
1F95 2FBF goto 0x1FBF
1F96 2FC2 goto 0x1FC2
1F97 2FCE goto 0x1FCE
1F98 2FA1 goto 0x1FA1
1F99 2FA1 goto 0x1FA1
1F9A 1383 bcf STATUS,IRP ; (Bank 0,1 00h ffh) Used for Indirect Addressing
1F9B 186B btfsc 0x6B,0x0
1F9C 1783 bsf STATUS,IRP ; (Bank 2,3 100 1ffh)
1F9D 080F movf 0xF,W
1F9E 0084 movwf 0x4
1F9F 0800 movf 0x0,W
1FA0 008F movwf 0xF ; High Byte
** WAIT FOR HIGH TO LOW TRANSITION ON DATA
1FA1 1283 bcf STATUS,RP0 ; Bank 2
1FA2 0064 clrwdt
1FA3 1F06 btfss PORTB,DATA ; Read Data Line
1FA4 2FA2 goto 0x1FA2 ; Wait for low to High Transition
1FA5 2F19 goto 0x1F19
** SAVE VALUE of 0x6D to FILE REGISTERS (0x0F)
1FA6 1383 bcf STATUS,IRP ; Indirect Addressing Register Bank
1FA7 186B btfsc 0x6B,0x0 ; If 6B Bit 0 = 0 Bank 0,1 (00h -> FFh)
1FA8 1783 bsf STATUS,IRP ; = 1 Bank 2,3 (100h -> 1FFh)
1FA9 080F movf 0xF,W ;
1FAA 0084 movwf FSR ; Move Address of Data Memory from W to FSR
1FAB 086D movf 0x6D,W ;
1FAC 0080 movwf 0x0 ; Save Contents of REG6D to Addr 0xF
1FAD 2FA1 goto 0x1FA1
** SEND VALUE IN 6D
1FAE 086D movf 0x6D,W
1FAF 2FA0 goto 0x1FA0
** SEND VALUE IN 6E
1FB0 086E movf 0x6E,W
1FB1 2FA0 goto 0x1FA0
** SEND VALUE IN 70
1FB2 0870 movf 0x70,W
1FB3 2FA0 goto 0x1FA0
** SEND VALUE IN 6F
1FB4 086F movf 0x6F,W
1FB5 2FA0 goto 0x1FA0
1FB6 080F movf 0xF,W
1FB7 00ED movwf 0x6D
1FB8 2FA1 goto 0x1FA1
1FB9 080F movf 0xF,W
1FBA 00EE movwf 0x6E
1FBB 2FA1 goto 0x1FA1
1FBC 080F movf 0xF,W
1FBD 00F0 movwf 0x70
1FBE 2FA1 goto 0x1FA1
1FBF 090F comf 0xF,W
1FC0 00EF movwf 0x6F
1FC1 2FA1 goto 0x1FA1
1FC2 080F movf 0xF,W
1FC3 1283 bcf STATUS,RP0 ; Bank 0?
1FC4 008C movwf 0xC ; PIR1
1FC5 1683 bsf STATUS,RP0 ; Bank 1
1FC6 138C bcf 0xC,0x7 ; PIE1
1FC7 150C bsf 0xC,0x2 ; PIE1
1FC8 3055 movlw 0x55
1FC9 008D movwf 0xD ; PIE2
1FCA 30AA movlw 0xAA
1FCB 008D movwf 0xD ; PIE2
1FCC 148C bsf 0xC,0x1
1FCD 2FA1 goto 0x1FA1
1FCE 080F movf 0xF,W ; TMR1H
1FCF 1283 bcf STATUS,RP0 ; BANK0
1FD0 008D movwf 0xD ; PIR2
1FD1 1683 bsf STATUS,RP0 ; BANK1
1FD2 138C bcf 0xC,0x7 (PIE1)
1FD3 140C bsf 0xC,0x0 (
1FD4 1283 bcf STATUS,RP0
1FD5 080C movf 0xC,W
1FD6 1683 bsf STATUS,RP0
1FD7 2FA0 goto 0x1FA0
The ICD module itself has a 3,6864 Mhz Xtal.
The demo board has an empty socket and link for (optional) osc module, but normally runs as an RC osc...
Let me direct you to an article which John Day, A Principal Field Application Engineer for Microchip wrote in Circuit Cellar, Issue 109, August 1999.
John writes, "The debug kernel is downloaded along with the target firmware via the ICSP interface. A non-maskable interrupt vectors execution to the kernel when the program counter equals a preselected hardware breakpoint address, after a single step, or when a halt command is received from the host."
"As with all interrupts, this interrupt pushes the return address onto the stack. On reset, the breakpoint register is set equal to the reset vector, so the kernel is entered immediately when the device comes out of reset. The ICD module issues a reset to the target '16F877 immediately after a download, the kernel is entered and control is passed to MPLAB running on the host."
"You can then command the target processor as you choose. All RAM registers including the PC and other special function registers can be modified or interrogated. You can single step, set a breakpoint, animate and start or stop full speed execution."
Now it doesn't take too much effort to work out that we need two bytes for the Breakpoint Register. An considering the 16F87x documentation shows only to registers which are reserved, life couldn't be easier. Locations 0x18E and 0x18F are the breakpoint register. I've written a little program which allows me to access internal registers via the serial port. This is great for debugging/learning the operation of peripherals. What this has also told me, that in normal operation these two registers can't be written too.
So when a breakpoint occurs where does the program vector too? Maybe 0x1F00, the start of that all secret debug target code?
Tonight's Homework: Write a program at 0x1F00 to flash a LED or something similar. Then write a loop at 0x0000 so in normal operation, the code at 0x1F00 never gets executed. Then run the program both with the Debug Bit Clear and Set. Then summarize your observations to the PIC List . . . . (No I won't be marking it)
I have done this a couple of months back, but where getting mixed results. This was at the time my programmer was also given mixed results!, thus I could never verify exactly what was happening. However I suspect there is more to this. I also observed that is I placed about 10 NOP's at 0000 it would work. We do know for sure, reading from the ICD manual that you need to program the first location with a NOP. This is due to the fact that the breakpoint register is compared to the PC address after execution of the instruction.
John continues to write under the heading Silicon Requirements, "The breakpoint address register and compactor, along with some logic to single step and recognize asynchronous commands from the host, make up most of what is needed in the silicon. The ICSP interface is in place to support programming and doesn't constitute and additional silicon requirement."
"recognize asynchronous commands" This has stumped me. What I believe is that there is some other ICSP command which enables and disables operation? I'm open to any suggestions . . . .
Also check my reply to Robin Abbott dated Mon, 24 Jan 2000 if you are desperately scratching for more information. . . http://www.infosite.com/%7Ejkeyzer/piclist/2000/Jan/1552.html
From MChip App Note TB033:
Certain resources are consumed when the MPLAB-ICD In-Circuit Debugger is used to develop code. These resources are released when the debugger is not used. The resources include:
- Last 256 words of program memory: IF00h to IFFh
- Program memory location 0000h must be a NOP instruction
- Pins RB6 and RB7: CLK and Data for ICD
- MCLR/VPP used for programming @ 13V
- Data memory locations 70h, 1EBh 1EFh (Eh? its 18Eh - 18Fh right?)
Processor File Registers Used Program Memory Used PIC16F870/871/872 0x70, 0x0BB-0x0BF 0x06E0-0x07FF PIC16F873/874 0x70, 0x0EB-0x0F0 0x0EE0-0x0FFF PIC16F876/877 0x70, 0x1EB-0x1EF 0x1F00-0x1FFF- 1 Level of stack