Shop OBEX P1 Docs P2 Docs Learn Events
Quick propeller font questions — Parallax Forums

Quick propeller font questions

Dr_AculaDr_Acula Posts: 5,484
edited 2012-02-24 18:18 in Propeller 1
I'm trying to work out how the propeller font gets read.

I believe this object uses the internal font http://obex.parallax.com/objects/67/

Reading through the code, I can't seem to see where the font gets read. Ascii bytes get moved to a screen buffer, and longs get moved out to the display, and somewhere in there the ascii byte must be translated to font pixels.

I gather the font is stored in internal rom so the code that reads this may only be one or two lines using a jump table based on the ascii value which I suspect is why it is hard to spot.

Another pair of eyes would be most appreciated here!

Comments

  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-23 16:43
    I think if you pull apart line 172 of TV_Text.spin, you'll find an encoding of the address of the font. See TV.spin lines 615-626.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-23 16:53
      screen[row * cols + col] := (color << 1 + c & 1) << 10 + $200 + c & $FE    
    

    Yes there is something clever going on there.

    Hmm - screen is a word array rows*cols so that is 40x13*2 bytes. Is that enough to contain the bitmap for the font though? (16 longs per char). Or does that line above now contain an "address" to the bitmap in rom?

    I'm working on a little bit of spin code to get the font bitmap out of rom and into an array so I can manipulate the bits (maybe resize the font by averaging the bits etc).

    Addit: Do'h *hits head*

    It probably is something simple like
    address := $8000
    myvalue :=long[@address]
    

    and then (reading p32 of the manual) - undo the interleaving.
  • kuronekokuroneko Posts: 3,623
    edited 2012-02-23 17:19
    See if this helps. Pressing a key (PST) will cycle through the character patterns.
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    OBJ
      serial: "FullDuplexSerial"
      
    PUB null : n
    
      serial.start(31, 30, %0000, 115200)
      waitcnt(clkfreq*3 + cnt)
    
      repeat
        serial.tx(0)
        print(n++)
        serial.rx
    
    PRI print(ch) : n | addr
    
      ch &= $FF
      repeat n from 0 to 31
        addr := @long[$8000 + 128 * (ch >> 1)][n]
        serial.hex(addr, 8)
        serial.tx(" ")
        print_line(long[addr], ch)
    
    PRI print_line(pattern, ch) : n
    
      pattern >>= ch & 1
      repeat n from 0 to 15
        serial.tx(lookupz(pattern & 1: " ", "#"))
        pattern >>= 2
      serial.tx(13)
      
    DAT
    
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-23 17:19
    $200 << 6 = $8000

    Part of the word is left-shifted by 6 in the TV.spin source.
  • average joeaverage joe Posts: 795
    edited 2012-02-23 18:33
    Dr A, check out my pfw. This is unoptimized right now, but it works.
    FONT_ROM_ADDRESS              = $8000 
    
    VAR
    long BackgroundColor,ActiveColor, ActiveTextColor, InactiveTextColor, Row, Col, RowBorder,ColBorder, WindowX1, WindowX2, WindowY1, WindowY2
    long ScreenBuffer
    
    PUB WriteActiveCr(Character, PosR, PosC, RBorder, CBorder, BgC, TxC) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2
      odd_even                      := character & $0001
      characterpointer              := character & $fffe
      characterpointer              >>= 1
      characterpointer              *= 32
       repeat idx from RBorder to 31 - RBorder 
         bitpatern[idx] := long[FONT_ROM_ADDRESS][characterpointer + idx]   ' this is the line that reads longs off the eprom
         
       Row              := PosR      
       Col              := PosC
       RowBorder        := RBorder
       ColBorder        := CBorder
       BackgroundColor  := BgC
       ActiveTextColor  := Txc
    
      y1 :=  PosC + CBorder 
      y2 := (PosC + 15) - CBorder
      x1 :=  PosR + RBorder
      x2 := (PosR + 31) - RBorder
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
      repeat idx from RBorder to 31 - RBorder        
         repeat pxlidx from odd_even + (CBorder*2) to (odd_even + 30) - (CBorder*2) step 2
           pxlidxdcd := |< pxlidx   
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Com(REG_RAMDATAWRITE)
             Lcd_Write_Data(TxC)
           else
             Lcd_Write_Com(REG_RAMDATAWRITE)
             Lcd_Write_Data(BgC)         
      if (((Col + 16) >  319 ) and  ((Row + 32) > 223))
        Row := 0
        Col := 0
      elseif (((Col + 16) >  319 ) and  ((Row + 32) < 223)) 
        Row := Row + 32
        Col := 0
      else
        Col := Col + 16
     return
    
    PUB SetWindow(x1, y1, x2, y2) | HORIZONTALRAMADDRESSPOS
     WindowX1 := x1
     WindowX2 := x2
     WindowY1 := y1
     WindowY2 := y2
        HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8)      
           Lcd_Write_Com (REG_HORIZONTALRAMADDRESSPOS)
           Lcd_Write_Data(HORIZONTALRAMADDRESSPOS)
           Lcd_Write_Com (REG_VERTICALRAMADDRESSSTART)
           Lcd_Write_Data(y1)
           Lcd_Write_Com (REG_VERTICALRAMADDRESSEND)
           Lcd_Write_Data(y2)
    PUB SetGAddress(x,y)
           Lcd_Write_Com (REG_SETGDDRxADDRESSCOUNTER) ''max %1111_1111, $FF
           Lcd_Write_Data(x)
           Lcd_Write_Com (REG_SETGDDRyADDRESSCOUNTER) ''max %1_0011_1111, $13f
           Lcd_Write_Data(y)
    
    I'm sure there is a better way to do this, but this is what I was able to get working. The prop font is stored in ram starting @ address $8000. Characters are encoded in pairs, with bits30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0 representing character 0 and bits 31,29,27,25,232,21,19,17,15,13,11,9,7,5,3,1 represent character 1. Each character pair is encoded in 32 longs. This makes each character 16 x 32. I hope this helps. I thing I've got it figured out pretty well. Let me know if you need more info. I am converting this stuff to asm, so i will have that for you later if you want.

    *edit* BTW. The characters are encoded in ascii, so reading them is real easy. RomAddress+ (character * 32 The propeller tool has a handy font reference.
  • tonyp12tonyp12 Posts: 1,951
    edited 2012-02-23 19:35
    You just want in general want to know how the font is read?
    I think most drivers use 4 color mode, but back-ground and 2 other colors are the same,
    you would not have to un-interleave the fonts by using this trick.

    But in my VGA font test I do un-interleave the font, the source code is in description.
    Font test:
    http://youtu.be/dtahz8WwBm0
    Smooth scroller:
    http://youtu.be/dZZMfN2loAg
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-23 19:42
    Dr_Acula wrote: »
    It probably is something simple like
    address := $8000
    myvalue :=long[@address]
    

    and then (reading p32 of the manual) - undo the interleaving.
    Almost:
      screen[row * cols + col] := (color << 1 + c & 1) << 10 + $200 + c & $FE    
    

    ($200+(high 7-bits of c)) << 5 = the address of the character pair.

    (color << 1 + (low bit of c)) << 10 = the word portion that selects color for the tile. Color selection is used to choose the high-bit of each pair of bits in the word, or the low bit.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-23 22:59
    Thanks everyone. This forum is fantastic!

    Yes this is for the ILI9325 display. At the moment you need to read a font off the SD card in order to display anything. But you can't print a message like "SD card not found" because you need the font first. So even a simple display (320/16 = 20 chars wide) using the propeller font will be very helpful for startup debugging.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-23 23:04
    Then I guess tonyp12's response would be most useful to you.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-23 23:24
    All the replies are very useful - thanks++.

    In a way, super fast speed is not so important so Spin will be fine. One you can print a message on the screen saying the SD card has been found, and that it is loading a font, then you can use that loaded font to display things faster using existing pasm.

    So it is mainly just to display whether i) an SD card has been found and ii) whether certain essential files like icons and fonts have been found on that SD card.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-24 00:30
    I suspect that deinterleaving the font would be an intensive enough operation that you would want to do that in pasm (512 operations per character), else it could take several seconds to say "No SD card found", but once that's done, everything else could be done in spin.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-24 05:47
    This is a little slow (circuitsoft's guess on the time is exactly correct!), but this does work and it would be very useful for debugging an SD card
    PUB Propfont  ' use propeller font in the rom for bootup messages when debugging sd cards
        curx := 0                               ' set cursor to top left of screen (common variable)
        cury := 0
        Propfont_string(string("Loading SD"))   ' string to send
        Propfont_string(string("Loading Font"))
    
    PUB Propfont_string(stringptr)                          'print at curx,cury
      repeat strsize(stringptr)
        ILI9325.draw(curx,cury,curx+15,cury+31)             ' location to start drawing    
        Propfont_out(byte[stringptr++])   
        curx +=16
      curx := 0
      cury += 32                                            ' new line at end of string
    
    PUB Propfont_out(ascii) | address,pixels
        address := $8000 + (ascii >> 1) << 7                ' get rom address
        repeat 32                                           ' 32 rows per character, split in two parts
          pixels := long[address]                           ' get rom font data
          pixels := pixels >> (ascii & 1)                    ' shift for odd characters
          repeat 16 ' 16 columns
            if pixels & 1
              ILI9325.pixel(%00000111_11100000)             ' foreground color RRRRRGGG_GGGBBBBB
            else
              ILI9325.pixel(%00000000_00000000)             ' background color 
            pixels := pixels >> 2                           ' alternate pixels interleaved so shift 2
          address += 4                                      'increment address by 4 bytes
    

    Thanks ++ to everyone who contributed here - this is much appreciated.
    320 x 200 - 13K
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-02-24 06:27
    I started writing this, then realized I had other work to do.

    Sorry.
    {{
    Fill romfont with ROM Font[32..127] decoded into separate 16x32 bitmaps
    }}
    VAR
        long romfont[144]
        
    PUB FillRomFont
        cognew(@fillromfont, @romfont)
        
    PUB GetChar(c)
        return @romfont[(c-32)<<4]
        
    DAT
                  org 0
    fillromfont   mov  romfaddr, par   
    newchar       xor  thisline, thisline
                  xor  nextline, nextline
                  xor  lineidx, lineidx
    newline       rdlong theline, fontline
                  add  fontline, #1
                  mov  bitcnt, 16
    nextbit       shr  theline, #1 wc
                  rcr  thisline, #1
                  shr  theline, #1 wc
                  rcr  nextline, #1
                  djnz bitcnt, #nextbit
                  rdlong theline, fontline
                  add  fontline, #1
                  mov  bitcnt, 16
    nextbit2      shr  theline, #1 wc
                  rcr  thisline, #1
                  shr  theline, #1 wc
                  rcr  nextline, #1
                  djnz bitcnt, #nextbit2
                  wrlong thisline, romfaddr
                  add  romfaddr, 16
                  wrlong nextline, romfaddr
                  sub  romfaddr, 15
                  djnz lineidx, #newline ' Starting about here is incomplete
                  sub  romfaddr, 
                  jmp  newchar  
    
    
    
    fontline      long $8000 ' Address of input for current line
    bitcnt        res 1      ' How many bits to pull from each line
    theline       res 1      ' Buffer for current fontline 
    lineidx       res 1      ' Current line number
    romfaddr      res 1      ' Address of output for current line
    thisline      res 1      ' Line of this char
    nextline      res 1      ' Line of next char
    
    Can someone else finish it?
    クロネコさん、ありがとう。
  • kuronekokuroneko Posts: 3,623
    edited 2012-02-24 18:18
    No attempt at finishing it but a different view. This will decode the requested character on demand and place it into a 32 word buffer from where it can be stored somewhere else. Character definitions are still stored so that the display sequence is LSB..MSB (left..right). Nothing a >< 16 in SPIN wouldn't cure.
    VAR
      long  command, cog
      word  font[32]
        
    PUB null
    '' This is not a top level object.
        
    PUB GetChar(c)
    
      ifnot cog
        ifnot cog := cognew(@fillchar, @command) + 1        ' start cog on demand
          abort
    
      command := $200|c.byte{0}                             ' query bitmap
      repeat                                                ' |
      while command                                         ' wait for completion
    
      return @font{0}
        
    DAT             org     0
    
    fillchar        add     addr, par               ' @font[0]
    :idle           rdlong  char, par wz
            if_z    jmp     #$-1
    
                    mov     temp, char              ' where to begin
                    shr     temp, #1                '  2 chars/long
                    shl     temp, #7                ' 32 longs/char
    
                    test    char, #1 wc
                    muxnc   shft, #1                ' even/odd
                    
                    mov     lcnt, #32               ' 32 rows
    
    :loop           rdlong  char, temp              ' read line from ROM
                    shl     char, shft              ' adjust for even/odd
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 15
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 12
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 8
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 4
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 0
    
                    wrword  line, addr              ' update hub array
                    add     addr, #2                ' advance dst
                    add     temp, #4                ' advance src
                    
                    djnz    lcnt, #:loop            ' repeat
    
                    sub     addr, #64               ' rewind
                    
                    wrlong  zero, par
                    jmp     #:idle
    
    ' initialised data and/or presets
    
    addr            long    8
    shft            long    0
    
    ' uninitialised data and/or temporaries
    
    temp            res     1
    char            res     1
    lcnt            res     1
    line            res     1
    
                    fit
    
    CON
      zero = $1F0   ' par
      
    DAT
    
Sign In or Register to comment.