Assembly VGA font Print Routines

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Assembly VGA font Print Routines

Post by lassar »

This will print using vga 8x16 fonts on 640x480 32 bit screen.

vga.f16 font Download

Code: Select all

'========================================
' Assembly VGA font Print Routines
' Released into public domain
' By Randall Glass
'========================================
'
' Screen Resolution 640x480 32 bits 
'
' Language fblite
'
'========================================
#LANG "fblite"

DECLARE SUB CPrint(BYVAL Fc AS UINTEGER, BYVAL Bc AS UINTEGER, BYVAL row AS LONG, BYVAL col AS LONG, Txt$)
DECLARE SUB YXPrint (BYVAL Y%,BYVAL X%,BYVAL Colour AS UINTEGER,Txt$)
DECLARE SUB PPrint(BYVAL Fc AS UINTEGER,BYVAL row AS UINTEGER,BYVAL col AS UINTEGER, Txt$)
DECLARE SUB LoadFont(FontFile$)
DECLARE SUB CCLS(BYVAL COLOUR%)

DIM SHARED Black%,Blue%,Green%,Cyan%,Red%,Magenta%,Brown%,White%,Gray%
DIM SHARED LightBlue%,LightGreen%,LightCyan%,LightRed%,LightMagenta%,Yellow%,BrightWhite%


' 0 = black          6 = brown            12 = light red
' 1 = blue           7 = white            13 = light magenta
' 2 = green          8 = gray             14 = yellow
' 3 = cyan           9 = light blue       15 = high intensity white
' 4 = red           10 = light green
' 5 = magenta       11 = light cyan


Black% = RGB(0,0,0)
Blue% = RGB(0,0,168)
Green% = RGB(0,110,0)
Cyan% = RGB(151,187,187)
Red% = RGB(168,0,0)
Magenta% = RGB(168,0,168)
Brown% = RGB(132,84,40)

White% = RGB(168,168,168)
Gray% = RGB(84,84,84)
LightBlue% = RGB(84,84,252)
LightGreen% = RGB(84,252,84)
LightCyan% = RGB(196,128,60)
LightRed% = RGB(36,24,12)
LightMagenta% = RGB(252,84,252)
LightWhite% = RGB(180,180,180)
Yellow% = RGB(64,40,16)
BrightWhite% = RGB(252,252,252)

Yellow2% = RGB(184,186,39)
LightBlue2% = RGB(185,185,218)


DIM SHARED VideoPtr AS Any PTR
DIM SHARED Font(4095) AS UBYTE = ANY
DIM SHARED FONTOFF AS ANY PTR

FontOff = VARPTR(Font(0))

LoadFont "fonts/vga.f16"

SCREENRES 640,480,32,,&H01
VideoPtr = SCREENPTR

CCLS Cyan%

PPrint Black%,6,6,"Hello there. Be still my soul."
SLEEP
END



SUB LoadFont(FontFile$)
    FF& = FREEFILE
    OPEN FontFile$ FOR BINARY AS #FF&
    GET #FF&,,Font()
    CLOSE #FF&
END SUB


SUB CCLS(BYVAL COLOUR%)
    SCREENLOCK
    ASM
        CLD
        MOV     EDI,[VideoPtr]
        Mov     ECX, 307200
        Mov     EAX,[Colour%]
        rep     stosd
    END ASM
    SCREENSYNC
    SCREENUNLOCK
END SUB


