Mercurial > public > mk2
diff code_part1/OSTC_code_asm_part1/aa_wordprocessor.asm @ 83:3e351e25f5d1
adding anti-aliased fonts frame and merging some patches from Jeando
author | heinrichsweikamp |
---|---|
date | Tue, 07 Dec 2010 22:36:19 +0100 |
parents | |
children | 3bcccb697bce |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/code_part1/OSTC_code_asm_part1/aa_wordprocessor.asm Tue Dec 07 22:36:19 2010 +0100 @@ -0,0 +1,468 @@ +;============================================================================= +; +; file aa_wordprocessor.asm +; brief Anti-aliased word processor +; author JD Gascuel. +; +; copyright (c) 2010, JD Gascuel. All rights reserved. +; $Id: aa_wordprocessor.asm 72 2010-11-29 22:45:12Z gascuel $ +;============================================================================= +; HISTORY +; 2010-11-22 : [jDG] Creation. +; +; BUGS : None known yet... +;============================================================================= +; +; MEMORY FOOTPRINT: +;------------------ +; +; wp_wordprocessor : 8KB, including fonts. +; aa_wordprocessor : 0.5KB code +; + 3.5KB aa_font28 (reduced to 99 chars) +; + 1.6KB aa_font48 +; + 2.2KB aa_font90 +; = 7.9 KB including fonts... +; +; Input registers: +; letter:26 String to print. +; win_font Font size (0=small, 1=medium, 2=large) +; win_color1:2 16bits unpacked color +; win_top, win_leftx2 Position on screen +; win_inverse Inverse video mode. +; +; Available general purpose registers: +; PRODH, PRODL (needed for array indexing) +; FSRx 12bits. Usefull as RAM pointers. +;============================================================================= + +; Flags allocation: +#define aa_antialias aa_flags,0 +#define aa_color_quart aa_flags,1 +#define aa_color_half aa_flags,2 + +; Extracted from p3_wordprocessor includes: +#include aa_fonts.asm +aa_wp code ; Mark segment into the .map file + +;------------------------------------------------------------------------------ +; Setup pointers for a char: +; Inputs WREG = char to draw, win_font +; Output aa_start, aa_end, aa_height, aa_flags +; Trashed PRODH, PRODL, TBLPTR, TABLAT +; +aa_char_setup: + movwf PRODL,A ; save char into PROD for now. + + movf win_font,W,BANKED ; Get font number (updates Z flag) + bnz aa_char_1 + + ; SMALL font ----------------------------------------------------- + ; Font SMALL character folding... +aa_char_0: +; movlw 0x7E ; Skip chars between ~ and ¡ +; cpfsgt PRODL,A ; Compare with char; +; bra aa_char_01 +; movlw -.34 ; substract 34 (decimal!) +; addwf PRODL,F,A ; put back to PRODL +;aa_char_01: + movlw LOW aa_font28_block + movwf TBLPTRL,A + movlw HIGH aa_font28_block + movwf TBLPTRH,A + bra aa_char_3 + + ; MEDIUM font ---------------------------------------------------- +aa_char_1: + decfsz WREG,A ; This is medium font ??? + bra aa_char_2 + + ; Font MEDIUM block: + movlw LOW aa_font48_block + movwf TBLPTRL,A + movlw HIGH aa_font48_block + movwf TBLPTRH,A + bra aa_char_3 + + ; LARGE font ----------------------------------------------------- +aa_char_2: + ; Font LARGE block: + movlw LOW aa_font90_block + movwf TBLPTRL,A + movlw HIGH aa_font90_block + movwf TBLPTRH,A + + ; Execute font block --------------------------------------------- +aa_char_3: + movlw UPPER aa_font28_block + movwf TBLPTRU,A + +aa_char_30: + tblrd*+ ; Read FROM char + movf TABLAT,W ; Get it, and set Z,N + bz aa_char_32 ; Break at end of translations + + tblrd*+ ; Read TO char + cpfseq PRODL,A ; FROM == current char ? + bra aa_char_30 ; Different: loop + movff TABLAT, PRODL ; make substitution + bra aa_char_30 ; Loop. + +aa_char_32: + tblrd*+ ; Read first char + movf TABLAT,W ; get it. + subwf PRODL,F ; (char - first) --> PRODL + + tblrd*+ ; Read nb chars + movf TABLAT,W ; nbchars --> WREG + tblrd*+ ; Read default char + cpfslt PRODL ; if char > WREG ? + movff TABLAT,PRODL ; replace PRODL +aa_char_33: + clrf aa_flags,BANKED ; Default to no AA + tblrd*+ ; Read font height + AA flag + movf TABLAT,W ; into WREG + bnn aa_char_34 ; High bit set ? + bsf aa_antialias,BANKED ; YES : then the font is AA. +aa_char_34 + andlw 0x7F ; Keep just font height, + movwf aa_height,BANKED ; then save it (its a register) + + movf PRODL,W ; Read back char + mullw 2 ; PROD = 2*(char - base), TBLPTR=idx + movf PRODL,W + addwf TBLPTRL,F ; Add into TBLPTR (low byte) + movf PRODH,W + addwfc TBLPTRH,F ; and high byte. + + tblrd*+ ; aa_start = PROM16(*tblptr++) + movff TABLAT,aa_start ; Read low byte + tblrd*+ + movff TABLAT,aa_start+1 ; and high byte + + tblrd*+ ; aa_end = PROM16(*tblptr++) + movff TABLAT,aa_end ; Read low byte + tblrd*+ + movff TABLAT,aa_end+1 ; and high byte + + return + +;------------------------------------------------------------------------------ +; Character width +; Inputs aa_start, aa_end, aa_width, aa_height, aa_flags +; Output width added to aa_width +; Trashed aa_bitlen, TBLPTR, TABLAT +; +aa_char_width: + movff aa_start, TBLPTRL ; TBLPTR = aa_start + movff aa_start+1, TBLPTRH + clrf aa_bitlen,BANKED ; clear reminders... + + ; Read bitmap byte, and decode length: +aa_char_width_1: + ifdef AA_BYTE_SWAP + btg TBLPTRL,0,A ; Toggle low ptr bit. + tblrd* + movf TABLAT,W,A ; Store to WREG + btg TBLPTRL,0,A ; Get is back + tblrd*+ ; then increment (but trash TABLAT) + movwf TABLAT,A ; Then restore copy to TABLAT. + else + tblrd*+ ; Normal read... + movf TABLAT,W,A ; Store copy to WREG + endif + btfss aa_antialias,BANKED ; Antialiased font ? + bra aa_char_width_10 ; No: always 7 bits count + + bn aa_char_width_10 ; Non-white pixels ? + andlw 0x1F ; Yes : 5 bits count. +aa_char_width_10: + andlw 0x7F ; No: 7 bit count. + incf WREG,A ; WREG = repetition count + addwf aa_bitlen,F,BANKED ; Add remaining pixels from last code. + + movf aa_height,W,BANKED ; WREG = - height + negf WREG,A + + ; This is a hand-made division by successive substraction of height +aa_char_width_2: + addwf aa_bitlen,F,BANKED ; Try to substract aa_height + bn aa_char_width_3 ; If neg it was a bad idea... + + infsnz aa_width,F,BANKED ; Succeded: do a 12bit increment + incf aa_width+1,F,BANKED ; on the aa_width counter. + bra aa_char_width_2 ; and loop. + +aa_char_width_3: + negf WREG,A ; WREG = +height + addwf aa_bitlen,F,BANKED ; Restore true reminder. + + ; Are we done ? + movf TBLPTRL,W,A ; Compare TBLPTR to aa_end + cpfseq aa_end,BANKED + bra aa_char_width_1 ; Loop if LOW is different + movf TBLPTRH,W,A + cpfseq aa_end+1,BANKED ; Loop to if HIGH is different + bra aa_char_width_1 + + return + +;------------------------------------------------------------------------------ +; String width +; Inputs letter (SHOULD BE NULL TERMINATED) +; Output aa_width, aa_height +; Trashed PROD, TBLPTR, FSR2, aa_bitlen, aa_start, aa_end, aa_flags +; +aa_string_width: + lfsr FSR2, letter ; FSR2 pointer to start of string. + + clrf aa_width,BANKED ; Clear width sum. + clrf aa_width+1,BANKED ; (12 bit counter) + +aa_string_width_1: + movf POSTINC2,W,A ; WREG = *FSR2++ + bz aa_string_width99 ; Exit if null byte encountered. + + rcall aa_char_setup ; setup aa_start / aa_end + rcall aa_char_width ; sum-up width into aa_width + bra aa_string_width_1 ; and loop. + +aa_string_width99: + return + +;------------------------------------------------------------------------------ +; Fast macros to write to OLED display. +; Adding a call/return adds 3 words and a pipeline flush, hence make it +; nearly twice slower... +; +; Input : commande as macro parameter. +; Output : NONE +; Trash : WREG +; +AA_CMD_WRITE macro cmd + movlw cmd + bcf oled_rs ; Cmd mode + movwf PORTD,A + bcf oled_rw ; Tick the clock + bsf oled_rw + endm +; +; Input : PRODH:L as 16bits data. +; Output : NONE +; Trash : NONE +; +AA_DATA_WRITE_PROD macro + bsf oled_rs ; Data mode + movff PRODH,PORTD ; NOTE: OLED is BIGENDIAN! + bcf oled_rw ; Tick the clock + bsf oled_rw + movff PRODL,PORTD + bcf oled_rw ; Tick the clock + bsf oled_rw + endm + +;------------------------------------------------------------------------------ +; Output OLED Window Address commands. +; Inputs : win_top, win_leftx2, aa_height, aa_width. +; Output : PortD commands. +; Trashed: PROD +; +aa_box_cmd: + movf win_leftx2,W,BANKED ; Compute left = 2*leftx2 + mullw 2 + AA_CMD_WRITE 0x35 ; this is the left border + AA_DATA_WRITE_PROD + + movf aa_width,W,BANKED ; right = left + width - 1 + addwf PRODL,F,A + movf aa_width+1,W,BANKED + addwfc PRODH,F,A + decf PRODL,F,A ; decrement result + bc aa_box_cmd_1 ; No borrow (/Carry) ? skip propagating. + decf PRODH,F,A +aa_box_cmd_1: + + AA_CMD_WRITE 0x36 ; Write and the right border + AA_DATA_WRITE_PROD + + movf win_top,W,BANKED ; Write top / bottom window + movwf PRODH,A ; (remember PRODH output first) + addwf aa_height,W,BANKED + decf WREG,A + movwf PRODL,A ; And PRODL is later... + AA_CMD_WRITE 0x37 + AA_DATA_WRITE_PROD + + movf win_leftx2,W,BANKED ; Start ptr left + mullw 2 + AA_CMD_WRITE 0x20 + AA_DATA_WRITE_PROD + + movf win_top,W,BANKED ; Start ptr top + mullw 1 ; Load into PRODH:L + AA_CMD_WRITE 0x21 + AA_DATA_WRITE_PROD + + return + +;------------------------------------------------------------------------------ +; Decode a compressed char. +; Inputs aa_start, aa_end, aa_height, win_invert, win_color1, win_color2 +; Output none +; Trashed TBLPTR, TABLAT, PROD, aa_bitlen, aa_flags, aa_colorDir:2 +; +aa_decode_char: + movff aa_start, TBLPTRL ; TBLPTR = aa_start + movff aa_start+1, TBLPTRH + + ; Read bitmap byte, and decode color & length +aa_decode_1: + ifdef AA_BYTE_SWAP + btg TBLPTRL,0,A ; Toggle low ptr bit. + tblrd* + movf TABLAT,W,A ; Store to WREG + btg TBLPTRL,0,A ; Get is back + tblrd*+ ; then increment (but trash TABLAT) + movwf TABLAT,A ; Then restore copy to TABLAT. + else + tblrd*+ ; Normal read... + movf TABLAT,W,A ; Store copy to WREG + endif + btfss aa_antialias,BANKED ; Antialiased font ? + bra aa_decode_10 ; No: always 7 bits count + bn aa_decode_10 ; Non-white pixels ? + andlw 0x1F ; Yes : 5 bits count. +aa_decode_10: + andlw 0x7F ; No: 7 bit count. + incf WREG,A + movwf aa_bitlen,BANKED ; repetition count --> aa_bitlen + + ;---- COLOR DECODING --------------------------------------------- + ; + ; Code Normal Inverse + ; 1xx 0% 100% : Managed by aa_decode_13 + ; 011 25% 75% + ; 010 50% 50% + ; 001 75% 25% + ; 000 100% 0% : Managed by aa_decode_13 too. + ; + movf TABLAT,W,A ; Get back code + btfss aa_antialias,BANKED ; Antialiased font ? + bra aa_decode_13 ; NO: 1bit case + + ; Asymetry test: 1xx code is another case for 1bit color. + ; This have to be done before inverse video, because + ; of the asymetric processing ! + bn aa_decode_13 ; decode as not-aa + + ; Manage 000 special case too: + andlw 0xE0 ; Select color bits + bz aa_decode_13 ; That's a 000 ! + + ; Apply reverse video, in a reversed way + btfss win_invert,0 ; Inverse video mode ? + sublw 0x80 + + ; Move the two bits to aa_color_half and aa_color_quarter: + swapf WREG ; --> 0000.0LL0 byte + iorlw b'001' ; We are in AA mode, don't forget it ! + movwf aa_flags ; save that to aa_color_(half/quad)/AA flags. + + ;---- 2 bit x RGB(16bits) computation ---------------------------- + clrf PRODL ; We will accumulate result here... + clrf PRODH + + ; Take color div 2 into aa_colorDiv. Max red = 15/31 + rrcf win_color1,W,BANKED ; xRRRRxGG + andlw b'01111011' ; 0RRRR0GG (don't change C) + movwf aa_colorDiv+0,BANKED + rrcf win_color2,W,BANKED ; GGGxBBBB + andlw b'11101111' ; GGG0BBBB + movwf aa_colorDiv+1,BANKED + + btfss aa_color_half + bra aa_decode_12 + + movff aa_colorDiv+0,PRODH ; Add color/2 if bit set. + movff aa_colorDiv+1,PRODL ; OLED is big endian, so swap here. +aa_decode_12: + btfss aa_color_quart + bra aa_decode_3 + + ; Divide it once again by 2. Max red = 7/31. + rrcf aa_colorDiv+0,W,BANKED ; xxRRRxxG + andlw b'00111001' ; 00RRR00G (don't change C) + movwf aa_colorDiv+0,BANKED + rrcf aa_colorDiv+1,W,BANKED ; GGGxxBBB + andlw b'11100111' ; GGG00BBB + movwf aa_colorDiv+1,BANKED + + movf aa_colorDiv+1,W,BANKED ; Add color/4 + addwf PRODL,F ; NOTE: 7/31+15/31=22/31, + movf aa_colorDiv+0,W,BANKED ; hence composants won't overlap. + addwfc PRODH,F ; In right order, to propagate carry. + + bra aa_decode_3 ; Done. + + ; ---- Simple BLACK and WHITE cases ------------------------------ +aa_decode_13: ; Got a 1xx or a 000 code... + btfsc win_invert,0 ; Inverse video mode ? + xorlw 0x80 ; YES: invert levels. + bn aa_decode_2 ; Then test high bit. + + ; WHITE pixel (ie. full color) + movff win_color1,PRODH ; current draw color + movff win_color2,PRODL ; (rem: OLED is big endian) + bra aa_decode_3 + +aa_decode_2: + clrf PRODH,A ; BLACK pixel + clrf PRODL,A + +aa_decode_3: + ;---- PIXEL WRITE LOOP ------------------------------------------- + AA_DATA_WRITE_PROD + decf aa_bitlen,BANKED + bnz aa_decode_3 + + ;---- BYTE-CODE LOOP --------------------------------------------- + ; Are we done ? + movf TBLPTRL,W,A ; Compare TBLPTR to aa_end + cpfseq aa_end,BANKED + bra aa_decode_1 ; Loop if LOW is different + movf TBLPTRH,W,A + cpfseq aa_end+1,BANKED ; Loop to if HIGH is different + bra aa_decode_1 + + return + +;------------------------------------------------------------------------------ +; Setup pointers for a char: +; Inputs : letter : string to print (SHOULD BE NULL TERMINATED) +; Output : OLED commands on port D + clocks. +; +aa_wordprocessor: + ; Make sure context is well known + movlb HIGH aa_start ; Switch to bank 0... + + rcall aa_string_width ; Set aa_height, compute aa_width + rcall aa_box_cmd ; Use that for the box. + + ; Restart the loop for each char to print + lfsr FSR2, letter ; FSR2 pointer to start of string. + + ; DATA bloc commande: + AA_CMD_WRITE 0x22 + +aa_wordprocessor_1: + movf POSTINC2,W,A ; WREG = *FSR2++ + bz aa_wordprocessor_99 ; Exit if null byte encountered. + + rcall aa_char_setup ; setup aa_start / aa_end + rcall aa_decode_char ; sum-up width into aa_width + bra aa_wordprocessor_1 ; and loop. + +aa_wordprocessor_99: + ; END of bloc commande + AA_CMD_WRITE 0x00 + + return