home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
programming
/
asm_programming
/
ASSEMDOC.DOC
< prev
next >
Wrap
Text File
|
1989-01-18
|
24KB
|
786 lines
3/50: Assembly Langauge Programming
Name: Lazerith #1
Date: Mon Dec 12 20:33:46 1988
Okay, gents, here's the deal. I'm going to begin a series of posts on the
hows and whys of assembly langauge programming. Now, because I've got so many
open projects right now I'll generally be slow to respond, so don't lose track
of what I've already said, because I do not wish to repeat it too often.
Here's what you have to have:
Turbo Assembler 1.0 by Borland -OR- Microsoft version 5.10
(I prefer Microsoft and will use it as my default langauge.)
Enough free disk space (or floppy disks) to hold the assembler AND about
two hundred thousand free bytes or MUCH MORE.
8087 will not be necessary for now, and I'll be starting with 8088/8086
CPUs, so IBM users are the only one's likely to benefit.
80286 and 80386 are completely compatible and will be individually
explored later.
IBM CGA (or better) is preferred, because I know most of you will be more
interested in graphics than anything else, HOWEVER, the first
project will be strictly text.
DOS 3.30 is preferred, although it will be a long time before the DOS
version will make a difference.
Here's the project:
We will begin by collectively writting a program I will call DataComm (if
anyone knows of a project already called this, then I need to hear about
it soon!) It will be a modem program specifically designed for use with
MBBS (Which is our future BBS written in both OS/2 and DOS). Eventually
you'll all have completed copies about the same time the new BBS is ready.
Ok, the next post and any following will be titled "DataComm - Lesson 1", etc.
Please E-mail me if your interested and I'll keep it going. Otherwise, I'll
can the whole idea. Thanks,
Lazerith
4/50: DataComm - Lesson 1: "Basic Skeleton"
||||> Permanent Message
Name: Lazerith #1
Date: Mon Dec 12 20:56:38 1988
The basic structure of all of my assembly language projects is the same. In
assembly, one quickly learns to be consistant. To fail to do so is to insure
Never Ending Project from Hell and Everlasting Work! (NEPHEW). Therefore this
is the basic structure of ALL assembly language I'll show you:
.Model Small <- The .Model directive specifies the default style of
your code in Masm 5.10. A "SMALL" indicates that
you expect your code to all reside within 1 block
of 64k memory and that each of you code segments
will themselves take up only 64k. (Information on
segments will follow).
.8086 <- Tells assembly to code ONLY for 8086 (Unnecessary)
.data <- Tells assembler that an initialized data segment
follows.
txtCOPYR db "Copyright (C) 1988 - By the Möebius Group"
Defines a location called "txtCOPYR" which will
contain the string "Copyright...Group"
.code <- Tells assembler that a code segment follows
Main Proc Far <- Tells assembler that a procedure called "Main"
follows which is in a "Far" segment (later).
push ds <- Pushes the value of register DS on to stack
(again, I'll explain these later).
mov ax,0 <- Moves a zero into register AX.
push ax <- Pushes a zero (in AX) onto stack.
; Program starts here
nop <- Does nothing "No OPeration"
; Program ends here
ret <- Return to previous routine (DOS)
Main Endp <- Tells assembler that this is the end of "Main"
.stack <- Tells assembler to make a stack and put it here
End Main <- Tells assembler that this is the end of the file
and that execution should begin with the routine
called "Main"
Now, enter the yellow words into the file exactly as is and run it. Don't ask
questions, I'll explain everything in time. This should work as is.
The commands are "MASM DataComm.asm;" followed by "LINK DataComm;" This
should work, if not, let me know.
Lazerith
Read:(1-50,^4),? :
9/50: ASSEMBLY
Name: White Knight #124
Date: Wed Dec 21 10:31:05 1988
I have a few questions. Some of them may sound dumb, but please bear
through with me. They are:
1. How do I know if my CPU is 8088/8086 or Other?
2. What is Masm 5.10?
3. What is the difference between Move and Push?
4. Could I d/l MicroSoft 5.10 and Brief?
I would appreciate any help. This is a great sub and I hope Lazerith
continues in it.
Later.
Read:(1-50,^9),? :
10/50: Answers
||||> Permanent Message
Name: Lazerith #1
Date: Wed Dec 21 15:15:17 1988
1. How can I tell what CPU I have?
Easiest way is to run Norton's SI.EXE (System Information) or similar
program. As to 8086 vs 8088, I don't think there's any way to tell except
to look at the serial number on the chip.
2. What is MASM 5.10?
That's the name of Microsoft's Macro Assembler version 5.10, the latest and
greatest assembler available (from Microsoft). This latest version adds a
whole series of simplifications for quicker programming.
3. What is Move vs. Push?
In assembler a MOV instruction (Move) copies a value from one place to
another - usually between registers and memory. It's very general purpose
and can be used to copy from anywhere to anywhere. PUSH on the other hand
is a very SPECIALIZED type of move. It copies the value "onto the stack."
The stack is a specialized area of memory used by the cpu to remember
things that go on between your various subroutines and programs. For
instance, when you call, say, a Print routine, the cpu must remember where
you called from (in order to return there). Also the stack is often used
to pass parameters. In our example, you could push the string to be
written onto the stack, to be read by the next subroutine.
The stack operates like (the classic example) a stack of plates at a
cafeteria. That is, as you push plates onto the stack, each new plate is
at the top. When you call to pull then off the stack, you receive them in
the LAST PUSHED FIRST POPPED order (better known as LAST IN FIRST OUT or
LIFO). The command in assembler to recover the last pushed is "POP".
Lazerith
12/50: Help...
Name: Dr. Poison #46
Date: Fri Dec 23 17:59:19 1988
I am writing a program using Turbo Pascal 4.0 and I am looking for a way to
determine what character is located at a specific position on the screen.
For example, I would like a way to figure out what character is at position
15,3; which should return some sort of ascii equivalent at fifteen units
across and three units down (or something similar).
Any help would be greatly apreciated.
Dr. Poison
13/50: ...
Name: Def Jim #54
Date: Sat Dec 24 13:29:40 1988
There's two basic ways to do it.
You can directly check screen memory to get the value. This involves
computing the address in screen memory where you want to check and then simply
reading it. You can accomplish this through the mem[] array of Turbo Pascal
(if it still exists past TP 3.0). The only drawback to this method is that
the computation formula will change depending if you have a CGA, a MCA, a EGA,
or what have you. These all arrange their screen memory differently.
The second way gets around the problems with different screen types. You use
a particular INT 10H function to get the contents of the screen. I don't have
any books here at home for it, but I think you have to set the cursor position
to the location you want (using INT 10H) and then read the contents at the
cursor position (using INT 10H). This method is the 'portable' one working
across all display types. I'm sure someone will post the details on this
method.
14/50: READING the screen.
Name: Lazerith #1
Date: Sat Dec 24 14:18:05 1988
In assembly langauge the ONLY efficient way to it is to use the Int 10h
function to read the characters off the screen. This routine figures out
which mode your in and on which card and reads it as appropriate. IT EVEN
READS OFF OF GRAPHICS SCREENS.
Now Pascal VERY probably has the same routine, but I don't have the chance to
go check now. So in a little bit I'll either post an INLINE function (that
is, using assembly INSIDE dos) or the appropriate pascal routine.
-Lazerith
Read:(1-50,^14),? :
15/50: Thanks,
Name: Dr. Poison #46
Date: Sat Dec 24 23:28:30 1988
Please elaborate on INT 10h when you get a chance.
Dr. Poison
Read:(1-50,^15),? :
16/50: Reading the Screen using BIOS
Name: Gryps Rex #2
Date: Sun Dec 25 23:02:35 1988
there are several BIOS functions that allow a programmer to read from the
screen. They are:
function 3: read cursor position
AH = 3
BH = video page number (0-7)
function 8: read attribute/character at cursor position
AH = 8
BH = video page number (0-7)
return:
AL = character read
AH = attribute of character (in alphga modes only)
(IBM BIOS Tech Ref Apr87)
-Gryps Rex
17/50: That
Name: Megaton Man #61
Date: Sun Dec 25 23:20:16 1988
in Turbo Pascal 3.0 they have a procedure MsDOS (var);
In turbo Pascal 4.0 it dont have it...
I was wondering how to do Assembly INterrupt or Dos Calls in TP...
Teach me how to do INLINE in tp...
meg
18/50: DOS/BIOS Interrupts
Name: Gryps Rex #2
Date: Mon Dec 26 10:51:08 1988
You CAN use the INTR() procedure in Turbo Pascal 4.0/5.0 and it has the
following syntax:
Intr( IntNo : byte; var Regs : Registers )
example:
{ set the cursor position using BIOS }
procedure locate(row, column : integer)
var
regs : registers;
begin
regs.ax = $200;
regs.bx = 0;
regs.dx = (row * 256) + column;
Intr($10,regs)
end; { locate }
to access the Registers type, you must include the Dos unit in the uses
statement at the top of your code (i.e. Uses Crt, Dos; )
-Gryps Rex
19/50: DataComm - Lesson 2: "Out1"
||||> Permanent Message
Name: Lazerith #1
Date: Mon Dec 26 17:48:34 1988
Ok, if you're not keeping up with this feedback!
The most important (and usually first) routine is always the "Out1" routine
which will output 1 character to the screen. Later on, we'll make this into a
wonderfully complicated routine, but for now, it'll just be DOS.
Immediately ahead of "Main Proc Far" insert:
Out1 Proc Near <-Indicates a "Near" routine (Within 64k)
push dx <-Store DX, because we're screwing with it.
push ax <-Store AX, ditto
mov dl,al ; dl=Character to Output (Passed in AL)
mov ah,6 ; ah="DOS: Direct I/O"
int 21h ; Call DOS service AH (6) Outputs to Screen
pop ax <-Restores AX
pop ax <-Restores DX (Note the reverse order)
ret <-Return to caller
Out1 Endp <-End of procedure
Inside Main (after "mov ds,ax") add:
mov al,"H" ; al="H"
call Out1 ; Output "H"
mov al,"e" ; al="e"
call Out1 ; Output "e"
mov al,"l" ; al="l"
call Out1 ; Output "l"
call Out1 ; Output "l"
mov al,"o" ; al="o"
call Out1 ; Output "o"
mov al,0Dh ; al=Carriage Return
call Out1 ; Output CR
mov al,0Ah ; al=Linefeed
call Out1 ; Output LF
File it, Compile it, Run it.
Lazerith
20/50: DataComm - OOPS!
||||> Permanent Message
Name: Lazerith #1
Date: Mon Dec 26 18:12:03 1988
Uh, rather than inserting the second stuff after "mov ds,ax" (which isn't in
the code anywhere ... heh); replace the line "nop" with the code...
To keep things straight, the whole asm file is now in the TEXT dload section!
-Lazerith
21/50: A Question bout 'C' and WWIV
Name: Jolly Green Giant #5
Date: Wed Dec 28 11:51:32 1988
If someone istalls one of the mods called the FROM mod how can you make it
so you change it in the UEDIT instead of just viewing it?
Read:(1-50,^21),? :
22/50: ...
Name: Def Jim #54
Date: Wed Dec 28 23:22:41 1988
I assume "we're" going to be moving past OUT1 and have a OUTSTR function
posted, right?
Read:(1-50,^22),? :
23/50: DataComm - Lesson 3: "Out$" (aka OutStr)
||||> Permanent Message
Name: Lazerith #1
Date: Thu Dec 29 03:39:03 1988
As Def Jim predicted, calling Out1 with every letter in your messages is
extremely inefficient, so we'll need a string handling routine. There are
three popular methods of string handling: Asciiz, Highbit, and Count.
Asciiz: Strings are terminated by a null (ascii 00h) like this:
"This is an asciiz string",0
This method is unquestionably the most flexible allowing 65535
characters in a string and allow 255 (all except 00) as characters.
Highbit: Strings are terminated by the last character having the highbit set
like this:
"This is a highbit strin","g"+128
This method is common among programs with space restrictions because
it saves one byte per string. Strings can be 65536 characters long
like in asciiz, but are limited to characters 00-7F (0-127).
Count: Strings are preceded by a count like this:
24,"This is a highbit string"
This method allows for FAST string manipulation (like centering,
windowing, etc. It also allows all 256 characters to be in the
string. The major limitation, however, is that strings can only be
as long as the count will allow (here we've used bytes which would
limit our strings to 255 characters in length).
Dos: Oh yeah, then there's the way DOS does it:
"This is a dos string$"
It is the same basic method as asciiz except that some moron
somewhere decided to use a displayable character ("$") as a
terminating character. It's just fine it you never have to use
a dollar-sign... (Here that Lotus?)
Naturally, we'll be using Asciiz. This is because, A) we don't have a space
limitation, B) it allows us to display the range of characters 01-FE (FF is
undisplayable thanks to a limitation of our Out1 routine handed down from DOS,
but is not a problem because both 00 and FF display as spaces anyway), and C)
it is not very complicated (or indeed very slow) to count the length of our
strings using 8086 string functions.
The following post will include the routine, if you're falling behind, tell me.
-Lazerith
24/50: DataComm - Lesson 3: "Out$"
||||> Permanent Message
Name: Lazerith #1
Date: Thu Dec 29 04:07:59 1988
Remove all the code insert previously between the ";code begins here" and
";code ends here" and replace it with:
lea si,txtCOPYRIGHT ; ds:si>"Copyright..."
call Out$
And AFTER Out1 and BEFORE Main add this procedure:
Out$ Proc Near
push si
push ax
@@: lodsb ; al=character from string
or al,al ; Is character end-of-line?
jz @f ; If so, exit
call Out1 ; Display character
jmp short @b ; Loop thru string
@@: pop ax
pop si
ret
Out$ Endp
Explanations of all the new commands will follow this post.
-Lazerith
25/50: DataComm - Lesson 3: Out$ ----- Commentary
||||> Permanent Message
Name: Lazerith #1
Date: Thu Dec 29 04:15:08 1988
A lot of new commands have popped up I need to explain:
push Tells the CPU to push the word onto the stack to be popped off later.
pop Recovers a previously pushed word into target register.
@@: Under Masm 5.10, this is a local label to which the next two refer.
jmp @b References the previous ("back") @@ label.
jmp @f References the next ("forward") @@ label.
(These instructions take up no symbol space by always using the same label.)
lodsb A 8086 command the Loads from DS:SI into AL and increments SI.
or al,al A neat trick. By "or'ing" a reg with itself, sets ZF if reg is zero.
jmp SHORT label
The short tells the processor that the jump is within 127 bytes.
I can explain further any questions you have. Indeed, I'm being intentionally
obscure so I know if any of this is helping!
-Lazerith
26/50: @@:
Name: Megaton Man #61
Date: Fri Dec 30 15:57:00 1988
@@: dont work with Turbo Assembler right? Cause I tried it.
The rest.... well.... review to me... But keep going.... Very interesting!
Oh, How can you change Colors in Assembly!
wait wait!!!! GRYPS!!
When you showed the INTR(xxx) for TP 4.0 adn 5.0 what about DOS FUNCTIONS!
You only showed BIOS Interrupts!
Meg
Read:(1-50,^26),? :
27/50: DOS Interrupts ...
Name: Gryps Rex #2
Date: Fri Dec 30 16:08:14 1988
Basically they follow the same approach with the exception that the interrupt
number is 21 hex (33 dec). Use of the OFS() and SEG() functions are permitted
when using registers. Example:
var regs : registers;
begin
regs.ax = $1a00;
regs.bx = ofs(data);
regs.es = seg(data);
intr($21,regs)
and so forth...
-Gryps Rex
Read:(1-50,^27),? :
28/50: Also ...
Name: Gryps Rex #2
Date: Fri Dec 30 16:15:45 1988
Just checking the manual, page 448, regarding the MsDos function. The
interrupt number is not required in this case.
var regs : registers;
begin
regs.ax := $1A00;
regs.bx := ofs(data);
regs.es := seg(data);
msdos(regs);
end;
same as above.
-Gryps Rex
Read:(1-50,^28),? :
29/50: Procedure Locate
Name: Dr. Poison #46
Date: Fri Dec 30 20:32:35 1988
The procedure Locate works fine, but for those of us who aren't very good at
assembly, how would I find what character/atrribute is at that location?
(Using Turbo Pascal 4.0).
Dr. Poison
32/50: Turbo Tutor
Name: Gryps Rex #2
Date: Sat Dec 31 01:25:26 1988
program readscreen;
uses crt, dos;
var
screen_segment : word;
function ReadCharAttrAtCursor : word;
var
regs : registers;
begin
regs.ax := $0800;
regs.bx := $0000;
intr($10,regs);
ReadCharAttrAtCursor := regs.ax;
end;
function FasterRead : word;
var
regs : registers;
begin
regs.ax := $0300;
regs.bx := $0000; { this is the video page, in lo byte }
intr($10,regs); { read the current cursor position }
FasterRead := mem[screen_segment:(lo(regs.dx)*2+hi(regs.dx)*160)];
end;
var
regs : registers;
begin
intr($11,regs);
if (regs.ax and $30) then screen_segment := $B000
else screen_segment := $B800;
.
.
writeln('Character/attribute at 10,10 is: ',FasterRead);
.
.
end.
or something like that, but the 'FasterRead' is faster.
-Gryps Rex
34/50: ...
Name: Def Jim #54
Date: Sat Dec 31 16:48:37 1988
Some routines and services from other operating systems store the strings
delimted by C/Rs. The ASCIIZ method is the preferred method considering the
fact that you probably want to write the routine to handle arguments from your
HLL C program. ASCIIZ is the method used in C/Unix. The len+string method is
used in BASIC and TP.
I didn't read the code, but are you using BIOS functions for the I/O, or are
you going straight to the port?
Read:(1-50,^37),? :
44/50: VGA test
Name: Gryps Rex #2
Date: Mon Jan 09 23:59:13 1989
from the C:\> prompt type the following:
debug <CR>
a
mov ax,13
int 10
<CR>
p=100
p
now, if nothing happens, then you don't have TRUE VGA.
46/50: Assembling MASM 5.10 code with TASM ...
Name: Gryps Rex #2
Date: Wed Jan 11 15:57:28 1989
tasm /jMASM51 /jQUIRKS [options] filename
this enables the Turbo Assembler to assemble the code that you use with
Microsoft Macro Assembler 5.10
-Gryps Rex
47/50: Um, a Question.
Name: Io Lisp #113
Date: Tue Jan 17 14:54:39 1989
In Assembly, how do you display Graphics ? I.e., how would you put a
single dot on the screen at location 1,1 ?
═╦═╔═╗ ╔ ═╦═╔═╔═╗
═╩═╚═╝ ╚═══╩═╝ ║═╝
48/50: Okay.
Name: Lazerith #1
Date: Wed Jan 18 11:08:30 1989
To perform graphics, understand the screen first:
In AlphaNumeric mode (That would be modes 0-3...) Data stored at B800:0000
thru B800:1000 (approximately) is used to display characters (and no graphics)
on the screen, like this:
B800:0000
41 07 42 07 43 07 44 07 45 07
^ ^ ^ ^ ^
"A" "B" "C" "D" "E"
The "07" represents "White Characters on a Black Background".
In a Graphics mode, data stored at B800:0000 now represents pixel information.
In mode 6 (Black and White 640x200) the pixel information is like this:
47h = 01000111b = " . ..." pixels (white on black).
6Ch = 01101100b = " .. .. " p
98h = 10011000b = ". .. " p
As you can see (I hope) every bit in the hex number equals a bit on the
screen. To put it more simply: In either graphics or alphanumeric mode, the
display interprets the data stored at B800:0000 to form either characters or
graphics.
In some modes the base paragraph is not B800, but A000 or B000 or something
like that.
In some modes every other pixel might be color information like:
00b = Black (or Background)
01b = Color 1
10b = Color 2
11b = White (or Color 3)
Etc...
More?
-Lazerith
49/50: I'm hoping this isn't very long,
Name: Io Lisp #113
Date: Wed Jan 18 16:42:59 1989
But how do you change screen modes then?
The Beginner, IoLisp
Read:(1-50,^49),? :
50/50: Video Modes
Name: Lazerith #1
Date: Wed Jan 18 18:57:35 1989
Video Modes are numbered by IBM and can be engaged by BIOS. They are:
0 - Alpha/Numeric 40x25 Black & White
1 - Alpha/Numeric 40x25 Color
2 - Alpha/Numeric 80x25 Black & White
3 - Alpha/Numeric 80x25 Color
4 - Graphics 320x200 4-Color
5 - Graphics 320x200 4-Black & White
6 - Graphics 640x200 2-Black & White
7 - Monochrome Alpha/Numeric 80x25
13 - Graphics 320x200 16-Color
14 - Graphics 640x200 16-Color
15 - Graphics 640x350 2-Black & White
16 - Graphics 640x350 16-Color
17 - Graphics 640x480 2-Color
18 - Graphics 640x480 16-Color
19 - Graphics 320x200 256-Color
The number of modes available to you is directly dependant on which video card
you have. For instance CGA only allows you to use modes 0 thru 6.
To engage the mode use BIOS call 10h (<- That's 16 in decimal...) like this:
mov al,VideoMode ; al=Video Mode number
xor ah,ah ; ah=BIOS Service 00
int 10h ; Call BIOS to set mode.
It's that easy.
-Lazerith