SUB CPrint(BYVAL Fc AS UINTEGER, BYVAL Bc AS UINTEGER, BYVAL row AS LONG, BYVAL col AS LONG, Txt$)
    'SUB BackGroundPrint(BYVAL bc,BYVAL row AS LONG,BYVAL col AS LONG,BYVAL LineLength AS ULONG) static
    DIM YAdress AS UINTEGER, X%, Y%, ScreenAddress AS UINTEGER
    DIM CharLen AS LONG
    SCREENLOCK
    ASM

        MOV     EAX,0
        MOV     EBX,[Txt$]
        MOV     ECX,[EBX+4]
        MOV     [CharLen], ECX
        CMP     ECX,0
        JNE     SprintContinue
        JMP     ExitPrint

        SprintContinue:

        MOV     ESI,[EBX]          'ESI contains String Adress

        '  Change this to: YAdress = Y * 640 + VideoPtr

        mov     EBX,[row]
        DEC     EBX
        shl     EBX,4
        'Y = 16 *(Row -1)
        mov     [Y%],EBX
        shl     EBX, 7
        mov     EAX, ebx            ' EAX = Y * 128
        shl     EBX, 2              ' EBX = Y * 512
        add     EBX, EAX            ' EBX = Y * (512 + 128)
        shl     EBX, 2              ' adjust for 32 bit colour
        add     EBX, [VideoPtr]
        mov     [YAdress], EBX
        mov     EDI, [YAdress]

        mov     EAX,[Col]               ' X = 8 * (Column -1)
        dec     EAX
        shl     EAX,3
        mov     [X],EAX
        SHL     EAX, 2              'adjust for 32 bit colour
        add     EDI, EAX               ' Add X to Address
        mov     [ScreenAddress],EDI

        PUSH    EDI
        PUSH    ESI
        PUSH    ECX

        mov     EAX,[Bc]         ' put colour into EBX

        mov     ECX,[CharLen]
        shl     ECX,3
        mov     EDX, ECX
        mov     EBX, 16
        ZapPixels:                                '  xref 952E:0138
        mov     ECX,EDX
        rep     stosd
        add     [ScreenAddress], DWORD ptr 2560
        mov     EDI,[ScreenAddress]
        dec     EBX
        cmp     EBX,0
        ja      ZapPixels                 ' Jump if above

        POP     ECX
        POP     ESI
        POP     EDI

        'Print string
        mov     EBX, 0
        mov     EAX, 0

        GetChar:
        mov     EDI,[YAdress]
        MOV     EAX,[X%]
        SHL     EAX, 2              'adjust for 32 bit colour
        ADD     EDI,EAX

        MOV     EAX, 0
        MOV     AL,[ESI]

        PUSH    ESI
        PUSH    EBX
        PUSH    ECX

        mov     ESI,FontOff        'ESI now contains Offset pointer to char data
        NextCheck:
        'Character location = Font Offset + Character * 16 + Row
        mov     EBX,EAX
        SHL     EBX, 4
        ADD     ESI,EBX
        mov     ECX,16
        ADD     EDI,28              ' add 7 * 4 bytes per pixel
        PrintRow:
        mov     al,[ESI]     'move the pixel into ah
        bit0:
        test    Al,&B00000001             'IF bit(Pixel,0) THEN
        jz      bit1
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit1:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00000010             'IF bit(Pixel,0) THEN
        jz      bit2
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit2:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00000100             'IF bit(Pixel,0) THEN
        jz      bit3
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit3:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00001000             'IF bit(Pixel,0) THEN
        jz      bit4
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit4:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00010000             'IF bit(Pixel,0) THEN
        jz      bit5
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit5:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00100000             'IF bit(Pixel,0) THEN
        jz      bit6
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit6:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B01000000             'IF bit(Pixel,0) THEN
        jz      bit7
        mov     EBX,[Fc]
        mov     [EDI],EBX
        bit7:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B10000000             'IF bit(Pixel,0) THEN
        jz      EndRow
        mov     EBX,[Fc]
        mov     [EDI],EBX
        EndRow:
        inc     ESI
        ADD     EDI,2588           'add 647 * 4 four bytes per pixel
    Loop    PrintRow
    ExitPut:

    POP     ECX
    POP     EBX
    POP     ESI

    INC     EBX
    CMP     EBX,ECX
    JZ      ExitPrint
    INC     ESI
    ADD     [X%],DWORD ptr 8

    JMP     GetChar
    ExitPrint:
END ASM
SCREENUNLOCK
END SUB

