Hogwarts Wand Docs: ../sw/kload.asm

Wand Sourcecode: ../sw/kload.asm

;
; kload.asm - kernel loader
;
;
; Copyright (C) 2006  Nathan (Acorn) Pooley
; 
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; version 2 as published by the Free Software Foundation.
; 
; This program 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 (gpl.txt) for more details. 
; 
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
; 
; You can contact the author, Nathan (Acorn) Pooley, by writing
; to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA  94086, USA
; or through the form at http://www.rawbw.com/~acorn/wand/feedback.html
; 
;#@DOC@ This is the kernel loader - for re-flashing the kernel program to wand

;###########################################################################
;################################ KERNEL STUFF #############################
;###########################################################################

#include        "chip.inc"
#include        "kernel.inc"


    radix       dec
    expand


;###########################################################################
;###########################################################################
;################################ VARIABLES ################################
;###########################################################################
;###########################################################################


vldr_tmp1       equ 0x10    ; tmp value

vldr_endl       equ 0x11    ; end of new kernel (also size of new kernel)
vldr_endh       equ 0x12    ; 

vldr_ptrl       equ 0x13    ; address of next block to write
vldr_ptrh       equ 0x14    ; 

vldr_datl       equ 0x15    ; data
vldr_dath       equ 0x16    ; 
vldr_datu       equ 0x17    ; 


vldr_version    equ 0x18    ; version of new kernel

vldr_bits       equ 0x19    ; 

vldr_ee_data    equ 0x1a    ; 

#define bldr_first  vldr_bits,0

;
; buffer for program data
;
RAMBUF_LOADER       equ 0x200

;###########################################################################
;###########################################################################
;################################ CODE #####################################
;###########################################################################
;###########################################################################


;###########################################################################
;################################ LOADER ###################################
;###########################################################################

    org     KERNVAL_LOADER_BEGIN

loader_main:
    clrf    INTCON      ; no interrupts

    clrf    T1CON       ; Timer1 off
    clrf    T0CON       ; Timer0 off

#if (KK_CHIP!=18252)
    movlw   KERNVAL_OSCTUNE
    movwf   OSCTUNE
#endif

    movlw   KERNVAL_OSCCON
    movwf   OSCCON

    ;
    ; The following registers default values are fine
    ;
    ; WDTCON set to 0 by default (watchdog off)
    ; T2CON defaults to T2 disabled
    ; T3CON defaults to T3 disabled
    ; CCP1CON disabled by default
    ; CCP2CON disabled by default
    ; PIE1 all interrupts disabled by default
    ; PIE2 all interrupts disabled by default
    ; CMCON has all comparitors disabled by defalt
    ;

    movlw   KERNVAL_PORTA
    movwf   PORTA
    movlw   KERNVAL_TRISA
    movwf   TRISA

    movlw   KERNVAL_PORTB
    movwf   PORTB
    movlw   KERNVAL_TRISB
    movwf   TRISB

    movlw   KERNVAL_PORTC
    movwf   PORTC
    movlw   KERNVAL_TRISC
    movwf   TRISC

    movlw   KERNVAL_ADCON0
    movwf   ADCON0
    movlw   KERNVAL_ADCON1
    movwf   ADCON1
#if (KK_CHIP!=18252)
    movlw   KERNVAL_ADCON2
    movwf   ADCON2
