📄 ex8.asm
字号:
; Sample program for Chapter Eight
; Demonstrates the use of many MASM features discussed in Chapter Six
; including label types, constants, segment ordering, procedures, equates,
; address expressions, coercion and type operators, segment prefixes,
; the assume directive, conditional assembly, macros, listing directives,
; separate assembly, and using the UCR Standard Library.
;
; Include the header files for the UCR Standard Library. Note that the
; "stdlib.a" file defines two segments; MASM will load these segments into
; memory before "dseg" in this program.
;
; The ".nolist" directive tells MASM not to list out all the macros for
; the standard library when producing an assembly listing. Doing so would
; increase the size of the listing by many tens of pages and would tend to
; obscure the real code in this program.
;
; The ".list" directive turns the listing back on after MASM gets past the
; standard library files. Note that these two directives (".nolist" and
; ".list") are only active if you produce an assembly listing using MASM's
; "/Fl" command line parameter.
.nolist
include stdlib.a
includelib stdlib.lib
.list
; The following statement includes the special header file for this
; particular program. The header file contains external definitions
; and various data type definitions.
include matrix.a
; The following two statements allow us to use 80386 instructions
; in the program. The ".386" directive turns on the 80386 instruction
; set, the "option" directive tells MASM to use 16-bit segments by
; default (when using 80386 instructions, 32-bit segments are the default).
; DOS real mode programs must be written using 16-bit segments.
.386
option segment:use16
dseg segment para public 'data'
Rows integer ? ;Number of rows in matrices
Columns integer ? ;Number of columns in matrices
; Input line is an input buffer this code uses to read a string of text
; from the user. In particular, the GetWholeNumber procedure passes the
; address of InputLine to the GETS routine that reads a line of text
; from the user and places each character into this array. GETS reads
; a maximum of 127 characters plus the enter key from the user. It zero
; terminates that string (replacing the ASCII code for the ENTER key with
; a zero). Therefore, this array needs to be at least 128 bytes long to
; prevent the possibility of buffer overflow.
;
; Note that the GetArray module also uses this array.
InputLine char 128 dup (0)
; The following two pointers point at arrays of integers.
; This program dynamically allocates storage for the actual array data
; once the user tells the program how big the arrays should be. The
; Rows and Columns variables above determine the respective sizes of
; these arrays. After allocating the storage with a call to MALLOC,
; this program stores the pointers to these arrays into the following
; two pointer variables.
RowArray dword ? ;Pointer to Row values
ColArray dword ? ;Pointer to column values.
; ResultArrays is an array of dope vectors(*) to hold the results
; from the matrix operations:
;
; [0]- addition table
; [1]- subtraction table
; [2]- multiplication table
; [3]- division table
;
; [4]- modulo (remainder) table -- if the symbol "DoMOD" is defined.
;
; The equate that follows the ResultArrays declaration computes the number
; of elements in the array. "$" is the offset into dseg immediately after
; the last byte of ResultArrays. Subtracting this value from ResultArrays
; computes the number of bytes in ResultArrays. Dividing this by the size
; of a single dope vector produces the number of elements in the array.
; This is an excellent example of how you can use address expressions in
; an assembly language program.
;
; The IFDEF DoMOD code demonstrates how easy it is to extend this matrix.
; Defining the symbol "DoMOD" adds another entry to this array. The
; rest of the program adjusts for this new entry automatically.
;
; You can easily add new items to this array of dope vectors. You will
; need to supply a title and a function to compute the matrice's entries.
; Other than that, however, this program automatically adjusts to any new
; entries you add to the dope vector array.
;
; (*) A "Dope Vector" is a data structure that describes a dynamically
; allocated array. A typical dope vector contains the maximum value for
; each dimension, a pointer to the array data in memory, and some other
; possible information. This program also stores a pointer to an array
; title and a pointer to an arithmetic function in the dope vector.
ResultArrays DopeVec {AddTbl,Addition}, {SubTbl,Subtraction}
DopeVec {MulTbl,Multiplication}, {DivTbl,Division}
ifdef DoMOD
DopeVec {ModTbl,Modulo}
endif
; Add any new functions of your own at this point, before the following equate:
RASize = ($-ResultArrays) / (sizeof DopeVec)
; Titles for each of the four (five) matrices.
AddTbl char "Addition Table",0
SubTbl char "Subtraction Table",0
MulTbl char "Multiplication Table",0
DivTbl char "Division Table",0
ifdef DoMOD
ModTbl char "Modulo (Remainder) Table",0
endif
; This would be a good place to put a title for any new array you create.
dseg ends
; Putting PrintMat inside its own segment demonstrates that you can have
; multiple code segments within a program. There is no reason we couldn't
; have put "PrintMat" in CSEG other than to demonstrate a far call to a
; different segment.
PrintSeg segment para public 'PrintSeg'
; PrintMat- Prints a matrix for the cross product operation.
;
; On Entry:
;
; DS must point at DSEG.
; DS:SI points at the entry in ResultArrays for the
; array to print.
;
; The output takes the following form:
;
; Matrix Title
;
; <- column matrix values ->
;
; ^ *------------------------*
; | | |
; R | |
; o | Cross Product Matrix |
; w | Values |
; | |
; V | |
; a | |
; l | |
; u | |
; e | |
; s | |
; | | |
; v *------------------------*
PrintMat proc far
assume ds:dseg
; Note the use of conditional assembly to insert extra debugging statements
; if a special symbol "debug" is defined during assembly. If such a symbol
; is not defined during assembly, the assembler ignores the following
; statements:
ifdef debug
print
char "In PrintMat",cr,lf,0
endif
; First, print the title of this table. The TTL field in the dope vector
; contains a pointer to a zero terminated title string. Load this pointer
; into es:di and call PUTS to print that string.
putcr
les di, [si].DopeVec.TTL
puts
; Now print the column values. Note the use of PUTISIZE so that each
; value takes exactly six print positions. The following loop repeats
; once for each element in the Column array (the number of elements in
; the column array is given by the Dim2 field in the dope vector).
print ;Skip spaces to move past the
char cr,lf,lf," ",0 ; row values.
mov dx, [si].DopeVec.Dim2 ;# of times to repeat the loop.
les di, ColArray ;Base address of array.
ColValLp: mov ax, es:[di] ;Fetch current array element.
mov cx, 6 ;Print the value using a
putisize ; minimum of six positions.
add di, 2 ;Move on to next array element.
dec dx ;Repeat this loop DIM2 times.
jne ColValLp
putcr ;End of column array output
putcr ;Insert a blank line.
; Now output each row of the matrix. Note that we need to output the
; RowArray value before each row of the matrix.
;
; RowLp is the outer loop that repeats for each row.
mov Rows, 0 ;Repeat for 0..Dim1-1 rows.
RowLp: les di, RowArray ;Output the current RowArray
mov bx, Rows ; value on the left hand side
add bx, bx ; of the matrix.
mov ax, es:[di][bx] ;ES:DI is base, BX is index.
mov cx, 5 ;Output using five positions.
putisize
print
char ": ",0
; ColLp is the inner loop that repeats for each item on each row.
mov Columns, 0 ;Repeat for 0..Dim2-1 columns.
ColLp: mov bx, Rows ;Compute index into the array
imul bx, [si].DopeVec.Dim2 ; index := (Rows*Dim2 +
add bx, Columns ; columns) * 2
add bx, bx
; Note that we only have a pointer to the base address of the array, so we
; have to fetch that pointer and index off it to access the desired array
; element. This code loads the pointer to the base address of the array into
; the es:di register pair.
les di, [si].DopeVec.Data ;Base address of array.
mov ax, es:[di][bx] ;Get array element
; The functions that compute the values for the array store an 8000h into
; the array element if some sort of error occurs. Of course, it is possible
; to produce 8000h as an actual result, but giving up a single value to
; trap errors is worthwhile. The following code checks to see if an error
; occurred during the cross product. If so, this code prints " ****",
; otherwise, it prints the actual value.
cmp ax, 8000h ;Check for error value
jne GoodOutput
print
char " ****",0 ;Print this for errors.
jmp DoNext
GoodOutput: mov cx, 6 ;Use six print positions.
putisize ;Print a good value.
DoNext: mov ax, Columns ;Move on to next array
inc ax ; element.
mov Columns, ax
cmp ax, [si].DopeVec.Dim2 ;See if we're done with
jb ColLp ; this column.
putcr ;End each column with CR/LF
mov ax, Rows ;Move on to the next row.
inc ax
mov Rows, ax
cmp ax, [si].DopeVec.Dim1 ;Have we finished all the
jb RowLp ; rows? Repeat if not done.
ret
PrintMat endp
PrintSeg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
;GetWholeNum- This routine reads a whole number (an integer greater than
; zero) from the user. If the user enters an illegal whole
; number, this procedure makes the user re-enter the data.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -