;
; MR-9090 bootloader
;
; LICENSE
; Creative Commons Attribution-NonCommercial-ShareALike 2.5
;
; You are free:
;
; * to copy, distribute, display, and perform the work
; * to make derivative works
;
; Under the following conditions:
;	
; 1. Attribution. You must attribute the work in the manner specified by the 
;    author or licensor.
; 2. Noncommercial. You may not use this work for commercial purposes.
; 3. Share Alike. If you alter, transform, or build upon this work, you may 
;    distribute the resulting work only under a license identical to this one.
;
; * For any reuse or distribution, you must make clear to others the license 
;   terms of this work.
; * Any of these conditions can be waived if you get permission from the 
;   copyright holder.
;
; Your fair use and other rights are in no way affected by the above.
;
; This is a human-readable summary of the Legal Code.
; See full license at http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode
;
; Copyright: Marko Kanala (raato@mulletronic.com).
;

; put program start vector at 0x0004
#define BOOTSTRAP	0x0004

; bootloader vars
    cblock 0
        expected
        hcounter
        lcounter
        bl_wait1
        bl_wait2
        bl_wait3
		timeout
    endc
    
    cblock 10
        buffer:64
    endc

;  18f442 == 16k program flash
    ORG 0x3F00
bootloader:
    ;;; set up midi 
    bsf     PIE1, RCIE

    ; set baudrate to 31250 baud (midi)
    movlw   2 * 0x0a - 1
    movwf   SPBRG
    ; no transmit, "low speed"
    clrf    TXSTA

    ; serial port enabled, 8-bit, enable receiver
    movlw   (1 << SPEN) | (1 << CREN)
    movwf   RCSTA

    ; make sure that USART receive buffer is empty
    bcf     RCSTA, CREN
    movf    RCREG, W
    bsf     RCSTA, CREN
    
	clrf	TRISE
	clrf	TRISD
	clrf	timeout
	clrf	PORTE

    ;;; listen to midi for a while and wait for sysex

    ; F0 71 55 17 7F <firmware data, see below> F7

	incf	PORTE
bootloader_loop:
	decf	PORTE

    movlw   0xF0
    rcall   bootloader_receive_expect
	tstfsz	timeout
	bra		bootloader_go
    ; we got 0xf0, check for our sysex id 0x715517
    movlw   0x71
    rcall   bootloader_receive_expect
	tstfsz	timeout
	bra		bootloader_go
    movlw   0x55
    rcall   bootloader_receive_expect
	tstfsz	timeout
	bra		bootloader_go
    movlw   0x17
    rcall   bootloader_receive_expect
	tstfsz	timeout
	bra		bootloader_go
    ; expect 0x7f == firmware
    movlw   0x7F
    rcall   bootloader_receive_expect
	tstfsz	timeout
	bra		bootloader_go

    ;;; okay, it seems we've got incoming firmware data chunk, receive and flash
    
    ; program data:
    ;
    ; AH AL <64 bytes of midi encoded data (data>>7 data&0x7f ...)>, cc = 0 .. 63
    ;
    ; set 20ms between sysex messages when dumping so flash writes get written
    ;  correctly!
    ;
    ;  AH = address >> 7 & 0x7f
    ;  AL = address & 0x7f
    ;  so address = AH<<7 | AL
    ;
    ; Note: supports addresses 14-bit addresses 0x0000 - 0x3FFF (18f442)

    clrf    TBLPTRU
    clrf    TBLPTRL

    rcall   bootloader_receive 	 	; AH	
	tstfsz	timeout
	bra		bootloader_go
	bcf		STATUS, C
	rrcf	WREG
	movwf	TBLPTRH
	btfsc	STATUS, C
	bsf		TBLPTRL, 7
    rcall   bootloader_receive  	; AL
	tstfsz	timeout
	bra		bootloader_go
    iorwf   TBLPTRL     

    movlw   64
    movwf   lcounter
    
    ; receive count (max 64) bytes to buffer
    lfsr    FSR0, buffer - 1    
bootloader_loop_64:    
    rcall   bootloader_receive  ; receive high bit
	tstfsz	timeout
	bra		bootloader_go
    rrncf   WREG    
    movwf   PREINC0             ; store to buffer, FSR0 points to stored byte
    rcall   bootloader_receive  ; receive bits 6:0
	tstfsz	timeout
	bra		bootloader_go
    iorwf   INDF0       
    decfsz  lcounter
    bra     bootloader_loop_64    

	; LEDS
	incf	PORTE

    ; erase 64 bytes
    movlw   b'10010100'
    rcall   bootloader_flash

    lfsr    FSR0, buffer
    movlw   8                   ; 8 ...
    movwf   hcounter    
bootloader_flashloop:
    movlw   8                   ;   ... x 8 bytes == 64 byte buffer
    movwf   lcounter
bootloader_prepareloop:         ; write 8 bytes to holding registers
    movf    POSTINC0, W
    movwf   TABLAT              ; buffer to latch
    tblwt*+
	; LEDS
	movwf	PORTD
    decfsz  lcounter
    bra     bootloader_prepareloop
    
	tblrd*-						; addr-1
    movlw   b'10000100'
    rcall   bootloader_flash    ; flash 8 bytes
	tblrd*+						; addr+1
    decfsz  hcounter
    bra     bootloader_flashloop
    bcf     EECON1, WREN
    bra     bootloader_loop     ; and reloop
    
; starts the actual program
bootloader_go:
    ; kill uart and start the program
	movlw	b'00000011'
	movwf	PORTE		; shut leds
    clrf    RCSTA
    goto    BOOTSTRAP
    
; receives a byte from a midi and timeouts in a while,
; WREG = byte expected or if 0 anything is accepted
;
;  received byte is returned in WREG
bootloader_receive:
    clrf    WREG
bootloader_receive_expect:
    movwf   expected
    movlw   25			; ca 1.5s
    movwf   bl_wait3
bootloader_receive_wait3:
    clrf    bl_wait2
bootloader_receive_wait2:
    clrf    bl_wait1
bootloader_receive_wait1:
    btfsc   PIR1, RCIF
    bra     bootloader_received
    ; nothing received, wait for timeout
bootloader_receive_continue:
    decfsz  bl_wait1
    bra     bootloader_receive_wait1
    decfsz  bl_wait2
    bra     bootloader_receive_wait2
    decfsz  bl_wait3
    bra     bootloader_receive_wait3
    ; got timeout, just start
	decf	timeout
	return
bootloader_received:
	movf    RCREG, W
	bcf		PIR1, RCIF			; clear irq
	tstfsz  expected
    bra     bootloader_received_chk_exp
    ; something received, return
    return
bootloader_received_chk_exp:
    ; we got something, check if matches with expected
    cpfseq  expected
    ; doesn't match what we expected, continue receiving
    bra     bootloader_receive_continue
    return
    
; writes data to flash
bootloader_flash:
    movwf   EECON1
    movlw   0x55
    movwf   EECON2
    movlw   0xAA
    movwf   EECON2
    bsf     EECON1, WR
    nop
bootloader_waitflash:
    btfsc   EECON1, WR
    bra     bootloader_waitflash
    return


External Labels :

BOOTSTRAP