Page 1 of 4

real mode dos assembly trouble

Posted: Tue Sep 11, 2007 3:35 pm
by Zacariaz
Ok, nothing to do...
No Problemo, i desided to do some 16 bit dos asm programing, only problem being that, what little i might have know about the subject, was gone...
Well, ill just have to read a few guides and tutorials, piece of cake...
However, there was a few things that i wanted from a tutorial.

1. Of course it has to involve 16 bit real mode dos programing.
2. NASM/Intel specific. NASM because i do not want to worry about what little difference there might be between different assemblers, or download other assemblers to avoid the problem that way, and Intel syntax because AT&T allways confuses me.
3. Tutorial with examples please and also i dont need to learn stuff like the binary/hexadecimal numbering system all from scratch. Im a big boy now!
4. I want to do the code from scratch, e.g. no prewriten code/macros to downloade and include...

I searched for about an hour or so before giving up. At that point my google search looked something like this: "(asm|assembly) (tutorial|guide) (programming|programing) nasm (16bit|"16.bit") dos -linux (realmode|"real.mode")"

Everything i found was either bad tutorials, wrong language, HLL assembly, AT&T syntax, utterly useless C**P that noobody will ever use for everything, etc.

I know its out there, i have found it before and it wasnt that hard, why is it that suddenly i cant find anything that i care to read?

Posted: Tue Sep 11, 2007 5:20 pm
by Zacariaz
Eurika! I wrote something that worked?! Well it was sorta trial and error as i was unable to find a proper tutorial.

Code: Select all

org 100h
section .text
start:
mov dx,MSG
mov ah,9 ; display string
int 21h
mov ax,4c00h ; return to dos
int 21h
section .data
MSG db 'I Looove Assembly!', 13, 10, '$'
section .bss
Its probably filled with inproper code and stuff, BUT IT WORKS!

Now next step is getting it to print a value from a register... hmm... im boned.

Posted: Tue Sep 11, 2007 9:40 pm
by Dex
First i would like to congratulate you, on choosing a great language :wink: .
But first i would addvice you to chose Fasm thats because its syntax is similar to nasm, but its simpler to use, eg: no linker, it's got well supported forum, can do 64bit, it very easy to port, took me 2 hours to port to DexOS :shock: .
eg: your OS only needs a read/write for floppy or hdd, a print function, a memory function and a way to load and unload programs.
Heres your code in fasm:

Code: Select all

; fasm example of writing 16-bit COM program

	org	100h			; code starts at offset 100h
	use16				; use 16-bit code


	mov	ah,9
	mov	dx,hello
	int	21h

	int	20h

hello db 'Hello world!',24h
Also note ASM tut are mostly very old and are for tasm, but the good thing about ASM is once you have the basics you can code anything, it may not be the most optimised
But that can come later.
So just keep trying to add a bit more to your code and you will soon get the hang of it.

I found the best way to learn, it to code a simple game, first change mode, then plot a pixel, then move that pixel.
Heres a good example of a pong game, with built in AI

Code: Select all

; c:\fasm pong.asm pong.com
org 0x100
use16
START:

mov	al,0x13
int	0x10

MAIN:
push	word 0x8000
pop	es
push	cs
pop	ds

mov	cx,0xFFFF
mov	al,0
rep	stosb
mov	si,BALLYI
call	PutLine
mov	bx,[si-6]
mov	dx,[si-4]
cmp	dx,195
jb	CMPY
jmp	NEGY
CMPY:
cmp	dx,1
jg	ADDY
NEGY:
neg	word[si]
ADDY:
add	dx,[si]
dec	si
dec	si
cmp	bx,310
jb	CMPX
jmp	NEGX
CMPX:
cmp	bx,6
jg	ADDX
NEGX:
neg	word[si]
ADDX:
add	bx,[si]
sub	si,8
mov	di,dx
imul	di,320
add	di,bx
mov	cl,4
BALL:
mov	[es:di], dword 0x0f0f0f0f
add	di,320
loop	BALL
mov	[si+4],bx
mov	[si+6],dx

; PADS
mov     bp,si
cmp	[si+9],byte 0
je	PAD2
PAD1:
call	PADCHK
jmp	PADS
PAD2:
add	bp,2
call	PADCHK

PADS:
mov	ax,[si]
mov	di,2
call	DRAWPAD
mov	ax,[si+2]
mov	di,314
call	DRAWPAD
push	es
pop	ds
push	word 0xA000
pop	es
mov	cx,32000
xor	si,si
mov	di,si
rep	movsw
mov	ah,0x11
int	0x16
jz	MAIN
mov	ax,0x0003
int	0x10

