Difference between revisions of "Output"
m (added link for pc speaker sound example) |
|||
(70 intermediate revisions by 6 users not shown) | |||
Line 5: | Line 5: | ||
=== Outputting in Textmode (80x25) === | === Outputting in Textmode (80x25) === | ||
− | + | ==== Hello World / High Level function ==== | |
− | + | Here's an obligatory "Hello World" program in text mode, using a [http://www.ctyme.com/intr/rb-2562.htm "high level" MS-DOS function]. With a small optimization already included (using <code>XCHG BP,AX</code> instead of <code>MOV AH,09h</code>), this snippet is 20 bytes in size. | |
− | [[File: | + | [[File:Hello world.png|thumb|Hello World!]] |
− | + | <syntaxhighlight lang="nasm"> | |
+ | org 100h ; we start at CS:100h | ||
+ | xchg bp,ax ; already a trick, puts 09h into AH | ||
+ | mov dx,text ; DX expects the adress of a $ terminated string | ||
+ | int 21h ; call the DOS function (AH = 09h) | ||
+ | ret ; quit | ||
+ | text: | ||
+ | db 'Hello World!$' | ||
+ | </syntaxhighlight> | ||
+ | Of course, this gets shorter with each byte you remove from the text itself. Now let's look into arbitrary screen access. Right after the start of your program you are in mode 3, that is 80x25 in 16 colors. See the [http://www.columbia.edu/~em36/wpdos/videomodes.txt Video Modes List] [[File:Drawchar example.png|thumb|draw char example]] So, to show something on the screen, you would need to set a segment register to 0xB800, then write values into this segment. | ||
+ | ==== Low level access ==== | ||
The following three snippets showcase how to draw a red smiley in three different ways. All example snippets are meant to be standalone programs, starting with the first instruction and nothing before it. The target coordinate (40,12) is about the middle of the screen. We need a multiplier 2 since one char needs two bytes in memory (char and color is a byte each). The high byte 0x04 means red (4) on black (0) while the 0x01 is the first ASCII char - a smiley. | The following three snippets showcase how to draw a red smiley in three different ways. All example snippets are meant to be standalone programs, starting with the first instruction and nothing before it. The target coordinate (40,12) is about the middle of the screen. We need a multiplier 2 since one char needs two bytes in memory (char and color is a byte each). The high byte 0x04 means red (4) on black (0) while the 0x01 is the first ASCII char - a smiley. | ||
− | + | <syntaxhighlight lang="nasm">push 0xb800 | |
− | |||
− | |||
− | |||
− | |||
− | <syntaxhighlight lang="nasm"> | ||
− | push 0xb800 | ||
pop ds | pop ds | ||
mov bx,(80*12+40)*2 | mov bx,(80*12+40)*2 | ||
mov ax, 0x0401 | mov ax, 0x0401 | ||
mov [bx],ax | mov [bx],ax | ||
− | ret | + | ret</syntaxhighlight> |
− | </syntaxhighlight> | ||
− | <syntaxhighlight lang="nasm"> | + | <syntaxhighlight lang="nasm">push 0xb800 |
− | push 0xb800 | ||
pop es | pop es | ||
mov di,(80*12+40)*2 | mov di,(80*12+40)*2 | ||
mov ax, 0x0401 | mov ax, 0x0401 | ||
stosw | stosw | ||
− | ret | + | ret</syntaxhighlight> |
− | </syntaxhighlight> | ||
− | <syntaxhighlight lang="nasm"> | + | <syntaxhighlight lang="nasm">push ss |
− | push ss | ||
push 0xb800 | push 0xb800 | ||
pop ss | pop ss | ||
Line 49: | Line 49: | ||
push ax | push ax | ||
pop ss | pop ss | ||
− | int 0x20 | + | int 0x20</syntaxhighlight> |
− | </syntaxhighlight> | ||
You might notice that the ''push <word>'' + ''pop seg_reg'' combination is always the same and occupies four bytes alltogether. If correct alignment is not important to you and you really just want ''any'' pointer to the screen, there is another way to get a valid one: | You might notice that the ''push <word>'' + ''pop seg_reg'' combination is always the same and occupies four bytes alltogether. If correct alignment is not important to you and you really just want ''any'' pointer to the screen, there is another way to get a valid one: | ||
Line 60: | Line 59: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | That's also four bytes, but it already has the | + | That's also four bytes, but it already has the <code>stosb</code> opcode (for putting something onto the screen) integrated and even one slot free for another one-byte-instruction. It works because <code>SI</code> initially points to the start of our code, and <code>stosb</code> has the hexadecimal representation of <code>0AAh</code>. After the first command, the segment register <code>ES</code> contains the value <code>0AA90h</code>. If you repeatedly write something to the screen with <code>stosb</code> you will eventually reach the <code>0B800h</code> segment and chars will appear on the screen. With a careful selection of the free one-byte-opcode you can also reintroduce some alignment. This works also with the <code>stosw</code> opcode <code>0ABh</code>. |
− | |||
− | |||
− | |||
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | <code> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </code> | ||
− | |||
− | |||
− | |||
+ | ==== Alternative high level functions ==== | ||
− | + | Besides the direct way of accessing memory there are also other ways of bringing char to the screen (f.e) | |
+ | * [http://www.ctyme.com/intr/rb-4124.htm INT 29h] | ||
+ | * [http://www.ctyme.com/intr/rb-2558.htm INT 21h AH=6] | ||
+ | * [http://www.ctyme.com/intr/rb-2562.htm INT 21h AH=9] |
Latest revision as of 13:19, 8 April 2024
Contents
Outputting to the screen
First, be aware of the MSDOS memory layout
Outputting in Textmode (80x25)
Hello World / High Level function
Here's an obligatory "Hello World" program in text mode, using a "high level" MS-DOS function. With a small optimization already included (using XCHG BP,AX
instead of MOV AH,09h
), this snippet is 20 bytes in size.
org 100h ; we start at CS:100h
xchg bp,ax ; already a trick, puts 09h into AH
mov dx,text ; DX expects the adress of a $ terminated string
int 21h ; call the DOS function (AH = 09h)
ret ; quit
text:
db 'Hello World!$'
Low level access
The following three snippets showcase how to draw a red smiley in three different ways. All example snippets are meant to be standalone programs, starting with the first instruction and nothing before it. The target coordinate (40,12) is about the middle of the screen. We need a multiplier 2 since one char needs two bytes in memory (char and color is a byte each). The high byte 0x04 means red (4) on black (0) while the 0x01 is the first ASCII char - a smiley.
push 0xb800
pop ds
mov bx,(80*12+40)*2
mov ax, 0x0401
mov [bx],ax
ret
push 0xb800
pop es
mov di,(80*12+40)*2
mov ax, 0x0401
stosw
ret
push ss
push 0xb800
pop ss
mov sp,(80*12+40)*2
mov ax, 0x0401
push ax
pop ss
int 0x20
You might notice that the push <word> + pop seg_reg combination is always the same and occupies four bytes alltogether. If correct alignment is not important to you and you really just want any pointer to the screen, there is another way to get a valid one:
les bx,[si]
nop
stosb
That's also four bytes, but it already has the stosb
opcode (for putting something onto the screen) integrated and even one slot free for another one-byte-instruction. It works because SI
initially points to the start of our code, and stosb
has the hexadecimal representation of 0AAh
. After the first command, the segment register ES
contains the value 0AA90h
. If you repeatedly write something to the screen with stosb
you will eventually reach the 0B800h
segment and chars will appear on the screen. With a careful selection of the free one-byte-opcode you can also reintroduce some alignment. This works also with the stosw
opcode 0ABh
.
Alternative high level functions
Besides the direct way of accessing memory there are also other ways of bringing char to the screen (f.e)