v0.4 - Some fixups in the bootstrap code (I actually had to put the PIC in my PICSTAR...
authorWerner Johansson <wj@xnk.nu>
Wed, 5 Mar 2003 06:16:57 +0000 (22:16 -0800)
committerWerner Johansson <wj@xnk.nu>
Sun, 17 Oct 2010 00:33:08 +0000 (17:33 -0700)
Signed-off-by: Werner Johansson <wj@xnk.nu>

wj-uni.asm

index f2a186d..31f5bc1 100644 (file)
@@ -25,6 +25,7 @@
 ;----------------------------------------------------------------\r
 ;  Version\r
 ;\r
+;  0.4  Some fixups in the bootstrap code (I actually had to put the PIC in my PICSTART Plus programmer again :))\r
 ;  0.3  Implementing more Unilink commands and RingIndicator control (to wake the computer from sleep)\r
 ;  0.2  First attempt at responding to the Anyone command\r
 ;  0.1  Receives Unilink data OK, relays it to serial\r
@@ -69,6 +70,9 @@
 ;----------------------------------------------------------------\r
 Dcount         equ     20h\r
 e_LEN          equ     21h\r
+\r
+Counter                equ     22h\r
+SlaveBreakState        equ     23h             ; Hold state and time-out information about slave break, indicates when it can happen\r
 Icount         equ     2Dh             ; Offset of string to print\r
 TxTemp         equ     2Eh             ; blahblah\r
 TxTemp2                equ     2Fh             ; Blahblah2\r
@@ -126,7 +130,7 @@ IRQW                equ     7fh             ;
 ;  Also because of the real-time requirements for clocking data onto the Unilink bus the first check in the ISR\r
 ;  is to see whether the Unilink clock rise was the reason for the interrupt. This results in a "clock rise to\r
 ;  bit ready" time of less than 30 instruction cycles, should be plenty of spare time waiting for clock to go low\r
-;  again after that.\r
+;  again after that. Other interrupts might introduce latencies, but let's see how this works..\r
 \r
        org     4                       ; ISR vector is at address 4\r
        movwf   IRQW                    ; Save W\r
@@ -134,8 +138,8 @@ IRQW                equ     7fh             ;
        clrf    STATUS                  ; Zero out the status reg, gives Reg Bank0\r
        movwf   IRQSTATUS               ; Store the STATUS reg\r
        movf    PCLATH,w                ; Get the PCLATH reg\r
