LIST P=16F84a #include __CONFIG 3FF2h ; Not write protected + Power up timer enabled + WDT disabled + HS ; *************************************************************************************** ; DECLARATIONS (VARIABLES + DEFINE + equ + MACRO) ; *************************************************************************************** ; Beginning of usable RAM (before 0x0C, RAM is for special registers: INTCON, STATUS, etc) ; There are 68 of them usable RAM bytes CBLOCK 0x0C ___TEMP0 : 1 ___TEMP1 : 1 ___TEMP2 : 1 ___TEMP3 : 1 ___TEMP4 : 1 ___TEMP5 : 1 ___TEMP6 : 1 ___TEMP7 : 1 ___TEMP8 : 1 ___TEMP9 : 1 ___TEMP10 : 1 ___TEMP11 : 1 ___TEMP12 : 1 ___TEMP13 : 1 ___TEMP14 : 1 ___TEMP15 : 1 ___T_DIV10 : 1 ___DO_DISPLAY : 1 ; Containers to prevent the data latch to mess up with the I/Os ___PORT_A : 1 ___PORT_B : 1 ; To display, each one = [0;9] ___D5_H : 1 ___D4 : 1 ___D3 : 1 ___D2 : 1 ___D1 : 1 ___D0_L : 1 ; Temporary containers for 24bit numbers ___T_H : 1 ___T_M : 1 ___T_L : 1 ; Counts from the SBM20 ___COUNT_H : 1 ___COUNT_M : 1 ___COUNT_L : 1 ; Copy - used when INTerrupts are disabled ; Real counter (___COUNT_[H,M,L]) is copied to that to be processed, every second ___COUNT_COPY_H : 1 ___COUNT_COPY_M : 1 ___COUNT_COPY_L : 1 ; Copy of a copy - used to adjust the time consumed by those interruptions ___COUNT_COPY_ADJUST_H : 1 ___COUNT_COPY_ADJUST_M : 1 ___COUNT_COPY_ADJUST_L : 1 ; Main accumulator ___ACCUMULATOR_H : 1 ___ACCUMULATOR_M : 1 ___ACCUMULATOR_L : 1 ; For copy purposes, to 'factorize' code ___ACCUMULATOR_COPY_H : 1 ___ACCUMULATOR_COPY_M : 1 ___ACCUMULATOR_COPY_L : 1 ___TICKS : 1 ___DIV_AND_MOD_10_Q : 1 ___DIV_AND_MOD_10_R : 1 ___INT_STATUS : 1 ___INT_W : 1 ENDC ; Pins: ; 7887: 11 inputs ; I: 4:RS ; I: 5:R/!W ; I: 6:E ; I: 7-14:DB4-DB7 ; ; RA0: (7887) RS ; RA1: (7887) E ; (7887.R/!W is connected to GND, since we won't ever read anything from it) ; ; RB0: ; INTerrupt from the SBM20 ; ; RB4-7: ; (7887) DB4-DB7 (Note: 4 wires = 4 bit mode) ; 1=IN 0=OUT CFG_TRISA EQU b'00011100' CFG_TRISB EQU b'00001111' ; PORTA PA_RS EQU 0x00 PA_E EQU 0x01 ; Note: PORTB pins cannot be interchanged! ; PORTB PB_INT EQU 0x00 PB_DB4 EQU 0x04 PB_DB5 EQU 0x05 PB_DB6 EQU 0x06 PB_DB7 EQU 0x07 ; --------------------------------------------------------------------------------------- ; 6 cycles M__ADD_1_TO_DESTINATION MACRO D_H, D_M, D_L MOVLW 0x01 ADDWF D_L, F BTFSC STATUS, C ADDWF D_M, F BTFSC STATUS, C ; It is cool to do so, because even if there was a carry set, ; adding S_M to D_M would never call another carry INCF D_H, F ENDM ; --------------------------------------------------------------------------------------- ; 6 cycles M__SUB_1_FROM_DESTINATION MACRO D_H, D_M, D_L MOVLW 0x01 SUBWF D_L, F BTFSS STATUS, C SUBWF D_M, F BTFSS STATUS, C DECF D_H, F ENDM ; --------------------------------------------------------------------------------------- ; 13 cycles M__ADD_SOURCE_TO_DESTINATION MACRO S_H, S_M, S_L, D_H, D_M, D_L ; Adds the 2 least significant bytes MOVF S_L, W ADDWF D_L, F MOVLW 0x01 ; Prepare for second carry adding... BTFSC STATUS, C ADDWF D_M, F BTFSC STATUS, C ; It is cool to do so, because even if there was a carry set, ; adding S_M to D_M would never call another carry INCF D_H, F ; Adds the middle byte MOVF S_M, W ADDWF D_M, F BTFSC STATUS, C INCF D_H, F ; Adds the most significant byte MOVF S_H, W ADDWF D_H, F ENDM ; --------------------------------------------------------------------------------------- ; 13 cycles M__SUB_SOURCE_FROM_DESTINATION MACRO S_H, S_M, S_L, D_H, D_M, D_L ; Notes: ; C is not set when X - Y, if X < Y ; C is set when X - Y, if X >= Y MOVF S_L, W SUBWF D_L, F MOVLW 0x01 BTFSS STATUS, C SUBWF D_M, F BTFSS STATUS, C DECF D_H, F MOVF S_M, W SUBWF D_M, F BTFSS STATUS, C DECF D_H, F MOVF S_H, W SUBWF D_H, F ENDM ; --------------------------------------------------------------------------------------- ; 6 cycles M__COPY_SOURCE_TO_DESTINATION MACRO S_H, S_M, S_L, D_H, D_M, D_L MOVF S_H, W MOVWF D_H MOVF S_M, W MOVWF D_M MOVF S_L, W MOVWF D_L ENDM ; --------------------------------------------------------------------------------------- ; 3 cycles M__CLEAR MACRO D_H, D_M, D_L CLRF D_H CLRF D_M CLRF D_L ENDM ; --------------------------------------------------------------------------------------- ; 4 cycles ; Extracts the least significant 4 bits of an 8 bit value ; Output is 0 <= x <= 15 M__EXTRACT_L_NIBBLE MACRO SOURCE, DESTINATION MOVF SOURCE, W MOVWF DESTINATION MOVLW 0x0F ANDWF DESTINATION, F ENDM ; --------------------------------------------------------------------------------------- ; 5 cycles ; Extracts the least significant 4 bits of an 8 bit value, divides by 16 ; Output is 0 <= x <= 15 M__EXTRACT_H_NIBBLE MACRO SOURCE, DESTINATION MOVF SOURCE, W MOVWF DESTINATION SWAPF DESTINATION, F MOVLW 0x0F ANDWF DESTINATION, F ENDM ; --------------------------------------------------------------------------------------- ; 2 cycles M__WRITE_A MACRO MOVF ___PORT_A, W MOVWF PORTA ENDM ; --------------------------------------------------------------------------------------- ; 2 cycles M__WRITE_B MACRO MOVF ___PORT_B, W MOVWF PORTB ENDM ; *************************************************************************************** ; EEPROM ; *************************************************************************************** ORG 2100h ; ---- DATA a' ' DATA a'G' DATA a'e' DATA a'i' DATA a'g' DATA a'e' DATA a'r' DATA a' ' DATA a'c' DATA a't' DATA a'r' DATA a' ' DATA a'v' DATA a'1' DATA a'.' DATA a'1' ; ---- DATA a'C' ; b'10101001' ; Copyright symbol DATA a'0' DATA a'9' DATA a'/' DATA a'2' DATA a'0' DATA a'1' DATA a'2' DATA a'A' DATA a'V' DATA a'a' DATA a's' DATA a's' DATA a'e' DATA a'u' DATA a'r' ; ---- DATA a' ' DATA a'a' DATA a'h' DATA a'r' DATA a'n' DATA a'o' DATA a' ' DATA a' ' DATA a'.' DATA a'v' DATA a'a' DATA a's' DATA a's' DATA a'e' DATA a'u' DATA a'r' ; ---- DATA a' ' DATA a'@' DATA a'g' DATA a'm' DATA a'a' DATA a'i' DATA a'l' DATA a' ' DATA a' ' DATA a' ' DATA a'.' DATA a'c' DATA a'o' DATA a'm' DATA a' ' DATA a' ' ; ---- ; *************************************************************************************** ; MAIN ; *************************************************************************************** ; [1.1] ; 20120920 Interrupt logic is done ; 20120920 'READ_COUNT' is no more ; 20120920 Added the 'M__ADD_1_TO_DESTINATION' macro ; 20120919 Began the INTerrupt-based logic ; [1.0] ; 20120914 Changed the pin disposition again: now the 74150's Strobe input is not connected to the PIC anymore, but it is connected to GND ; 20120914 Just forgot that RA4 is an open-drain output: it can't output anything without a pull-up resistor! Thus the CD4040 never resetting... Changed that for RA3, and put (74150) !W instead ; 20120914 Made a huge bug-fix in the averaging procedure: was not correctly displaying things, was badly handling the "(accumulator2Ticks > ticks && ticks%2 == 0 && ticks != 40)" condition ; 20120913 Debugged the 'DIVIDE_T24_BY_3' function: was only testing if T<0, but we needed to test if T<=0 (also saved 15 instructions in the process) ; 20120913 Now displays the CPM only when ___TICKS == 40 - otherwise, displays "~~~~~~" (for "approximation") ; 20120913 Added even more delay to the reset of the 4040 (~200µs) ; 20120913 Fixed a bug in the PCL adding logic: adding 1 made it go to TICKS_2, instead of going to TICKS_WAIT ; 20120912 Added some delay to the reset of the 4040 ; 20120912 Fixed a bug in the 'M__SUB_SOURCE_FROM_DESTINATION' macro: was decrementing D_M instead of D_H ; 20120912 Now only displays if ticks per second > 1, when ___TICKS < 40 ; 20120912 Fixed a bug, 'READ_COUNT' function: was disabling the LCD (but not writing so that had no effect), instead of enabling the 74150 ; 20120911 Saved approximately 20 instructions by factorizing the copy of the Accumulator to the temporary 24bit registers ; 20120911 Saved approximately 71 instructions by creating a TICKS helper function ; 20120911 All the averaging functions made! Pay attention though, many approximations: look for 'Approx.' for the list of them ; 20120911 Added divide by 2, 2^12 and 3 functions ; 20120911 Made the function 'DIV_AND_MOD_10' fixed-instruction - automatically the 'DECODE_20_BITS' function is, too ; 20120911 Simplified the 'DIV_AND_MOD_10' function ('hasCarry' part) ; 20120910 Got the final signature ; 20120910 'LCD_WRITE_DISPLAY_USVH' and 'LCD_WRITE_DISPLAY_CPM': added space(s) at the beginning ; 20120910 Fixed the 'READ_COUNT' function: was counting when port A-3 was tied to +, but the 74150 has its output inverted! ; 20120910 Fixed the 'M__ADD_SOURCE_TO_DESTINATION' macro: was adding a extra carry, because I used INCF to set a carry (and INCF cannot) - replaced by an ADDWF ; 20120909 Checked the LCD logic on real hardware: works! ; 20120909 Added the main averaging logic ; 20120909 Changed the 'DECODE_20_BITS' function, to use the ___T_x inputs instead of the ___D_x (which don't exist anymore) ; 20120909 Added function 'LCD_GOTO_LINE_2' ; 20120908 Added the LCD control logic, with all the necessary timers ; 20120908 Fixed a bug in the initialization of PORTA: was enabling the LCD instead of disabling the 74150 ; 20120907 Added the 'MULTIPLY_T24_BY_2' function ; 20120907 Added the 'READ_COUNT' function ; 20120907 Defined the pins ; 20120906 Added the 'DECODE_20_BITS' function ; 20120906 Added 'M__EXTRACT_H_NIBBLE' and 'M__EXTRACT_L_NIBBLE' macros ; 20120905 Added the (variable-cycle) 'DIV_AND_MOD_10' function ; 20120905 Added a major part of the loop ; 20120905 Added 'M__ADD_SOURCE_TO_DESTINATION' and 'M__CLEAR' macros ; 20120905 Added the main RAM values ; 20120904 Added the signature to the EEPROM ; 20120903 Added 'getExtendedRAMByte' ; 20120902 Added 'WAIT250US', 'WAIT1MS' ; 20120902 Made skeleton ; *************************************************************************************** ; Notes: ; SUBWF ___TICKS, F: carry is set if the result is >= 0 ; Ex: ; 0x10 - 0x01 ; <=> ; 0x10 + (0xFE+1) (= 2's complement) ; 0x010E --> C=1, result=0x0E ; ; Code reference: outputs until reaches 0x00 ; CLRF ___TEMP10 ;LCD_SIGNATURE_0: ; MOVF ___TEMP10, W ; CALL EEPROM_READ ; BTFSC STATUS, Z ; GOTO LCD_SIGNATURE_1 ; CALL LCD_WRITE_DATA ; INCF ___TEMP10, F ; CALL WAIT250MS ; GOTO LCD_SIGNATURE_0 ;LCD_SIGNATURE_1: ; Code reference: do 8 times ; MOVLW 0x01 ; MOVWF ___TEMP11 ;LCD_SIGNATURE_0: ; MOVF ___TEMP11, W ; ; ; ; BCF STATUS, C ; RLF ___TEMP11, F ; BTFSS STATUS, C ; GOTO LCD_SIGNATURE_0 ; *************************************************************************************** ; Main entry point ORG 0000h GOTO START ; TODO: handle dead time - pay attention to use only specific registers in that routine, to avoid screwing other routines' register values ; INTerrupts ; 3 to 4 cycles delay to get there, when an interrupt occurred ORG 0004h ; --- MOVWF ___INT_W SWAPF STATUS, W MOVWF ___INT_STATUS ; Clears the INTF flag (INTF: RB0/INT External Interrupt Flag bit) BCF INTCON, INTF ; Do the processing here M__ADD_1_TO_DESTINATION ___COUNT_H, ___COUNT_M, ___COUNT_L ;6 SWAPF ___INT_STATUS,W MOVWF STATUS SWAPF ___INT_W, F SWAPF ___INT_W, W RETFIE ; --- 16 cycles + 4 (delay) = 20 cycles, IC START: ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; Put test code here ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; ======================================================================================= ; Clears RAM MOVLW 0x0C MOVWF FSR CLEARRAM_SUB: CLRF INDF INCF FSR, F MOVF FSR, W XORLW 0x50 ;80 BTFSS STATUS, Z ; All done? GOTO CLEARRAM_SUB ; RB0, INT on falling edge BSF STATUS, RP0 BCF OPTION_REG, INTEDG BCF STATUS, RP0 ; Sets the inputs/outputs BSF STATUS, RP0 MOVLW CFG_TRISA MOVWF TRISA MOVLW CFG_TRISB MOVWF TRISB BCF STATUS, RP0 CLRF ___PORT_A M__WRITE_A CLRF ___PORT_B M__WRITE_B ; Initializes the LCD, so that it is ready to accept commands and data CALL LCD_INITIALIZE CALL LCD_CLEAR_AND_RETURN_HOME ; Outputs a nice signature ;) CALL LCD_SIGNATURE ; --------------------------------------------------------------------------------------- ;Difficulty: ; - handle numbers of up to 2^20bits wide (do the computation on an 8bit architecture) ; - convert them to 6-digit, decimal numbers (do the computation on an 8bit architecture) ; - /10 ; - %10 ; The SBM20: ; Dead time: 190µs ; -> Up to 5263 counts per second ; -> 315780 CPM ; -> 0.00µSv/h -> 2105.20µSv/h CALL LCD_CLEAR_AND_RETURN_HOME ; Makes sure all INTerrupts are disabled CLRF INTCON ; Enables RB0 interrupts ONLY BSF INTCON, INTE ; Enables all INTerrupts through the Global Interrupt Enable bit BSF INTCON, GIE LOOP: ;ticks++; INCF ___TICKS, F ; Disables all INTerrupts BCF INTCON, GIE ; Reads the count M__COPY_SOURCE_TO_DESTINATION ___COUNT_H, ___COUNT_M, ___COUNT_L, ___COUNT_COPY_H, ___COUNT_COPY_M, ___COUNT_COPY_L M__CLEAR ___COUNT_H, ___COUNT_M, ___COUNT_L ; Enables all INTerrupts BSF INTCON, GIE ; TODO: Test INT bit for interruption during INT blocking (INT bits are set, even if interrupts have been disabled) ;BTFSS INTCON, INTF ;BCF INTCON, INTF ;accumulator += count; M__ADD_SOURCE_TO_DESTINATION ___COUNT_COPY_H, ___COUNT_COPY_M, ___COUNT_COPY_L, ___ACCUMULATOR_H, ___ACCUMULATOR_M, ___ACCUMULATOR_L ; Save the accumulator somewhere else M__COPY_SOURCE_TO_DESTINATION ___ACCUMULATOR_H, ___ACCUMULATOR_M, ___ACCUMULATOR_L, ___ACCUMULATOR_COPY_H, ___ACCUMULATOR_COPY_M, ___ACCUMULATOR_COPY_L ; Computation and display ; ****************************************************************************************************************** M__COPY_SOURCE_TO_DESTINATION ___ACCUMULATOR_H, ___ACCUMULATOR_M, ___ACCUMULATOR_L, ___T_H, ___T_M, ___T_L DECF ___TICKS, W ; See comment next line ADDWF PCL, F ; Adding 0 will make it go to the next line anyway, but ___TICKS will never be equal to 0 here! GOTO TICKS_1 ; 1 GOTO TICKS_2 ; 2 GOTO TICKS_3 ; 3 GOTO TICKS_4 ; 4 GOTO TICKS_5 ; 5 GOTO TICKS_6 ; 6 GOTO TICKS_7 ; 7 GOTO TICKS_8 ; 8 GOTO TICKS_9 ; 9 GOTO TICKS_10 ; 10 ; General algorithm ;float temp = ((float)accumulator)/((float)ticks); // Counts per Second (acc/ticks) ;float uSv = temp*40; ;System.out.println("I "+(uSv/100.0f)+"µSv/h"); ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_1: ;99 ; ticks == 1 -> accumulator*(40)/1 = accumulator*40 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_10 ;69 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_2: ;85 ; ticks == 2 -> accumulator*(40)/2 = accumulator*20 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_10 ;69 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_3: ;499 ; ticks == 3 -> accumulator*(40)/3 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_10 ;69 CALL DIVIDE_T24_BY_3 ;400 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_4: ;71 ; ticks == 4 -> accumulator*(40)/4 = accumulator*10 CALL MULTIPLY_T24_BY_10 ;69 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_5: ;48 ; ticks == 5 -> accumulator*(40)/5 = accumulator*8 CALL MULTIPLY_T24_BY_8 ;46 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_6: ;485 ; ticks == 6 -> accumulator*(40)/6 = accumulator*20/3 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_10 ;69 CALL DIVIDE_T24_BY_3 ;400 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_7: ;61 ; ticks == 7 -> accumulator*(40)/7 = accumulator*6 (Approx.) CALL MULTIPLY_T24_BY_6 ;59 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_8: ;61 ; ticks == 8 -> accumulator*(40)/8 = accumulator*5 CALL MULTIPLY_T24_BY_5 ;59 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_9: ;899 ; ticks == 9 -> accumulator*(40)/9 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_10 ;69 CALL DIVIDE_T24_BY_3 ;400 CALL DIVIDE_T24_BY_3 ;400 GOTO TICKS_INF_TO_10_HELPER ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ; TICKS < 10 helper TICKS_INF_TO_10_HELPER: CALL DECODE_20_BITS ;2459 ; Only display if ticks per second > 1 ;if (accumulator2Ticks > ticks) ;{ ; ___TICKS will never be >10 ; So: ; if ___ACCUMULATOR_H is != 0, it is superior ; if ___ACCUMULATOR_M is != 0, it is superior ; if ___ACCUMULATOR_L - ___TICKS > 0, it is superior CLRF ___DO_DISPLAY ; if ___ACCUMULATOR_H is != 0, it is superior MOVLW 0xFF ANDWF ___ACCUMULATOR_H, F BTFSS STATUS, Z INCF ___DO_DISPLAY, F ; if ___ACCUMULATOR_M is != 0, it is superior ANDWF ___ACCUMULATOR_M, F BTFSS STATUS, Z INCF ___DO_DISPLAY, F MOVF ___TICKS, W SUBWF ___ACCUMULATOR_L, W ; carry is set if the result is >= 0 BTFSC STATUS, C INCF ___DO_DISPLAY, F ;} MOVF ___DO_DISPLAY, W BTFSC STATUS, Z GOTO TICKS_INF_TO_10_WAIT ; --- ; Display the µSv/h CALL LCD_GOTO_LINE_1 ;10039 CALL LCD_WRITE_DISPLAY_USVH ;3490 ; Display those CPM, only if ___TICKS == 10 - otherwise, display "~~~~~~" ; 7E --> '~' ; We're going to use this 'LCD_WRITE_DISPLAY_CPM' method, which automatically adds 0x30 to the decimal, to map them to the character map ; By setting the ___D_[X] to 0x4E, they're going to be mapping character 0x4E + 0x30 = 0x7E, which is what we want MOVLW 0x4E MOVWF ___D5_H MOVWF ___D4 MOVWF ___D3 MOVWF ___D2 MOVWF ___D1 MOVWF ___D0_L CALL LCD_GOTO_LINE_2 ;10039 CALL LCD_WRITE_DISPLAY_CPM ;3490 CALL RESET_A_T_IF_NEED_BE ;16 ; --- 27081 cycles GOTO TICKS_END TICKS_INF_TO_10_WAIT: ; Must wait 27081-1 = 27080 cycles (-1 because of the BTFSC and GOTO) GOTO TICKS_END ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_10: ; --- ; Display the µSv/h ;float uSv = (((float)accumulator)*4.0f); // 10s*4 = 40s; /100 for µSv CALL MULTIPLY_T24_BY_2 ;14 CALL MULTIPLY_T24_BY_2 ;14 CALL DECODE_20_BITS ;2459 CALL LCD_GOTO_LINE_1 ;10039 CALL LCD_WRITE_DISPLAY_USVH ;3490 ; Display those CPM M__COPY_SOURCE_TO_DESTINATION ___ACCUMULATOR_COPY_H, ___ACCUMULATOR_COPY_M, ___ACCUMULATOR_COPY_L, ___T_H, ___T_M, ___T_L ;6 CALL MULTIPLY_T24_BY_6 ;59 CALL DECODE_20_BITS ;2459 CALL LCD_GOTO_LINE_2 ;10039 CALL LCD_WRITE_DISPLAY_CPM ;3490 ;ticks = 0; CLRF ___TICKS ;accumulator = 0; M__CLEAR ___ACCUMULATOR_H, ___ACCUMULATOR_M, ___ACCUMULATOR_L ;3 ; --- 32073 cycles ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| TICKS_END: ; ****************************************************************************************************************** ;CALL WAIT250MS ;CALL WAIT250MS ;CALL WAIT250MS ;CALL WAIT250MS ; TODO: wait the rest (1s - time of all instructions in the LOOP) ; TODO: adjust ; 0x00C350 = 50000 = 1000000 instructions/second / 20 instructions (INT time) MOVLW 0x00 MOVWF ___COUNT_COPY_ADJUST_H MOVLW 0xC3 MOVWF ___COUNT_COPY_ADJUST_M MOVLW 0x50 MOVWF ___COUNT_COPY_ADJUST_L M__SUB_SOURCE_FROM_DESTINATION ___COUNT_COPY_H, ___COUNT_COPY_M, ___COUNT_COPY_L, ___COUNT_COPY_ADJUST_H, ___COUNT_COPY_ADJUST_M, ___COUNT_COPY_ADJUST_L ;count = 0; M__CLEAR ___COUNT_COPY_H, ___COUNT_COPY_M, ___COUNT_COPY_L ; Wait in relation to the number of INTerrupts that have been executed ; 20 cycles in loop INT_LOOP: M__SUB_1_FROM_DESTINATION ___COUNT_COPY_ADJUST_H, ___COUNT_COPY_ADJUST_M, ___COUNT_COPY_ADJUST_L ;6 CLRF ___DO_DISPLAY MOVF ___COUNT_COPY_ADJUST_H, W BTFSS STATUS, Z INCF ___DO_DISPLAY, F MOVF ___COUNT_COPY_ADJUST_M, W BTFSS STATUS, Z INCF ___DO_DISPLAY, F MOVF ___COUNT_COPY_ADJUST_L, W BTFSS STATUS, Z INCF ___DO_DISPLAY, F MOVF ___DO_DISPLAY, W BTFSS STATUS, Z GOTO INT_LOOP GOTO LOOP ; --------------------------------------------------------------------------------------- ; *************************************************************************************** ; ROUTINES ; *************************************************************************************** ; 16 cycles, IC RESET_A_T_IF_NEED_BE: ;if (accumulator > 4096) { ; ticks = 0; ; accumulator = 0; ;} MOVF ___ACCUMULATOR_H, W BTFSS STATUS, Z GOTO RESET_A_T_IF_NEED_BE_RESET_0 MOVF ___ACCUMULATOR_M, W ; 0000|0000 00000000 ANDLW 0xF0 BTFSS STATUS, Z GOTO RESET_A_T_IF_NEED_BE_RESET_1 GOTO RESET_A_T_IF_NEED_BE_RESET_M1 RESET_A_T_IF_NEED_BE_RESET_M1: NOP GOTO RESET_A_T_IF_NEED_BE_END RESET_A_T_IF_NEED_BE_RESET_0: GOTO RESET_A_T_IF_NEED_BE_RESET_0_0 RESET_A_T_IF_NEED_BE_RESET_0_0: GOTO RESET_A_T_IF_NEED_BE_RESET_1 RESET_A_T_IF_NEED_BE_RESET_1: CLRF ___TICKS M__CLEAR ___ACCUMULATOR_H, ___ACCUMULATOR_M, ___ACCUMULATOR_L ; 12 cycles to get there RESET_A_T_IF_NEED_BE_END: RETURN ; --------------------------------------------------------------------------------------- ; Important notice: in this section, pay attention not to use temporary registers that are already in use elsewhere! ; 14 cycles, IC ; I/O: ___T_x MULTIPLY_T24_BY_2: BCF STATUS, C RLF ___T_H, F BCF STATUS, C RLF ___T_M, F BTFSC STATUS, C INCF ___T_H, F BCF STATUS, C RLF ___T_L, F BTFSC STATUS, C INCF ___T_M, F RETURN ; 15 cycles, IC ; I/O: ___T_x DIVIDE_T24_BY_2: BCF STATUS, C RRF ___T_L, F MOVLW 0x80 BCF STATUS, C RRF ___T_M, F BTFSC STATUS, C ADDWF ___T_L, F BCF STATUS, C RRF ___T_H, F BTFSC STATUS, C ADDWF ___T_M, F RETURN ; 59 cycles, IC ; Multiply by 5: (counts<<2) + counts ; I/O: ___T_x ; Uses ___TEMP0, ___TEMP1, ___TEMP2 MULTIPLY_T24_BY_5: CALL COPY_T_HML_2_TEMP210 CALL MULTIPLY_T24_BY_2 CALL MULTIPLY_T24_BY_2 CALL ADD_TEMP210_2_T_HML RETURN ; 69 cycles, IC ; Multiply by 10: ((counts<<2) + counts)<<1 ; I/O: ___T_x ; Uses ___TEMP0, ___TEMP1, ___TEMP2 MULTIPLY_T24_BY_10: CALL MULTIPLY_T24_BY_5 CALL MULTIPLY_T24_BY_2 RETURN ; 59 cycles, IC ; Multiply by 6: ((counts<<1) + counts)<<1 ; I/O: ___T_x ; Uses ___TEMP0, ___TEMP1, ___TEMP2 MULTIPLY_T24_BY_6: CALL COPY_T_HML_2_TEMP210 CALL MULTIPLY_T24_BY_2 CALL ADD_TEMP210_2_T_HML CALL MULTIPLY_T24_BY_2 RETURN ; 46 cycles, IC ; Multiply by 8: (counts<<3) ; I/O: ___T_x MULTIPLY_T24_BY_8: CALL MULTIPLY_T24_BY_2 CALL MULTIPLY_T24_BY_2 CALL MULTIPLY_T24_BY_2 RETURN ; 400 cycles, IC ; I/O: ___T_x ; Uses ___TEMP[0-5] ; Perfect for all input [0; 1611006048], which is sufficient here ;) ; And is >2^24, BTW DIVIDE_T24_BY_3: ;int Q = ((A >> 2) + A) >> 2; /* Q = A*0.0101 */ CALL COPY_T_HML_2_TEMP210 CALL DIVIDE_T24_BY_2 CALL DIVIDE_T24_BY_2 CALL ADD_TEMP210_2_T_HML CALL DIVIDE_T24_BY_2 CALL DIVIDE_T24_BY_2 ;Q = ((Q ) + A) >> 2; /* Q = A*0.010101 */ CALL ADD_TEMP210_2_T_HML CALL DIVIDE_T24_BY_2 CALL DIVIDE_T24_BY_2 ;Q = ((Q ) + A) >> 2; /* Q = A*0.01010101 */ CALL ADD_TEMP210_2_T_HML CALL DIVIDE_T24_BY_2 CALL DIVIDE_T24_BY_2 ;Q = ((Q ) + A) >> 2; /* Q = A*0.0101010101 */ CALL ADD_TEMP210_2_T_HML CALL DIVIDE_T24_BY_2 CALL DIVIDE_T24_BY_2 ;Q = ((Q ) + A) >> 1; /* Q = A*0.10101010101 */ CALL ADD_TEMP210_2_T_HML CALL DIVIDE_T24_BY_2 ;Q = ((Q >> 12) + Q) ; /* Q = A*0.10101010101010101010101 */ CALL COPY_T_HML_2_TEMP543 ; Contains a savestate of Q CALL DIVIDE_T24_BY_2_P12 CALL ADD_TEMP543_2_T_HML ;Q = ((Q >> 24) + Q) >> 1; /* Q = A*0.010101010101001010101010101 ... */ ; Note: we haven't got the necessary precision to divide some 24bit value by 2^24... CALL DIVIDE_T24_BY_2 ; ___T_[H,M,L] contains Q CALL COPY_T_HML_2_TEMP543 ; Contains a savestate of Q ;int R = (Q << 1) + Q; CALL MULTIPLY_T24_BY_2 CALL ADD_TEMP543_2_T_HML ;R = A - R; M__SUB_SOURCE_FROM_DESTINATION ___T_H, ___T_M, ___T_L, ___TEMP2, ___TEMP1, ___TEMP0 ; A is modified ;int T = R - 3; ; Note that 0 <= R < 3 ;if (T >= 0) Q = Q + 1; CLRF ___T_H CLRF ___T_M CLRF ___T_L MOVLW 0x03 SUBWF ___TEMP0, W BTFSC STATUS, C INCF ___T_L, F CALL ADD_TEMP543_2_T_HML ;if (T >= 0) R = T; ; Don't care this one RETURN ; 16 cycles, IC DIVIDE_T24_BY_2_P12: ; <<12 ;00000000 0000|0000 00000000 SWAPF ___T_M, W ANDLW 0x0F MOVWF ___T_L MOVF ___T_H, W MOVWF ___T_M SWAPF ___T_M, F MOVF ___T_M, W ANDLW 0xF0 ADDWF ___T_L, F MOVLW 0x0F ANDWF ___T_M, F CLRF ___T_H RETURN ; Optimization COPY_T_HML_2_TEMP210: M__COPY_SOURCE_TO_DESTINATION ___T_H, ___T_M, ___T_L, ___TEMP2, ___TEMP1, ___TEMP0 RETURN ; Optimization COPY_T_HML_2_TEMP543: M__COPY_SOURCE_TO_DESTINATION ___T_H, ___T_M, ___T_L, ___TEMP5, ___TEMP4, ___TEMP3 RETURN ; Optimization ADD_TEMP210_2_T_HML: M__ADD_SOURCE_TO_DESTINATION ___TEMP2, ___TEMP1, ___TEMP0, ___T_H, ___T_M, ___T_L RETURN ; Optimization ADD_TEMP543_2_T_HML: M__ADD_SOURCE_TO_DESTINATION ___TEMP5, ___TEMP4, ___TEMP3, ___T_H, ___T_M, ___T_L RETURN ; --------------------------------------------------------------------------------------- ; Don't-care cycles ; Method: http://joshuagalloway.com/lcd.html LCD_INITIALIZE: ; Wait 20ms for LCD to power up CALL WAIT20MS ; Wait for the LCD logic to settle down BCF ___PORT_A, PA_E ; Just to be sure... BCF ___PORT_A, PA_RS M__WRITE_A ; Write D7-4 = 3 hex, with RS = 0 MOVLW b'00110000' MOVWF ___PORT_B M__WRITE_B CALL LCD_SET_ENABLE ; Wait 5ms CALL WAIT5MS ; Write D7-4 = 3 hex, with RS = 0, again CALL LCD_SET_ENABLE ; Wait 200us CALL WAIT200US ; Write D7-4 = 3 hex, with RS = 0, one more time CALL LCD_SET_ENABLE ; Wait 200us CALL WAIT200US ; Write D7-4 = 2 hex, to enable four-bit mode MOVLW b'00100000' MOVWF ___PORT_B M__WRITE_B CALL LCD_SET_ENABLE ; Wait 5ms CALL WAIT5MS ; Write 28 hex (4-Bits, 2-lines) MOVLW 0x28 CALL LCD_WRITE_COMMAND ; Write 08 hex (don't shift display, hide cursor) MOVLW 0x08 CALL LCD_WRITE_COMMAND ; Write 01 hex (clear and home display) MOVLW 0x01 CALL LCD_WRITE_COMMAND ; Write 06 hex (move cursor right) MOVLW 0x06 CALL LCD_WRITE_COMMAND ; Write 0C hex (turn on display) MOVLW 0x0C CALL LCD_WRITE_COMMAND RETURN ; 10 cycles, IC LCD_SET_ENABLE: BSF ___PORT_A, PA_E ; Must wait at least 450ns, which is the case M__WRITE_A BCF ___PORT_A, PA_E M__WRITE_A RETURN ; 434 cycles, IC ; W: contains data LCD_WRITE_DATA: MOVWF ___PORT_B M__WRITE_B ; Make Sure "EN" is 0 or low BCF ___PORT_A, PA_E ; Just to be sure... ; Set "R/S" to 0 for a command, or 1 for data/characters BSF ___PORT_A, PA_RS M__WRITE_A ; Put the HIGH BYTE of the data/command on D7-4 ; Already done ;) ; Set "EN" (EN= 1 or High) ; Wait At Least 450 ns!!! ; Clear "EN" (EN= 0 or Low) CALL LCD_SET_ENABLE ; Wait 5ms for command writes, and 200us for data writes. CALL WAIT200US ; Put the LOW BYTE of the data/command on D7-4 SWAPF ___PORT_B, F M__WRITE_B ; Set "EN" (EN= 1 or High) ; Wait At Least 450 ns!!! ; Clear "EN" (EN= 0 or Low) CALL LCD_SET_ENABLE ; Wait 5ms for command writes, and 200us for data writes. CALL WAIT200US RETURN ; 10034 cycles, IC ; W: contains data LCD_WRITE_COMMAND: MOVWF ___PORT_B M__WRITE_B BCF ___PORT_A, PA_E ; Just to be sure... BCF ___PORT_A, PA_RS ; Set "R/S" to 0 for a command, or 1 for data/characters M__WRITE_A CALL LCD_SET_ENABLE CALL WAIT5MS SWAPF ___PORT_B, F M__WRITE_B CALL LCD_SET_ENABLE CALL WAIT5MS RETURN ; 10039 cycles, IC LCD_CLEAR_AND_RETURN_HOME: MOVLW 0x01 CALL LCD_WRITE_COMMAND RETURN ; 10039 cycles, IC LCD_GOTO_LINE_1: MOVLW b'10000000' CALL LCD_WRITE_COMMAND RETURN ; 10039 cycles, IC LCD_GOTO_LINE_2: MOVLW b'11000000' CALL LCD_WRITE_COMMAND RETURN ; 3490 cycles, IC ; Numerals, alphabetical characters: same code as in the ASCII code ; 00110000 (0x30) -> 0 ; 00110001 (0x31) -> 1 ; etc... ; 01000001 (0x41) -> A ; 01100001 (0x61) -> a LCD_WRITE_DISPLAY_USVH: ; µSv/h section ; A space at the beginning MOVLW 0x20 CALL LCD_WRITE_DATA MOVF ___D5_H, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D4, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D3, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D2, W ADDLW 0x30 CALL LCD_WRITE_DATA ; Write a '.' MOVLW b'00101110' CALL LCD_WRITE_DATA MOVF ___D1, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D0_L, W ADDLW 0x30 CALL LCD_WRITE_DATA RETURN ; 3490 cycles, IC LCD_WRITE_DISPLAY_CPM: ; CPM section ; 2 spaces at the beginning MOVLW 0x20 CALL LCD_WRITE_DATA MOVLW 0x20 CALL LCD_WRITE_DATA MOVF ___D5_H, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D4, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D3, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D2, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D1, W ADDLW 0x30 CALL LCD_WRITE_DATA MOVF ___D0_L, W ADDLW 0x30 CALL LCD_WRITE_DATA RETURN ; Don't-care cycles ; Assume LCD has just been initialized (so the cursor is at home) ; Uses ___TEMP10, ___TEMP11, ___TEMP0, ___TEMP1 LCD_SIGNATURE: ; EEPROM pointer CLRF ___TEMP10 CALL LCD_SIGNATURE_2L CALL LCD_SIGNATURE_2L CALL LCD_SIGNATURE_2L CALL LCD_SIGNATURE_2L RETURN ; Don't-care cycles ; Outputs 2 lines from the EEPROM ; Uses ___TEMP10, ___TEMP11, ___TEMP0, ___TEMP1 LCD_SIGNATURE_2L: CALL LCD_GOTO_LINE_1 CALL LCD_SIGNATURE_8CHARS CALL LCD_GOTO_LINE_2 CALL LCD_SIGNATURE_8CHARS CALL WAIT250MS CALL WAIT250MS CALL WAIT250MS RETURN ; Don't-care cycles ; Outputs a full line from the EEPROM ; ___TEMP10 to contain the address in the EEPROM ; Uses ___TEMP10, ___TEMP11 LCD_SIGNATURE_8CHARS: MOVLW 0x01 MOVWF ___TEMP11 LCD_SIGNATURE_8CHARS_0: MOVF ___TEMP11, W ; ---- MOVF ___TEMP10, W CALL EEPROM_READ CALL LCD_WRITE_DATA INCF ___TEMP10, F ; ---- BCF STATUS, C RLF ___TEMP11, F BTFSS STATUS, C GOTO LCD_SIGNATURE_8CHARS_0 RETURN ; --------------------------------------------------------------------------------------- ; EEPROM location to read to be in W ; Result also in W ; 10 cycles, IC EEPROM_READ: BCF STATUS, RP0 ; Bank 0 MOVWF EEADR ; Address to read BSF STATUS, RP0 ; Bank 1 BSF EECON1, RD ; EE Read - automatically cleared by hardware BCF STATUS, RP0 ; Bank 0 MOVF EEDATA, W ; W = EEDATA RETURN ; --------------------------------------------------------------------------------------- ; 2459 (0x099B) cycles, IC ; Original idea: http://homepage.cs.uiowa.edu/~jones/bcd/decimal.html ; Inputs: ___T_[H, M, L] ; Outputs: ___D0_L, ___D[1, 2, 3, 4], ___D5_H ; ___TEMP0 => n4 ; ___TEMP1 => n3 ; ___TEMP2 => n2 ; ___TEMP3 => n1 ; ___TEMP4 => n0 ; ___TEMP5 => a1_carry ; ___TEMP6 => a0_carry ; ___TEMP7 => rest ; ___TEMP8 => temp ; ___TEMP9 => cYs ; ___TEMP10 => a4 ; ___TEMP11 => a3 ; ___TEMP12 => a2 ; ___TEMP13 => a1 ; ___TEMP14 => a0 ; ___TEMP15 => general temporary container DECODE_20_BITS: ;char n4 = (char)(((value&0x000F0000)>>16)&0x0F); M__EXTRACT_L_NIBBLE ___T_H, ___TEMP0 ;char n3 = (char)(((value&0x0000F000)>>12)&0x0F); M__EXTRACT_H_NIBBLE ___T_M, ___TEMP1 ;char n2 = (char)(((value&0x00000F00)>>8)&0x0F); M__EXTRACT_L_NIBBLE ___T_M, ___TEMP2 ;char n1 = (char)(((value&0x000000F0)>>4)&0x0F); M__EXTRACT_H_NIBBLE ___T_L, ___TEMP3 ;char n0 = (char)(value&0x0000000F); M__EXTRACT_L_NIBBLE ___T_L, ___TEMP4 ;boolean a1_carry = false; CLRF ___TEMP5 ;boolean a0_carry = false; CLRF ___TEMP6 ;char rest = (char)(0); CLRF ___TEMP7 ;char temp = (char)(0); CLRF ___TEMP8 ; a3 <= 135 ;char a3 = (char)(((char)(n4+n4+n4+n4+n4 + n3+n3+n3+n3))&0xFF); MOVF ___TEMP0, W MOVWF ___TEMP11 BCF STATUS, C RLF ___TEMP11, F ;] Multiply by 4 RLF ___TEMP11, F ;] ADDWF ___TEMP11, F ; a3 = 5*n4 MOVF ___TEMP11, W ; W = a3 (= 5*n4) MOVWF ___TEMP12 ; a2 = 5*n4 MOVF ___TEMP0, W ; W = n4 ADDWF ___TEMP11, W ; W = 6*n4 MOVWF ___TEMP10 ;] For a4 - hence contains 6*n4 MOVWF ___TEMP14 ;] For a0 - hence contains 6*n4 MOVF ___TEMP1, W ADDWF ___TEMP11, F ADDWF ___TEMP11, F ADDWF ___TEMP11, F ADDWF ___TEMP11, F ; a4 <= 6*15=90 ;char a4 = (char)(((char)(n4+n4+n4+n4+n4+n4))&0xFF); ; Already done ;) ; a2 <= 105 ;char a2 = (char)(((char)(n4+n4+n4+n4+n4 + n2+n2))&0xFF); MOVF ___TEMP2, W ADDWF ___TEMP12, F ADDWF ___TEMP12, F ; a1 <= 288 ;char a1 = (char)(((char)(n3+n3+n3+n3+n3+n3+n3+n3+n3 + n2+n2+n2+n2+n2 + n1))&0xFF); // Max: 15*15 = 225 = 255 - 30 MOVF ___TEMP1, W MOVWF ___TEMP13 BCF STATUS, C RLF ___TEMP13, F ;] Multiply by 8 RLF ___TEMP13, F ;] RLF ___TEMP13, F ;] ADDWF ___TEMP13, F MOVF ___TEMP2, W ADDWF ___TEMP13, F ADDWF ___TEMP13, F ADDWF ___TEMP13, F ADDWF ___TEMP13, F ADDWF ___TEMP13, F MOVF ___TEMP3, W ADDWF ___TEMP13, F ;rest = (char)(((char)(255-a1))&0xFF); MOVLW 0xFF MOVWF ___TEMP7 MOVF ___TEMP13, W SUBWF ___TEMP7, F ;temp = (char)(((char)(n4+n4+n4))&0xFF); MOVF ___TEMP0, W MOVWF ___TEMP8 ADDWF ___TEMP8, F ADDWF ___TEMP8, F ;if (temp > rest) { ; a1_carry = true; ;} BCF STATUS, C MOVF ___TEMP7, W SUBWF ___TEMP8, W BTFSC STATUS, C BSF ___TEMP5, 0 ;a1 = (char)(((char)(n4+n4+n4)+((char)a1))&0xFF); MOVF ___TEMP0, W ADDWF ___TEMP13, F ADDWF ___TEMP13, F ADDWF ___TEMP13, F ;// a0 <= 375 ;char a0 = (char)(n4+n4+n4+n4+n4+n4 + n3+n3+n3+n3+n3+n3 + n0); // Max: 13*15 = 195 = 255 - 60 ; ___TEMP14 already contains 6*n4 MOVF ___TEMP1, W ADDWF ___TEMP14, F ADDWF ___TEMP14, F ADDWF ___TEMP14, F ADDWF ___TEMP14, F ADDWF ___TEMP14, F ADDWF ___TEMP14, F MOVF ___TEMP4, W ADDWF ___TEMP14, F ;rest = (char)(((char)(255-a0))&0xFF); MOVLW 0xFF MOVWF ___TEMP7 MOVF ___TEMP14, W SUBWF ___TEMP7, F ;temp = (char)(((char)(n2+n2+n2+n2+n2+n2))&0xFF); MOVF ___TEMP2, W MOVWF ___TEMP8 BCF STATUS, C RLF ___TEMP8, F ;] Multiply by 4 RLF ___TEMP8, F ;] ADDWF ___TEMP8, F ADDWF ___TEMP8, F MOVF ___TEMP8, W ;] Prepare for some instructions after... MOVWF ___TEMP15 ;] ;if (temp > rest) { ; a0_carry = true; ;} BCF STATUS, C MOVF ___TEMP7, W SUBWF ___TEMP8, W BTFSC STATUS, C BSF ___TEMP6, 0 ;a0 = (char)(((char)(n2+n2+n2+n2+n2+n2)+((char)a0))&0xFF); MOVF ___TEMP15, W ADDWF ___TEMP14, F ;rest = (char)(((char)(255-a0))&0xFF); MOVLW 0xFF MOVWF ___TEMP7 MOVF ___TEMP14, W SUBWF ___TEMP7, F ;temp = (char)(((char)(n1+n1+n1+n1+n1+n1))&0xFF); MOVF ___TEMP3, W MOVWF ___TEMP8 ADDWF ___TEMP8, F ADDWF ___TEMP8, F ADDWF ___TEMP8, F ADDWF ___TEMP8, F ADDWF ___TEMP8, F MOVF ___TEMP8, W ;] Prepare for some instructions after... MOVWF ___TEMP15 ;] ;if (temp > rest) { ; a0_carry = true; ;} BCF STATUS, C MOVF ___TEMP7, W SUBWF ___TEMP8, W BTFSC STATUS, C BSF ___TEMP6, 0 ;a0 = (char)(((char)(n1+n1+n1+n1+n1+n1)+((char)a0))&0xFF); MOVF ___TEMP15, W ADDWF ___TEMP14, F ;char[] c1d0 = div10AndMod10(a0, a0_carry, (char)0); ;c1 = c1d0[0]; // q ;d0 = c1d0[1]; // r MOVF ___TEMP14, W MOVWF ___DIV_AND_MOD_10_R MOVF ___TEMP6, W MOVWF ___TEMP0 CLRF ___TEMP1 CALL DIV_AND_MOD_10 ;c1 = ___DIV_AND_MOD_10_Q MOVF ___DIV_AND_MOD_10_R, W MOVWF ___D0_L ;char[] c2d1 = div10AndMod10(a1, a1_carry, (char)c1); ;c2 = c2d1[0]; ;d1 = c2d1[1]; MOVF ___TEMP13, W MOVWF ___DIV_AND_MOD_10_R MOVF ___TEMP5, W MOVWF ___TEMP0 MOVF ___DIV_AND_MOD_10_Q, W MOVWF ___TEMP1 CALL DIV_AND_MOD_10 ;c2 = ___DIV_AND_MOD_10_Q MOVF ___DIV_AND_MOD_10_R, W MOVWF ___D1 ;char[] c3d2 = div10AndMod10(a2, false, (char)c2); // a2+c2 <= 105+37 <= 255 (37 is the maximum for cY) ;c3 = c3d2[0]; ;d2 = c3d2[1]; MOVF ___TEMP12, W MOVWF ___DIV_AND_MOD_10_R CLRF ___TEMP0 MOVF ___DIV_AND_MOD_10_Q, W MOVWF ___TEMP1 CALL DIV_AND_MOD_10 ;c3 = ___DIV_AND_MOD_10_Q MOVF ___DIV_AND_MOD_10_R, W MOVWF ___D2 ;char[] c4d3 = div10AndMod10(a3, false, (char)c3); // a3+c3 <= 135+37 <= 255 (37 is the maximum for cY) ;c4 = c4d3[0]; ;d3 = c4d3[1]; MOVF ___TEMP11, W MOVWF ___DIV_AND_MOD_10_R CLRF ___TEMP0 MOVF ___DIV_AND_MOD_10_Q, W MOVWF ___TEMP1 CALL DIV_AND_MOD_10 ;c4 = ___DIV_AND_MOD_10_Q MOVF ___DIV_AND_MOD_10_R, W MOVWF ___D3 ;char[] c5d4 = div10AndMod10(a4, false, (char)c4); // a4+c4 <= 90+37 <= 255 (37 is the maximum for cY) ;c5 = c5d4[0]; ;d4 = c5d4[1]; MOVF ___TEMP10, W MOVWF ___DIV_AND_MOD_10_R CLRF ___TEMP0 MOVF ___DIV_AND_MOD_10_Q, W MOVWF ___TEMP1 CALL DIV_AND_MOD_10 ;c5 = ___DIV_AND_MOD_10_Q MOVF ___DIV_AND_MOD_10_R, W MOVWF ___D4 ;d5 = c5; MOVF ___DIV_AND_MOD_10_Q, W MOVWF ___D5_H RETURN ; --------------------------------------------------------------------------------------- ; 458 instructions, IC ; Inputs: ; ___DIV_AND_MOD_10_R to contain the value ; ___TEMP0 to contain: 0 if it doesn't have a carry, !=0 if it has ; ___TEMP1 to contain toAdd ; Outputs: ; ___DIV_AND_MOD_10_Q: result ; ___DIV_AND_MOD_10_R: modulo ; Uses ___T_DIV10 ; Proved (exhaustive test) to be valid for 0 <= toAdd <= 245. ; Beginning from toAdd = 246, it'll fail. ; Never fails with all i (0->255), all hasCarry (representing value 256). ; Original, approx. cycles version: 36 instructions, NIC ; Used 31 more instructions to make it fixed-instruction DIV_AND_MOD_10: ;char q = 0xFF; CLRF ___DIV_AND_MOD_10_Q DECF ___DIV_AND_MOD_10_Q, F ;char r = i; ; The value is already in ___DIV_AND_MOD_10_R ; For fixed-instruction count support ; 'i' can be up to 255, thus the 'DIV_AND_MOD_10_0' code entry point can iterate 26 times ; Use 27 (easy computing) MOVLW 0x1B ;27 MOVWF ___T_DIV10 ;do { DIV_AND_MOD_10_0: DECF ___T_DIV10, F ;q = (char)(((char)(q+1))&0xFF); INCF ___DIV_AND_MOD_10_Q, F ;r = (char)(((char)(r-10))&0xFF); MOVLW 0x0A ;10 SUBWF ___DIV_AND_MOD_10_R, F ; Clears the carry if the result is <0 ;} while (r >= 0); BTFSS STATUS, C GOTO DIV_AND_MOD_10_1 GOTO DIV_AND_MOD_10_0 DIV_AND_MOD_10_1: NOP DIV_AND_MOD_10_0_ADJ: ; 8 instructions in the loop 'DIV_AND_MOD_10_0' GOTO DIV_AND_MOD_10_0_ADJ_0 DIV_AND_MOD_10_0_ADJ_0: GOTO DIV_AND_MOD_10_0_ADJ_1 DIV_AND_MOD_10_0_ADJ_1: NOP DECFSZ ___T_DIV10, F GOTO DIV_AND_MOD_10_0_ADJ NOP ;r = (char)(((char)(r+10))&0xFF); MOVLW 0x0A ;10 ADDWF ___DIV_AND_MOD_10_R, F ; -------------------------------------------------------------- HAS CARRY - 17 cycles ;if (hasCarry) { MOVLW 0xFF ANDWF ___TEMP0, F BTFSC STATUS, Z GOTO DIV_AND_MOD_10_NO_CARRY_ADJ ; *** 13 cycles ;r = (char)(((char)(r+6))&0xFF); // 6 = 256%10 -> r <= 255 MOVLW 0x06 ;6 ADDWF ___DIV_AND_MOD_10_R, F ; q = (char)(((char)(q+25))&0xFF); MOVLW 0x19 ;25 ADDWF ___DIV_AND_MOD_10_Q, F ;if (r > 10) MOVLW 0x0A ;10 SUBWF ___DIV_AND_MOD_10_R, W BTFSS STATUS, C GOTO DIV_AND_MOD_10_2_ADJ ; Take that if W<0 (R<10) ;{ ;q = (char)(((char)(q+1))&0xFF); INCF ___DIV_AND_MOD_10_Q, F ;r = (char)(((char)(r-10))&0xFF); MOVLW 0x0A ;10 SUBWF ___DIV_AND_MOD_10_R, F GOTO DIV_AND_MOD_10_2 ;} DIV_AND_MOD_10_2_ADJ: NOP NOP GOTO DIV_AND_MOD_10_2 ; *** DIV_AND_MOD_10_NO_CARRY_ADJ: ; Wait 12 cycles - sad and boring but works GOTO DIV_AND_MOD_10_NO_CARRY_ADJ_0 DIV_AND_MOD_10_NO_CARRY_ADJ_0: GOTO DIV_AND_MOD_10_NO_CARRY_ADJ_1 DIV_AND_MOD_10_NO_CARRY_ADJ_1: GOTO DIV_AND_MOD_10_NO_CARRY_ADJ_2 DIV_AND_MOD_10_NO_CARRY_ADJ_2: GOTO DIV_AND_MOD_10_NO_CARRY_ADJ_3 DIV_AND_MOD_10_NO_CARRY_ADJ_3: GOTO DIV_AND_MOD_10_NO_CARRY_ADJ_4 DIV_AND_MOD_10_NO_CARRY_ADJ_4: GOTO DIV_AND_MOD_10_2 DIV_AND_MOD_10_2: ; -------------------------------------------------------------- DIV_AND_MOD_10_NO_CARRY: ;q = (char)(((char)(q-1))&0xFF); DECF ___DIV_AND_MOD_10_Q, F ;r = (char)(((char)(r+toAdd))&0xFF); MOVF ___TEMP1, W ADDWF ___DIV_AND_MOD_10_R, F ; For fixed-instruction count support ; 'toAdd' can be up to 245, thus the 'DIV_AND_MOD_10_4' code entry point can iterate 25 times ; Use 26 (easy computing) MOVLW 0x1A ;26 MOVWF ___T_DIV10 ;do { DIV_AND_MOD_10_4: DECF ___T_DIV10, F ;q = (char)(((char)(q+1))&0xFF); INCF ___DIV_AND_MOD_10_Q, F ;r = (char)(((char)(r-10))&0xFF); MOVLW 0x0A ;10 SUBWF ___DIV_AND_MOD_10_R, F ;} while (r >= 0); BTFSS STATUS, C GOTO DIV_AND_MOD_10_5 GOTO DIV_AND_MOD_10_4 ;} DIV_AND_MOD_10_5: NOP DIV_AND_MOD_10_5_ADJ: ; 8 instructions in the loop 'DIV_AND_MOD_10_0' GOTO DIV_AND_MOD_10_5_ADJ_0 DIV_AND_MOD_10_5_ADJ_0: GOTO DIV_AND_MOD_10_5_ADJ_1 DIV_AND_MOD_10_5_ADJ_1: NOP DECFSZ ___T_DIV10, F GOTO DIV_AND_MOD_10_5_ADJ NOP ;r = (char)(((char)(r+10))&0xFF); MOVLW 0x0A ;10 ADDWF ___DIV_AND_MOD_10_R, F RETURN ; --------------------------------------------------------------------------------------- ; All included: caller ; Uses ___TEMP0, ___TEMP1 WAIT20MS: MOVLW 0x13 ;19 MOVWF ___TEMP1 WAIT20MS_DECREMENT1: CALL WAIT1MS DECFSZ ___TEMP1, F GOTO WAIT20MS_DECREMENT1 MOVLW 0xFF ;255 MOVWF ___TEMP0 WAIT20MS_DECREMENT2: DECFSZ ___TEMP0, F GOTO WAIT20MS_DECREMENT2 MOVLW 0x39 ;57 MOVWF ___TEMP0 WAIT20MS_DECREMENT3: DECFSZ ___TEMP0, F GOTO WAIT20MS_DECREMENT3 RETURN ; All included: caller ; Uses ___TEMP0 WAIT200US: MOVLW 0x41 ;65 MOVWF ___TEMP0 WAIT200US_DECREMENT: DECFSZ ___TEMP0, F GOTO WAIT200US_DECREMENT NOP NOP RETURN ; All included: caller ; Uses ___TEMP0, ___TEMP1 WAIT250MS: MOVLW 0xFE ;249 MOVWF ___TEMP1 WAIT250MS_DECREMENT1: CALL WAIT1MS DECFSZ ___TEMP1, F GOTO WAIT250MS_DECREMENT1 MOVLW 0x52 ;82 MOVWF ___TEMP0 WAIT250MS_DECREMENT2: DECFSZ ___TEMP0, F GOTO WAIT250MS_DECREMENT2 NOP RETURN ; All included: caller ; Uses ___TEMP0 WAIT5MS: CALL WAIT1MS CALL WAIT1MS CALL WAIT1MS CALL WAIT1MS CLRF ___TEMP0 WAIT5MS_DECREMENT1: DECFSZ ___TEMP0, F GOTO WAIT5MS_DECREMENT1 MOVLW 0x4B ;75 MOVWF ___TEMP0 WAIT5MS_DECREMENT2: DECFSZ ___TEMP0, F GOTO WAIT5MS_DECREMENT2 GOTO WAIT5MS_DECREMENT2_END WAIT5MS_DECREMENT2_END: RETURN ; All included: caller ; Uses ___TEMP0 WAIT1MS: CLRF ___TEMP0 WAIT1MS_DECREMENT1: DECFSZ ___TEMP0, F GOTO WAIT1MS_DECREMENT1 MOVLW 0x4B ;75 MOVWF ___TEMP0 WAIT1MS_DECREMENT2: DECFSZ ___TEMP0, F GOTO WAIT1MS_DECREMENT2 GOTO WAIT1MS_DECREMENT2_END WAIT1MS_DECREMENT2_END: RETURN ; All included: caller ; Uses ___TEMP0 WAIT250US: MOVLW 0x51 ;81 MOVWF ___TEMP0 WAIT250US_DECREMENT: DECFSZ ___TEMP0, F GOTO WAIT250US_DECREMENT NOP NOP RETURN ; --------------------------------------------------------------------------------------- END