SUB YXPrint (BYVAL Y%,BYVAL X%,BYVAL Colour AS UINTEGER,Txt$)
    DIM YAdress AS UINTEGER
    SCREENLOCK

    ASM
        MOV     EBX,[Txt$]
        MOV     ECX,[EBX+4]
        CMP     ECX,0
        JNE     ZSprintContinue
        JMP     ZExitPrint
        ZSprintContinue:

        MOV     ESI,[EBX]          'ESI contains String Adress

        '  Change this to: YAdress = (Y * 640) * 4 + VideoPtr


        mov     EBX, [Y%]           ' EBX = Y
        shl     EBX, 7
        mov     EAX, EBX            ' EAX = Y * 128
        shl     EBX, 2              ' EBX = Y * 512
        add     EBX, EAX            ' EBX = Y * (512 + 128)
        shl     EBX, 2              ' adjust for 32 bit colour
        add     EBX,[VideoPtr]
        mov     [YAdress], EBX
        '  End of Change
        MOV     EBX, 0

        ZGetChar:
        MOV     EDI,[YAdress]
        MOV     EAX,[X%]
        SHL     EAX, 2              'adjust for 32 bit colour
        ADD     EDI,EAX
        MOV     EAX, 0
        MOV     AL,[ESI]
        PUSH    ESI
        PUSH    EBX
        PUSH    ECX

        mov     ESI,FontOff        'ESI now contains Offset pointer to char data
        ZNextCheck4:
        'Character location = Font Offset + Character * 16 + Row
        mov     EBX,EAX
        SHL     EBX, 4
        ADD     ESI,EBX
        mov     ECX,16
        ADD     EDI,28              ' add 7 * 4 bytes per pixel
        ZPrintRow:
        mov     al,[ESI]     'move the pixel into ah
        Zbit0:
        test    Al,&B00000001             'IF bit(Pixel,0) THEN
        jz      Zbit1
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit1:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00000010             'IF bit(Pixel,0) THEN
        jz      Zbit2
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit2:
        SUB     EDI,4
        test    Al,&B00000100             'IF bit(Pixel,0) THEN
        jz      Zbit3
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit3:
        SUB     EDI,4
        test    Al,&B00001000             'IF bit(Pixel,0) THEN
        jz      Zbit4
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit4:
        SUB     EDI,4
        test    Al,&B00010000             'IF bit(Pixel,0) THEN
        jz      Zbit5
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit5:
        SUB     EDI,4
        test    Al,&B00100000             'IF bit(Pixel,0) THEN
        jz      Zbit6
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit6:
        SUB     EDI,4
        test    Al,&B01000000             'IF bit(Pixel,0) THEN
        jz      Zbit7
        mov     EBX,[Colour]
        mov     [EDI],EBX
        Zbit7:
        SUB     EDI,4
        test    Al,&B10000000             'IF bit(Pixel,0) THEN
        jz      ZEndRow
        mov     EBX,[Colour]
        mov     [EDI],EBX
        ZEndRow:
        inc     ESI
        ADD     EDI,2588           'add 647 * 4 four bytes per pixel
    Loop    ZPrintRow
    ZExitPut:

    POP     ECX
    POP     EBX
    POP     ESI

    INC     EBX
    CMP     EBX,ECX
    JZ      ZExitPrint
    INC     ESI
    ADD     [X%],DWORD ptr 8
    JMP     ZGetChar
    ZExitPrint:
END ASM
SCREENUNLOCK
END SUB


SUB PPrint(BYVAL Fc AS UINTEGER,BYVAL row AS UINTEGER,BYVAL col AS UINTEGER, Txt$)
    'SUB YXPrint (BYVAL Y%,BYVAL X%,BYVAL Colour AS UBYTE,Txt$)
    DIM YAdress AS UINTEGER, ScreenAddress AS UINTEGER, X%, Y%
    SCREENLOCK

    ASM
        MOV     EBX,[Txt$]
        MOV     ECX,[EBX+4]
        CMP     ECX,0
        JNE     XSprintContinue
        JMP     XExitPrint
        XSprintContinue:

        MOV     ESI,[EBX]          'ESI contains String Adress

        '  Change this to: YAdress = Y * 640 + VideoPtr

        mov     EBX,[row]
        DEC     EBX
        shl     EBX,4
        'Y = 16 *(Row -1)

        shl     EBX, 7
        mov     EAX, EBX            ' EAX = Y * 128
        shl     EBX, 2              ' EBX = Y * 512
        add     EBX, EAX            ' EBX = Y * (512 + 128)
        shl     EBX, 2              ' adjust for 32 bit colour
        add     EBX,[VideoPtr]
        mov     [YAdress], EBX

        '  End of Change
        MOV     EBX, 0

        mov     EAX,[col]           ' X = 8 * (Column -1)
        dec     EAX
        shl     EAX,3
        mov     [X%],EAX

        XGetChar:
        MOV     EDI,[YAdress]
        MOV     EAX,[X%]
        SHL     EAX, 2              'adjust for 32 bit colour
        ADD     EDI,EAX             ' Add X to Address
        MOV     EAX, 0

        MOV     AL,[ESI]

        PUSH    ESI
        PUSH    EBX
        PUSH    ECX

        mov     ESI,FontOff        'ESI now contains Offset pointer to char data
        XNextCheck4:
        'Character location = Font Offset + Character * 16 + Row
        mov     EBX,EAX
        SHL     EBX, 4
        ADD     ESI,EBX
        mov     ECX,16
        ADD     EDI,28              ' add 7 * 4 bytes per pixel
        XPrintRow:
        mov     al,[ESI]     'move the pixel into ah
        Xbit0:
        test    Al,&B00000001             'IF bit(Pixel,0) THEN
        jz      Xbit1
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit1:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00000010             'IF bit(Pixel,0) THEN
        jz      Xbit2
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit2:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00000100             'IF bit(Pixel,0) THEN
        jz      Xbit3
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit3:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00001000             'IF bit(Pixel,0) THEN
        jz      Xbit4
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit4:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00010000             'IF bit(Pixel,0) THEN
        jz      Xbit5
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit5:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B00100000             'IF bit(Pixel,0) THEN
        jz      Xbit6
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit6:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B01000000             'IF bit(Pixel,0) THEN
        jz      Xbit7
        mov     EBX,[Fc]
        mov     [EDI],EBX
        Xbit7:
        SUB     EDI,4                     ' subtract 4 bytes per pixel
        test    Al,&B10000000             'IF bit(Pixel,0) THEN
        jz      XEndRow
        mov     EBX,[Fc]
        mov     [EDI],EBX
        XEndRow:
        inc     ESI
        ADD     EDI,2588           'add 647 * 4 four bytes per pixel
    Loop    XPrintRow
    XExitPut:

    POP     ECX
    POP     EBX
    POP     ESI

    INC     EBX
    CMP     EBX,ECX
    JZ      XExitPrint
    INC     ESI
    ADD     [X%],DWORD ptr 8
    JMP     XGetChar
    XExitPrint:
