real mode dos assembly trouble
real mode dos assembly trouble
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?
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?
Last edited by Zacariaz on Wed Sep 12, 2007 12:04 pm, edited 1 time in total.
Eurika! I wrote something that worked?! Well it was sorta trial and error as i was unable to find a proper tutorial.
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.
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
Now next step is getting it to print a value from a register... hmm... im boned.
First i would like to congratulate you, on choosing a great language .
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 .
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:
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
But do not be too worried if you can not work it out, just see whats possible with the power of asm.
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 .
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
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
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
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
Heres a exe example:
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/
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
;=======================================================================
NOTE: you can even assemble with fasm online see here:
http://fasm.ctrl-alt-del.si/
If you are creating a DOS .COM, please make sure you've put this:
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:
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!:
or this:
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:
or this:
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 ).
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 ? -> Just leave them alone and you will be fine [FASM doesnt support the keyword "section" if I am correct though ]
Good luck.
Regards
inflater
Code: Select all
start:
mov ax,cs
mov es,ax
mov ds,ax
...
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
...
Code: Select all
org 0x100
use16
start:
Message: db 'Hello',0
mov ax,1803
...
Code: Select all
...
xor ax,ax
int 16h
...
Message db 'Hi again',0
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
...
Code: Select all
...
int 20h
...
HelloWorld2: db "Hello World...",0
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 ).
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 ? -> Just leave them alone and you will be fine [FASM doesnt support the keyword "section" if I am correct though ]
Good luck.
Regards
inflater
My web site: http://inflater.wz.cz (Slovak)
Derrick operating system: http://derrick.xf.cz (Slovak and English )
Derrick operating system: http://derrick.xf.cz (Slovak and English )
Also, a simple hello world program for compiled as .COM in fasm:
(Yep I am a FASM fan too )
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
Regards
inflater
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
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
Regards
inflater
My web site: http://inflater.wz.cz (Slovak)
Derrick operating system: http://derrick.xf.cz (Slovak and English )
Derrick operating system: http://derrick.xf.cz (Slovak and English )
Mods: 16-bit real mode is not usually long mode !
My web site: http://inflater.wz.cz (Slovak)
Derrick operating system: http://derrick.xf.cz (Slovak and English )
Derrick operating system: http://derrick.xf.cz (Slovak and English )
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact: