Author Topic: x86-16 Draw frame around 80 x 25 screen  (Read 5181 times)

Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
x86-16 Draw frame around 80 x 25 screen
« on: February 11, 2013, 12:03:13 AM »
This procedure draws a 16 pixel frame around a 640 x 400 resolution (BIOS mode 3) screen using BIOS colors

Code: [Select]

; ============================================================================================
; Draw a non-destructive frame around screen.

; ENTRY: BP + 7 = Border color ( Background & Character )
;      6 = Body color   (      "          "      )
;                    4 = Display page ( 0 - 7 )

; LEAVE: Nothing changed except flags & AX

; Sun Feb 10 16:32:58 MST 2013 41H = 64 Bytes
; --------------------------------------------------------------------------------------------

Frame push bp
mov bp, sp ; Empty frame so args can be addressed

push es
push di ; Preserve all resgisters used except AX
push cx

; Determine offset in video memory of selected page.  Mode 3 - 80 x 24 color is
; assumed.

mov ax, [bp + 4] ; Get page number
shl ax, 8
add ah, 184 ; AH += B8
mov es, ax ; Point to page 1 video
xor di, di ; Start @ top left corner

; Display top line

mov al, [bp + 7] ; Get Border/Character color mask
mov cx, 82 ; Fill first 82 characters
   .L0 inc di
    stosb ; Only changes color not characters
    loop .L0
   
; We are now at second character of second line. Fill next 23 lines with next
; attribute

mov cl, 23 ; Number of lines to intialize

.Next push cx ; Needed for ouside loop
    mov cl, 76
    push ax
    mov al, [bp + 6] ; Get Background and text color
   
   .L1 inc di
    stosb ; Store attribute without modifying text
    loop .L1
   
; This sets the vertical border to the last two characters of this line and first
; two of the next.

    pop ax ; Restore border color
    mov cl, 4
   .L2 inc di
    stosb
    loop .L2    

    pop cx ; Restore line counter
    loop .Next ; Contine for 23 lines
   
; Finish by filling in bottom horizonal line

mov cl, 78
   .L3 inc di
    stosb
    loop .L3    
   
    pop cx
    pop di ; Restore
    pop es
   
    leave ; Kill frame
    ret 4 ; Waste arguments
   
« Last Edit: February 11, 2013, 01:53:42 AM by TightCoderEx »

Offline Gerhard

  • Jr. Member
  • *
  • Posts: 50
Re: x86-16 Draw frame around 80 x 25 screen
« Reply #1 on: February 11, 2013, 05:16:26 PM »
Hi TightCoderEx,

thank you for sharing your code. It seems to me that's a 16 bit procedure, callable from Pascal, isn't it?

Gerhard

Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
Re: x86-16 Draw frame around 80 x 25 screen
« Reply #2 on: February 12, 2013, 12:24:18 AM »
Actually for no particular reason and probably out of habit, this conforms to CDECL.  Wouldn't take much to swap references to BP to make it PASCAL compatible.  I code exclusively in assembly so dependant upon circumstances I may change up from any of the calling conventions.  Depends what suites the circumstances at the time.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2379
  • Country: us
Re: x86-16 Draw frame around 80 x 25 screen
« Reply #3 on: February 12, 2013, 01:28:57 AM »
Code: [Select]
...
    ret 4 ; Waste arguments
         

Would this not make it "stdcall" rather than "cdecl"? As I see it, there are two "issues" we need to deal with. One is the "order of parameters" - that's just a case of which way the "other language" writes 'em: "frame (page, body, border)" vs "frame (border, body, page)". We push 'em where we push 'em. The other issue is "who cleans up stack" - caller or callee. You've got a "callee cleans up" function. I think "cdecl" would be "caller cleans up". (I forget which way Pascal does that) As you point out, the code is easily modified for another calling convention, if need be.

16-bit code also has the "near call" vs "far call" distinction. You've got a "near call". If it were a "far call" the return address on the stack would include segment as well as offset, and the parameters would start two bytes further up the stack. (data might be "near" or "far" as well)

