procedure intrh is
    -- this is the interrupt handler
    pragma interrupt            

    assembler
        local checkb4clr
        local checkb4
        local dominute
        local dohour
        local b4clrcounter
        local docounter
        local sincr
        local dodisplay
        local notblank
        local writedata
        local theend
        
        bcf status_rp1          -- in bank 0
        bcf status_rp0          -- ...

    -- on an interrupt, check the status of rb7 and rb4
    -- to debounce, require 12 successive clicks on either
    -- pin to flip over to the next time.
    -- note: rb4 and rb7 are active low
        btfsc pin_b1            -- if rb7 is not being pushed
        goto checkb4clr         -- check rb4 and clear rb7cnt
        incf rb7cnt,f           -- otherwise, increment rb7cnt
        movlw 0x04              -- xor 4 with...
        xorwf rb7cnt,w          -- ...rb7cnt
        btfsc status_z          -- if rb7cnt == 0x04
        goto dominute           -- increment the minutes
        goto checkb4            -- else check on rb4

    checkb4clr:
        clrf rb7cnt             -- rb7 is not active; clear rb7cnt
    checkb4:
        btfsc pin_b0            -- if rb4 is not being pushed
        goto b4clrcounter       -- do counter and clear rb4cnt
        incf rb4cnt,f           -- otherwise, increment rb4cnt
        movlw 0x04              -- xor 4 with...
        xorwf rb4cnt,w          -- ...rb4cnt
        btfsc status_z          -- if rb4cnt == 0x04
        goto dohour             -- increment the hour   
        goto docounter          -- else do the counter

    dominute:
                                -- don't clear rb7cnt until
                                -- it goes inactive again
                                -- one push == one minute

                                -- start the display cycle over
        movlw 0x28              -- put 40 in...
        movwf sixtieths         -- ...sixtieths
        clrf baz                -- and clear baz

                                -- now update minutes
        clrf seconds            -- clear seconds
        incf minutes,f          -- increment minutes
        movlw 0x3C              -- xor 60 with...
        xorwf minutes,w         -- minutes
        btfss status_z          -- if minutes != 60
        goto docounter          -- go to the counter stuff
        clrf minutes            -- clear the minutes

    dohour:
                                -- start the display cycle over
        movlw 0x28              -- put 40 in...
        movwf sixtieths         -- ...sixtieths
        clrf baz                -- and clear baz

        incf hours,f            -- now increment hours
        movlw 0x18              -- xor 24 with...
        xorwf hours,w           -- hours
        btfsc status_z          -- if hours == 24
        clrf hours              -- clear hours
        goto docounter          -- don't clear rb4cnt
                                -- one button push increments
                                -- by exactly one hour

    b4clrcounter:
        clrf rb4cnt             -- inactive r4b or fallthrough
                                -- clear rb4cnt
    docounter:
        btfss intcon_t0if       -- if the t0if isn't set
        goto theend             -- we're done

        bcf intcon_t0if         -- otherwise...
        movlw 0xFF              -- reset clkset value
        movwf tmr0              -- put it in tmr0

        incf sixtieths,f        -- increment sixtieths
        movlw 0x32              -- xor 50 with...
        xorwf sixtieths,w       -- ...sixtieths
        btfss status_z          -- if sixtieths != 50
        goto dodisplay          -- just update the display
                                -- else fall through into seconds

        movlw 0x01              -- if 1...
        subwf baz,f             -- ...subtracted from baz
        btfsc status_c          -- ...is not less than 0...
        goto sincr              -- just increment seconds
        movlw 0x02              -- otherwise
        movwf baz               -- baz = 2
    	incf writeleft,f	-- each time baz resets, we swap
				-- the side on which we display
				-- the lone hours digit

    sincr:
        clrf sixtieths          -- clear sixtieths
        incf seconds,f          -- increment seconds
        movlw 0x3C              -- xor 60 with...
        xorwf seconds,w         -- ...seconds
        btfss status_z          -- if seconds != 60
        goto dodisplay          -- just update the display
                                -- else fall through into minutes

        clrf seconds            -- clear seconds
        incf minutes,f          -- increment minutes
        movlw 0x3C              -- xor 60 with...
        xorwf minutes,w         -- ...minutes
        btfss status_z          -- if seconds != 60
        goto dodisplay          -- just update the display
                                -- else fall through into hours

        clrf minutes            -- clear minutes
        incf hours,f            -- increment hours
        movlw 0x18              -- xor 24 with...
        xorwf hours,w           -- ...hours
        btfsc status_z          -- if hours == 24
        clrf hours              -- clear hours

    dodisplay:
        movf baz,f              -- if baz...
        btfss status_z          -- != 0
        goto notblank           -- we're writing something
        movlw 0xFF              -- otherwise
	movwf port_b		-- blank...
	movlw 0x0F		-- ...the...
        movwf port_a            -- ...display
        movf hours,w            -- when we're blanking
        movwf tmphours          -- update tmphours
        movf minutes,w          -- and
        movwf tmpminutes        -- tmpminutes
        goto theend             -- and we're done

    notblank:
        movf tmphours,w         -- load hours
        btfsc dispmin           -- if dispmin
        movf tmpminutes,w       -- load minutes instead
        bsf status_rp0          -- bank 1
        movwf f628_eeaddr       -- write address into eeaddr
        bsf f628_eecon1_rd      -- read the data

    writedata:
        movf f628_eedata,w      -- load data to write
        bcf status_rp0          -- bank 0
	    movwf port_b		    -- write to port_b
	    andlw 0x0F		        -- cut off high nibble
        movwf port_a            -- write to port_a
	    btfsc dispmin	    	-- if we're doing the minute display
	    bsf pin_a6		        -- turn on the left dot
	    btfss dispmin		    -- if we're doing the hour display
	    bsf pin_a7		        -- turn on the right dot

    -- do PWM stuff
        movlw 0x4A              -- load 74 into w
        addwf sixtieths,w       -- add the sixtieths value
        bsf status_rp0          -- bank 1
        movwf f628_eeaddr       -- write this to the eeaddr
        bsf f628_eecon1_rd      -- read the data
        movf f628_eedata,w      -- load the data into w
        bcf status_rp0          -- bank 0
        movwf ccpr1l            -- this is the PWM value

    theend:
        bsf intcon_t0ie         -- enable timer interrupt
    end assembler
end procedure