#endif

    ;
    ; this will indicate an error if we fail right away
    ;
    movlw   ERROR_A4_LOADER
    movwf   vk_error


    ;
    ; light the first LED
    ;
    bcf     bk_led0
    rcall   ldr_pause
    rcall   ldr_pause

    ;
    ; light the second LED
    ;
    bsf     bk_led0
    bcf     bk_led1
    rcall   ldr_pause
    rcall   ldr_pause

    ;
    ; check the header of the new kernel
    ;
    clrf    TBLPTRU
    movlw   HIGH KERNVAL_LOADER_NEW_KERNEL
    movwf   TBLPTRH
    movlw   LOW  KERNVAL_LOADER_NEW_KERNEL
    movwf   TBLPTRL
    rcall   ldr_flash_read

    ;
    ; header starts at offset 0x10
    ;
    lfsr    FSR1,RAMBUF_LOADER+0x10

    movf    POSTINC1,w
    addlw   -0xa5           ; hdr[0]: 0xa5
    bnz     ldr_error

    movf    POSTINC1,w
    addlw   -0x5a           ; hdr[1]: 0x5a
    bnz     ldr_error

    movf    POSTINC1,w
    movwf   vldr_version    ; hdr[2]: new kernel version
    bz      ldr_error       ; must not be 0

    movf    POSTINC1,w
    bnz     ldr_error       ; hdr[3]: 0x00

    movf    POSTINC1,w
    bz      ldr_error       ; expect at least 0x100 bytes
    movwf   vldr_endh       ; hdr[4]: end addr (high)

    movf    POSTINC1,w
    addlw   0x80            ; add 2 blocks to end
    movwf   vldr_endl       ; hdr[5]: end addr (low)

    btfsc   STATUS,C
    incf    vldr_endh,f

    movf    vldr_endh,w
    addlw   -(HIGH KERNVAL_LOADER_BEGIN)
    bc      ldr_error       ; new kernel is too big - overlaps loader

    bra     ldr_go
    
;
; error occurred - abort
;
ldr_error:
    movlw   ERROR_A4_LOADER
    movwf   vk_error
    reset

;
; Point of no return! Start programming the new kernel!
;
ldr_go:
    ;
    ; setup block 0 to call loader_main
    ; That way if a failure occurs the loader will get restarted next boot.
    ;
    rcall   ldr_ram_clear
    lfsr    FSR1,RAMBUF_LOADER+64-4
    movlw   LOW (loader_main>>1)
    movwf   POSTINC1

    movlw   0xef        ; goto opcode
    movwf   POSTINC1
    movlw   HIGH (loader_main>>1)
    movwf   POSTINC1
    movlw   UPPER (loader_main>>1)|0xf0
    movwf   POSTINC1

    clrf    TBLPTRU
    clrf    TBLPTRH
    clrf    TBLPTRL
    rcall   ldr_flash_write

    ;
    ; light third LED
    ;
    bsf     bk_led1
    bcf     bk_led2
    rcall   ldr_pause
    rcall   ldr_pause

    ;
    ; write each block of the new kernel to flash.
    ; start with the last block.
    ;
    movff   vldr_endl,vldr_ptrl
    movff   vldr_endh,vldr_ptrh
ldr_go_loop:
    movf    vldr_ptrl,w
    iorwf   vldr_ptrh,w
    bz      ldr_done        ; done when we reach 0

    ;
    ; subract 64 (prev block)
    ;
    movlw   -0x40
    addwf   vldr_ptrl,f
    movlw   0xff
    addwfc  vldr_ptrh,f

    ;
    ; load block into ram
    ;
    movlw   LOW KERNVAL_LOADER_NEW_KERNEL
    addwf   vldr_ptrl,w
    movwf   TBLPTRL

    movlw   HIGH KERNVAL_LOADER_NEW_KERNEL
    addwfc  vldr_ptrh,w
    movwf   TBLPTRH

    rcall   ldr_flash_read

    ;
    ; write block to flash
    ;
    movf    vldr_ptrl,w
    movwf   TBLPTRL
    movf    vldr_ptrh,w
    movwf   TBLPTRH

    rcall   ldr_flash_write

    ;
    ; pause and blink leds
    ;
    rcall   ldr_pause_10
    btg     bk_led2
    btg     bk_led3
    rcall   ldr_pause_10

    ;
    ; loop to do next block
    ;
    bra     ldr_go_loop

ldr_done:
    ;
    ; light fourth LED
    ;
    bsf     bk_led2
    bsf     bk_led3
    bcf     bk_led4

    ;
    ; init eeprom
    ;
    rcall   ldr_eeprom_initialize
    
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause

    ;
    ; scroll LEDS once
    ;
    bsf     bk_led4
    bcf     bk_led3
    rcall   ldr_pause

    bsf     bk_led3
    bcf     bk_led2
    rcall   ldr_pause

    bsf     bk_led2
    bcf     bk_led1
    rcall   ldr_pause

    bsf     bk_led1
    bcf     bk_led0
    rcall   ldr_pause

    bsf     bk_led0
    bcf     bk_led1
    rcall   ldr_pause

    bsf     bk_led1
    bcf     bk_led2
    rcall   ldr_pause

    bsf     bk_led2
    bcf     bk_led3
    rcall   ldr_pause

    bsf     bk_led3
    bcf     bk_led4
    rcall   ldr_pause
    rcall   ldr_pause
    rcall   ldr_pause

    reset