DRAWPAD:
imul	ax,320
add	di,ax
mov	cx,16
PAD:
mov	[es:di], dword 0x0f0f0f0f
add	di,320
loop	PAD
ret

PADCHK:
cmp	dx,[bp]
jge	PADDOWN
dec	word [bp]
jmp	ENDCHK
PADDOWN:
sub	dx,12
cmp	dx,[bp]
jbe	ENDCHK
inc	word [bp]
ENDCHK:
ret

PutLine:
mov     al,15
mov     di,158
mov     cl,198
@@:
add     di,319
stosb
loop    @b
xor     di,di
call    Hline
xor     dx,dx
xor     di,di
mov     cl,199
Gridlp3:
stosb
add     di,318
stosb
loop    Gridlp3
call    Hline
ret
	       
Hline:
mov     al,15
mov     cx,320
rep     stosb
ret

PAD1Y	dw	100
PAD2Y	dw	100
BALLX	dw	160
BALLY	dw	100
BALLXI	dw	-1
BALLYI	dw	-1

But do not be too worried if you can not work it out, just see whats possible with the power of asm.

Posted: Tue Sep 11, 2007 9:58 pm
by Zacariaz
well fasm actually do look prettyer than nasm, ill give it a try, thanks.

still, im not much of a game guy, more of a math guy, can you give me a hint to how to print a value contained in a register onscreen? doesnt really matter if its hex ot dec, but binary is overkill ;)

Posted: Wed Sep 12, 2007 1:32 am
by Combuster
Nasm can assemble directly to DOS .com files as well. Just make sure your file starts with org 0x100, then you can use this command line:

Code: Select all

nasm -f bin -o program.com program.asm

Posted: Wed Sep 12, 2007 2:12 am
by Dex
Heres a exe example:

Code: Select all

; fasm example of writing simple EXE program

format MZ
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    mov  ax,es ; saving current es and ds in registers
    mov  dx,ds
;-----------------------------------------------------------------------
    mov  cx,cs ; initializing segment registers
    mov  ds,cx
    mov  es,cx
;-----------------------------------------------------------------------
    mov  [dsv],dx ; save es and ds values into memory cells
    mov  [esv],ax
;-----------------------------------------------------------------------
    mov  ax,cs    ; printing cs
    call typeword ; prints line "XS: XXXXh", XXXX in ax
;-----------------------------------------------------------------------
    mov  ax,[dsv] ; get old ds value into ax
    mov  byte [segmname + 1],"D"
    call typeword ; printing ds
;-----------------------------------------------------------------------
    mov  ax,[esv]
    mov  byte [segmname + 1],"E"
    call typeword ; printing es
;-----------------------------------------------------------------------
    mov  ax,ss
    mov  byte [segmname + 1],"S"
    call typeword ; printing ss
;-----------------------------------------------------------------------
    xor   ah,ah
    int   16h     ; wait for keypressing
;-----------------------------------------------------------------------
    mov  ax,4C00h ; terminate
    int  21h
;=======================================================================
dsv     dw ?
esv     dw ?
;-----------------------------------------------------------------------
segmname    db @F-$-1,"CS: "
testword    db "    h",13,10
            @@:
;-----------------------------------------------------------------------
hex_str db "0123456789ABCDEF" ; xlat table for values 0h..Fh
;-----------------------------------------------------------------------
byte2hex: ; in: al - byte, out: al - high hex digit, ah - low hex digit
    mov bx,hex_str
    mov ah,al
    shr ah,4
    and al,15
    xlatb
    xchg al,ah
    xlatb
    ret
;-----------------------------------------------------------------------
typeword: ; in: ax - word to be printed
    mov si,segmname
    mov dx,ax
    call byte2hex  ; convert al and place to string
    mov word [testword + 2],ax
    mov al,dh
    call byte2hex ; convert ah and place to string
    mov word [testword],ax
    jmp typestr ; print string
;-----------------------------------------------------------------------
typestr: ; in: si - pascal string
    lodsb ; get length of string to be printed
typestrnum:
    test al,al ; if length = 0 - there is nothing to do
    jz typestr_exit
    movzx ecx,al ; mov to counter
    mov bx,7     ; color attributes
    mov ah,0Eh   ; bios function
@@:
    lodsb ; get byte into al and dec cx
    int   10h
    loop  @B ; if cx not zero - loop
typestr_exit:
    ret
;=======================================================================
You get all the info you need from the demo.

NOTE: you can even assemble with fasm online see here:
http://fasm.ctrl-alt-del.si/

Posted: Wed Sep 12, 2007 8:19 am
by inflater
If you are creating a DOS .COM, please make sure you've put this:

Code: Select all

