; ; 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