;###########################################################################
;################################ PAUSE FUNCTION ###########################
;###########################################################################

;
; pause about 1/2 sec
;
ldr_pause:
    rcall   ldr_pause_10
    rcall   ldr_pause_10
    rcall   ldr_pause_10
    rcall   ldr_pause_10

;
; Pause for about 1/10 sec
;
; 1cycle = 1usec
;
; 1/10sec = 100,000 cycles
;
; 4*256 = 1024
;
; 100,000/1024 = 97
;
ldr_pause_10:
    movlw   97
    movwf   vldr_tmp1
    movlw   0x00
ldr_pause_loop:
    nop
    decfsz  WREG,w
    bra     ldr_pause_loop
    decfsz  vldr_tmp1,f
    bra     ldr_pause_loop
    
    return

;###########################################################################
;################################ FLASH FUNCTIONS ##########################
;###########################################################################

;===========================================================================
; ldr_flash_erase - erase flash block
;===========================================================================
;
; erase 64 bytes at TBLPTRH,L
;
ldr_flash_erase:

    ;
    ; ensure any pending eeprom operations are done
    ;
    rcall   ldr_eeprom_wait

    ;
    ; set up pointer
    ;
    movlw   0xc0
    andwf   TBLPTRL,f   ; align to 64 byte boundary
    clrf    TBLPTRU     ; always 0

    ;
    ; check to see if block is erased
    ;
    movlw   64
    movwf   vldr_tmp1
    tblrd*-                 ; decrement TBLPTR

ldr_flash_erase_check:
    tblrd+*                 ; read with preinc
    incf    TABLAT,w
    bnz     ldr_flash_erase_go  ; was not 0xff - need to erase it

    decfsz  vldr_tmp1,f
    bra     ldr_flash_erase_check
    
    ;
    ; all 64 read as 0xff - so we are done!
    ;
    movlw   0xc0
    andwf   TBLPTRL,f   ; align to 64 byte boundary
    return

ldr_flash_erase_go:
    ;
    ; align pointer again
    ;
    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary

    ;
    ; erase flash at TBLPTR
    ;
    bsf     EECON1,EEPGD    ; flash memory
    bsf     EECON1,FREE     ; erase (free) block (cleared automatically)
    rcall   ldr_table_write ; erase (stall here for ~2ms)

    ;
    ; loop to confirm erase
    ;
    bra     ldr_flash_erase


;===========================================================================
; ldr_flash_write - write flash block
;===========================================================================
;
; erase & write 64 bytes from RAMBUF_LOADER to TBLPTRH,L
;
ldr_flash_write:

    bsf     bldr_first

ldr_flash_write2:

    ;
    ; see if bytes already match
    ;
    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary

    movlw   64
    movwf   vldr_tmp1
    tblrd*-                 ; decrement TBLPTR

    ;
    ; input buffer is RAMBUF_LOADER
    ;
    lfsr    FSR1,RAMBUF_LOADER

ldr_flash_write_check:
    movf    POSTINC1,w
    tblrd+*                 ; read with preinc
    subwf   TABLAT,w
    bnz     ldr_flash_write_go
    decfsz  vldr_tmp1,f
    bra     ldr_flash_write_check

    ;
    ; all bytes matched - we are done!
    ;
    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary
    return

    ;
    ; not the same - erase it and write it
    ;
ldr_flash_write_go:
    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary

    btfsc   bldr_first
    rcall   ldr_flash_erase

    bsf     bldr_first

    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary

    ;
    ; write 64 bytes
    ;
    movlw   64
    movwf   vldr_tmp1
    tblrd*-                 ; decrement TBLPTR

    ;
    ; input buffer is RAMBUF_LOADER
    ;
    lfsr    FSR1,RAMBUF_LOADER

