Hi,
I have a simple program which should display two As on two consecutive lines (line 1 and line 2) but its not working.
The code is given below:
.model tiny
.386
.code
start:
jmp test1
test1:
cld
mov cx,2
mov ax,0B800h
next: mov es,ax
push ax
xor di,di
mov ax,4A41h
stosw
pop ax
add ax, 50h
Loop next
loop1:
jmp loop1
org 510
dw 0AA55h
end start
It prints the next 'A' after four or five lines. Can somebody plz help me with this program??
Zulfi.
mov ax,0b800h and mov ds,ax
those instructions sould be before the loop
once you have the ES register set to B800h, leave it alone
you want to add to DI, instead
and, i think you have to add 0A0h for each line - not 50h
that is because each character is 2 bytes (char and attribute)
Hi,
I have changed the code to following but still its not printing the next 'A' at the start of next line:
.model tiny
.386
.code
start:
jmp test1
test1:
cld
mov cx,2
xor di,di
mov ax,0B800h
mov es,ax
mov ax,4A41h
next:stosw
add di, 50h
Loop next
loop1:
jmp loop1
org 510
dw 0AA55h
end start
My logic is to add 80D to B800H so that I would be at the start of next line. Note each line can have 80 characters. At this point I dont want to use 0AH. However it can be done through it also.
Zulfi.
Quotejmp test1
test1:
what is that ? - lol
get rid of those lines
cld
mov ax,0B800h
mov es,ax
xor di,di
mov ax,4A41h
mov cx,2
next: stosw
add di,158 ;160-2
loop next
loop1: jmp loop1
Quote from: zak100 on August 28, 2009, 10:10:38 AM
My logic is to add 80D to B800H so that I would be at the start of next line. Note each line can have 80 characters. At this point I dont want to use 0AH. However it can be done through it also.
Adding 80 to the segment address will shift the absolute address 80 * 16 = 1280 bytes = 8 lines further down in the buffer. Before you decide to use segment indexing for this, you should first learn how segment addressing works:
absolute address = (segment address SHL 4) + offset address
In general, when dealing with a buffer that will fit in a single segment, you should leave the segment address fixed and manipulate the offset address.
Hi,
Thanks for the help. I am able to print 25 As, one one on each line.
Zulfi.
ok Zulfi
you should be able to display whatever you like, and in multiple colors, too - lol
I have not checked but I want to know can we display images also using BIOS?
Zulfi.
sure - set the video mode and put pixels in the buffer, rather than characters
the simplest graphics modes are:
320 x 200, 4 color
640 x 400, 16 color
320 x 200, 256 color
all other graphics modes are very tricky to program
Hi Zulfi.,
QuoteI have not checked but I want to know can we display images also using BIOS?
Yes, INT 10H is the video BIOS interrupt.
Use function 0 (zero) to set the video mode.
MOV AH,0 ; Function 0
MOV AL,13H ; set 320 x 200 256 color mode
INT 10H ; Video BIOS Call
Use function 0CH to write a pixel.
MOV AH,0CH ; function 0CH
MOV BH,0 ; page number
MOV CX,100 ; X or column
MOV DX,100 ; Y or row
MOV AL,15 ; Color value
INT 10H ; Video BIOS Call
Or some such.
'Luck,
Steve
Edit, fix wrong function 0B => 0C.
SRN
Zulfi,
The BIOS SetPixel function is easy to use, but it's slow. For mode 13h (320x200, 256-color), drawing pixels by accessing the display buffer directly is simple and easy to do, and much faster than using the BIOS.
i'm with Michael on that one
320 x 200, 256 color mode is simple to program
the pixels are a little too large for detailed work like pictures, though
but, you can make some fun stuff with that mode, nonetheless
each pixel is represented by a byte, which makes it very easy to do lines and circles and all that
i think it is an ideal mode for beginners to start out on graphics
Hi,
Actually, Micheal is right. Once you have done it a few
times, BIOS calls are less convenient (easy) than doing it
directly in mode 13H. However, that wasn't the question
asked (nit pick!). And I think it is a good way to start out.
Modes 4, 6, 12H, and 13H for instance use the same form
with the BIOS function, but are quite different with direct
memory writes.
Dave is right that mode 13H is a bit coarse, so try 11H
and 12H for finer detail. Less colors though, so images
need to be selected carefully to look good.
Cheers,
Steve N.
the problem with larger resolutions is, the buffer no longer fits into a single segment
for those video modes, you either have to use BIOS calls to place pixels (slow) or get fancy with the video CRT registers
for mode 13h, the entire screen fits into a single segment and you can calculate the address of a pixel:
Address = 320 * Y + X
(X,Y = 0,0 is the upper left corner of the display)
you have a palette of 256 colors from 262,144 possible values
Hi,
All of the standard VGA modes are addressed in a single
segment. Only when you use SVGA or VESA modes does
that require more than one segment's address range.
And yes, while 640 x 480 = 307,200, which would seem
to require more than one 65,536 byte segment, it doesn't.
You multiplex 8 pixels per byte, and start playing with
color "planes". And getting used to that is a whole 'nother
kettle of fish. Talk about ignoring the man behind the curtain.
Starting with BIOS functions may be the first step on a
fairly interesting journey. But it is a fairly easy step to take.
Cheers,
Steve N.
Hi,
As the speed of BIOS functions versus writing to memory
is always brought up when a put pixel is mentioned, I put
together two throw-away programs. One each for video
mode 12H and 13H. And assembled for both BIOS calls
and direct memory writes. Note: the memory write routines
are general purpose, and while good, are not optimized for
speed.
Enjoy,
Steve N.
Thanks for these replies. It would take sometime for me to start graphics.
Zulfi.
Hi,
Steve, I ran your application and found them very interesting. I dont thing I would be doing such a beautiful stuff but its something I must appreciate. Its a new idea. I havent seen them before. I might consider such exercises for my graphics course.
Zulfi.
Hi Zulfi,
Glad you liked them. Most benchmarks are a bit dull so I used
some existing code to make them a bit more colorful.
Since I did print out the times for the 16 color program, I'll
post some results for our friends in the Laboratory sub-forum
that like to see numbers. "Undocumented DOS" showed
that DOS interrupts could slow down by factor of ten when
run under a protected mode environment. So I ran that
experiment, but didn't see that dramatic an effect. Though
I may have to try that on the Win 98 machine.
Cheers,
Steve N.
Shows Pythagorean triangles.
BIOS time: Subroutine time:
Pentium III, Matrox Video
0:01:14.47 0:00:36.47 OS/2 4.0 VDM
0:01:11.07 0:00:25.65 Windows 2000 Command Prompt
0:00:33.89 0:00:24.01 DOS 5.0 HIMEM.SYS
0:00:32.63 0:00:23.18 DOS 5.0
Pentium, Western Digital Video
0:01:45.57 0:00:56.91 DOS 6.2x
0:02:32.86 0:01:02.78 DOS 6.2x HIMEM.SYS EMM386.SYS
0:02:28.51 0:01:03.06 As above + Windows 3.11 MS-DOS Prompt
0:02:38.71 0:01:03.59 OS/2 4.0 VDM
Pentium MMX, Nvidia Video
0:03:59.97 0:00:45.98 Windows 98
AMD 64, RADEON Video
0:00:58.55 0:00:25.98 Windows XP
0:00:40.75 0:00:26.26 DOS 5.0
Hi,
I dont know much about what you have said and what you have done but as a programmer I want to tell something about win98. It gave me problem of spaces but later on when I was working on TurboC (DOS application) and trying hard to take the printout of graphics stuff, it came out that this can only be done on win 98.
Zulfi.
hi Zulfi
yah - some programmers wanted fast graphics
on older systems, that meant programming the video card directly
while some of that can be done under NT+ OS's, not all functionality may be available
in general, XP and other newer OS's do not allow direct i/o
i have played with it a little bit, and i see you are able to program the palette registers, etc (XP Pro, here)
from a boot floppy, though, you do not have any limitations, because you are providing the OS
Hi Steve,
I am also interested in your timing work.Have you done it programmatically? Once I tried to compare the timings of a pool of threads with a standalone program.In that case, I used the prime number program. But I was not printing the timings. If its not a secret and if you have some spare time, kindly guide me how you accomplished this task??
Zulfi.
Zulfi
most of us use timing macros by MichaelW
the macros are available in the first post of the first thread in the Laboratory Forum
there are two sets - slightly different
timers.asm and counter2.asm
d/l them, unzip them, and place them in the \masm32\macros folder
here is an example program....
Quote from: FORTRANS on September 05, 2009, 01:30:32 PM
Hi,
As the speed of BIOS functions versus writing to memory
is always brought up when a put pixel is mentioned, I put
together two throw-away programs. One each for video
mode 12H and 13H. And assembled for both BIOS calls
and direct memory writes. Note: the memory write routines
are general purpose, and while good, are not optimized for
speed.
Enjoy,
Steve N.
Good coding. Thanks a lot.
I may copy them to my floppy boot disk and compare the speed with running under XP.
Andy
Quote from: zak100 on September 11, 2009, 03:49:45 AM
Hi Steve,
I am also interested in your timing work.Have you done it programmatically? Once I tried to compare the timings of a pool of threads with a standalone program.In that case, I used the prime number program. But I was not printing the timings. If its not a secret and if you have some spare time, kindly guide me how you accomplished this task??
Zulfi.
Hi,
Not a secret at all, I use the DOS function 2CH (44) "Get
Time". I call it before running the benchmark, and then
again when the benchmark is complete. Subtract the values,
format for printing, and print them.
; Let the program time stuff.
SCALL GTIME ; MS-DOS fn 2CH
MOV [FHun],DL
MOV [FSec],DH
MOV [FMin],CL
MOV [FHour],CH
Calling again and subtracting is pretty dull, so I'll
skip that. Here is the format and print. SCALL is
a simple macro to call MS-DOS functions with a mnemonic.
CONOUT is "Console Output" function 2, which prints
a character.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OutSaveT: ; Output saved time.
; 26 September 2007, SRN
; Enter: BX, Offset into saved time array.
; Uses AX, CX, DX.
MOV DL,' '
SCALL CONOUT
; MS-DOS System Time
; CH = Hour, CL = Minute, DH = Seconds, DL = 1/100 s
XOR AH,AH
MOV AL,[Fhour+BX] ; Play with hour
AAM ; ASCII Adjust AX after Multiply (unpack BCD digits).
OR AX,3030H
CMP AH,30H ; suppress leading zero?
JNZ OST_1
MOV AH,' '
OST_1: PUSH AX
MOV DL,AH
SCALL CONOUT
POP AX
MOV DL,AL
SCALL CONOUT
MOV DL,':'
SCALL CONOUT
MOV AL,[FMin+BX] ; Play with minutes
XOR AH,AH
AAM ; unpack
OR AX,3030H ; convert binary to ASCII
PUSH AX
MOV DL,AH
SCALL CONOUT
POP AX
MOV DL,AL
SCALL CONOUT
MOV DL,':'
SCALL CONOUT
XOR AH,AH
MOV AL,[FSec+BX] ; Play with seconds
AAM
OR AX,3030H
PUSH AX
MOV DL,AH
SCALL CONOUT
POP AX
MOV DL,AL
SCALL CONOUT
MOV DL,'.'
SCALL CONOUT
XOR AH,AH
MOV AL,[FHun+BX] ; Play with 1/100 seconds
AAM
OR AX,3030H
PUSH AX
MOV DL,AH
SCALL CONOUT
POP AX
MOV DL,AL
SCALL CONOUT
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hm, probably should skip the hundredths of a second.
HTH,
Steve N.
Quote from: zak100 on August 29, 2009, 10:13:15 AM
I have not checked but I want to know can we display images also using BIOS?
Zulfi.
I dug this out of 16 bit code dungeon and attached to source code and com file.
Andy
; AMB2.ASM [ For DOS ] Much help from Annie from alt.lang.asm newsgroup
; An ambulance races across the bottom of the screen
; with its siren wailing and its light flashing.
;
; Code added to turn off cursor allows this to work in a DOS box under
; Win XP.
;
; Animation code extracted from the "Ambulance"
; by AK 10/02
;
.model tiny
.386
.code
org 100h ; DOS .COM file
begin:
jmp start ; go start the program
;
BDA_addr equ 40h ; BDA (Bios Data Area) segment address
BDA_video_mode equ 49h ; BDA location of current video mode
BDA_timer_counter equ 6Ch ; BDA location of nmbr of timer ticks
; (18.2 per second) since midnight
counter dw 9
;
start:
mov ch,10h ; set bits to turn cursor off
call cursor ; do it
host:
nop
;
real_start:
call find_displacement
db 01h ; Used to make this add up to 3 bytes
find_displacement:
pop si
sub si, offset host
call payload
next_step:
ret
payload:
push es
mov ax, word ptr [si+counter-4]
and ax, 00000111b
cmp ax, 00000110b ; Show payload every eighth
; (starting with the sixth) time
;
; Did we already show the car?
;
mov ax, BDA_addr
mov es, ax
call show_payload
exit_payload:
pop es
mov ch,5 ; set bits to turn cursor on
mov cl,6 ; ditto
call cursor ; go do it
int 20h ; exit to DOS
;
; Setup and show the 'ambulance car'
;
show_payload:
;
; Check video mode
;
; Text mode 3 (80x25) - video buffer address (color) = 0B800h
; Text mode 7 (80x25) - video buffer address (monochrome) = 0B000h
;
push ds
mov di, 0B800h
mov ax, BDA_addr
mov ds, ax
mov al, ds:BDA_video_mode
cmp al, 7 ; Check which video mode we're
jne setup_video_n_tune ; on, if not Monochrome text
mov di, 0B000h ; mode 7, assume mode 3
setup_video_n_tune:
mov es, di
pop ds
mov bp, 0FFF0h ; Setup number of tones to play
; (will increment up to 50h)
setup_animation:
mov dx, 0 ; Setup ambulance_data column
mov cx, 16 ; Number of characters that make
; up one ambulance_data line
do_ambulance:
call show_ambulance ; Print the ambulance to screen
inc dx
loop do_ambulance
call play_siren ; Play a tone of the 'siren'
call wait_tick ; and wait for a tick
inc bp
cmp bp, 50h ; Already played the 'ambulance
jne setup_animation ; siren' tune 12 times?
call speaker_off ; If yes, then turn speaker off
push ds
pop es
ret
;
; Turn the PC speaker off
;
; 8255 PPI - Programmable Peripheral Interface
; Port 61h, 8255 Port B output
;
; (see description below)
;
speaker_off:
in al, 61h
and al, 11111100b ; Disable timer channel 2 and 'ungate'
out 61h, al ; its output to the speaker
ret
;
; Turn on the speaker and play the "ambulance siren" sound
;
; Select tone frequency to generate
;
; Tone frequency is selected by means of the 3rd least significant bit of BP
;
;
; Bit(s) Description
; ------ -----------
; ... 3 2 1 0
; ... x 0 x x Play 1st tone frequency
; ... x 1 x x Play 2nd tone frequency
;
; If we consider A to be the 1st tone and B to be the 2nd tone,
; then the whole 'ambulance siren' tune will be: (AAAABBBB) x 12
;
play_siren:
mov dx, 07D0h ; "ambulance siren" 1st tone freq.
test bp, 00000100b ; Check if we are to play
jz speaker_on ; the first or the second
; tone frequency
mov dx, 0BB8h ; "ambulance siren" 2nd tone frequency
;
; Turn on the speaker
;
; 8255 PPI - Programmable Peripheral Interface
; Port 61h, 8255 Port B output
;
; Bit(s) Description
; ------ -----------
; 7 6 5 4 3 2 1 0
; . . . . . . . 1 Timer 2 gate to speaker enable
; . . . . . . 1 . Speaker data enable
; x x x x x x . . Other non-concerning fields
;
speaker_on:
in al, 61h
test al, 00000011b ; If speaker is already on, then
jnz play_tone ; play the sound tone
or al, 00000011b ; Else, enable timer channel 2 and
out 61h, al ; 'gate' its output to the speaker
;
; Program the PIT
;
; 8253 PIT - Programmable Interval Timer
; Port 43h, 8253 Mode Control Register
;
; Bit(s) Description
; ------ -----------
; 7 6 5 4 3 2 1 0
; . . . . . . . 0 16 binary counter
; . . . . 0 1 1 . Mode 3, square wave generator
; . . 1 1 . . . . Read/Write LSB, followed by write of MSB
; 1 0 . . . . . . Select counter (channel) 2
;
mov al, 10110110b ; Set 8253 command register
out 43h, al ; for mode 3, channel 2, etc
;
; Generate a tone from the speaker
;
; 8253 PIT - Programmable Interval Timer
; Port 42h, 8253 Counter 2 Cassette and Speaker Functions
;
play_tone:
mov ax, dx
out 42h, al ; Send LSB (Least Significant Byte)
mov al, ah
out 42h, al ; Send MSB (Most Significant Byte)
ret
;
; Show the 'ambulance car'
;
show_ambulance:
push cx
push dx
lea bx, [si+ambulance_data-4]
add bx, dx ; Setup which ambulance_data column
; we're going to print
add dx, bp ; Don't show ambulance_data columns
or dx, dx ; which aren't still visible
js ambulance_done
cmp dx, 50h ; Check if the column we're printing
jae ambulance_done ; is past the screen limit
; If yes, then don't print it
mov di, 3200 ; Point to start of screen's 64th line
add di, dx ; Point to the column we're supposed
add di, dx ; to be printing at
sub dx, bp ; Restore to initial column value
mov cx, 5 ; Set it up so we're in the first line
decode_character:
mov ah,4d ; Set color attribute to red
; ; 7 = white
; Decode the character
;
; It's really pretty ingenius. Each character is encoded in such a way
; that for each line beyond the first one, that character is incremented
; by one -- and for each column beyond the first, the same thing happens.
; So taking that into account, it's not difficult to understand how it
; all works, and how to decode the ambulance_data.
;
mov al, [bx] ; Get the character
sub al, 7
add al, cl ; Account for which line we're in
sub al, dl ; Account for which column we're in
cmp cx, 5 ; Are we in the first line?
jne print_character ; If we are, then...
mov ah,1 ; Set color attribute to hi-inten blue
test bp, 00000011b ; Is this the ending tone of a AAAA or
; BBBB tune sequence?
jz print_character ; If not, then go ahead and print the
; 'siren' characters
mov al, ' ' ; Else, replace them with a ' ' (to
; accomplish the visual 'siren' effect
print_character:
stosw ; Print the character to screen
add bx, 16 ; Point to next ambulance_data line
add di, 158 ; Point to next screen line
loop decode_character
ambulance_done:
pop dx
pop cx
ret
;
; Wait for one tick (18.2 per second) to pass
;
wait_tick:
push ds
mov ax, BDA_addr
mov ds, ax
mov ax, ds:BDA_timer_counter ; Get ticks since midnight
check_timer:
cmp ax, ds:BDA_timer_counter ; Check if one tick has
je check_timer ; already passed
pop ds
ret
;
; Our cursor manipulation routine.
;
cursor:
mov ah,1 ; function 1 - cursor control
int 10h ; call ROM BIOS video services
ret ; return to caller
;
; Data from here below
;
ambulance_data:
first_line db 22h, 23h, 24h, 25h, 26h, 27h, 28h, 29h, 66h, 87h, 3Bh
db 2Dh, 2Eh, 2Fh, 30h, 31h
second_line db 23h, 0E0h, 0E1h, 0E2h, 0E3h, 0E4h, 0E5h, 0E6h, 0E7h
db 0E7h, 0E9h, 0EAh, 0EBh, 30h, 31h, 32h
third_line db 24h, 0E0h, 0E1h, 0E2h, 0E3h, 0E8h, 2Ah, 0EAh, 0E7h
db 0E8h, 0E9h, 2Fh, 30h, 6Dh, 32h, 33h
fourth_line db 25h, 0E1h, 0E2h, 0E3h, 0E4h, 0E5h, 0E7h, 0E7h, 0E8h
db 0E9h, 0EAh, 0EBh, 0ECh, 0EDh, 0EEh, 0EFh
fifth_line db 26h, 0E6h, 0E7h, 29h, 59h, 5Ah, 2Ch, 0ECh, 0EDh, 0EEh
db 0EFh, 0F0h, 32h, 62h, 34h, 0F4h