flat assembler
Message board for the users of flat assembler.
Index
> DOS > I Have A Problem With A Simple .COM That Displays Text |
Author |
|
crc 07 Jul 2004, 22:23
I'd just use a macro to set up the string and pass arguments to the WriteStr routine. It'd be something like:
Code: ORG 100H TX = 80 TY = 25 virtual at 0 write: .x dw ? .y dw ? .back db ? .fore db ? .size = $ end virtual macro write_string data, x, y, bgcolor, fgcolor { local a, b, size mov [write.x], x mov [write.y], x mov [write.back], bgcolor mov [write.fore], fgcolor mov ax, a mov cx, [size] jmp b label a db data label size dw $-a label b call WriteStr } push cs pop ds mov ax,03h int 10h write_string 'This is a test', 10, 10, 1, 3 xor ax,ax int 16h int 20h WriteStr: push $B800 pop es push cx mov si, ax mov ax, [write.y] ; (Y*TX-(TX-X))*2 ;((Y-1)*TX+X)*2 mov bx, TX mul bx sub bx, [write.x] sub ax, bx mov cx, 2 mul cx mov di, ax mov ah, [write.back] mov al, [write.fore] shl ah, 4 or ah, al pop cx Continue: mov al, byte [si] stosw inc si loopnz Continue ret This could be modified a bit; I'll see if I can come up with something more like your example later tonight or tomorrow morning. |
|||
07 Jul 2004, 22:23 |
|
crc 07 Jul 2004, 22:50
Ok, how about this:
Code: ORG 100H TX = 80 TY = 25 virtual at 0 write: .x dw ? .y dw ? .back db ? .fore db ? .size = $ end virtual macro mov a, b { local c, d, e if b eqtype '' jmp e label c db b label d dw $-c label e mov ax, c mov cx, [d] else move a, b end if } move fix mov push cs pop ds mov ax,03h int 10h mov [write.x], 10 mov [write.y], 10 mov [write.back], 1 mov [write.fore], 3 mov [write.str], 'this is a test' call WriteStr xor ax,ax int 16h int 20h WriteStr: push $B800 pop es push cx mov si, ax mov ax, [write.y] ; (Y*TX-(TX-X))*2 ;((Y-1)*TX+X)*2 mov bx, TX mul bx sub bx, [write.x] sub ax, bx mov cx, 2 mul cx mov di, ax mov ah, [write.back] mov al, [write.fore] shl ah, 4 or ah, al pop cx Continue: mov al, byte [si] stosw inc si loopnz Continue ret This redefines mov to create a string, jump over it, and set ax=address, cx=length. If you use mov normally, nothing will change, so your code should work ok. (Note that I added a push cx, pop cx pair to the WriteStr routine as well) |
|||
07 Jul 2004, 22:50 |
|
Gambino 09 Jul 2004, 04:28
Hey crc u got an A+ from me...
Both variants are good, but i like the second write_string thingie You took it one step farther ! Can u tell me if i can optimise the code even more ? Thanx Man You're Good |
|||
09 Jul 2004, 04:28 |
|
crc 09 Jul 2004, 11:26
Well the easiest way to optomize for size is to use the BIOS functions For speed, your method looks good to me. It's flexible, and pretty clean. I made one more version (supporting both your syntax, and my write_str macro) with a couple of minor updates that make the code more reliable:
Code: ORG 100H TX = 80 TY = 25 ; Some color names to use instead of raw numbers BLACK = 0 BLUE = 1 GREEN = 2 PURPLE = 3 RED = 4 CYAN = 5 BROWN = 6 WHITE = 7 GREY = 8 BRIGHTBLUE = 9 BRIGHTGREEN = 10 BRIGHTPURPLE = 11 BRIGHTRED = 12 BRIGHTCYAN = 13 BRIGHTBROWN = 14 BRIGHTWHITE = 15 virtual at 0 write: .x dw ? .y dw ? .back db ? .fore db ? .str dw ? .size dw ? end virtual macro mov a, b { local c, d, e if b eqtype '' jmp e label c db b label d dw $-c label e mov ax, c mov [write.str], ax mov cx, [d] mov [write.size], cx else move a, b end if } move fix mov macro write_string text, x, y, fg, bg { local a, b, size mov [write.x], x mov [write.y], y mov [write.back], bg mov [write.fore], fg mov [write.str], text call WriteStr } push cs pop ds push $b800 ; Set ES here, unless you need to alter it later on pop es ; It'll save a little time when you call WriteStr mov ax,03h int 10h mov [write.x], 10 mov [write.y], 10 mov [write.back], GREY mov [write.fore], BLUE mov [write.str], 'this is a test' call WriteStr ; Or this way: ; write_str 'this is a test', 10, 10, GREY, BLUE xor ax,ax int 16h int 20h WriteStr: mov si, [write.str] mov ax, [write.y] ; (Y*TX-(TX-X))*2 ;((Y-1)*TX+X)*2 mov bx, TX mul bx sub bx, [write.x] sub ax, bx mov cx, 2 mul cx mov di, ax mov ah, [write.back] mov al, [write.fore] shl ah, 4 or ah, al mov cx, [write.size] Continue: mov al, byte [si] stosw inc si loop Continue ; Was: loopnz ret This now loads si from write.str and cx from write.size. These changes will prevent some errors if the registers are assigned out of order I also fixed a bug in the write_str macro (which assigned both X & Y to the same value). I'll see if I can shave off a couple of bytes though. One last change for now: I defined the names and values of some colors to make using this easier. |
|||
09 Jul 2004, 11:26 |
|
Gambino 09 Jul 2004, 21:39
Code: ORG 100H USE16 TX = 80 ; TY = 25 NOT NEEDED ; Some color names to use instead of raw numbers BLACK = 0 BLUE = 1 GREEN = 2 PURPLE = 3 RED = 4 CYAN = 5 BROWN = 6 WHITE = 7 GREY = 8 BRIGHTBLUE = 9 BRIGHTGREEN = 10 BRIGHTPURPLE = 11 BRIGHTRED = 12 BRIGHTCYAN = 13 BRIGHTBROWN = 14 BRIGHTWHITE = 15 ;------------------ ; define procedure. ;------------------ macro proc name,[arg] { common if used name name: virtual at bp+6 if ~ arg eq forward local ..arg ..arg dw ? arg equ ..arg common end if ..ret = $ - (bp+6) end virtual local ..dynamic_data, ..dynamic_size dynamic_data equ ..dynamic_data dynamic_size equ ..dynamic_size virtual at bp - dynamic_size dynamic_data: } ;------------------------------ ; begin procedure instructions. ;------------------------------ macro begin { dynamic_size = $ - dynamic_data end virtual enter dynamic_size,0 } ;----------------------- ; Return from procedure. ;----------------------- macro endp { leave if ..ret = 0 retf else retf ..ret end if end if ; for "used" check in proc macro } ;---------------- ; Call procedure. ;---------------- macro callhere proc,[arg] { if ~ arg eq reverse push arg end if common call proc } ;---------------------------------------- ; Make far call in the same code segment. ;---------------------------------------- macro callp proc,[arg] { if ~ arg eq reverse push arg end if common push cs call proc } push cs pop ds mov ax,03h int 10h callp WriteStr,30,20,BLUE,BRIGHTBROWN,mm callp WriteStr,30,21,BLUE,BRIGHTWHITE,mm callp WriteStr,30,23,15,BRIGHTRED,mmm ; 15-WHITE+BLINK xor ax,ax int 16h int 20h proc WriteStr,x,y,b,f,msg begin push $B800 pop es mov ax, [msg] mov si, ax mov ax, [y] ; THIS ROUTINE WAS FIXED dec ax ; THE OFFSET ONSCREEN mov cx, 80 ; WAS CALCULATED WRONG mul cx ; NOW THIS IS OK ! add ax, [x] ; ; ;mov cx, 2 ; this 2 lines replaced ;mul cx ; by the one below shl ax, 1 ; optimised mov di, ax mov ah, byte [b] ; Here We Calculate Color mov al, byte [f] ; For BackGround And shl ah, 4 ; ForeGround or ah, al ; mov al, byte [si] Continue: stosw inc si mov al, byte [si] or al, 0 jnz Continue endp mm db 'Testing',0 mmm db 'Hey look FASM is good !',0 hey is this better using procedures ? or not ? (i think not...) i optimised and fixed a bug anyway in the main routine... this is better so crc u can do the same for your version if u want we can compare speeds to see how fast it is any optimisation will be wellcome |
|||
09 Jul 2004, 21:39 |
|
crc 09 Jul 2004, 22:11
I prefer the version without procedures. I did a new version with your changes to WriteStr:
Code: ORG 100H TX = 80 ; Some color names to use instead of raw numbers BLACK = 0 BLUE = 1 GREEN = 2 PURPLE = 3 RED = 4 CYAN = 5 BROWN = 6 WHITE = 7 GREY = 8 BRIGHTBLUE = 9 BRIGHTGREEN = 10 BRIGHTPURPLE = 11 BRIGHTRED = 12 BRIGHTCYAN = 13 BRIGHTBROWN = 14 BRIGHTWHITE = 15 virtual at 0 write: .x dw ? .y dw ? .back db ? .fore db ? .str dw ? end virtual macro mov a, b { local c, d if b eqtype '' jmp d label c display b db b,0 label d mov ax, c mov [write.str], ax else move a, b end if } move fix mov macro write_string text, x, y, fg, bg { mov [write.x], x mov [write.y], y mov [write.back], bg mov [write.fore], fg mov [write.str], text call WriteStr } push cs pop ds push $b800 ; Set ES here, unless you need to alter it later on pop es ; It'll save a little time when you call WriteStr mov ax,03h int 10h mov [write.x], 10 mov [write.y], 10 mov [write.back], GREY mov [write.fore], BLUE mov [write.str], 'this is a test' call WriteStr ; Or this way: ; write_str 'this is a test', 10, 10, GREY, BLUE xor ax,ax int 16h int 20h WriteStr: mov ax, [write.y] ; THIS ROUTINE WAS FIXED dec ax ; THE OFFSET ONSCREEN mov cx, TX ; WAS CALCULATED WRONG/ mul cx ; NOW THIS IS OK ! add ax, [write.x] ; shl ax, 1 ; optimised mov di, ax mov ah, [write.back] mov al, [write.fore] shl ah, 4 or ah, al mov si, [write.str] Continue: mov al, byte [si] stosw inc si cmp al, 0 jnz Continue ret This is 107 bytes in length, so it's getting to be pretty tight now. I find procedures to be complex; simple code is better. Besides, a macro like write_str is just as useful IMO. I'm going to try to do a version that passes parameters on the stack; that might be smaller or faster. Or maybe not |
|||
09 Jul 2004, 22:11 |
|
Gambino 10 Jul 2004, 11:50
Code: ORG 100H USE16 ;just for show TX = 80 ; TY = 25 Not Needed ; Some color names to use instead of raw numbers BLACK = 0 BLUE = 1 GREEN = 2 PURPLE = 3 RED = 4 CYAN = 5 BROWN = 6 WHITE = 7 GREY = 8 BRIGHTBLUE = 9 BRIGHTGREEN = 10 BRIGHTPURPLE = 11 BRIGHTRED = 12 BRIGHTCYAN = 13 BRIGHTBROWN = 14 BRIGHTWHITE = 15 virtual at 0 write: .x dw ? .y dw ? .back db ? .fore db ? .str dw ? .size dw ? end virtual macro mov a, b { local c, d, e if b eqtype '' jmp e label c db b label d dw $-c label e mov ax, c mov [write.str], ax mov cx, [d] mov [write.size], cx else move a, b end if } move fix mov macro write_str text, x, y, fg, bg { local a, b, size mov [write.x], x mov [write.y], y mov [write.back], bg mov [write.fore], fg mov [write.str], text call WriteStr } push cs pop ds ;push $b800 ; Set ES here, unless you need to alter it later on ;pop es ; It'll save a little time when you call WriteStr mov ax,03h int 10h ; mov [write.x], 10 ; mov [write.y], 10 ; mov [write.back], GREY ; mov [write.fore], BLUE ; mov [write.str], 'this is a test' ; call WriteStr ; Or this way: write_str 'this is a test', 10, 10, GREY, BLUE ; Fixed was write_string ; and was declared write_str xor ax,ax int 16h int 20h WriteStr: mov ax, 0B800h ;leave this here it should work like a proc mov es, ax ;push 0B800h, pop es was better mov ax, [write.y]; dec ax ; mov cx, TX ; mul cx ;this routine calculates offset on-screen add ax, [write.x]; shl ax, 1 ; mov di, ax ;put offset in di mov ah, [write.back] ; mov al, [write.fore] ;this routine calculates back and fore shl ah, 4 ; or ah, al ; mov cx, [write.size] ;the size of the string to be printed mov si, [write.str] ;here we move the offset of message in si Continue: ;mov al, byte [si] ;optimised with lodsb (i think...) lodsb stosw ;inc si ;si is automatic increased by lodsb loop Continue ret Optimised a little i think.... I don't want the strings to be 0 terminated but it was required by procedures...now back to normal Working ar ClearScreen and others Thinking....How much we can optimise this code ??? This code is part of a command iterpreter for an OS i am working with Dexter |
|||
10 Jul 2004, 11:50 |
|
Gambino 10 Jul 2004, 12:16
Look at the command interpreter
http://board.flatassembler.net/topic.php?t=1823 We have bugs and need assistence... crc please take a look |
|||
10 Jul 2004, 12:16 |
|
crc 10 Jul 2004, 12:20
Do you want it optomized for size or for speed? How to proceed depends on which way you want it optomized. Let me know, and I'll see what I can do. If you want it optomized for speed, what CPU is it going to be run on? (Speed optomizations are highly specific to each CPU (386, 486, Pentium, Pentium II, Celeron, etc)
|
|||
10 Jul 2004, 12:20 |
|
pelaillo 10 Jul 2004, 15:12
Gambino wrote: I don't want the strings to be 0 terminated but it was required by procedures... What procedures? As long as you don't use C libs in your OS you don't need them. And if needed, you could use for interface only. |
|||
10 Jul 2004, 15:12 |
|
Gambino 11 Jul 2004, 14:05
crc i want the code to be optomized for size and speed...
they should be working on any 386+ but they exists only in museums ( i have a 386 but is missing a hdd ) so pentium is fine... ( i have a pentium too 133 mhz ) Question An OS should be optomized for speed or for size ? pelaillo i wanted to see what is the diffrence between procedures and simple call - ret , i'm just testing to see how will be better to implement an OS |
|||
11 Jul 2004, 14:05 |
|
pelaillo 11 Jul 2004, 15:34
I was talking about zero terminated strings. Who needs them in assembly?
speed or size? It depends on where your OS is supposed to run. IMHO, an assembly OS must be optimized for speed, as the size is already smaller compared to actual alternatives. |
|||
11 Jul 2004, 15:34 |
|
crc 11 Jul 2004, 17:12
Quote: crc i want the code to be optomized for size and speed... Ok, I will see what kind of balance would be best. Generally optomizations come at a cost of either size or speed. (A case in point is loop unrolling, which is faster, but much larger in size). Quote: pelaillo i wanted to see what is the diffrence between procedures and simple call - ret , i'm just testing to see how will be better to implement an OS Stick with call/ret; they tend to translate better if you start using interrupts for system calls. (If you intend to run programs that are not built into the kernel, you'll need some sort of system call interface.) Since this is a real mode kernel, taking over an interrupt is pretty easy; so I'd stick with call/ret. (Instead of calling a function, you use an interrupt; end the kernel routines that handles the interrupt with an iret). |
|||
11 Jul 2004, 17:12 |
|
Gambino 11 Jul 2004, 20:23
|
|||
11 Jul 2004, 20:23 |
|
Matrix 09 Sep 2004, 16:35
This problem is common, i wonder why
you should take a look at this http://board.flatassembler.net/topic.php?t=2186 MATRIX |
|||
09 Sep 2004, 16:35 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.