ldr_flash_write_loop:
    movf    POSTINC1,w
    movwf   TABLAT
    tblwt+*                 ; write with preinc
    decfsz  vldr_tmp1,f
    bra     ldr_flash_write_loop

    ;
    ; do the write
    ;
    bsf     EECON1,EEPGD    ; flash memory
    rcall   ldr_table_write

    ;
    ; loop back to verify write success
    ;
    bra     ldr_flash_write2

;===========================================================================
; ldr_flash_read - read flash block into ram
;===========================================================================
;
; read 64 bytes to RAMBUF_LOADER from TBLPTRH,L
;
ldr_flash_read:

    movlw   0xc0
    andwf   TBLPTRL,f       ; align to 64 byte boundary

    movlw   64
    movwf   vldr_tmp1
    tblrd*-                 ; decrement TBLPTR

    ;
    ; output buffer is RAMBUF_LOADER
    ;
    lfsr    FSR1,RAMBUF_LOADER

ldr_flash_read_loop:
    tblrd+*                 ; read with preinc
    movf    TABLAT,w
    movwf   POSTINC1
    decfsz  vldr_tmp1,f
    bra     ldr_flash_read_loop

    return


;===========================================================================
; ldr_table_write - common code for erase and write
;===========================================================================
;
; ldr_table_write - common FLASH/EEPROM write/erase sequence
;
ldr_table_write:

    ;
    ; clear interrupts during write
    ;
    clrf    INTCON

    ;
    ; enable writes
    ;
    bsf     EECON1,WREN

    ;
    ; following sequence must remain exactly the same
    ;
    movlw   0x55
    movwf   EECON2
    movlw   0xaa
    movwf   EECON2
    bsf     EECON1,WR

    ;
    ; disable writes; restore interrupts
    ;
    bcf     EECON1,WREN
    return

;===========================================================================
; ldr_ram_clear - clear ram buffer to 0xff
;===========================================================================
;
; write 64 bytes of RAMBUF_LOADER so they are all 0xff
;
ldr_ram_clear:

    movlw   64
    movwf   vldr_tmp1

    ;
    ; output buffer is RAMBUF_LOADER
    ;
    lfsr    FSR1,RAMBUF_LOADER

ldr_flash_clear_loop:
    setf    POSTINC1
    decfsz  vldr_tmp1,f
    bra     ldr_flash_clear_loop

    return

;###########################################################################
;################################ EEPROM FUNCTIONS #########################
;###########################################################################

;===========================================================================
; ldr_eeprom_wait - wait for eeprom operations to complete
;===========================================================================
    ;
    ; ldr_eeprom_wait  - wait for pending eeprom op to complete & clr EECON1
    ; ldr_eeprom_read  - read data from EEADR,EEADRH into w
    ; ldr_eeprom_write - write data in w to eeprom at EEADR,EEADRH
    ; ldr_eeprom_setup - write 0xff to EEPROM[0] so kernel will first-boot
    ;
    ; wait for any pending eeprom operation to complete
    ; clear EECON1 register
    ;
ldr_eeprom_wait:
    btfsc   EECON1,WR
    bra     ldr_eeprom_wait
    clrf    EECON1
    return

ldr_eeprom_read:
    rcall   ldr_eeprom_wait
    bsf     EECON1,RD
    movf    EEDATA,w
    return

ldr_eeprom_write:
    movwf   vldr_ee_data
ldr_eeprom_write_confirm:
    rcall   ldr_eeprom_read      ; what is there now?
    subwf   vldr_ee_data,w      ; same thing?
    btfsc   STATUS,Z
    return                      ; same - we are done!

    movff   vldr_ee_data,EEDATA

    ;
    ; do the write operation
    ;
    rcall   ldr_table_write

    ;
    ; check results
    ;
    bra     ldr_eeprom_write_confirm


;
; clear first word of eeprom to 0xff
;
ldr_eeprom_initialize:
#if (KK_CHIP!=18252)
    clrf    EEADRH              ; first byte of EEPROM
#endif
    clrf    EEADR               ; first byte of EEPROM
    setf    WREG                ; write 0xff
    bra     ldr_eeprom_write

;###########################################################################
;################################ END ######################################
;###########################################################################

    end

This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:19:56 PDT 2007