start:
mov ax,cs
mov es,ax
mov ds,ax
...
into the start of your code. This will initialize DS and ES to their correct values.
You can have your data stored really anywhere in your program :), like this:

Code: Select all

...
xor ax,ax
out 71h,al
jmp @f

Message: db "owned",0
Data dq 0

@@:
mov ah,9
mov dx,Message
int 21h
...
but if you have your data section at the very beginning or end of your program, please make sure the CPU won't get in there!:

Code: Select all

org 0x100
use16

start:
Message: db 'Hello',0
mov ax,1803
...
or this:

Code: Select all

...
xor ax,ax
int 16h
...

Message db 'Hi again',0
To exit from your .COM program and return to your OS, you can use RET (with unmodified stack of course), INT 20h (without params), INT 21h with AX=0 or INT 21h with AX=0x4C. Note that if you are running EXE, you are advised to use only AX=0x4C, INT 21h or you will surely screw the stack or any other DOS-related things... :)

If you forget to exit from the program or you would let the CPU go directly into these strings above, CPU will treat them as hexadecimal opcodes and the result can be unpredictable... Be sure to put JMP START or something at the beginning of your program (if you want to plan your data section at the beginning of course), like this:

Code: Select all

org 0x100
use16
jmp start

Helloworld: db "Hello World!",0

start:
mov ax,1993
...
or this:

Code: Select all

...
int 20h
...

HelloWorld2: db "Hello World...",0
Also be sure that DOS .COM must be less than 64 kB and if you will create too much code, or you will try to address very high addresses, FASM will report an error, like "value out of range", because it crosses the 64 kB segment boundary. ;) Or your program will freeze. That is, why I recommend putting your data section at the beginning of your .COM. ;)

If you want to create bigger and multi-segmented applications, you are advised to use your only choice for DOS programming, the MZ EXE. :) [Standard 16-bit relocatable format]. So COM is suitable only for small applications, like drivers, and MZ EXE for the bigger ones. Compiling small applications as MZ EXE can grow your application by 50%, compared by .COM (try compiling your helloworld app in .COM and then in .EXE and you will see :D).
Note that if you use EXE, do not MOV AX,CS; MOV ES,AX, etc. -> you need to create your own segments for data, code, and optionally, stack. :) TASM has a good explanation for this, altough it can be a bit complicated.

Also do not use thingies like section .bss, section .text or any other things in your application. I think its *useless*. ;) You do not need sections in .COM, do you ? :D -> Just leave them alone and you will be fine [FASM doesnt support the keyword "section" if I am correct though :?]

Good luck. ;)

Regards
inflater

Posted: Wed Sep 12, 2007 8:28 am
by inflater
Also, a simple hello world program for compiled as .COM in fasm:

Code: Select all

org 0x100
use16
jmp start

HelloWrld: "Hello World from 16-bit assembly! :-)",13,10
                "Press ENTER to exit...$"

start:
push cs
pop ds
push ds
pop es

mov ax,9
mov dx,HelloWrld
int 21h
xor ax,ax
int 16h
int 20h
(Yep I am a FASM fan too :D)

NOTE: When you are using DOS to output ASCII strings, they must be terminated with the char "$", and not the 0... :) Or else, like said,... CPU would go whenever it is possible :lol:

Regards
inflater

Posted: Wed Sep 12, 2007 12:17 pm
by inflater
Mods: 16-bit real mode is not usually long mode :lol: ! :D

Posted: Wed Sep 12, 2007 2:15 pm
by Zacariaz
inflater wrote:Mods: 16-bit real mode is not usually long mode :lol: ! :D
Where did i write long mode?

Posted: Wed Sep 12, 2007 2:17 pm
by Combuster
Zacariaz wrote:Where did i write long mode?
You just did :P

Posted: Wed Sep 12, 2007 3:26 pm
by Zacariaz
Combuster wrote:
Zacariaz wrote:Where did i write long mode?
You just did :P
now im confused, its sounds like something i could have done, but i cant find it!

Posted: Wed Sep 12, 2007 3:29 pm
by Brynet-Inc
Zacariaz wrote:now im confused, its sounds like something i could have done, but i cant find it!
You renamed the topic accidentally? It said "long mode".. So either you corrected it and forgot :?, or the fine moderation staff did.. :wink:

Posted: Wed Sep 12, 2007 3:33 pm
by Zacariaz
the mod must have done it.

Anyway i got a hole lot more responces than expected, and you are ofcourse welcome to write more tips and stuff, but for now i got more that enough.

Posted: Thu Sep 13, 2007 10:25 am
by Candy
Brynet-Inc wrote:or the fine moderation staff did.. :wink:
:wink: *darkness winking back* :wink: