; ; kernel.inc - main kernel sourcecode ; ; ; 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@ main kernel sourcecode - compiled into kernel and wand programs #define SIM 0 #define KK_DEBUG 1 #define KK_VERSION 28 #ifndef KK_CHIP ;#define KK_CHIP 18252 ;#define KK_CHIP 182525 #define KK_CHIP 182620 ;#define KK_CHIP 182680 #endif #if (KK_CHIP==18252) #include "d18252.inc" #endif #if (KK_CHIP==182525) #include "d182525.inc" #endif #if (KK_CHIP==182620) #include "d182620.inc" #endif #if (KK_CHIP==182680) #include "d182680.inc" #endif radix dec expand #define KK_DEBUG_ISRSAVE 0 ;########################################################################### ;################################ CONFIG SETTINGS ########################## ;########################################################################### ; ; NOTE: ; 1 = set to 1 ; 0 = set to 0 ; . = not sure; default is 0 ; ; = not sure; default is 1 ; - = unimplemented (set to 1) ; ; 0x300000 = ? ; ; 0x300001 = CONFIG1H = 00-- 1000 ; 7 IESO = 0 two speed startup disabled ; 6 FCMEN = 0 disable fail-safe clock monitor ; 5-4 reserved = -- ; 3-0 FOSC3-0 = 1000 internal oscillator (RA6, RA7 are port bits) ; __CONFIG _CONFIG1H,0x38 ; ; 0x300002 = CONFIG2L = ---1 1001 ; 7-5 reserved = --- ; 4-3 BORV1-0 = 11 brown out voltage min value ; 2-1 BOREN1-0 = 01 brown out under SW control ; 0 /PWRTEN = 1 power up timer disbled (?) ; #if KK_VERSION>=12 __CONFIG _CONFIG2L,0xfb #else __CONFIG _CONFIG2L,0xf9 #endif ; ; 0x300003 = CONFIG2H = ---1 1110 = 0xfe ; 7-5 reserved = --- ; 4-1 WDTPS3-0 = 1111 watchdog prescale 1:32768 ; 0 WDTEN = 0 watchdog disabled ; __CONFIG _CONFIG2H,0xfe ; ; 0x300004 = ? ; ; 0x300005 = CONFIG3H = 1--- -011 = 0xfb ; 7 MCLRE = 1 MCLR enabled ; 6-3 reserved = ---- ; 2 LPT1OSC = 0 T1 osc high power mode (try low power too?) ; 1 PBADEN = 1 PortB<4:0> are analog inputs on reset ; 0 CC2P2MX = 1 CCP2 bit is multiplexed with RC1 ; __CONFIG _CONFIG3H,0xfb ; ; 0x300006 = CONFIG4L = 10-- -0-1 = 0xbb ; 7 /DEBUG = 1 debug disabled ; 6 XINST = 0 extended instruction set disabled ; 5-3 reserved = --- ; 2 LVP = 0 single-supply ICSP (programming) disabled ; 1 reserved = - ; 0 STVREN = 1 stack under/over flow causes reset ; __CONFIG _CONFIG4L,0xbb ; ; 0x300007 = ? ; ; 0x300008 = CONFIG5L = ---- 0000 = 0xf0 ; 7-4 reserved = ---- ; 3-0 CP3-0 = 0000 FLASH protected (no external r/w) ; ; __CONFIG _CONFIG5L,0xf0 __CONFIG _CONFIG5L,0xff ; ; 0x300009 = CONFIG5H = 00-- ---- = 0x3f ; 7 CPD = 0 EEPROM proteced (no external r/w) ; 6 CPB = 0 boot flash proteced (no external r/w) ; 5-0 reserved = ------ ; ; __CONFIG _CONFIG5H,0x3f __CONFIG _CONFIG5H,0xff ; ; 0x30000a = CONFIG6L = ---- 1111 = 0xff ; 7-4 reserved = ---- ; 3-0 WRT3-0 = 1111 enable table writes to flash ; __CONFIG _CONFIG6L,0xff ; ; 0x30000b = CONFIG6H = 111- ---- = 0xff ; 7 WRTD = 1 enable table writes to eeprom ; 6 WRTB = 1 enable table writes to boot flash ; 5 WRTC = 1 enable table writes to config ; 4-0 reserved = ----- ; __CONFIG _CONFIG6H,0xff ; ; 0x30000c = CONFIG7L = ---- 1111 = 0xff ; 7-4 reserved = ---- ; 3-0 EBTR3-0 = 1111 enable table read from any block ; __CONFIG _CONFIG7L,0xff ; ; 0x30000d = CONFIG7H = -1-- ---- = 0xff ; 7 reserved = - ; 6 EBTRB = 1 enable table read from any block ; 5-0 reserved = ------ ; __CONFIG _CONFIG7H,0xff ;########################################################################### ;################################ PORT SETTINGS ############################ ;########################################################################### #ifndef KERNVAL_PORTA error " KERNVAL_PORTA required: default PORTA setting" #endif #ifndef KERNVAL_TRISA error " KERNVAL_TRISA required: default TRISA setting" #endif #ifndef KERNVAL_PORTB error " KERNVAL_PORTB required: default PORTB setting" #endif #ifndef KERNVAL_TRISB error " KERNVAL_TRISB required: default TRISB setting" #endif #ifndef KERNVAL_PORTC error " KERNVAL_PORTC required: default PORTC setting" #endif #ifndef KERNVAL_TRISC error " KERNVAL_TRISC required: default TRISC setting" #endif #ifndef KERNVAL_TRISB_LED_MASK error " KERNVAL_TRISB_LED_MASK required: set bits which are LED outputs" #endif #ifndef bki_alive error " bki_alive required: bit to toggle to show its running" #endif #ifndef bki_led_alive error " bki_led_alive required: bit to toggle to show its working" #endif #ifndef bki_led_serial error " bki_led_serial required: bit to toggle when serial i/o occurs" #endif #define bki_serial_detect PORTC,RX ;########################################################################### ;################################ BOOT SETTINGS ############################ ;########################################################################### ; ; INTCON2 = 1111 0000 ; 7 /RBPU = 1 disable portB pullup resistors ; 6 INTEDG0 = 1 rising edge for intr0 ; 5 INTEDG1 = 1 rising edge for intr1 ; 4 INTEDG2 = 1 rising edge for intr2 ; 3 reserved = 0 ; 2 TMR0IP = 0 T0 isr is low priority ; 1 reserved = 0 ; 0 RBIP = 0 portB change interrupt is low priority ; KERNVAL_INTCON2 equ 0xf0 ; ; INTCON3 = 0000 0000 ; 7 INT2IP = 0 intr2 is low priority ; 6 INT1IP = 0 intr1 is low priority ; 5 reserved = 0 ; 4 INT2IE = 0 intr2 disabled ; 3 INT1IE = 0 intr1 disabled ; 2 reserved = 0 ; 1 INT2IF = 0 intr2 flag cleared ; 0 INT1IF = 0 intr1 flag cleared ; KERNVAL_INTCON3 equ 0x00 ; ; internal oscillator control ; ; OSCTUNE = 1000 0000 ; ; 7 INTSRC = 1 31kHz clock from 8MHz internal clock ; 6 PLLEN = 0 PLL off ; 5 reserved = 0 ; 4-0 TUN4-0 = 00000 tune to center frequency ; KERNVAL_OSCTUNE equ 0x80 ; ; OSCCON = 1110 0000 ; ; 7 IDLEN = 1 entire IDLE on SLEEP instruction ; 6-4 IRCF2-0 = 110 4MHz clock ; 3 OSTS = 0 (read-only) ; 2 IOFS = 0 (read-only) ; 1-0 SCS1-0 = 00 Primary oscillator (from config bits) ; KERNVAL_OSCCON equ 0xe0 ; ; T0CON = 0000 1000 ; ; 7 TMR0ON = 0 T0 off (not running) ; 6 T08BIT = 0 T0 is 16 bit counter ; 5 T0CS = 0 clock source=FOSC ; 4 T0SE = 0 increment on low-to-hi ; 3 PSA = 1 prescaler not used ; 2-0 T0PS2-0 = 000 1:2 prescale (not used) ; KERNVAL_T0CON equ 0x08 ; ; T1CON = 0111 1111 ; ; 7 RD16 = 0 8 bit reads/writes ; 6 T1RUN = 1 use t1 Oscillator ; 5-4 T1CKPS1-0 = 11 1:8 prescale ; 3 T1OSCEN = 1 t1 osc enabled ; 2 /T1SYNC = 1 do not syncronize external clock input ; 1 TMR1CS = 1 external clock ; 0 TMR1ON = 1 t1 on (running) ; ; 32768 Hz / 8 = 4096 HZ ; TMR1L wraps 4096Hz/256 = 16Hz = every 0.0625 sec ; TMR1H wraps 16Hz/256 = every 16 seconds ; ; TMR1H = ssss qqff ; ssss = seconds ; qq = quarter seconds ; ff = fractions of quarter seconds ; KERNVAL_T1CON equ 0x7f ; ; RCON = 1101 1111 ; 7 IPEN = 1 enable intr priority levels ; 6 SBOREN = 1 enable brown-out reset ; 5 reserved = 0 ; 4 /RI = 1 set to 0 on reset instruction ; 3 /TO = 1 read-only (set to 0 if WDT times out) ; 2 /PD = 1 read-only (set to 0 if MCLR or WDT) ; 1 /POR = 1 this is set to 0 on power up ; 0 /BOR = 1 this is set to 0 on brown-out or power up ; KERNVAL_RCON equ 0xdf ; ; ADCON0 = 0000 0000 ; 7-6 reserved 00 ; 5-2 CHS3-0 0000 select channel 0 ; 1 GO/DONE 0 do not start conversion ; 0 ADON 0 A/D unit off ; KERNVAL_ADCON0 equ 0x00 ; ; ADCON1 = 0000 0000 ; 7-6 reserved 00 ; 5 VCFG1 0 Vref- = Vss ; 4 VCFG0 0 Vref+ = Vdd ; 3-0 PCFG3-0 0000 all available pins set as analog inputs ; KERNVAL_ADCON1 equ 0x00 ; ; ADCON2 = 0001 0001 ; 7 ADFM = 0 left justified formt) ; 6 reserved = 0 ; 5-3 ACQT2-0 = 010 4 Tad cycles for acquisition ; 2-0 ADCS2-0 = 001 A/D conversion clock = Fosc/8 (Tad = 2usec) ; KERNVAL_ADCON2 equ 0x11 ; ; TXSTA ; ; 7 CSRC = 0 dont care ; 6 TX9 = 0 use 8 bit data ; 5 TXEN = 0 transmit disabled ; 4 SYNC = 0 Async mode ; 3 SENDB = 0 do not send sync break ; 2 BRGH = 1 ; 1 TRMT = 0 read-only ; 0 TX9D = 0 dont care ; KERNVAL_TXSTA equ 0x24 ; ; RCSTA ; ; 7 SPEN = 1 enable serial port ; 6 RX9 = 0 use 8 bit data ; 5 SREN = 0 dont care ; 4 CREN = 1 receive enable ; 3 ADDEN = 0 dont care ; 2 FERR = 0 read-only ; 1 OERR = 0 read-only ; 0 RX9D = 0 read-only ; KERNVAL_RCSTA equ 0x90 ; ; BAUDCON ; ; 7 ABDOVF = 0 dont care ; 6 RCIDL = 0 read-only ; 5 reserved = 0 ; 4 SCKP = 0 dont care ; 3 BRG16 = 0 ; 2 reserved = 0 ; 1 WUE = 0 disable wakeup interrupt ; 0 ABDEN = 0 disable auto-baud rate detect ; KERNVAL_BAUDCON equ 0x00 ; ; SPBRG ; 9600 baud: 1ms per byte ; 186000 baud: 53 usec per byte (too fast) ; B ; R B ; G R ; 1 G ; 6 H ; - - ; 0 0 rate = 4MHz/(64(n+1)) = 9600 ; n = 4MHz/(64*9600) - 1 = 5.5 ; (n=5) rate = 10416 ; (n=6) rate = 8928 ; ; 0 1 rate = 4MHz/(16(n+1)) = 9600 ; or n = 4MHz/(16*9600) - 1 = 25.04 ; 1 0 (n=25) rate = 9615 ; (n=26) rate = 9259 ; ; 1 1 rate = 4MHz/(4(n+1)) = 9600 ; n = 4MHz/(4*9600) - 1 = 103.17 ; (n=103) rate = 9615 ; (n=104) rate = 9523 ; ; USE ; BRG16 = 0 ; BRGH = 1 ; SPBRG = 25 ; SPBRGH = 0 (dont care) ; KERNVAL_SPBRG equ 25 ; CMCON ; 7 C2OUT 0 read-only ; 6 C1OUT 0 read-only ; 5 C2INV 0 not inverted ; 4 C1INV 0 not inverted ; 3 CIS 0 dont care ; 2-0 CM2-CM0 111 comparitors off ; KERNVAL_CMCON equ 0x07 ; This is the reset value ;########################################################################### ;########################################################################### ;################################ MACROS ################################### ;########################################################################### ;########################################################################### ; ; Macros ; ; COUT - print character in w ; COUTCR - print character in w followed by CR ; SOUT - print string ; SOUT0 - print string from str_base0 string table ; ERR - error occurred ; ERRL - error occurred ; BRKPT - cause a breakpoint ; ; SET_LED - set DEBUG LED value ; DB_WHERE - Remember where in the code we are (DEBUG) ; DB_WHERE2 - Remember where in the code we are (DEBUG) ; DB_IWHERE - Remember where in the code we are (DEBUG) ; EEPROM_BEGIN - prepare to read/write eeprom at offset ; EEPROM_READ1 - read byte from eeprom into w ; SET_RUNSTATE - set current runstate to vki_runstate_* ; ; ; COUT - print character in w ; COUT macro char movlw char rcall kk_cout endm COUTL macro char movlw char call kk_cout endm ; ; COUTCR - print character in w ; COUTCR macro char movlw char rcall kk_cout rcall kk_outcr endm COUTCRL macro char movlw char call kk_cout call kk_outcr endm ; ; SOUT - print string ; SOUT macro str_addr movlw LOW str_addr movwf TBLPTRL movlw HIGH str_addr rcall kk_sout_wh endm SOUTL macro str_addr movlw LOW str_addr movwf TBLPTRL movlw HIGH str_addr call kk_sout_wh endm ; ; SOUT - print string from str_base0 string table ; SOUT0 macro str_addr movlw str_addr-kki_str_base0 rcall kki_sout_base0 endm SOUT0L macro str_addr movlw str_addr-kki_str_base0 call kki_sout_base0 endm ; ; ERR - error occurred ; ERR macro errnum movlw errnum bra kk_doerror endm ERRL macro errnum movlw errnum goto kk_doerror endm ; ; BRKPT - cause a breakpoint ; BRKPT macro brknum movwf vki_breakpt_w movlw brknum rcall kk_dobreak endm BRKPTL macro brknum movwf vki_breakpt_w movlw brknum call kk_dobreak endm ; ; SET_LED - set DEBUG LED value ; SET_LED macro trisb_val movlw trisb_val rcall kki_led_set endm ; ; DB_WHERE - Remember where in the code we are (DEBUG) ; DB_WHERE macro wh movlw wh movwf vk_where endm ; ; DB_WHERE2 - Remember where in the code we are (DEBUG) ; DB_WHERE2 macro wh movlw wh movwf vk_where2 endm ; ; DB_IWHERE - Remember where in the code we are (DEBUG) ; DB_IWHERE macro wh movlw wh movwf vk_iwhere endm ; ; EEPROM_BEGIN - prepare to read/write eeprom at offset ; EEPROM_BEGIN macro offset movlw offset-1 ; kk_eeprom_read pre-increments movwf EEADR endm ; ; EEPROM_READ1 - read 1 byte from eeprom into w ; EEPROM_READ1 macro offset EEPROM_BEGIN offset rcall kk_eeprom_read ; read eeprom into w endm ; ; SET_RUNSTATE - set current runstate to kki_runstate_* ; SET_RUNSTATE macro runstate movlw runstate-kki_runstate_table rcall kki_set_runstate endm ;########################################################################### ;################################ ERRORS & BREAKPOINTS ##################### ;########################################################################### ERROR_A1_TIME4SEC equ 0xa1 ; kk_main_run not called for >4 sec ERROR_A2_STACK equ 0xa2 ; stack over/under flow ERROR_A3_RUNSTATE equ 0xa3 ; bad runstate offset ERROR_A4_LOADER equ 0xa4 ; kernel loader failed ERROR_A5_TX equ 0xa5 ; error in tx registers ;########################################################################### ;########################################################################### ;################################ VARIABLES ################################ ;########################################################################### ;########################################################################### ; ; kk_* - kernel public label ; vk_* - kernel public byte variables ; bk_* - kernel public bit variables ; ; kki_* - kernel private label ; vki_* - kernel private byte variables ; bki_* - kernel private bit variables ; ; vaddr - next free RAM byte ; variable vaddr=0 ;########################################################################### ;################################ SFR REGISTER NOTES ####################### ;########################################################################### ; FSR0 is used as a general purpose FSR register. The main program may use it ; but must assume it may be scrambled when kk_main_run or other kernel ; functions are called. ; ; FSR1 is used by the kernel, but its value is always saved. Therefore it ; cannot be used in ISR rotines, but otherwise can be assumed to maintain ; its value. It is also used as a paramter in kk_eeprom_write. ; ; FSR2 is not used by the kernel at all ; ;########################################################################### ;################################ EEPROM LAYOUT ############################ ;########################################################################### EEPROM_A5 equ 0x0000 ; set to 0xa5 if valid EEPROM_VERSION equ 0x0001 ; set to EEPROM_VERSION_VALUE if valid EEPROM_RUNSTATE equ 0x0002 ; run state - see vki_runstate_bits EEPROM_HOUR equ 0x0003 ; last recorded hour EEPROM_MINUTE equ 0x0004 ; last recorded minute EEPROM_END equ 0x0005 ; first unused eeprom location EEPROM_VERSION_VALUE equ KK_VERSION ;########################################################################### ;################################ PERSISTANT GLOBAL VARIABLES ############## ;########################################################################### ; ; These variables are preserved across warm boot. ; ;=========================================================================== ; These variables have specific addesses (DO NOT CHANGE THEM!!) ;=========================================================================== ; ; The loader & debugger access these variables, so they should always stay ; at the same address. ; vki_runstate_bits equ 0x0000 ; kernel runstate bits vk_error equ 0x0001 ; current error code (0 if not in err mode) vk_breakpt equ 0x0002 ; current or most recent breakpoint code vaddr=3 ;=========================================================================== ; RUNSTATE ;=========================================================================== vki_runstate_prompt equ vaddr+0 vaddr+=1 ; ; bits in vki_runstate_bits ; #define bk_rs_debug vki_runstate_bits,0 ; debug (always set in halt) #define bk_rs_halt vki_runstate_bits,1 ; halted (only run boot code) #define bki_rs_breakpt vki_runstate_bits,2 ; set if breakpoint occurred #define bki_rs_error vki_runstate_bits,3 ; set if error occurred #define bki_rs_warmboot vki_runstate_bits,5 ; set to do a warm boot restart ; ; valid vki_runstate_bits values ; RUNSTATE_BITS_BREAK equ 0x07 ; xxxx x1xx breakpoint (debug) RUNSTATE_BITS_ERROR equ 0x0b ; xxxx 10xx error occurred (debug) ; xx10 00xx warmboot RUNSTATE_BITS_HALT equ 0x03 ; xx00 001x halted (debug) RUNSTATE_BITS_DEBUG equ 0x01 ; xx00 0001 running in debug mode RUNSTATE_BITS_RUN equ 0x00 ; xx00 0000 running in non-debug mode ;=========================================================================== ; state variables ;=========================================================================== vk_persisth equ vaddr+0 ; # of bytes at end of memory to save on reset vk_persistl equ vaddr+1 ; # of bytes at end of memory to save on reset vaddr+=2 ;=========================================================================== ; time variables ;=========================================================================== vk_hour equ vaddr+0 ; hour - 0-23=day0 24-47=day1 etc. clamp 255 vk_minute equ vaddr+1 ; minute - 0-59 vk_qsec equ vaddr+2 ; quarter second - 0-239 vaddr+=3 ;=========================================================================== ; debugging variables ;=========================================================================== #if KK_VERSION<19 vk_breakpt1 equ vaddr+0 ; current or most recent breakpoint code vk_breakpt2 equ vaddr+1 ; current or most recent breakpoint code vk_breakpt3 equ vaddr+2 ; current or most recent breakpoint code vk_breakpt4 equ vaddr+3 ; current or most recent breakpoint code vk_breakpt5 equ vaddr+4 ; current or most recent breakpoint code vaddr+=5 #endif #if KK_VERSION>=19 #define bk_boot_serial_enabled vk_boot0_bbits,0 #define bk_boot_first vk_boot0_bbits,1 #define bk_boot_cold vk_boot0_bbits,2 #define bk_boot_warm vk_boot0_bbits,3 #define bk_boot_common vk_boot0_bbits,4 vk_boot0_bbits equ vaddr+0 ; boot bits (for debugging) vk_boot0_runstate equ vaddr+1 ; runstate at boot (from EEPROM) vaddr+=2 #endif vk_boot0_error equ vaddr+0 ; vk_error at last boot vk_boot1_error equ vaddr+1 ; vk_error at previous boot vk_boot2_error equ vaddr+2 ; vk_error 2 boots ago vk_boot0_rcon equ vaddr+3 ; RCON at last boot vk_boot1_rcon equ vaddr+4 ; RCON at last boot vk_boot2_rcon equ vaddr+5 ; RCON at last boot vk_boot3_rcon equ vaddr+6 ; RCON at last boot vk_boot0_stkptr equ vaddr+7 ; STKPTR at last boot vaddr+=8 vk_where equ vaddr+0 ; where in program we are (top level) vk_where2 equ vaddr+1 ; where in kernel subroutines we are vk_iwhere equ vaddr+2 ; where in isr we are (0=not in isr) vaddr+=3 ;=========================================================================== ; persistant local variables ;=========================================================================== vki_last_tmr1h equ vaddr+0 ; last checked TMR1H value vki_tmp1 equ vaddr+1 ; temporary variable vki_tmp2 equ vaddr+2 ; temporary variable vki_tmp3 equ vaddr+3 ; temporary variable vki_ten equ vaddr+4 ; const: '9'+1 vaddr+=5 KERN_RAM_PERSIST equ vaddr ;########################################################################### ;################################ GLOBAL VARIABLES ######################### ;########################################################################### ;=========================================================================== ; global bit variables ;=========================================================================== #define bk_qsec vk_time_bits,0 ; set one main-loop every quarter sec #define bk_minute vk_time_bits,1 ; set one main-loop every minute #define bk_hour vk_time_bits,2 ; set one main-loop every hour ;=========================================================================== ; parameter passing ;=========================================================================== vk_w equ vaddr+0 ; w is restored from here in kk_jump vaddr+=1 ;########################################################################### ;################################ LOCAL VARIABLES ########################## ;########################################################################### ;=========================================================================== ; generic variables ;=========================================================================== vki_lbits0 equ vaddr+0 ; bit variables vaddr+=1 ;=========================================================================== ; saving values ;=========================================================================== vki_breakpt_w equ vaddr+0 ; WREG when breakpt occurred vaddr+=1 vki_fsr1l_save equ vaddr+0 ; save FSR1 (in kki_serial_rx) vki_fsr1h_save equ vaddr+1 ; save FSR1 (in kki_serial_rx) vaddr+=2 vki_led_val equ vaddr+0 ; halt LED value vaddr+=1 vki_isrl_save_s equ vaddr+0 ; save s in isrl vki_isrl_save_w equ vaddr+1 ; save w in isrl vki_isrl_save_fsr0l equ vaddr+2 ; save FSR0L in isrl vki_isrl_save_fsr0h equ vaddr+3 ; save FSR0H in isrl vaddr+=4 ;=========================================================================== ; time variables ;=========================================================================== vk_time_bits equ vaddr+0 ; contains time bit variables. Cleared each loop vaddr+=1 ;=========================================================================== ; serial tx variables ;=========================================================================== vk_tx_cnt equ vaddr+0 ; # of chars in tx buffer vki_tx_head equ vaddr+1 ; where next char will go vki_tx_tail equ vaddr+2 ; next char to send vki_tx_ctime equ vaddr+3 ; TMR1H when last char was sent vki_tx_cksum equ vaddr+4 ; sum of chars sent on line vaddr+=5 #if KK_VERSION>=17 vki_tx_gap_cnt equ vaddr+0 ; chars left before gap insert vaddr+=1 #endif #define bki_tx_overflow vki_lbits0,0 ; set on overflow, clr on buf empty #define bki_tx_docksum vki_lbits0,1 ; set to send checksum each line ;=========================================================================== ; serial rx variables ;=========================================================================== #define bki_rx_err_oflow vki_rx_error,0 ; bit 0: overflow buffer #define bki_rx_err_orun vki_rx_error,OERR ; bit 1: overrun error #define bki_rx_err_frame vki_rx_error,FERR ; bit 2: frame error #define bki_rx_err_badchar vki_rx_error,3 ; bit 3: bad char #define bki_rx_err_txfull vki_rx_error,4 ; bit 4: tx buffer full #define bki_rx_new vki_rx_state,0 ; new char available #define bki_rx_synerr vki_rx_state,1 ; syntax error parsing command #define bki_rx_write vki_rx_state,2 ; write command #define bki_rx_rw_ram vki_rx_state,3 ; r/w ram command #define bki_rx_rw_flash vki_rx_state,4 ; r/w flash command #define bki_rx_rw_eeprom vki_rx_state,5 ; r/w eeprom command #if KK_VERSION>=27 #define bki_rx_fdump vki_rx_state,6 ; fast flash dump command #define bki_tx_flushing vki_rx_state,7 ; flushing tx buffer #endif KERNVAL_RX_STATE_READ equ 0x38 ; all rw bits vki_rx_error equ vaddr+0 ; rx error bits vki_rx_head equ vaddr+1 ; next buffer byte to write vki_rx_echo equ vaddr+2 vki_rx_tail equ vaddr+3 ; next byte to echo vki_rx_state equ vaddr+4 ; command state bits vki_rx_cnt equ vaddr+5 ; # data bytes in command vki_rx_cmd equ vaddr+6 ; current command (ASCII) vki_rx_rw_ptrh equ vaddr+7 ; r/w command data pointer (low) vki_rx_rw_ptrl equ vaddr+8 ; r/w command data pointer (high) vki_rx_err_badchar equ vaddr+9 ; bad rx char vaddr+=10 ;=========================================================================== ; buffers ;=========================================================================== RAMBUF_TX equ 0x100 ; serial transmit buffer (256 bytes) RAMBUF_RX equ 0x200 ; command byte buffer (256 bytes) ;########################################################################### ;################################ RESET CODE ############################### ;########################################################################### org 0x0000 bra kk_boot #if SIM kk_breakpt: return kk_error: return #endif ;########################################################################### ;################################ ISR CODE ################################# ;########################################################################### ; ; high priority isr ; org 0x0008 goto kk_app_isr_high ; ; Data record at 0x0010 ; ; addr value ; ------ ---------- ; 0x0010 0xa5 ; 0x0011 0x5a ; 0x0012 KK_VERSION ; 0x0013 <unused> ; 0x0014 high byte of kk_app_main ; 0x0015 low byte of kk_app_main ; 0x0016 <unused> ; 0x0017 <unused> ; org 0x0010 db 0xa5, 0x5a db KK_VERSION, 0 db HIGH kk_app_main, LOW kk_app_main db 0,0 ; ; low priority isr ; org 0x0018 movff STATUS,vki_isrl_save_s movwf vki_isrl_save_w movff FSR0L,vki_isrl_save_fsr0l movff FSR0H,vki_isrl_save_fsr0h DB_IWHERE 1 bra kki_isrl_begin org 0x40 ; 2nd 64-byte flash block ; ; If we reach here it means that the first 64 bytes are hosed (probably ; erased to 0xff which is a nop). This probably means we are running ; the loader and it failed after clearing the first block of memory. ; Jump to the loader address to continue loading. ; goto KERNVAL_LOADER_BEGIN kki_isrl_begin: #if KK_DEBUG_ISRSAVE vki_sv_intcon equ vaddr+0 vki_sv_intcon2 equ vaddr+1 vki_sv_intcon3 equ vaddr+2 vki_sv_PIE1 equ vaddr+3 vki_sv_PIE2 equ vaddr+4 vki_sv_PIR1 equ vaddr+5 vki_sv_PIR2 equ vaddr+6 vki_sv_IPR1 equ vaddr+7 vki_sv_IPR2 equ vaddr+8 vki_sv_RCON equ vaddr+9 vki_sv_RCSTA equ vaddr+10 vki_sv_TXSTA equ vaddr+11 vki_sv_STKPTR equ vaddr+12 vki_sv2_PIE1 equ vaddr+13 vki_sv2_PIR1 equ vaddr+14 vaddr+=15 movff INTCON,vki_sv_intcon movff INTCON2,vki_sv_intcon2 movff INTCON3,vki_sv_intcon3 movff PIE1,vki_sv_PIE1 movff PIE2,vki_sv_PIE2 movff PIR1,vki_sv_PIR1 movff PIR2,vki_sv_PIR2 movff IPR1,vki_sv_IPR1 movff IPR2,vki_sv_IPR2 movff RCON,vki_sv_RCON movff RCSTA,vki_sv_RCSTA movff TXSTA,vki_sv_TXSTA movff STKPTR,vki_sv_STKPTR #endif ; ; jump to application low priority isr (unless halted) ; kki_isrl_user: btfss bk_rs_halt call kk_app_isr_low ; ; serial RX isr ; kki_isrl_rx: DB_IWHERE 2 #if SIM bcf b_rcie ; ; SIM RX - put bytes to read at 0x300 (0 terminate) ; vki_sim_rcreg equ vaddr+0 vaddr+=1 btfss b_int1if bra kki_isrl_return bcf b_int1if lfsr FSR0,0x300 movf POSTINC0,w bz kki_isrl_return movwf vki_sim_rcreg vki_isrl_rx_sim_loop: movf POSTDEC0,w movwf POSTINC0 movf POSTINC0,w bnz vki_isrl_rx_sim_loop #endif ; ; got an RX character! ; ; SPECIAL RX CHARACTERS: ; any negative char: error ; CR (0x0d): end of command ; LF (0x0a): end of command ; ^C (0x03): ignore preceding command ; ^X (24): ignore preceding command ; ; SPECIAL CHARS IN BUFFER: ; 0xff: end of command ; 0xfe: ignore preceding command ; 0xfd: error ; other negative: error ; movf vki_rx_error,w bnz kki_isrl_rx_err_end ; error - ignore incoming chars DB_IWHERE 3 lfsr FSR0,RAMBUF_RX movff vki_rx_head,FSR0L bsf bki_rx_new btg bki_led_serial movf RCSTA,w andlw 0x06 ; FERR or OERR bits set? bnz kki_isrl_rx_fault #if KK_VERSION<18 btfsc bki_tx_overflow bra kki_isrl_rx_txfull #endif DB_IWHERE 4 #if SIM movf vki_sim_rcreg,w #else btfss b_rcif ; PIR1,5 bra kki_isrl_return movf RCREG,w ; get RX byte and clear RCIF #endif bn kki_isrl_rx_badchar bz kki_isrl_rx_badchar kki_isrl_rx_store: movwf INDF0 addlw -0x0a bz kki_isrl_rx_cr ; got LF? store a 0xff addlw 0x0a-0x0d bz kki_isrl_rx_cr ; got CR? store a 0xff addlw 0x0d-3 ; ctrl-C? store a 0xfe bz kki_isrl_rx_kill addlw 3-24 ; ctrl-X? store a 0xfe bz kki_isrl_rx_kill DB_IWHERE 5 kki_isrl_rx_next: incf vki_rx_head,f ; next buffer loc incf vki_rx_head,w ; are we right before tail? subwf vki_rx_tail,w bnz kki_isrl_return ; ; overflowed buffer here (1 spot left) ; store error code in extra spot ; DB_IWHERE 6 bsf bki_rx_err_oflow movlw 0xfd movwf INDF0 bra kki_isrl_rx_err_end ; ; end of line conditions: ; rx error (store 0xfd) ; badchar (store 0xfd) ; kill (store 0xfe) ; cr (store 0xff) ; kki_isrl_rx_fault: iorwf vki_rx_error,f ; set error bit 0x2 and/or 0x4 bra kki_isrl_rx_err kki_isrl_rx_badchar: movwf vki_rx_err_badchar bsf bki_rx_err_badchar #if KK_VERSION<18 bra kki_isrl_rx_err kki_isrl_rx_txfull: bsf bki_rx_err_txfull #endif kki_isrl_rx_err: movlw 0xff ; 0xff -1 -1 = 0xfd = error kki_isrl_rx_kill: decf WREG,w ; store 0xfe (kill) into buf kki_isrl_rx_cr: decf WREG,w ; store 0xff (end-of-command) bra kki_isrl_rx_store kki_isrl_rx_err_end: movf RCREG,w ; clear interrupt flag bcf b_rcie ; disable receive interrupts kki_isrl_return: #if KK_DEBUG_ISRSAVE movff PIE1,vki_sv2_PIE1 movff PIR1,vki_sv2_PIR1 #endif DB_IWHERE 0 movff vki_isrl_save_fsr0h,FSR0H movff vki_isrl_save_fsr0l,FSR0L movf vki_isrl_save_w,w movff vki_isrl_save_s,STATUS retfie 0 ;########################################################################### ;################################ STRINGS ################################## ;########################################################################### kki_str_base0: kki_str_rx_syntax_err: db "Syntax\0" kki_str_rx_badcmd_err: db "Bad Cmd\0" kki_str_rx_illcmd_err: db "Illegal Cmd\0" kki_str_ram: db "ram 0x\0" kki_str_eeprom: db "eeprom 0x\0" kki_str_flash: db "flash 0x\0" kki_str_prompt_run: db "Run> \0" kki_str_prompt_debug: db "Debug> \0" kki_str_prompt_halt: db "Halt> \0" kki_str_prompt_error: db "Error> \0" kki_str_prompt_break: db "Break> \0" kki_str_hello: db "Hello! Kernel 0x\0" kki_str_error: db "Error: \0" kki_str_error_rx: db "RX=\0" kki_str_rarrow: db " -> \0" kki_str_written: db "Written\0" kki_str_tx_overflow: db "...tx err...\0" kki_str_boot: db "==Boot==\0" kki_str_errboot: db "==ErrBoot==\0" kki_str_tick: db "tick\0" kki_str_kill: db "<kill>\0" kki_str_00: db "00:\0" kki_str_help: db "H Halt \n" db "R Run\n" db "D Debug\n" db "G Go (brk/err) \n" db "J Jump \n" db "P Prog \n" db "E Eeprom \n" db "V Var\n" #if KK_VERSION>=27 db "F Fast dump\n" #endif db "C Restart\n" db "M Warm Reset \n" db "B Cold Reset \n" db "S Cksum\n" db "I instructions \n\0" ;########################################################################### ;################################ SUBROUTINES ############################## ;########################################################################### ; ; kki_led_set - set LED state to w ; kki_led_check - set LEDs to saved value ; kki_led_set: movwf vki_led_val kki_led_check: movlw KERNVAL_TRISB_LED_MASK iorwf TRISB,f movf vki_led_val,w iorlw (~KERNVAL_TRISB_LED_MASK)&0xff andwf TRISB,f return ;########################################################################### ;################################ BOOT CODE ################################ ;########################################################################### ;=========================================================================== ; kk_boot - reset entry point ;=========================================================================== kk_boot: movlw KERNVAL_T1CON movwf T1CON kk_boot2: #if (KK_CHIP!=18252) movlw KERNVAL_OSCTUNE movwf OSCTUNE #endif movlw KERNVAL_OSCCON movwf OSCCON movlw KERNVAL_T0CON movwf T0CON ; avoid setting TMR1L,TMR1H ; cold reset - arbitrary value ; warm reset - continue with old value ; ; 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 ; ; ; all interrupts off ; clrf INTCON movlw KERNVAL_PORTA movwf PORTA movlw KERNVAL_TRISA movwf TRISA movlw KERNVAL_PORTB movwf PORTB movlw KERNVAL_TRISB movwf TRISB #if KK_VERSION<24 movlw KERNVAL_ADCON1 movwf PORTA #endif 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 ; ; save first 0x100 bytes of ram to 0x500 (DEBUG) ; movlw 0x00 lfsr FSR0,0x0000 lfsr FSR1,0x0500 kki_zpdump_loop: movff POSTINC0,POSTINC1 decfsz WREG,w bra kki_zpdump_loop ; ; save some boot values ; movff vk_boot2_rcon,vk_boot3_rcon movff vk_boot1_rcon,vk_boot2_rcon movff vk_boot0_rcon,vk_boot1_rcon movff RCON,vk_boot0_rcon movff STKPTR,vk_boot0_stkptr #if KK_VERSION>=19 clrf vk_boot0_bbits #endif #if KK_DEBUG ; ; save and clear stack ; movlw 32 lfsr FSR0,0x400 kki_stkdump_loop: clrf POSTINC0 movff TOSU,POSTINC0 movff TOSH,POSTINC0 movff TOSL,POSTINC0 clrf TOSU clrf TOSH clrf TOSL incf STKPTR,f decfsz WREG,w bra kki_stkdump_loop #endif clrf STKPTR kki_constants: ; ; always keep TBLPTRU, PCLATU, and EEADRH clear ; clrf TBLPTRU clrf PCLATU #if (KK_CHIP!=18252) clrf EEADRH #endif DB_WHERE 1 #if KK_VERSION>=19 ; ; serial enabled at boot time? (detect low = not attached) ; btfsc bki_serial_detect bsf bk_boot_serial_enabled #endif kki_eeprom_check: setf EEADR ; EEADR=0xff (next read will come from ++EEADR == 0) ; ; first byte should be 0xA5 ; rcall kk_eeprom_read addlw -0xa5 bnz kki_boot_first ; ; second byte should match EEPROM_VERSION_VALUE ; rcall kk_eeprom_read addlw -EEPROM_VERSION_VALUE bnz kki_boot_first #if KK_VERSION>=19 ; ; read runstate from eeprom ; rcall kk_eeprom_read movwf vk_boot0_runstate #endif ; ; check for cause of reset ; #if KK_VERSION>=19 btfss vk_boot0_rcon,POR #else btfss RCON,POR #endif bra kki_boot_cold ; powerup reset ; ; user-requested warm boot? ; btfsc bki_rs_warmboot bra kki_boot_warm ; ; All other resets are error conditions: ; ; reset instruction (RCON,RI is clear) ; stack overflow (STKPTR,STKFUL is set) ; stack underflow (STKPTR,STKUNF is set) ; watchdog reset (RCON,TO is clear) ; brown out reset (RCON,BOR is clear) ; MCLR reset (if none of the above are true) ; ;=========================================================================== ; kki_boot_error - jump here if an error caused the reset ;=========================================================================== #if KK_DEBUG kki_boot_error: DB_WHERE 2 ; ; save old errors ; movff vk_boot1_error,vk_boot2_error movff vk_boot0_error,vk_boot1_error movff vk_error,vk_boot0_error ; ; always run error code if not in RUNSTATE_RUN ; btfsc bk_rs_debug bra kki_boot_error2 ; debug mode - run error code ; ; In RUNSTATE_RUN most resets should continue, but reset button ; should jump to error code if serial port is connected. ; Figure out what kind of reset this is and do the right thing. ; ; ; if any of these bits in RCON are clear then cold boot: ; 0x10 RI - reset instruction if 0 ; 0x08 TO - watch dog timeout if 0 ; 0x02 POR - power on reset if 0 (this is caught above) ; 0x01 BOR - brown out reset if 0 ; comf vk_boot0_rcon,w ; invert bits of RCON boot value andlw 0x1b ; check RI, TO, POR, and BOR bnz kki_boot_cold ; ; If these bits in STKPTR are set then cold boot: ; 0x80 STKFUL - stack full ; 0x40 STKUNF - stack undeflow ; movf vk_boot0_stkptr,w andlw 0xc0 ; check STKFUL, and STKUNF bnz kki_boot_cold ; ; Otherwise a mclr reset occurred - ; ; ; Here one of these two situations has occurred: ; - the reset button was pressed ; - an error occurred while we were not in RUNSTATE_RUN ; kki_boot_error2: ; ; If serial is low (not attached) then jump to coldboot ; #if !SIM btfss bki_serial_detect bra kki_boot_cold #endif ; ; Error occurred. Could be ; reset instruction (RCON,RI is clear) ; stack overflow (STKPTR,STKFUL set) ; stack underflow (STKPTR,STKUNF set) ; vk_error contains the error code ; SET_RUNSTATE kki_runstate_error rcall kk_serial_enable SOUT0 kki_str_errboot rcall kki_cr_prompt kki_boot_error_loop: rcall kk_main_run rcall kki_led_check ; ; loop in error until cleared ; btfsc bki_rs_error bra kki_boot_error_loop DB_WHERE 3 SET_RUNSTATE kki_runstate_halt clrf vk_error #endif bra kki_boot_cold ;=========================================================================== ; kki_boot_first - jump here on first kk_boot ever (or eeprom scrambled) ;=========================================================================== kki_boot_first: ; ; first time booting with this eeprom version ; ; ; init eeprom ; DB_WHERE 4 EEPROM_BEGIN EEPROM_A5 ; start writing at EEPROM_A5 movlw 0xa5 rcall kk_eeprom_write ; EEPROM_A5 movlw EEPROM_VERSION_VALUE rcall kk_eeprom_write ; EEPROM_VERSION movlw kki_runstate_halt-kki_runstate_table rcall kk_eeprom_write ; EEPROM_RUNSTATE movlw 0x00 rcall kk_eeprom_write ; EEPROM_HOUR movlw 0x00 rcall kk_eeprom_write ; EEPROM_MINUTE #if KK_VERSION>=19 bsf bk_boot_first #endif ; fall through to kki_boot_cold ;=========================================================================== ; kki_boot_cold - jump here for power-on resets ;=========================================================================== kki_boot_cold: ; ; save booted rcon val in TABLAT ; save boot bits in PRODH ; movff vk_boot0_rcon,TABLAT #if KK_VERSION>=19 movff vk_boot0_bbits,PRODH #endif ; ; clear persistant memory ; lfsr FSR0,0x000 movlw KERN_RAM_PERSIST kki_boot_pmemclr: clrf POSTINC0 decfsz WREG,w bra kki_boot_pmemclr DB_WHERE 5 ; ; Restore saved RCON from TABLAT ; Restore saved boot bits from PRODH ; movff TABLAT,vk_boot0_rcon #if KK_VERSION>=19 movff PRODH,vk_boot0_bbits bsf bk_boot_cold #endif ; ; initialize values ; clrf TMR1H clrf TMR1L clrf vk_persistl clrf vk_persisth ; ; read values from eeprom ; EEPROM_BEGIN EEPROM_HOUR ; read starting from EEPROM_HOUR rcall kk_eeprom_read ; EEPROM_HOUR movwf vk_hour rcall kk_eeprom_read ; EEPROM_MINUTE movwf vk_minute ; fall through to kki_boot_warm ;=========================================================================== ; kki_boot_warm - jump here for non-power-on-resets ;=========================================================================== kki_boot_warm: #if KK_VERSION>=25 bsf bk_boot_warm #endif bcf bki_rs_warmboot ; fall through to kki_boot_common ;=========================================================================== ; kki_boot_common - all kk_boot versions converge here ;=========================================================================== kki_boot_common: #if KK_VERSION>=25 bsf bk_boot_common #endif ; ; erase entire RAM except for persistant variables ; ; start at KERN_RAM_PERSIST (end of persistant memory) ; erase count is: ; RAM size (0xf80) ; - KERN_RAM_PERSIST (persistant at start of mem) ; - vk_persisth,l (persistant at end of mem) ; DB_WHERE 6 lfsr FSR0,KERN_RAM_PERSIST comf vk_persistl,w addlw LOW (0xf80-KERN_RAM_PERSIST+1) movwf vki_tmp2 movlw (HIGH (0xf80-KERN_RAM_PERSIST+1))+1 subfwb vk_persisth,w movwf vki_tmp1 kki_boot_memclr: clrf POSTINC0 decfsz vki_tmp2,f bra kki_boot_memclr decfsz vki_tmp1,f bra kki_boot_memclr ; ; set runstate from eeprom ; EEPROM_READ1 EEPROM_RUNSTATE #if KK_VERSION>=19 movwf vk_boot0_runstate #endif rcall kki_set_runstate ; ; enable serial communications ; DB_WHERE 7 rcall kk_serial_enable SOUT0 kki_str_boot rcall kki_cr_prompt ; ; clear stack ; clrf STKPTR ; ; clear error condition ; clrf vk_error ; fall through to main loop ;########################################################################### ;################################ MAIN LOOP ################################ ;########################################################################### ; ; An app can return to the main loop by jumping to kk_main_loop or by just ; returning. In the return case control returns here and kk_main_loop is ; called again. ; kki_main_loop2: rcall kk_main_loop bra kki_main_loop2 ;=========================================================================== ; kk_main_loop ;=========================================================================== kk_main_loop: DB_WHERE 8 rcall kk_main_run ; ; clear non-persistant mem & restart if bki_rs_warmboot is set ; btfsc bki_rs_warmboot bra kk_boot2 ; ; jump to main app function. ; Main app function can be either: ; 1) an infinite loop with calls to kk_main_run, or ; 2) branch back to kk_main_loop repeatedly ; DB_WHERE 9 btfss bk_rs_halt bra kk_app_main ; call out to application DB_WHERE 10 rcall kki_led_check bra kk_main_loop ;=========================================================================== ; kk_main_run - do internal kk_main_loop tasks ;=========================================================================== kk_main_run: DB_WHERE2 1 #if SIM ; ; simulate time by incrementing T1 timer ; incf TMR1L,f btfsc STATUS,C incf TMR1H,f #if 1 ; ; simulate rx ; kki_sim_rx: bsf b_int1ie lfsr FSR0,0x300 movf POSTINC0,w bz kki_sim_rx_none bsf b_int1if #if 1 ; ; send all available chars at once ; bra kki_sim_rx #endif kki_sim_rx_none: #endif #endif ; ; new chars arrived? ; DB_WHERE2 2 #if KK_VERSION<18 btfsc bki_tx_overflow bra kki_main_run_time #endif #if KK_VERSION>=18 bsf b_rcie ; enable serial interrupt ; PIE1,5 #endif btfsc bki_rx_new rcall kki_serial_rx_new bsf b_rcie ; enable serial interrupt ; PIE1,5 ; ; check for time change ; kki_main_run_time: DB_WHERE2 3 clrf vk_time_bits movf vki_last_tmr1h,w subwf TMR1H,w andlw 0xfc bnz kki_time_update kki_main_run_endtime: ; ; transmit next byte? ; DB_WHERE2 4 btfsc b_txif ; PIR1,4 rcall kki_serial_tx ; transmit next byte DB_WHERE2 5 ; ; if not halted then turn rx interrupts off again ; btfss bk_rs_halt bcf b_rcie ; PIE1,5 DB_WHERE2 0 return ;########################################################################### ;################################ TIME FUNCTION ############################ ;########################################################################### ; ; called approx every 1/4 sec. ; w contains ((number of quarter seconds since last update) * 4) ; (always a multiple of 4) ; ; kk_main_run Must be called at least once every 4 seconds or this ; code will fail with an error. ; ; (Note: time will be silently lost if kk_main_run is not called at least ; every 16 sec) ; ; DO NOT RETURN - jump back to kki_main_run_endtime ; kki_time_update: bsf bk_qsec ; ; blink the alive LED (PORTC alive) ; btg bki_alive ; ; in halt modes blink the alive LED (PORTB alive) ; btg bki_led_alive ; ; add the time in. Divide by 4 to get quarter-seconds ; (low 2 bits of w are never 0 here) ; addwf vki_last_tmr1h,f rrncf WREG,w rrncf WREG,w addwf vk_qsec,f ; ; did vk_qsec overflow by 4 or more seconds? ; bc kki_time_4sec_wrap ; ; check for vk_qsec overflow ; movlw -240 addwf vk_qsec,w bnc kki_main_run_endtime movwf vk_qsec ; ; vk_qsec overflowed - increment minute ; bsf bk_minute incf vk_minute,f ; ; check for minute overflow ; movlw -60 addwf vk_minute,w #if KK_VERSION>=26 bnz kki_time_save #else bnz kki_main_run_endtime #endif movwf vk_minute ; ; increment hour ; bsf bk_hour #if KK_VERSION>=28 incf vk_hour,f movlw 0x7f btfsc vk_hour,7 movwf vk_hour ; clamp to 0x7f #else infsnz vk_hour,f setf vk_hour ; clamp to 0xff #endif kki_time_save: btfss vk_hour,7 ; do not save time way after game is over rcall kki_save_time bra kki_main_run_endtime ; ; ERROR: waited too long (over 4 sec) between calls to kk_main_run ; kki_time_4sec_wrap: ERR ERROR_A1_TIME4SEC ;########################################################################### ;################################ SERIAL FUNCTIONS ######################### ;########################################################################### ; ; Convert ascii hex digit (in w) to binary nibble value (in w). ; Set bki_rx_synerr if not hex digit ; kki_serial_rx_hexdig: addlw -(1+'9') bc kki_serial_rx_hexadig addlw (1+'9')-'0' btfss STATUS,C kki_serial_rx_hexdig_err: bsf bki_rx_synerr return kki_serial_rx_hexadig: andlw 0xdf ; toupper addlw (1+'9')-(1+'F') bc kki_serial_rx_hexdig_err addlw (1+'F')-'A' bnc kki_serial_rx_hexdig_err addlw 10 return ; ; kki_serial_rx_new loops here to echo chars ; kki_serial_rx_echo: ; ; echo character at vki_rx_echo ; lfsr FSR0,RAMBUF_RX movwf FSR0L movf INDF0,w bn kki_serial_rx_eoc ; end of command ; ; replace ctrl chars with question marks ; addlw -0x20 btfsc STATUS,N movlw '?'-0x20 addlw 0x20 rcall kk_cout kki_serial_rx_next: incf vki_rx_echo,f ;=========================================================================== ; kki_serial_rx_new - process newly arrived chars (SERIAL ENTRY POINT) ;=========================================================================== kki_serial_rx_new: DB_WHERE2 0x10 bcf bki_rx_new movf vki_rx_echo,w cpfseq vki_rx_head bra kki_serial_rx_echo return #if KK_VERSION>=27 kki_end_flush: bsf bki_rx_new bcf bki_tx_flushing return #endif ; ; got end-of-command: ; w==0xff command ; w==0xfe kill command ; else error ; kki_serial_rx_eoc: #if KK_VERSION>=27 ; ; if flushing then just cancel flush and return ; btfsc bki_tx_flushing bra kki_end_flush #endif infsnz WREG,w bra kki_serial_rx_cmd ; 0xff = got command infsnz WREG,w bra kki_serial_rx_kill ; 0xfe = got kill kki_serial_rx_error: DB_WHERE2 0x11 SOUT0 kki_str_error SOUT0 kki_str_error_rx movf vki_rx_error,w rcall kk_outbyte COUT ' ' movf vki_rx_err_badchar,w rcall kk_outbyte bra kki_rx_init kki_serial_rx_kill: DB_WHERE2 0x12 SOUT0 kki_str_kill bra kki_serial_rx_cmd_end2 ; ; null command - continue printing or do nothing ; kki_serial_rx_cmd_null: DB_WHERE2 0x13 bcf bki_rx_write ; do not write movf vki_rx_state,w andlw KERNVAL_RX_STATE_READ ; any r/w bits set? bz kki_serial_rx_cmd_end movlw 16 movwf vki_rx_cnt ; show 16 bytes btfss bki_rx_rw_ram kki_rx_rw_entry1: bra kki_rx_rw_entry ; ; Ram - do not read into SFR (0x0f80 and above) ; DB_WHERE2 0x14 movf vki_rx_rw_ptrh,w addlw -0x0f bnz kki_rx_rw_entry1 movf vki_rx_rw_ptrl,w addlw 0x90 bnc kki_rx_rw_entry1 clrf vki_rx_state ; in sfr - cancel read command bra kki_serial_rx_cmd_end ; ; got command ; starts at vki_rx_tail ; ends at vki_rx_echo ; kki_serial_rx_cmd: DB_WHERE2 0x15 movff FSR1L,vki_fsr1l_save movff FSR1H,vki_fsr1h_save ; ; got complete command - echo CR ; rcall kk_outcr ; ; FSR0 = FSR1 = RAMBUF_RX + tail ; movlw HIGH RAMBUF_RX movwf FSR0H movwf FSR1H movf vki_rx_tail,w movwf FSR0L movwf FSR1L movf INDF0,w bn kki_serial_rx_cmd_null movwf vki_rx_cmd ; save cmd char clrf vki_rx_state ; ; convert rest of command from hex ; kki_serial_rx_cvt: DB_WHERE2 0x16 incf FSR0L,f movf INDF0,w bn kki_serial_rx_cmd_parse addlw -0x20 bz kki_serial_rx_cvt ; skip spaces addlw 0x20-':' bz kki_serial_rx_cvt ; skip colons addlw ':' rcall kki_serial_rx_hexdig swapf WREG,w movwf INDF1 incf FSR0L,f movf INDF0,w rcall kki_serial_rx_hexdig iorwf INDF1,f incf FSR1L,f btfss bki_rx_synerr ; set by kki_serial_rx_hexdig if non hex digit bra kki_serial_rx_cvt bra kki_rx_cmd_err_syntax kki_rx_outerr: movwf vki_tmp2 DB_WHERE2 0x13 rcall kk_outcr SOUT0 kki_str_error movf vki_tmp2,w rcall kki_sout_base0 bra kki_serial_rx_cmd_end ; ; subroutine: get next data byte ; kki_fsr1_nextbyte: movf INDF1,w incf FSR1L,f return ; ; call here after command is processed ; kki_serial_rx_cmd_end: movff vki_fsr1l_save,FSR1L movff vki_fsr1h_save,FSR1H ; ; set tail pointer to next command buffer location ; kki_serial_rx_cmd_end2: DB_WHERE2 0x17 incf vki_rx_echo,w movwf vki_rx_echo ; echo++ movwf vki_rx_tail ; echo --> tail bsf bki_rx_new DB_WHERE2 0 bra kki_cr_prompt kki_serial_rx_cmd_parse: ; ; Command table ; <addr> = 2 byte address in hex (0-9, a-z) ; <data> = 1 byte of data in hex (0-9, a-z) ; <pdata> = 64 bytes of program data in hex (0-9, a-z) ; ; In non-debug mode ONLY the <addr>H is accepted. ; ; ^C - immediate abort line ; ^X - immediate abort line ; Hbeefb0550 - halt with password ; H - halt ; R - run in non-debug mode ; D - debug - run in debug mode ; J<addr> - jump to subroutine at <addr> ; P<addr> - list 64 bytes of program memory ; P<addr>:<pdata> - write 64 bytes to <addr> - bytes follow <addr> ; E<addr> - show eeprom byte ; E<addr>:<data> - write eeprom byte ; V<addr> - show variable byte ; V<addr>:<data> - write variable byte ; F<start><end> - fast dump of prog mem. <start> and <end> are hi byte. ; C - clear non-persistant memory and restart (keeps time) ; M - warm reset chip (will gain/lose less than 1sec) ; B - boot (cold reset) chip (lose up to 1 minute) ; I - instructions ; S - toggle checksum mode ; DB_WHERE2 0x18 movf FSR1L,w movwf vki_rx_cnt movf vki_rx_tail,w subwf vki_rx_cnt,f ; # of data bytes movwf FSR1L ; point to first data byte movf vki_rx_cmd,w ; this is the command byte addlw -'H' bz kki_rx_cmd_halt addlw 'H'-'I' bz kki_rx_cmd_help btfss bk_rs_debug bra kki_rx_cmd_err_badcmd ; only halt command allowed if non-debug addlw 'I'-'R' bz kki_rx_cmd_run addlw 'R'-'D' bz kki_rx_cmd_debug addlw 'D'-'J' bz kki_rx_cmd_jump addlw 'J'-'P' bz kki_rx_cmd_prog addlw 'P'-'E' bz kki_rx_cmd_eeprom addlw 'E'-'V' bz kki_rx_cmd_varable addlw 'V'-'M' bz kki_rx_cmd_reset addlw 'M'-'B' bz kki_rx_cmd_boot addlw 'B'-'C' bz kki_rx_cmd_clear addlw 'C'-'S' bz kki_rx_cmd_cktoggle #if KK_VERSION>=27 addlw 'S'-'F' bz kki_rx_cmd_fastdump1 #endif ; fall through to badcmd kki_rx_cmd_err_badcmd: movlw kki_str_rx_badcmd_err-kki_str_base0 bra kki_rx_outerr kki_rx_cmd_err_syntax: movlw kki_str_rx_syntax_err-kki_str_base0 bra kki_rx_outerr kki_rx_cmd_cktoggle: btg bki_tx_docksum bra kki_serial_rx_cmd_end kki_rx_cmd_help: SOUT0 kki_str_help bra kki_serial_rx_cmd_end kki_rx_cmd_run: SET_RUNSTATE kki_runstate_run bra kki_serial_rx_cmd_end kki_rx_cmd_debug: SET_RUNSTATE kki_runstate_debug bra kki_serial_rx_cmd_end kki_rx_cmd_halt: btfsc bk_rs_debug bra kki_rx_cmd_dbhalt ; ; check for password: 0xbeefb055 ; movf vki_rx_cnt,w ; # of bytes of data addlw -4 ; need 4 bytes bnz kki_rx_cmd_err_illcmd rcall kki_fsr1_nextbyte addlw -0xbe bnz kki_rx_cmd_err_syntax rcall kki_fsr1_nextbyte addlw -0xef bnz kki_rx_cmd_err_syntax rcall kki_fsr1_nextbyte addlw -0xb0 bnz kki_rx_cmd_err_syntax rcall kki_fsr1_nextbyte addlw -0x55 bnz kki_rx_cmd_err_syntax ; ; password success - transition to RUNSTATE_HALT ; kki_rx_cmd_dbhalt: rcall kk_clear_interrupts SET_RUNSTATE kki_runstate_halt bra kki_serial_rx_cmd_end kki_rx_cmd_jump: movf vki_rx_cnt,w ; # bytes addlw -2 bnz kki_rx_cmd_err_syntax rcall kki_rx_cmd_jump2 bra kki_serial_rx_cmd_end kki_rx_cmd_jump2: rcall kki_fsr1_nextbyte movwf PCLATH rcall kki_fsr1_nextbyte movwf PCL ; this jumps to <addr> ; return will come back to rcall above kki_rx_cmd_clear: bsf bki_rs_warmboot ; do a warm restart at end of main loop bra kki_serial_rx_cmd_end kki_rx_cmd_boot: clrf RCON,POR ; simulate a cold boot kki_rx_cmd_reset: bsf bki_rs_warmboot ; do a warm reset reset ; ; illegal command ; kki_rx_cmd_err_illcmd: movlw kki_str_rx_illcmd_err-kki_str_base0 bra kki_rx_outerr #if KK_VERSION>=27 ; ; dump blocks of flash mem ; kki_rx_cmd_fastdump1: bsf bki_rx_fdump bra kki_rx_rw_cnt2 #endif ; ; read/write 64 bytes of flash mem ; kki_rx_cmd_prog: bsf bki_rx_rw_flash movlw 66 ; prog cmd is 66 bytes bra kki_rx_rw ; ; read/write an eeprom value ; kki_rx_cmd_eeprom: bsf bki_rx_rw_eeprom bra kki_rx_rw3 ; ; read/write ram ; kki_rx_cmd_varable: bsf bki_rx_rw_ram kki_rx_rw3: movlw 3 ; eeprom/ram write is 3 bytes kki_rx_rw: btfss bk_rs_halt ; only allow write if halted bra kki_rx_rw_cnt2 ; ; check vki_rx_cnt ; ==2 read ; ==w write (3 for eeprom/var 66 for prog) ; bsf bki_rx_write ; write command? subwf vki_rx_cnt,w bz kki_rx_rw_goodcnt kki_rx_rw_cnt2: bcf bki_rx_write ; read command? movf vki_rx_cnt,w addlw -2 bnz kki_rx_cmd_err_syntax kki_rx_rw_goodcnt: DB_WHERE2 0x19 rcall kki_fsr1_nextbyte movwf vki_rx_rw_ptrh rcall kki_fsr1_nextbyte movwf vki_rx_rw_ptrl movlw 1 movwf vki_rx_cnt ; # bytes to read #if KK_VERSION>=27 btfsc bki_rx_fdump bra kki_rx_cmd_fastdump #endif kki_rx_rw_entry: ; print string for type of mem movlw kki_str_ram-kki_str_base0 btfsc bki_rx_rw_eeprom movlw kki_str_eeprom-kki_str_base0 btfsc bki_rx_rw_flash movlw kki_str_flash-kki_str_base0 rcall kki_sout_base0 ; print address movf vki_rx_rw_ptrh,w rcall kk_outbyte movf vki_rx_rw_ptrl,w rcall kk_outbyte COUT ':' ; ; if reading, or if writing anything other than flash, then show byte ; kki_rx_rw_loop: rcall kki_rx_readbyte ; read byte btfsc bki_rx_write btfss bki_rx_rw_flash rcall kk_outbyte ; display byte btfsc bki_rx_write bra kki_rx_write ; do write ; ; loop read, or done ; COUT 0x20 infsnz vki_rx_rw_ptrl,f ; point to next byte incf vki_rx_rw_ptrh,f decfsz vki_rx_cnt,f ; check cnt bra kki_rx_rw_loop bra kki_serial_rx_cmd_end ; done ; ; write byte(s) ; kki_rx_write: DB_WHERE2 0x1a SOUT0 kki_str_rarrow movf INDF1,w kki_rx_write_ram: btfss bki_rx_rw_ram bra kki_rx_write_eeprom movff vki_rx_rw_ptrl,FSR0L movff vki_rx_rw_ptrh,FSR0H movwf INDF0 rcall kk_outbyte bra kki_serial_rx_cmd_end kki_rx_write_eeprom: btfss bki_rx_rw_eeprom bra kki_rx_write_flash decf EEADR,f rcall kk_eeprom_write movf INDF1,w rcall kk_outbyte bra kki_serial_rx_cmd_end kki_rx_write_flash: ; ; cannot write flash in breakpt or error modes or if not halted ; btfss bk_rs_halt bra kki_rx_cmd_err_illcmd btfsc bki_rs_error bra kki_rx_cmd_err_illcmd btfsc bki_rs_breakpt bra kki_rx_cmd_err_illcmd ; ; check for unaligned write ; movf vki_rx_rw_ptrl,w movwf TBLPTRL andlw 0x3f bnz kki_rx_cmd_err_illcmd ; error: not 64 byte aligned movf vki_rx_rw_ptrh,w movwf TBLPTRH ; ; check for clobbering boot code ; movlw LOW (-kk_app_main) addwf TBLPTRL,w movlw ((-kk_app_main)>>8)&0xff addwfc TBLPTRH,w bnc kki_rx_cmd_err_illcmd ; error: overwriting boot area ; ; write 64 bytes from FSR1 to TBLPTRH,L ; rcall kk_flash_write SOUT0 kki_str_written bra kki_serial_rx_cmd_end ; ; Functions to read & display bytes of memory ; kki_rx_readbyte: movf vki_rx_rw_ptrh,w btfsc bki_rx_rw_eeprom bra kki_rx_readbyte_eeprom btfsc bki_rx_rw_flash bra kki_rx_readbyte_flash kki_rx_readbyte_ram: movwf FSR0H movff vki_rx_rw_ptrl,FSR0L movf INDF0,w return kki_rx_readbyte_eeprom: #if (KK_CHIP!=18252) movwf EEADRH #endif decf vki_rx_rw_ptrl,w movwf EEADR rcall kk_eeprom_read #if (KK_CHIP!=18252) clrf EEADRH #endif return kki_rx_readbyte_flash: movwf TBLPTRH movff vki_rx_rw_ptrl,TBLPTRL tblrd* movf TABLAT,w return #if KK_VERSION>=27 ; ; Fast dump command ; kki_rx_cmd_fastdump: bsf bki_tx_flushing movf vki_rx_rw_ptrh,w rcall kk_outbyte SOUT0 kki_str_00 clrf TBLPTRL rcall kki_rx_cmd_fastdump_go movlw 0x40 movwf TBLPTRL rcall kki_rx_cmd_fastdump_go movlw 0x80 movwf TBLPTRL rcall kki_rx_cmd_fastdump_go movlw 0xc0 movwf TBLPTRL rcall kki_rx_cmd_fastdump_go rcall kk_outcr incf vki_rx_rw_ptrh,f movf vki_rx_rw_ptrh,w subwf vki_rx_rw_ptrl,w btfsc bki_tx_flushing bnz kki_rx_cmd_fastdump ; ; done - finished or cancelled by new command arriving ; bcf bki_rx_fdump bcf bki_tx_flushing bra kki_serial_rx_cmd_end kki_rx_cmd_fastdump_go: movf vki_rx_rw_ptrh,w movwf TBLPTRH kki_rx_cmd_fastdump_go_loop: tblrd*+ movf TABLAT,w rcall kk_outbyte movf TBLPTRL,w andlw 0x3f bnz kki_rx_cmd_fastdump_go_loop bra kki_tx_flush_sub #endif ;=========================================================================== ; kki_prompt - print the prompt ;=========================================================================== kki_cr_prompt: rcall kk_outcr kki_prompt: ; ; error prompt includes error number ; movf vk_error,w btfsc bki_rs_error bra kki_prompt_byte ; ; breakpoint prompt includes breakpoint number ; movf vk_breakpt,w btfss bki_rs_breakpt bra kki_prompt_string kki_prompt_byte: rcall kk_outbyte ; print the byte COUT ' ' ; space following byte kki_prompt_string: movf vki_runstate_prompt,w bra kki_sout_base0 ;=========================================================================== ; kk_serial_enable - enable & initialize serial communication ;=========================================================================== kk_serial_enable: DB_WHERE2 0x1b rcall kk_clear_interrupts ;TODO: is this needed? rcall kk_set_osc_8mhz ; setup to work in fast mode clrf RCSTA ; reset serial port bsf TRISC,TX #if 1 ; ; delay - let serial port cool off ; clrf vki_tmp1 kk_serial_enable_delay: decfsz vki_tmp1,f bra kk_serial_enable_delay #endif movlw KERNVAL_TXSTA movwf TXSTA #if (KK_CHIP!=18252) movlw KERNVAL_BAUDCON movwf BAUDCON clrf SPBRGH #endif movlw KERNVAL_SPBRG movwf SPBRG ; ; constant vki_ten = '9'+1 ; movlw '9'+1 movwf vki_ten ; ; setup tx buffer ; clrf vk_tx_cnt clrf vki_tx_head clrf vki_tx_tail clrf vki_tx_cksum bcf bki_tx_overflow bsf bki_tx_docksum rcall kk_outcr SOUT0 kki_str_hello #if KK_VERSION>=14 movlw KK_VERSION rcall kk_outbyte #endif ; ; setup rx variables ; kki_rx_init: DB_WHERE2 0x1c bcf b_rcie ; disable interrupts ; PIE1,5 bcf b_cren ; clear overrun error (if any) movlw KERNVAL_RCSTA movwf RCSTA ; clear errors & enable serial port clrf vki_rx_rw_ptrl clrf vki_rx_rw_ptrh clrf vki_rx_cnt clrf vki_rx_state clrf vki_rx_tail clrf vki_rx_echo clrf vki_rx_head clrf vki_rx_error movlw ' ' movwf vki_rx_err_badchar ; ; print prompt, setup rx logic, and return ; bra kki_cr_prompt ;=========================================================================== ; kk_serial_disable - disable serial communication ;=========================================================================== kk_serial_disable: DB_WHERE2 0x1d bcf RCSTA,SPEN ; disable serial port bcf TRISC,TX ; output high on TX pin #if KK_VERSION>=18 bsf bki_tx_overflow ; avoid adding chars to buffer clrf vk_tx_cnt ; make buffer look empty #else setf vk_tx_cnt ; keep cout from enabling b_txen #endif bcf b_txen ; disable b_txif bit ; TXSTA,5 return ;=========================================================================== ; kki_serial_tx - transmit a character ;=========================================================================== ; ; 32768 Hz / 8 = 4096 HZ ; TMR1L wraps 4096Hz/256 = 16Hz ; TMR1H wraps 16Hz/256 = every 16 seconds ; ; 9600 baud: ; 104.166 usec per bit ; 1041.66 usec per byte (10 bits) ; ; kki_serial_tx: DB_WHERE2 0x20 #if 1 ; ; sanity check tx registers ; movf vki_tx_tail,w subwf vki_tx_head,w subwf vk_tx_cnt,w bz kki_serial_tx_sane1 ERR ERROR_A5_TX kki_serial_tx_sane1: #endif ; ; chars left to send? ; movf vk_tx_cnt,w bz kki_serial_tx_done ; ; point FSR0 at buffer ; lfsr FSR0,RAMBUF_TX movff vki_tx_tail,FSR0L #if KK_VERSION>=17 ; ; pause every so often to avoid messed up transmission ; dcfsnz vki_tx_gap_cnt,f bra kki_serial_tx_mt #endif ; ; get the char ; movf INDF0,w ; ; if tx is empty then jump to kki_serial_tx_mt ; btfsc b_trmt ; TXSTA,1 bra kki_serial_tx_mt kki_serial_tx_xmit: movwf TXREG incf vki_tx_tail,f ; ; remember when the last char was sent (16ths of a sec) ; movff TMR1H,vki_tx_ctime decfsz vk_tx_cnt,f return ; ; just sent last char in buffer - check & clear overflow ; btfss bki_tx_overflow return ; ; clear overflow condition & send overflow string ; DB_WHERE2 0x21 bcf bki_tx_overflow rcall kk_outcr SOUT0 kki_str_tx_overflow bra kk_outcr ; ; empty - wait at least 1/16 sec between chars that are not adjacent ; (This fixes timing bug) ; kki_serial_tx_mt: DB_WHERE2 0x22 #if KK_VERSION>=17 ; ; allow 40 more chars before next forced gap ; movlw 40 movwf vki_tx_gap_cnt #endif movf vki_tx_ctime,w subwf TMR1H,w andlw 0xfe bz kki_serial_tx_return ; have not waited long enough ; ; waited long enough - send the next char ; movf INDF0,w bra kki_serial_tx_xmit ; ; no more characters to send ; turn off xmit (but only after empty for at least 1/16 sec) ; kki_serial_tx_done: DB_WHERE2 0x23 btfss b_trmt ; TXSTA,1 return ; not empty - leave it on movf vki_tx_ctime,w subwf TMR1H,w andlw 0xfe bz kki_serial_tx_return ; have not waited long enough ; ; waited long enough - turn xmit off ; bcf b_txen ; TXSTA,5 kki_serial_tx_return: DB_WHERE2 0 return ;=========================================================================== ; kk_outcr - output linefeed ;=========================================================================== kk_outcr: btfss bki_tx_docksum bra kki_outcr2 movlw '@' rcall kki_cout2 movf vki_tx_cksum,w rcall kk_outbyte kki_outcr2: movlw '\n' rcall kki_cout2 clrf vki_tx_cksum return ;=========================================================================== ; kk_outbyte - output byte in w ;=========================================================================== kk_outbyte: movwf vki_tmp1 swapf WREG,w rcall kki_outnib movf vki_tmp1,w ; fall through to kk_outnib kki_outnib: andlw 0x0f addlw '0' cpfsgt vki_ten addlw 'A'-'0'-10 ; fall through to kk_outc ;=========================================================================== ; kk_cout - output character in w (does not modify W) ;=========================================================================== kk_cout: addlw -0x0a bz kk_outcr addlw 0x0a addwf vki_tx_cksum,f ; add into checksum kki_cout2: #if KK_VERSION>=18 btfsc bki_tx_overflow return #endif incf vk_tx_cnt,f bz kki_cout_overflow ; buffer full? ; ; store char into buffer ; lfsr FSR0,RAMBUF_TX movff vki_tx_head,FSR0L movwf INDF0 incf vki_tx_head,f btfss b_txen bsf b_txen ; enable kki_serial_tx TXSTA,5 return kki_cout_overflow: decf vk_tx_cnt,f bsf bki_tx_overflow return #if KK_VERSION>=27 ;=========================================================================== ; kk_tx_flush - flush tx buffer ;=========================================================================== ; ; flush output buffer ; kk_flush: bsf bki_tx_flushing rcall kki_tx_flush_sub bcf bki_tx_flushing return ; ; flush sub ; kki_tx_flush_sub: movf vk_tx_cnt,w andlw 0xfc btfsc bki_tx_flushing btfsc STATUS,Z return rcall kk_main_run bra kki_tx_flush_sub #endif ;=========================================================================== ; kk_sout - output string in tblptrl,h ;=========================================================================== ; ; kk_sout prints string at TBLPTRH,L ; kk_sout_wh is just like kk_sout, but w is first copied to TBLPTRH ; kki_sout_base0 adds w to kki_str_base0 and prints that string ; kki_sout_base0: addlw LOW kki_str_base0 movwf TBLPTRL movlw HIGH kki_str_base0 addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) ; fall through to kk_sout_wh kk_sout_wh: movwf TBLPTRH bra kk_sout kki_sout_loop: rcall kk_cout kk_sout: tblrd*+ movf TABLAT,w bnz kki_sout_loop return ;########################################################################### ;################################ VITAL STATE ############################## ;########################################################################### ; ; Set runstate & save value in EEPROM ; ; ; Runstate table ; Each entry has 4 bytes: ; ; 0 = vki_runstate_bits ; bitmask ; 1 = runstate LEDs ; led values ; 2 = vki_runstate_prompt ; prompt string ; 3 = runstate offset ; offset to store in eeprom EEPROM_RUNSTATE ; kki_runstate_table: kki_runstate_run: db RUNSTATE_BITS_RUN,KERNVAL_TRISB_LED_RUN db kki_str_prompt_run-kki_str_base0,kki_runstate_run-kki_runstate_table kki_runstate_debug: db RUNSTATE_BITS_DEBUG,KERNVAL_TRISB_LED_DEBUG db kki_str_prompt_debug-kki_str_base0,kki_runstate_debug-kki_runstate_table kki_runstate_halt: db RUNSTATE_BITS_HALT,KERNVAL_TRISB_LED_HALT db kki_str_prompt_halt-kki_str_base0,kki_runstate_halt-kki_runstate_table kki_runstate_error: db RUNSTATE_BITS_ERROR,KERNVAL_TRISB_LED_ERROR db kki_str_prompt_error-kki_str_base0,kki_runstate_halt-kki_runstate_table kki_runstate_break: db RUNSTATE_BITS_BREAK,KERNVAL_TRISB_LED_BREAK db kki_str_prompt_break-kki_str_base0,kki_runstate_halt-kki_runstate_table kki_set_runstate: movwf TBLPTRL addlw -(kki_runstate_break-kki_runstate_table) bc kki_set_rs_error andlw 0x03 bnz kki_set_rs_error movlw LOW kki_runstate_table addwf TBLPTRL,f movlw HIGH kki_runstate_table addwfc TBLPTRU,w ; add 0 + c (TBLPTRU is always 0) movwf TBLPTRH tblrd*+ movff TABLAT,vki_runstate_bits tblrd*+ movf TABLAT,w rcall kki_led_set tblrd*+ movff TABLAT,vki_runstate_prompt tblrd*+ #if KK_VERSION>=19 EEPROM_BEGIN EEPROM_RUNSTATE ; write starting from EEPROM_RUNSTATE #endif movf TABLAT,w bra kk_eeprom_write_wait ; write runstate offset to eeprom ; ; error: bad runstate offset ; kki_set_rs_error: ERR ERROR_A3_RUNSTATE ; ; Save time to eeprom ; kki_save_time: EEPROM_BEGIN EEPROM_HOUR ; write starting from EEPROM_HOUR movf vk_hour,w rcall kk_eeprom_write ; write hour to eeprom movf vk_minute,w bra kk_eeprom_write_wait ; write minute to eeprom ;########################################################################### ;################################ UTILITY FUNCTIONS ######################## ;########################################################################### ; ; kk_set_osc_32khz - use 32.768 khz oscillator ; kk_set_osc_8mhz - use 8 MHz oscillator ; kk_clear_interrupts - turn all isrs off, then enable globally ; kk_set_osc_32khz: btfss RCSTA,SPEN ; serial port enabled? bsf OSCCON,0 ; run slowly (but not if serial enabled) return kk_set_osc_8mhz: bcf OSCCON,0 ; run quickly return kk_clear_interrupts: clrf INTCON ; IPR1 - set all interrupt priorities to LOW ; IPR2 - set all interrupt priorities to LOW clrf IPR1 clrf IPR2 movlw KERNVAL_INTCON2 movwf INTCON2 movlw KERNVAL_INTCON3 movwf INTCON3 clrf PIE1 clrf PIE2 ; ; setup RCON so we can detect different types of reset ; movlw KERNVAL_RCON movwf RCON ; ; enable high & low priority interrupts (global) ; movlw 0xc0 iorwf INTCON,f return ;########################################################################### ;################################ ERROR & DEBUG ############################ ;########################################################################### ;=========================================================================== ; error ;=========================================================================== kk_doerror: movwf vk_error #if SIM call kk_error #endif reset ;=========================================================================== ; breakpoint ;=========================================================================== kk_dobreakpt: movwf vk_breakpt #if SIM call kk_breakpt #endif movf vki_breakpt_w,w ; ; return if serial disabled or debug not enabled ; btfss RCSTA,SPEN ; serial port disabled? btfss bk_rs_debug return SET_RUNSTATE kki_runstate_break kki_dobreakpt_loop: rcall kk_main_run ; ; loop until breakpoint bit cleared ; btfsc bki_rs_breakpt bra kki_dobreakpt_loop SET_RUNSTATE kki_runstate_debug movf vki_breakpt_w,w return ;########################################################################### ;################################ JUMP TABLE FUNCTIONS ##################### ;########################################################################### ; ; implements a jump table ; jump here after setting W to the jump offset ; before the jump W is reloaded from vk_w ; kk_jump: addwf TOSL,f btfsc STATUS,C incf TOSH,f addwf TOSL,f btfsc STATUS,C incf TOSH,f movlw 2 addwf TOSL,f btfsc STATUS,C incf TOSH,f movf vk_w,w return #if 0 ; ; EXAMPLE CODE - use this to implement a jump table ; movwf vk_w ; vk_w will be put back into w before jumping movf v_table_index,w ; This should be the 0-based index into table ; Code here should ensure that w < sizeof table push bra kk_jump bra func0 ; this happens if v_table_index == 0 bra func1 ; this happens if v_table_index == 1 bra func2 ; this happens if v_table_index == 2 bra func3 ; this happens if v_table_index == 3 bra func4 ; this happens if v_table_index == 4 ;... #endif ;########################################################################### ;################################ MEMORY FUNCTIONS ######################### ;########################################################################### ; ; EECON1 ; 7 EEPGD = 0 0=eeprom 1=flash ; 6 CFGS = 0 0=eeprom/flash 1=config ; 5 reserved = 0 ; 4 FREE = 0 1 = erash flash block ; 3 WRERR = 0 1 = reset or write error ; 2 WREN = x 1 = enable writes ; 1 WR = 0 set to initiate a write/erase ; 0 RD = 0 set to initiate a read ; ; RD_EE EECON1 = 0000 0000 = 0x00 (set bit 0 (RD) to initiate read) ; WR_EE EECON1 = 0000 0100 = 0x04 (set bit 1 (WR) to initiate write) ; RD_FLASH EECON1 = **** **** = 0x** (dont care) ; ER_FLASH EECON1 = 1001 0100 = 0x00 (set bit 1 (WR) to initiate erase) ; WR_FLASH EECON1 = 1000 0100 = 0x00 (set bit 1 (WR) to initiate write) ; ;=========================================================================== ; Common memory functions ;=========================================================================== ; ; kki_table_write - common FLASH/EEPROM write/erase sequence ; kki_table_write: ; ; clear interrupts during write ; movff INTCON,vki_tmp1 movlw 0x3f andwf INTCON,f ; ; 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 movff vki_tmp1,INTCON return ;=========================================================================== ; Flash memory functions ;=========================================================================== ; ; kk_flash_write - erase & write 64 bytes from FSR1 to TBLPTRH,L ; kk_tblptr_addw - add w to TBLPTRL,H ; kk_flash_write: ; ; wait for any preceding eeprom read/write & clear EECON1 reister ; rcall kki_eeprom_setup ; ; erase flash at TBLPTR ; bsf EECON1,EEPGD ; flash memory bsf EECON1,FREE ; erase (free) block (cleared automatically) rcall kki_table_write ; erase (stall here for ~2ms) ; ; write 64 bytes ; movlw 64 movwf vki_tmp1 TBLRD*- ; decrement TBLPTR kk_flash_write_loop: movf INDF1,w incf FSR1L,f movwf TABLAT tblwt+* ; write with preinc decfsz vki_tmp1,f bra kk_flash_write_loop ; ; do the write and we are done! ; bsf EECON1,EEPGD ; flash memory bra kki_table_write ; ; add w to TBLPTRL,H ; kk_tblptr_addw: addwf TBLPTRL,f btfsc STATUS,C incf TBLPTRH,f return ;=========================================================================== ; eeprom memory functions ;=========================================================================== ; ; kki_eeprom_setup - Setup for eeprom access by ; 1) waiting for any pending writes to complete ; 2) set EECON1 for eeprom reads ; 3) increment EEADR ; ; kk_eeprom_read - read eeprom[EEADRH,++EEADR] -> w ; kk_eeprom_write - write w -> eeprom[EEADRH,++EEADR] ; kk_eeprom_write_wait - write and wait for write to complete ; kk_eeprom_read: rcall kki_eeprom_setup bsf EECON1,RD movf EEDATA,w return kk_eeprom_write: kk_eeprom_write_wait: movwf vki_tmp1 kki_eeprom_write_confirm: rcall kk_eeprom_read ; what is there now? subwf vki_tmp1,w ; same thing? btfsc STATUS,Z return ; same - we are done! movff vki_tmp1,EEDATA bra kki_table_write decf EEADR,f bra kki_eeprom_write_confirm kki_eeprom_setup: btfsc EECON1,WR bra kki_eeprom_setup clrf EECON1 incf EEADR,f return ;########################################################################### ;################################ MAIN PROGRAM VECTORS ##################### ;########################################################################### ; ; kk_app_main - kernel jumps here to run application ; kk_app_isr_low - low priority ISR starts here ; kk_app_isr_high - high priority ISR starts here ; #if KK_VERSION >= 9 kk_app_main equ 0xa00 #endif kk_app_isr_low equ kk_app_main+0x4 kk_app_isr_high equ kk_app_main+0x30 ; ; loader values - these should never change ; ; ; KERNVAL_HEADER equ 0x0010 ; location of header KERNVAL_LOADER_BEGIN equ 0x3000 ; where the loader starts KERNVAL_LOADER_NEW_KERNEL equ 0x4000 ; where the new kernel is loaded ;########################################################################### ;################################ 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:22:36 PDT 2007