-       movwf   IRQPCLATH               ; And store it\r
-       clrf    PCLATH                  ; Go to low memory\r
+;      movwf   IRQPCLATH               ; And store it\r
+;      clrf    PCLATH                  ; Go to low memory\r
 ; Maybe save FSR here as well (if there's a need for it in the non-ISR code)\r
 \r
        btfss   INTCON,INTF             ; Check if it's the INT edge interrupt (Unilink CLK)\r
@@ -208,6 +212,7 @@ IRQINTCLKWaitHigh
 ; the packet and take appropriate action.\r
 \r
 IRQINTRecvDone\r
+       clrf    SlaveBreakState         ; First of all, clear the break state - this got in the way, restart detection..\r
        movf    UnilinkTXRX,w           ; Find out which byte # that was received\r
        andlw   0fh                     ; Mask\r
        bnz     IRQINTRecvNotFirst      ; Not the first byte\r
@@ -451,12 +456,93 @@ IRQAfterINT
 \r
 IRQNotINT\r
 \r
+       btfss   PIR1,TMR2IF             ; Check if it's the TMR2 interrupt (0.5ms timing)\r
+       goto    IRQNotTMR2              ; No it's not, check the other sources\r
+\r
+; Slave break opportunity detection here - the logic works as follows:\r
+; Look for a data low period of at least 5 ms (10 loops)\r
+; Look for a data high period of at least 2 ms (4 loops)\r
+; If the Slave Break request bit has been set, issue a slave break by holding the data line low for 5ms (10 loops)\r
+; If a packet would be received the packet handler automatically clears out the SlaveBreakState, which means start all over\r
+\r
+;      incf    Counter,f               ; Increment the general purpose counter\r
+\r
+       btfsc   SlaveBreakState,5       ; Check if already pulling the data line low\r
+       goto    IRQTMR2SlaveBreak\r
+\r
+       btfsc   SlaveBreakState,7       ; Looking for low or high data\r
+       goto    IRQTMR2HighData\r
+       btfss   DATA_BIT                ; Looking for a low data line, if it's low, increment state, if it's high, reset state\r
+       goto    IRQTMR2LowDataOK\r
+       clrf    SlaveBreakState         ; Got a high data line while waiting for a low one, reset state\r
+       goto    IRQAfterTMR2            ; Leave ISR\r
+\r
+IRQTMR2HighData\r
+       btfsc   DATA_BIT                ; Looking for a high data line, if it's high - increment state, otherwise wait\r
+       goto    IRQTMR2HighDataOK\r
+       movlw   080h\r
+       btfss   SlaveBreakState,6       ; Test the "first time around" bit\r
+       clrw                            ; Not the beginning of the state, have to restart the entire thing now, not just this state\r
+       andwf   SlaveBreakState,f       ; Mask out the 1 upper control bits and restart this state\r
+       goto    IRQAfterTMR2\r
+\r
+IRQTMR2HighDataOK\r
+IRQTMR2LowDataOK\r
+       bsf     SlaveBreakState,6       ; Set the "first time around" bit\r
+       btfss   SlaveBreakState,4       ; Only increment to 0x10\r
+       incf    SlaveBreakState,f\r
+       \r
+       movf    SlaveBreakState,w\r
+       andlw   1fh\r
+\r
+       btfss   SlaveBreakState,7       ; Checking whether it's low or high\r
+       goto    IRQTMR2FoundLow\r
+\r
+       xorlw   4                       ; It's high now, and if 4 periods have passed we can activate slave break\r
+       skpz\r
+       goto    IRQAfterTMR2\r
+\r
+; Issue slave break here\r
+       incf    Counter,f\r
+;      clrf    SlaveBreakState\r
+       movlw   20h\r
+       movwf   SlaveBreakState\r
+       bcf     DATA_BIT\r
+       bsf     STATUS,RP0\r
+       bcf     DATA_BIT\r
+       bcf     STATUS,RP0\r
+       goto    IRQAfterTMR2\r
+\r
+IRQTMR2FoundLow\r
+       xorlw   7\r
+       skpz\r
+       goto    IRQAfterTMR2\r
+       movlw   80h                     ; Prepare for state 2, looking for data line high\r
+       movwf   SlaveBreakState\r
+       goto    IRQAfterTMR2\r
+       \r
+IRQTMR2SlaveBreak\r
+       movf    SlaveBreakState,w\r
+       andlw   01fh\r
+       xorlw   4\r
+       skpz\r
+       goto    IRQAfterTMR2\r
+       bsf     STATUS,RP0\r
+       bsf     DATA_BIT\r
+       bcf     STATUS,RP0\r
+       clrf    SlaveBreakState\r
+\r
+IRQAfterTMR2\r
+       bcf     PIR1,TMR2IF             ; Clear the IRQ source bit to re-enable TMR2 interrupts again\r
+\r
+IRQNotTMR2\r
+\r
 ; Finally restore CPU state and return from the ISR\r
 \r
 ; If I have to save the FSR in the beginning I also need to restore it here...\r
 \r
-       movf    IRQPCLATH,w\r
-       movwf   PCLATH                  ; Restore PCLATH\r
+;      movf    IRQPCLATH,w\r
+;      movwf   PCLATH                  ; Restore PCLATH\r
        swapf   IRQSTATUS,w\r
        movwf   STATUS                  ; Restore STATUS\r
        swapf   IRQW,f\r
@@ -468,20 +554,14 @@ IRQNotINT
        page\r
 \r
 ;----------------------------------------------------------------\r
-;  Data can be stored between here and 100h...\r
-\r
-StartUpText1\r
-       DT      "----- WJ UniLink"\r
-               \r
-LookUp  movwf   PCL                    ; Go to it (this assumes PCLATH == 00h)\r
-\r
-;----------------------------------------------------------------\r
 ;  Main program begins here. [Called after bootloader, lcdinit and irqinit...]\r
 \r
-       org     100h                    ; Maybe not force this to a specific address later\r
+;      org     100h                    ; Maybe not force this to a specific address later\r
 Main\r
+       movlw   high LookUp\r
+       movwf   PCLATH\r
 \r
-       movlw   StartUpText1            ; Show something on the LCD\r
+       movlw   low StartUpText1        ; Show something on the LCD\r
        call    TxLCD16B\r
 \r
 MainLoop\r
@@ -491,12 +571,14 @@ MainLoop
        call    TxLCDB\r
        bsf     LCD_RS_BIT\r
 \r
-       movlw   '0'\r
+;      movlw   '0'\r
+       movf    Counter,w               ; Debug timer\r
        btfsc   PORTA,4                 ; Test RST\r
        movlw   'R'\r
        call    TxLCDB\r
 \r
-       movlw   '0'\r
+;      movlw   '0'\r
+       movf    SlaveBreakState,w\r
        btfsc   PORTB,0                 ; Test CLK\r
        movlw   'C'\r
        call    TxLCDB\r
@@ -531,6 +613,7 @@ MainDontPrintCmd
 \r
 ;----------------------------------------------------------------\r
 ; IRQInit - Sets up the IRQ Handler\r
+; Set up Timer2 to generate 2000 interrupts per second, used for timing - 1/16 prescaler and a PR2 reg of 156 (0x9c) is set\r
 \r
 IRQInit\r
 \r
@@ -561,13 +644,21 @@ IRQInit
        movlw   UnilinkRAD              ; Get the pointer to the first byte in the receive buffer\r
        movwf   UnilinkTXRX             ; Store it\r
 \r
+       clrf    SlaveBreakState         ; Zero out the status, we're starting from the beginning\r
+\r
 ; Fix the output state of RI and BUSON_OUT to a safe default\r
 \r
        bsf     RS232_RI_BIT            ; RS232 RI should be inactive (inverted logic, a set bit here gives a negative output)\r
        bcf     BUSON_OUT_BIT           ; BUSON_OUT should be disabled for now, must be appointed first\r
 \r
+       movlw   06h                     ; Timer2 enabled + 1/16 prescaler\r
+       movwf   T2CON\r
+\r
        bsf     STATUS,RP0              ; Reg bank 1\r
 \r
+       movlw   09ch                    ; Timer PR2 reg giving 2000 interrupts per second\r
+       movwf   PR2\r
+\r
        bcf     RS232_RI_BIT            ; Both bits should be outputs\r
        bcf     BUSON_OUT_BIT           ;\r
 \r
@@ -575,6 +666,8 @@ IRQInit
 ;      bcf     OPTION_REG,INTEDG       ; We want RB0 to give us an IRQ on the falling edge\r
 \r
        bsf     INTCON,INTE             ; Enable the RB0/INT\r
+       bsf     INTCON,PEIE             ; Enable the peripheral interrupts\r
+       bsf     PIE1,TMR2IE             ; Enable the Timer2 peripheral interrupt\r
        bsf     INTCON,GIE              ; Enable global interrupts\r
 \r
        bsf     TXSTA,TXEN              ; Enable UART TX\r
@@ -799,6 +892,16 @@ DelayInner
        return\r
 \r
 \r
+;----------------------------------------------------------------\r
+;  Data can be stored between 600 and 6ffh...\r
+\r
+       org     600h\r
+StartUpText1\r
+       DT      "----- WJ UniLink"\r
+               \r
+LookUp movwf   PCL                     ; Go to it (this assumes PCLATH == 06h)\r
+\r
+\r
        subtitl "Bootstrap/Bootloader code"\r
        page\r
 \r
@@ -814,7 +917,6 @@ DelayInner
 \r
 ; RAM usage for the bootstrap code\r
 \r
-BootRXState    equ     7fh             ; What are we waiting for @RX\r
 BootBits       equ     7eh             ; bit0 1=write 0=read, bit1 1=PGM 0=EE, bit2 0=normal 1=no-op when prog\r
 BootAddrL      equ     7dh\r
 BootAddrH      equ     7ch\r
@@ -827,14 +929,10 @@ BootNumBytes      equ     76h
 BootDataVL     equ     75h\r
 BootDataVH     equ     74h\r
 BootHEXTemp    equ     73h\r
-BootStrTemp    equ     72h\r
 \r
-       org     700h                    ; Place the boot code at the top of memory\r
+       org     738h                    ; Place the boot code at the top of memory (currently the loader is exactly 200 bytes)\r
 \r
 Bootstrap\r
-       movlw   7\r
-       movwf   PCLATH                  ; Make sure the lookup code runs with the high PC bits set!\r
-\r
        bsf     STATUS,RP0              ; Access bank 1\r
        bsf     TXSTA,TXEN              ; Enable UART TX\r
        movlw   31                      ; Divisor for 9k6 @ 20MHz Fosc\r
@@ -844,8 +942,6 @@ Bootstrap
        bsf     RCSTA,SPEN              ; Enable serial port\r
        bsf     RCSTA,CREN              ; Enable UART RX\r
 \r
-;      clrf    BootRXState             ; Waiting for command\r
-\r
        movlw   low BootStartText       ; Send boot banner to the serial port\r
        call    BootTXStr\r
 \r
@@ -879,12 +975,11 @@ BootFlash
 \r
 BootLoop\r
        call    BootRXB                 ; First find the ':'\r
-       call    BootTXB                 ; Echo to terminal\r
        xorlw   ':'\r
        skpz\r
        goto    BootLoop                ; Loop until we find it!\r
 \r
-       call    BootRXHEX               ; Get one ASCII encoded byte (two chars) (this echoes automatically)\r
+       call    BootRXHEX               ; Get one ASCII encoded byte (two chars)\r
        movwf   BootNumBytes            ; This is the number of bytes to be programmed on the line\r
 ; Maybe clear cary here?\r
        rrf     BootNumBytes,f          ; Right shift because we're double addressing this 8-bit format\r
@@ -940,21 +1035,12 @@ BootWrite
        movf    BootDataVH,w\r
        movwf   BootDataH               ; Have to put the new H byte data in as well\r
 \r
-;      movlw   '+'\r
-;      call    BootTXB                 ; Send progword indicator\r
-\r
        bsf     BootBits,0\r
        call    BootEE                  ; Write directly into program mem\r
 \r
 ; Here a verify can take place, the read-back results are now in DataL/H\r
 \r
-;      movlw   '+'\r
-;      goto    BootWriteDone\r
-\r
 BootWriteSkip\r
-;      movlw   '-'\r
-BootWriteDone\r
-;      call    BootTXB\r
 \r
        incf    BootAddrL,f             ; Advance counter to next addr\r
        skpnz\r
@@ -963,11 +1049,6 @@ BootWriteDone
        decfsz  BootNumBytes,f\r
        goto    BootLineLoop\r
 \r
-;      movlw   13                      ; Progress\r
-;      call    BootTXB\r
-;      movlw   10                      ; Progress\r
-;      call    BootTXB\r
-\r
        goto    BootLoop\r
 \r
 BootFlashComplete\r
@@ -986,7 +1067,6 @@ BootReturnWait
        bcf     RCSTA,SPEN              ; Disable serial port\r
        bcf     RCSTA,CREN              ; Disable UART RX\r
 \r
-       clrf    PCLATH                  ; Go back to memory bank 0\r
        return                          ; Return to code        \r
 \r
 ;----------------------------------------------------------------------\r
@@ -1004,14 +1084,23 @@ BootTXW1
 ; BootTXStr - Sends ASCII string pointed to by W, zero terminated\r
 \r
 BootTXStr\r
-       movwf   BootStrTemp             ; Store offset\r
-       call    BootLookup              ; Lookup char\r
-       addlw   0\r
-       skpnz\r
+       movwf   BootAddrL               ; Store LSB of text pointer\r
+       movlw   07h                     ; MSB of pointer to the text (0700h in this boot loader)\r
+       movwf   BootAddrH\r
+       movlw   02h                     ; Select "Read Program Memory" operation\r
+       movwf   BootBits        \r
+BootTXStrLoop\r
+       call    BootEE                  ; Lookup char (actually two packed into one word)\r
+       rlf     BootDataL,w             ; Shift the MSB out into carry (that's the 2nd char LSB)\r
+       rlf     BootDataH,w             ; Shift it into 2nd char\r
+       call    BootTXB                 ; Send the high byte first\r
+       movf    BootDataL,w             ; Get the low byte\r
+       andlw   07fh                    ; Mask of the highest bit\r
+       skpnz                           ; Stop if zero\r
        return\r
        call    BootTXB                 ; Send char\r
-       incf    BootStrTemp,w           ; Retrieve\r
-       goto    BootTXStr\r
+       incf    BootAddrL,f             ; Increment pointer\r
+       goto    BootTXStrLoop\r
 \r
 ;----------------------------------------------------------------------\r
 ; BootRXB - Receives one byte from the UART, waits if nothing available\r
@@ -1021,6 +1110,7 @@ BootRXW1
        btfss   PIR1,RCIF               ; Wait for RX to complete\r
        goto    BootRXW1\r
        movf    RCREG,w                 ; Get the recvd byte\r
+       call    BootTXB                 ; Echo to terminal\r
        return\r
 \r
 ;----------------------------------------------------------------------\r
@@ -1028,7 +1118,6 @@ BootRXW1
 \r
 BootRXHEXNibble\r
        call    BootRXB                 ; Receive nibble\r
-       call    BootTXB                 ; Echo to terminal\r
        addlw   -'A'                    ; Convert from BCD to binary nibble\r
        skpc                            ; Test if if was 0-9 or A-F, skip if A-F\r
        addlw  'A' - 10 - '0'           ; It was numeric '0'\r
@@ -1103,20 +1192,22 @@ BootEEX
 \r
        return\r
 \r
+; To produce compact code the end zero byte has to be in the LSB (that means an even number of chars in every string)\r
 BootStartText\r
-       DT      "WJBoot - press ESC to flash",0\r
+       DW      0x2bca,0x216f,0x37f4,0x102d,0x1070,0x3965,0x39f3,0x1045,0x29c3,0x1074,0x37a0,0x336c,0x30f3,0x3400\r
+;      DE      "WJBoot - press ESC to flash\x00"\r
 BootFlashText\r
-       DT      13,10,"Send INHX8 file now...",13,10,0\r
+       DW      0x068a,0x29e5,0x3764,0x1049,0x2748,0x2c38,0x1066,0x34ec,0x32a0,0x376f,0x3bae,0x172e,0x0680\r
+;      DE      "\r\nSend INHX8 file now...\r\x00"\r
 BootRunText\r
-       DT      13,10,"Exiting loader",13,10,0\r
+       DW      0x068a,0x22f8,0x34f4,0x34ee,0x33a0,0x366f,0x30e4,0x32f2,0x0680\r
+;      DE      "\r\nExiting loader\r\x00"\r
 \r
-BootLookup\r
-       movwf   PCL                     ; Go fetch the char data\r
 \r
 ;----------------------------------------------------------------------\r
 ; EE Data (64 bytes), located at 2100h\r
 \r
         org 2100h\r
-;        data 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
+;      de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
 \r
        END\r