It's a mess!

Best,
Frank


Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
Re: x86-16 Draw frame around 80 x 25 screen
« Reply #4 on: February 12, 2013, 04:04:15 AM »

                    Would this not make it "stdcall" rather than "cdecl"?

                   It's a mess!


Absolutely and the way I'm doing it is even messier  :-\ Frank, but it is the only workaround I've figured out so far to mimic segmentation as in MASM.

Distance is not a major concern as this 16 bit segment of my loader is probably going to be within 4 to 5 sectors, and I've got 63 to work with before data and/or code are out of reach, as far as being near is concerned.  If it does become problematic, I'll just move it to a place where it's within 32k of any caller.

This is the part of the boot sector that brings us to next sector which is @ 80:0

FILE1
Code: [Select]
jmp 0x7c0:Start ; So I know CS is 7C0
nop

Start cli ; Disable interrupts

..... More code here

    .Read_Disk push es
    mov ax, LOAD_BASE
mov es, ax
xor bx, bx ; ES:BX = LOAD_BASE:0
mov cx, 2 ; Load second sector
mov ax, 0x220 ; AH = 2, AL = 32 sectors (16,384 bytes)
int DISK_IO
pop es
jc Prompt.Error

jmp LOAD_BASE:0 ; Execute main body of startup code

FILE2
Code: [Select]
; ============================================================================================
; Sector 2
; --------------------------------------------------------------------------------------------

mov ax, 0x507
int VIDEO

mov ah, YELLOW << 4 | BLACK ; Yellow border with WHITE text
mov al, D_GREY << 4 | BLACK ; Dark grey background with BLACK text.
push ax
mov ax, 7
push ax
push Begin

>>>>>     OP CODE FITS HERE   <<<<

Begin: mov ax, cs
mov ds, ax
mov es, ax

push Prompt             ; Work in progress
call ShowS

xor ax, ax
int 0x16 ; Wait for keystroke from operator

mov ax, 0x500 ; Switch to Page 0
int VIDEO

hlt
jmp $ - 1

/dev/sdb is my kill, crash and burn drive and I sure hope I never forget to use "b" as sda is my M$ drive and sdc is my Linux drive.

dd if=FILE1 of=/dev/sdb
dd if=FILE2 of=/dev/sdb seek=1

Now I have an image that which I can test with whatever, each of which have an origin of 0, but the first and last line of FILE1 sets CS appropriately to make this segmentation model work the way I want it to.

As documentation is severely fragmented. I'm designing a boot loader that will tell which drive I'm booting from, what the contents of all the registers are. A display of all interrupts 0:0000 - 0:037F I think it is and the contents of most of BIOS data area.

As I see it, there are two "issues" we need to deal with. One is the "order of parameters" - that's just a case of which way the "other language" writes 'em: "frame (page, body, border)" vs "frame (border, body, page)". We push 'em where we push 'em. The other issue is "who cleans up stack" - caller or callee. You've got a "callee cleans up" function. I think "cdecl" would be "caller cleans up". (I forget which way Pascal does that) As you point out, the code is easily modified for another calling convention, if need be.

16-bit code also has the "near call" vs "far call" distinction. You've got a "near call". If it were a "far call" the return address on the stack would include segment as well as offset, and the parameters would start two bytes further up the stack. (data might be "near" or "far" as well)

Once this code has done its job and hopefully the community will participate and let me know the results on thier versions of BIOS, it will be moth balled and I'll probably go right into protected long mode before I even leave boot sector.  The point being, a larger 16 bit project should certainly be aware of those points you brought up Frank.

Offline Gerhard

  • Jr. Member
  • *
  • Posts: 50
Re: x86-16 Draw frame around 80 x 25 screen
« Reply #5 on: February 12, 2013, 07:15:05 PM »
Thank you for clearifying,  TightCoderEx.

Gerhard