END ASM
SCREENUNLOCK
END SUB



srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: Assembly VGA font Print Routines

Post by srvaldez »

it would be nice to have a non-asm version for portability
paul doe
Moderator
Posts: 1733
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Assembly VGA font Print Routines

Post by paul doe »

Also, fblite? Like, seriously?
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Assembly VGA font Print Routines

Post by lassar »

This assembly code is good for windows, dos, and linux.

For instance, using non-assembly print routines for a raspberry 1 would be way too
slow.

What processor do you need portability for?

I myself have created a dos program, using freebasic, to be used on android smart
phones, using a dos emulator.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Assembly VGA font Print Routines

Post by dodicat »

But your fonts look exactly like:

Code: Select all

 

SCREENRES 640,480,32
width 640\8,480\16
color ,rgb(151,187,187)
cls
locate 8,6
color 0,rgb(151,187,187)
print "Hello there. Be still my soul."
SLEEP 
What am I missing?
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Assembly VGA font Print Routines

Post by lassar »

When you look at most monospace fonts, you'll notice more space between
other letters and lowercase i & L.

I redid the lowercase i & L so that the bottom of i & l is bigger.
Last edited by lassar on Sep 30, 2018 17:57, edited 1 time in total.
angros47
Posts: 2324
Joined: Jun 21, 2005 19:04

Re: Assembly VGA font Print Routines

Post by angros47 »

lassar wrote:This assembly code is good for windows, dos, and linux.

For instance, using non-assembly print routines for a raspberry 1 would be way too
slow.
And using Intel x86 assembly print routine for a raspberry 1 would just not work, since raspberry 1 uses an ARM cpu that has a completely different instruction set. Using non-assembly routines might be slower (not necessarily, since the optimizer will try to make it faster), but at least would work
I myself have created a dos program, using freebasic, to be used on android smart
phones, using a dos emulator.
You complained about the slowness of non-assembly instructions, and then, you use a dos emulator (likely written in Java, so emulation on an interpreted language) to run your code?
adele
Posts: 47
Joined: Jun 13, 2015 19:33

Re: Assembly VGA font Print Routines

Post by adele »

Hi,
lassar wrote: What processor do you need portability for?
AMD Ryzen in x64 mode
Adi
adele
Posts: 47
Joined: Jun 13, 2015 19:33

Re: Assembly VGA font Print Routines

Post by adele »

Hi Lassar,
kinda tuning.
Was:

Code: Select all

     
        CMP     ECX,0
        JNE     SprintContinue
        JMP     ExitPrint
SprintContinue  :
The "JMP ExitPrint" will be performed one time only / once. The JNE several times. A JMP/JNE/JA/JZ etc. that is _not_ performed will be executed faster than a performed one (decode/calculate the destination address).
The "JNE SprintContinue" JUMPs "forward". Not a loop backwards.
This might be slightly faster:

Might be:

Code: Select all

     
        OR     ECX,ECX
        JZ     ExitPrint
'      JMP   SprintContinue ' remove or comment it...
SprintContinue  :
etc etc
Couldn´t try it because of my x64 machine (grin).

Adi
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Assembly VGA font Print Routines

Post by lassar »

You complained about the slowness of non-assembly instructions, and then, you use a dos emulator (likely written in Java, so emulation on an interpreted language) to run your code?
My dos program is to be used on a android smart phone, using a dos emulator, Most likely a dosbox emulator.

Had to replace a whole lot of routines to assembly, so that it had enough speed to work on
a slow smart phone with a slow emulator.

Question, If I was to manage to compile it for arm using freebasic, do you know if the users
could add shortcut to the native program?

I myself do not have a smart phone, so I would not know how to do this.
Post Reply