Before I get started on the help I need I will say that yes this is a project for school so I'm not looking for anyone to give me the code but my group is new to MASM and struggling to get the code. We understand how to find the RREF on paper, but not through code. Here is our assignment:
Row-Echelon Matrix Reduction
Write a program that calculates the row-echelon form of a matrix of any size. The matrix values are all integer and stored in an input file. The reduced matrix is stored in an output file. The values of the output matrix should also be integer values.
And here is our current code, it's bad we know:
.MODEL SMALL ;Defines memory model as small which uses separate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
ROW DB ?
COLUMN DB ?
RREF DB "matrix.txt", 0
.CODE
;-------------------------------------------------------------------------------------------
READ MACRO
MOV CX, LENGTHOF RREF
MOV DX, OFFSET RREF
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 1
JNE QUIT
;-------------------------------------------------------------------------------------------
Main PROC FAR ;Defines procedure distance as far
.STARTUP
;Program:
MOV BP, 0
MOV SI, 0
MOV AX, 3D02h ;Open file
MOV DX, OFFSET RREF
INT 21H
MOV BX, AX
IF ROW<COLUMN
D=ROW
IF ROW>COLUMN
D=COLUMN
FOR d=1...D
e=M(d,d)
FOR r=d...(ROW-1)
X=M(ROW,d)/e
FOR col=d...COLUMN
M(r,col)=M(r,col)-e*X
PUSH BP
MOV BP, SP
CALL REDUCTION
JC QUIT
ADD SP 2+4
POP BP
MOV AH,40h
INT 21H
MOV AH, 3Eh
INT 21H
QUIT: .EXIT
MAIN ENDP
REDUCTION PROC
PUSHAD
MOVZX EAX, ROW
MOV EDX, EAX
MOVZX EBX, COLUMN
SUB EBX, 1
MUL EBX
JC QUIT
SUB EDX, 1
ADD EAX, EDX
JC QUIT
LOOP
POPAD
RET
REDUCTION ENDP
END
The code itself is all over the place. We have to open a file from MATLAB containing a matrix in the form [R,C,#,#,#,#,#,#,#,#,#,#, etc.] where the first two bytes are the row and column numbers respectively, and the rest are the elements of the matrix stored in 8 bytes each. The matrix can go all the way to R-C dimensions of 255,255 but that is randomly generated in MATLAB. Once we open and read the file, we have to calculate the reduced row echelon form with only the elements below the diagonal zeroed out, everything above the diagonal doesn't matter. Then we must write the RREF matrix to an output file to be opened in MATLAB and displayed.
Any and all help will be greatly appreciated, we just need to be steered in the right direction. Here is our trouble:
1. How to read two separate bytes, then each element, which are 8 bytes long a piece, and what to do with them
2. How to code for reducing the lower half of the matrix
3. How to write to an output file
Programs we are using are Textpad 6 and Codeview debugger
Hi,
Quote1. How to read two separate bytes,
Using parts of your code, it would look something like the
following.
MOV CX,2 ; Want to read two bytes.
MOV DX, OFFSET ROW
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 2
JNE QUIT
That will place one byte in ROW and one in COLUMN.
Quotethen each element, which are 8 bytes long a piece
Well, change the 2 to an 8 in the above code and point to an
element buffer, and you can read them in one at a time. Or
multiply the row times the column times 8 and read them in all at
once. Remember to allocate enough space to hold the whole lot.
Quoteand what to do with them
Find the MATLAB documentation and find what format the
elements are stored in. Real4 and integers are possible.
Regards,
Steve N.
Quote from: FORTRANS on April 18, 2013, 04:28:48 AM
Find the MATLAB documentation and find what format the
elements are stored in. Real4 and integers are possible.
MatLab is normally REAL8 aka "double". However, two bytes for rows and columns at the beginning is not a standard MatLab matrix. Only your supervisor knows what format that is. My best guess is 2 bytes R+C plus REAL8 elements. Which is a lousy format for performance reasons (badly aligned) but technically it can work, if you have no more that 256 rows...
Quote from: jj2007 on April 18, 2013, 05:19:05 AM
MatLab is normally REAL8 aka "double".
Hi,
Yes, my mistake. Thanks for the correction.
QuoteHowever, two bytes for rows and columns at the beginning is not a standard MatLab matrix. Only your supervisor knows what format that is. My best guess is 2 bytes R+C plus REAL8 elements. Which is a lousy format for performance reasons (badly aligned) but technically it can work, if you have no more that 256 rows...
At any rate, they need to know what the elements in the file
are. And I would hope no more than a 10x10 matrix. I would
not think alignment in the file would hurt amything? Alignment
in memory can hurt. But if getting a working program is the
goal, I would leave that to last to worry about.
Regards,
Steve N.
Quote from: jj2007 on April 18, 2013, 05:19:05 AM
Quote from: FORTRANS on April 18, 2013, 04:28:48 AM
Find the MATLAB documentation and find what format the
elements are stored in. Real4 and integers are possible.
MatLab is normally REAL8 aka "double". However, two bytes for rows and columns at the beginning is not a standard MatLab matrix. Only your supervisor knows what format that is. My best guess is 2 bytes R+C plus REAL8 elements. Which is a lousy format for performance reasons (badly aligned) but technically it can work, if you have no more that 256 rows...
Jochen, he said each element of matrix is 8 bytes, not real 8.
read it again else where [R, C ...]... :icon14:
Quote from: FORTRANS on April 18, 2013, 04:28:48 AM
Quoteand what to do with them
Find the MATLAB documentation and find what format the
elements are stored in. Real4 and integers are possible.
Thanks for the help so far. The matrix elements in the input and output file are both stored as integers. The max matrix size, as told by our instructor, will be 255x255. Our code needs to be able to read the row and column inputs, decide which of the values is smaller so that the correct diagonal can be setup, then loop all the way through the matrix beneath the diagonal to zero-out the elements.
Also, the file format is 2 bytes (R & C) then all the elements separated by one space each. i.e. R C (element) (element) (element) (element) (element) etc.
Quote from: brettc431 on April 18, 2013, 07:39:29 AM
Thanks for the help so far. The matrix elements in the input and output file are both stored as integers. The max matrix size, as told by our instructor, will be 255x255. Our code needs to be able to read the row and column inputs, decide which of the values is smaller so that the correct diagonal can be setup, then loop all the way through the matrix beneath the diagonal to zero-out the elements.
Also, the file format is 2 bytes (R & C) then all the elements separated by one space each. i.e. R C (element) (element) (element) (element) (element) etc.
Hi,
Well the two bytes for row and column are obviously binary
values if they can be as large as 255. Elements separated by
spaces sounds a bit odd. Are the integers ASCII (text) or
binary? Are the spaces part of the eight bytes or are there nine
bytes per matrix entry? These questions are minor considerations
anyway. Reading the data into your program should be relatively
easy.
Just reading the file into memory and writing it back out
would be a good starting point.
As far as the processing of the matrix, assuming there are
more than one of you, have one play dumb at a black board,
or a piece of paper, and have the rest walk through the algorithm
telling the victim what to do. Write down pseudo-code (or a
computer language you are familar with) to map out your
program logic. For example, use a grid of eight boxes for the
CPU registers. And another grid for locations in memory.
Another grid of eight boxes for the FPU registers, if needed
(that would be rather advanced). Write out a list of opcodes
that you are expected to use to help in telling someone what
to do.
What programming environment are you using? Do you
have a library of routines available? For ASCII to binary number
conversion for instance. What text book is the class using?
Regards,
Steve
Quote from: RuiLoureiro on April 18, 2013, 07:34:25 AMJochen, he said each element of matrix is 8 bytes, not real 8.
Rui, I had seen that and guessed that it was binary data, so 8 bytes = real8. But (see recent posts) it could also be text.
Brett, the best way to get clarity about the format is to post a sample "database". Just zip it and attach it.
Quote from: brettc431 on April 18, 2013, 07:39:29 AM
Quote from: FORTRANS on April 18, 2013, 04:28:48 AM
Quoteand what to do with them
Find the MATLAB documentation and find what format the
elements are stored in. Real4 and integers are possible.
Thanks for the help so far. The matrix elements in the input and output file are both stored as integers. The max matrix size, as told by our instructor, will be 255x255. Our code needs to be able to read the row and column inputs, decide which of the values is smaller so that the correct diagonal can be setup, then loop all the way through the matrix beneath the diagonal to zero-out the elements.
Also, the file format is 2 bytes (R & C) then all the elements separated by one space each. i.e. R C (element) (element) (element) (element) (element) etc.
Hi brettc431,
I could help you but
only and if only it was written in 32 bits
In this forum we may find "The calculator" that does matrix and you may find
also a library Math10 where you may find procedures to convert string to real and real to string. I already wrote code for matrix, all operations in real4, real8, real10, integer32 and integer64 but i need time to test all that work.
In "Campus" you can see the topic: "converting string to real4" and you can download the zip file. You will find a good procedure to convert string to real 4 in 32 bits
:icon14:
I've got a partner working on the open, read, write, and close. I'm working on the algorithm for reducing the matrix.
Here's what I've got so far but I don't know how to implement this into code:
Say the matrix is:
M = 1 2 3 4
5 6 7 9
10 11 12 13
Algorithm for reducing the matrix:
1. Determine the number of diagonal elements
2. Create a loop that goes through the diagonal elements
3. Read a diagonal element M(I,I) and the one next to it. The one next to it will the next element in the row below it. Use M[d*8+2] to get the diagonal element. Save both into variables: e=M(I,I) and ep1=M(I+1,I).
E.g. the first diagonal element is M(1,1), d = (1-1)*3+1-1=0 => M(1,1)=M[0*8+2]=M[2]. Move the file pointer to 2. Read 8 bytes into variable e. Then read another 8 bytes in ep1.
We want to perform the row subtraction for an entire row starting with the element under the diagonal and ending with the last column of the row
Also, we must scale the row subtraction to give 0 underneath the diagonal. Scale = -e/ep1.
E.g. for M(1,1) = 1; M(2,1) = 5; scale = -1/5.
Set r= I+1 = 2, set c = I=1.
M(r,c) = M(r,c)*scale + M(I,I) ;read M(r,c) by calculating M[8*d+2]
Write M(r,c) in the output file ;requires that the output file be initialized.
c = c+1
Repeat until c = Col = 4.
What this would do is
M(2,1)= 5(-1/5) + 1 = 0
M(2,2)= 6(-1/5) + 2 = -4/8
M(2,3)= 7(-1/5) + 3 = -8/5
M(2,4)= 8(-1/5) + 4 = -12/5
By initialized output file, I mean that the output file is not blank. This can be done by copying the input file into the output, or writing zero's equivalent to the size of the input file into the output file.
4. Make the diagonal M(I,I)=1. Divide the entire row of the diagonal by the value in the diagonal.
E.g. for the first diagonal element:
Set r=I=1, set c=I=1
M(r,c) = M(r,c)/e ; read M(r,c) by calculating M[8*d+2]
Write M(r,c) in the output file ;requires that the output file be initialized.
c = c+1
Repeat until c = Col = 4.
Step 4 is carried out after step 3 because it will be faster that way.
5. Loop to step 3.
Any help on the code itself? Even just a basic format would be a help at this point. The project has to be running by monday evening.
QuoteI've got a partner working on the open, read, write, and close. I'm working on the algorithm for reducing the matrix.
he got the better end of that deal - lol
(tell him to look up INT 21h, functions 3Ch, 3Dh, 3Eh, 3Fh, and 40h)
as Jochen mentioned....
http://masm32.com/board/index.php?topic=1813.msg18636#msg18636 (http://masm32.com/board/index.php?topic=1813.msg18636#msg18636)
it would make things easier if we could see an example database
that's not because of read and write
it's because we want to see the numeric format
I'm not sure what you're asking for, I am a total beginner to masm.
what we would like to see is an example file from MATLAB
you can attach ZIP files to your post by clicking on the "Attachments and other options" link under the reply window
we need to see exactly how the values are stored in the file
This is what the instructor sent us:
E.g. If the matrix is M = [
1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0]
Then input file will contain: 3,3,1.0,4.0,7.0,2.0,5.0,8.0,3.0,6.0,9.0
Note that the first 2 values are R and C, and the remaining values are the elements organized by columns. The values in hex will be:
03,03,3FF0000000000000,4010000000000000,401C000000000000,4000000000000000,4014000000000000,4020000000000000,4008000000000000,4018000000000000,4022000000000000
Matlab commands:
M = [1 2 3; 4 5 6; 7 8 9]; %creates a 3x3 matrix
[r c] = size(M); %find size of M
mvec = reshape(M,1,r*c); %converts matrix into a vector of columns
fid = fopen('inputfile','w') %opens a file to store mvec into
fwrite(fid,[r c],'uint8') %store the row and column a byte values
fwrite(fid,mvec, 'double') %Store as double precision values
fclose(fid) %close file
We are to use the above MATLAB commands to create a matrix with random elements, then reduce it through masm. I know it isn't a database, but I do not have MATLAB on my personal computer at home.
that is probably enough info for us to work with :t
assuming the values are stored in binary :P
the row and column values are "unsigned byte integers"
the matrix values are "real8 floating point" format, also known as double precision
we can align the data by aligning to 4 or 8, then padding the buffer with 2 or 6 bytes to align the reals
i.e., read data to buffer+2 or buffer+6
i haven't done much of this type stuff, but it doesn't look too difficult
http://en.wikipedia.org/wiki/Gauss%E2%80%93Jordan_elimination (http://en.wikipedia.org/wiki/Gauss%E2%80%93Jordan_elimination)
QuoteThere are three types of elementary row operations: 1) Swapping two rows, 2) Multiplying a row by a
non-zero number, 3) Adding a multiple of one row to another row. Using these operations a matrix can
always be transformed into an upper triangular matrix, and in fact one that is in row echelon form.
Hi,
Since the matrix elements are floating point numbers, you
will need to use the FPU or SSE instructions. And your
instructor should have routines to print the numbers out.
Cheers,
Steve N.
Steve,
the assignment is merely to re-order the matrix
they are using MATLAB to generate the original matrix - and to display the results
Hi Dave,
He's going to do the stuff in Reply #9 without adding, subtracting,
and comparing floats?
Cheers,
Steve N.
no - but he doesn't have to convert them to decimal :P
the hard part will be the compares
QuoteAnd your instructor should have routines to print the numbers out.
MATLAB
Worked on the code a bit this morning so here's another look:
.MODEL SMALL ;Defines memory model as small which uses seperate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
row DB ?
col DB ?
e DW ?
ep1 DW ?
D DB ?
d DW ?
ROW DB ?
COLUMN DB ?
M DW 65025 DUP(?)
RREF DB "matrix", 0
.CODE
MAIN PROC FAR
.STARTUP
;Program:
MOV BP, 0
MOV SI, 0
MOV AX, 3D02h ;Open file
MOV DX, OFFSET RREF
INT 21H
MOV BX, AX
MOV CX,1 ;Read two bytes.
MOV DX, OFFSET ROW
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 1
JNE QUIT
MOV CX,8 ;Read eight bytes.
MOV DX, OFFSET M
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 8
JNE QUIT
IF (ROW LT COLUMN)
MOV D, ROW
ELSEIF (ROW GT COLUMN)
MOV D, COLUMN
ENDIF
MOV row, D
MOV col, D
MOV AX, d
MOV BX, 8
MUL BX
ADD AX, 2 ;M[d] = d*8+2
MOV EAX, 0
;d=(col-1)*ROW+(row-1)
MOV AL, col ;Determine number of diagonals
SUB AL, 1
MOV BL, row
MOV DL, BL
SUB BL, 1
MUL DL
ADD AX, BL
MOV d, AX
;e=M(I,I)
;ep1=M(I+1,I)
MOV SI, LENGTHOF M
MOV EAX, M[SI]
MOV EBX, M[SI+1] ;Now I'm Stuck
QUIT: .EXIT
MAIN ENDP
END
I created an array with a length of 65025 dup (?) to account for a max value of 255x255. The code is in no particular order but I'm following the algorithm the instructor gave us from a few posts up. Am I completely lost or am I least on the right track? I know it has a lot left to be a working code but I'm struggling with the language and how to put the algorithm into code.
I haven't made any progress since my last post and the code has to be working by tomorrow evening. We are beginning to feel like it won't get done on time since we are having so much trouble with the language itself.
you seem to understand the concept of what the program needs to do
what you don't understand is the FPU code
i suggest you read Ray's FPU tutorial
http://www.ray.masmcode.com/fpu.html (http://www.ray.masmcode.com/fpu.html)
you don't need to use all the FPU instructions - so you won't need to understand the entire tutorial
but, you do need to understand how to use the FPU registers (aka stack)
you need to know how to get numbers into and out of the FPU
you need to know how to add, subtract, multiply, and compare
so, chapters 1-4 and 7-8 should get you going
Given that you have little time, study in the attachment:
fld
fst
fadd, fsub, fmul, fdiv (whatever you need)
On the net, read about fcomi (http://www.website.masmforum.com/tutorials/fptute/fpuchap7.htm#fcomi) (compare)
Dave's advice is valid, too, of course - maybe you can split the work. What I attach is the barebones of FPU work, what Dave suggests is more thorough.
Good luck :icon14:
Hi,
MOV CX,1 ;Read two bytes.
Your comment says to read two bytes. You are only reading one.
Either make another read section to read in one byte into the column
variable. Or actually read two bytes to fill both row and columns.
This affects all further reads from the file and they will all be off one
byte. And thus a bit wrong.
Steve
FORTRANS, that was an error on my partner's part, it should have the number 2.
Thanks everyone for the help with FPU. I'm reviewing it now and should hopefully have some more code in the thread in a little while.
the FPU registers will hold 8 values, and are typically addressed as a last-in-first-out stack
the stack top is refered to as ST(0), or just ST
the others are refered to as ST(1) to ST(7)
some operations allow you to perform an arithmetic function and "pop" the stack into memory, in a single instruction (FADDP for example)
if all the registers are full, and you try to load a new value, an exception will occur
not only will the results of the next operation be incorrect, but the code will execute very slowly
this is one thing that catches many beginners :P
half the trick of writing FPU code is to keep track of what is where in the register stack
i like to think of the register stack as an 8-shot revolver cylinder
(http://img35.imageshack.us/img35/2574/fpuregs.jpg)
a few instructions are intended for managing the stack
FFREE marks a register as empty, so that it may be loaded with a new value
notice that you can FFREE ST(7) to make room for a new value in ST(0)
the old ST(0) value becomes ST(1), the old ST(1) value becomes ST(2), and so on
FDECSTP and FINCSTP allow you to rotate the "cylinder" to select which value will be on the stack top
very handy
FFREE, FDECSTP, and FINCSTP are discussed in chapter 3 of Ray's tutorial
Here's some more code. No real progress:
.MODEL SMALL ;Defines memory model as small which uses seperate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
row DB ?
col DB ?
e DW ?
ep1 DW ?
D DB ?
d DW ?
ROW DB ?
COLUMN DB ?
M DW 65025 DUP(?)
RREF DB "matrix", 0
.CODE
MAIN PROC FAR
.STARTUP
;Program:
MOV BP, 0
MOV SI, 0
MOV AX, 3D02h ;Open file
MOV DX, OFFSET RREF
INT 21H
MOV BX, AX
MOV CX,2 ;Want to read two bytes.
MOV DX, OFFSET ROW
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 2
JNE QUIT
MOV CX,8 ;Want to read eight bytes.
MOV DX, OFFSET M
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 8
JNE QUIT
IF (ROW LT COLUMN)
MOV D, ROW
ELSEIF (ROW GT COLUMN)
MOV D, COLUMN
ENDIF
MOV row, D
MOV col, D
;MOV AX, d
;MOV BX, 8
;MUL BX
;ADD AX, 2 ;M[d] = d*8+2
MOV EAX, 0
MOV SI, D ;d=(col-1)*ROW+(row-1)
L1: MOV AL, col ;Determine number of diagonals
SUB AL, 1
MOV BL, row
MOV DL, BL
SUB BL, 1
MUL DL
ADD AX, BL
MOV d, AX
;e=M(I,I)
;ep1=M(I+1,I)
MOV EAX, M[d*8+2]
MOV e, EAX
MOV AL, col
SUB AL, 1
MOV BL, row
ADD BL, 1
MOV DL, BL
SUB BL, 1
MUL DL
ADD AX, BL
MOV d, AX
MOV EBX, M[d*8+2]
MOV ep1, EBX
ADD row, 1
MOV col, 1
FINIT
FLD1
FLD1
FADD ST(1), ST(1)
CMP ST(1), ep1
JE SKIP
L2: FADD ST(1), ST
CMP ST(1), ep1
JNE L2
SKIP: FCHS
FDIVR
QUIT: .EXIT
MAIN ENDP
END
Hi,
To compare registers in the FPU to something, use FCMP rather
than CMP, which is for the CPU registers or memory.
CMP ST(1), ep1
test43.asm(108) : error A2152: coprocessor register cannot be first operand
You also have some symbols defined more than once. Make a
listing to check for errors.
ROW DB ?
test43.asm(12) : error A2005: symbol redefinition : row
HTH,
Steve N.
Quote from: FORTRANS on April 22, 2013, 11:16:33 PM
To compare registers in the FPU to something, use FCMP rather
than CMP, which is for the CPU registers or memory.
Quote from: jj2007 on April 22, 2013, 06:02:25 AM
On the net, read about fcomi (http://www.website.masmforum.com/tutorials/fptute/fpuchap7.htm#fcomi) (compare)
AFAIK there is no FCMP (there is a MasmBasic Fcmp (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1201), though). FCOM works but it is difficult to handle, as it does not set the EFLAGS as we are expect them. Therefore FCOMI seems the easiest solution - if it works in 16-bit code and on the group's CPU, of course.
Hi,
Yes, I meant FCOM, or FCOMP, but was looking at CMP.
Or FCOMI of course, though I rarely remember that one,
though it should work.
Thanks,
Steve N.
New code:
.MODEL SMALL ;Defines memory model as small which uses seperate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
A DD ?
B DD ?
S DD ?
row DB ?
col DB ?
e DD ?
ep1 DD ?
M DD LENGTHOF row*LENGTHOF col DUP(?)
RREF DB "matrix", 0
;-------------------------------------------------------------------------------
calcoffset MACRO row, col
PUSH EDI, ESI
MOV ESI, row
MOV EDI, col
DEC EDI
MUL EDI
ADD EAX, ESI
DEC EAX ;M[EAX]
POP EDI, ESI
ENDM
;-------------------------------------------------------------------------------
.CODE
MAIN PROC FAR
.STARTUP
;Program:
MOV BP, 0
MOV SI, 0
MOV AX, 3D02h ;Open file
MOV DX, OFFSET RREF
INT 21H
MOV BX, AX
MOV CX,2 ;Want to read two bytes.
MOV DX, OFFSET ROW
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX,2
JNE QUIT
MOV CX,8 ;Want to read eight bytes.
MOV DX, OFFSET M
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 8
JNE QUIT
MOV ESI, 1
MOV EDI, 1
MOVZX EAX, row
MOV ECX, ESI
MOV EBP, 1
DEC ECX
L1: calcoffset EBP, EBP
MOV EDX, M[EAX]
MOV e, EDX
INC ESI
MOV ESI, EBP
MOV EDI, EBP
calcoffset ESI, EBP
MOV EDX, M[EAX]
MOV ep1, EDX
;calc scale to fpu
FINIT
FLD e
FLD ep1
FDIV
FST S
L2: calcoffset ESI, EDI
MOV EDX, M[EAX]
MOV A, EDX
;fpu to calc A*scale+e
FINIT
FLD A
FLD S
FMUL
FLD e
FADD
FST B
INC EDI
MOVZX EDX, col
CMP EDI, EDX
JBE L2
INC ESI
MOVZX EDX, row
CMP ESI, EDX
JBE L2
LOOP L1
MOV AH,40h
INT 21H
MOV AH, 3Eh
INT 21H
QUIT: .EXIT
MAIN ENDP
END
Getting syntax errors when attempting to call our macro calcoffset, it's claiming the apostrophe between our register values in the program itself is an issue. What could be causing this?
i don't see a syntax error
maybe you could give us the exact error text
we are pretty familiar with what problems cause what errors
i do see something that is going to give you trouble
the "M" array is going to be 1*1 bytes
i think you want it to be 255*255*8 bytes :P
as a suggestion, use more descriptive names for variables - single-letter names make it hard to follow
as a hint, do not call the macro in a line that contains a label. The reason is that MASM expand macros before the current line thus the label will be placed after the macro code.
Your code:
L2: calcoffset ESI, EDI
and that's how MASM handle it:
calcoffset ESI, EDI
L2:
Corrected the syntax errors so I'm all good there. Literally putting 255*255*8 (520200) for the M value returns:
Assembling: final.asm
final.asm(137) : error A2103: segment exceeds 64K limit : _DATA
Press any key to continue . . .
oh yah - i forgot - lol
you are writing 16-bit code - doh !
also - it didn't dawn on me that that is almost 512 K - could be a tight fit
you will have to do a little memory management
i think, for an EXE, you have to release memory above the program address
then, you can allocate it with INT 21h
actually, i think you own the memory already, but you cannot allocate until you release
it may help to add .DOSSEG at the beginning of the program
that will make the stack segment the highest used address
and, you can use SS:StackSize to calculate the release address
We haven't been taught .DOSSEG or SS:Stacksize so if we had it in our project, he'd start asking questions lol
at the beginning of your program you have a .STACK directive
just use
.STACK 4096
or how ever many bytes you want
thing is - you will know the stack size
i could look up the default, but i am too lazy - lol
at any rate, you can use SS:[4096] as a release address for memory
mov ax,ss
add ax,4096/16
;AX = release segment address
another directive is .DOSSEG
.DOSSEG
all it does is ensure the use of DOS segment ordering - no biggy, there
If you are using a small memory model and the startup directive, then you can calculate the actual memory footprint, in paragraphs, as:
PSP_Segment - (SS + (Initial_SP SHR 4) + 1
To understand the above calculation you probably need to know that the startup directive combines the stack and near data segments into a single segment known as DGROUP and places it at the end of the program (where "end" means at the highest address), sets DS and SS to the segment address of DGROUP, and sets SP to the end of the stack (where, again, "end" means at the highest address), and that a paragraph is 16 bytes.
Once you have the size in paragraphs, you pass it to the Set Memory Block Size function (Interrupt 21h Function 4Ah) in BX, along with the segment address of the memory block to resize, which in this case will be the segment address of the PSP, in ES. You can get the segment address of the PSP by any of several methods, but since the program loader will have initialized ES to the segment address of the PSP, you can just pass ES as is.
Quote from: dedndave on April 23, 2013, 10:36:01 AM
you will have to do a little memory management
i think, for an EXE, you have to release memory above the program address
then, you can allocate it with INT 21h
actually, i think you own the memory already, but you cannot allocate until you release
Hi,
There is no need to release memory just to allocate again. It
is allocated to you at program start-up by default. Just use it.
Find/put a symbol at the end of your code, and verify it is at the
end with a listing of the load map. At run time you check the
current address in memory of that symbol and compare it with
the next paragraph value in the PSP (it is the second word).
Those then tell you how much memory is available for you to use.
You can address much more than 64k that way. It seems a bit
out of order though for a beginner to play with. Perhaps Fn 42H,
Move File Pointer (also known as LSEEK) would be easier? That
gives the user random access into the file.
I think if he can get it to work with an 8 x 8 (10?) matrix, then
he can claim it would work for a larger matrix later.
Regards,
Steve N.
The instructor told us if we put our matrix into memory, it would limit the matrix size but he did not say we would be penalized for it. He also gave the class an extension until Thursday afternoon to get the code running. Only thing left for me to get working is the command tail and then I need to start checking that everything is working:
.MODEL SMALL ;Defines memory model as small which uses seperate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
mrc DD ?
scale DD ?
D DD ?
row DB ?
col DB ?
e DD ?
ep1 DD ?
M DD 10000 DUP(?)
INPUT DB "input", 0
OUTPUT DB "output", 0
;-------------------------------------------------------------------------------------
;calcoffset takes two input variables and calculates the equation: (op2-1)*op1+(op1-1)
;The value is returned into M[EAX]
;-------------------------------------------------------------------------------------
calcoffset MACRO op1, op2
PUSH ESI
PUSH EDI
MOV ESI, op1
MOV EDI, op2
DEC EDI
MUL EDI
ADD EAX, ESI
DEC EAX ;M[EAX]
POP EDI
POP ESI
ENDM
;------------------------------------------------------------------------------------
.CODE
MAIN PROC FAR
.STARTUP
;Program:
PUSHAD
MOV EAX, 0h
MOV AH, 62h
INT 21H
MOV ES, BX
MOV SI, 81h
CMP BYTE PTR ES: [SI-1], 1
JBE NO_TAIL
NO_TAIL: MOV DL, 0Ah
INT 21H
MOV DL, 0Dh
INT 21H
MOV BP, 0
MOV SI, 0
MOV AX, 3D02h ;Open file
MOV DX, OFFSET INPUT
INT 21H
MOV BX, AX
MOV CX,2 ;Want to read two bytes.
MOV DX, OFFSET D
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX,2
JNE QUIT
MOV CX,8 ;Want to read eight bytes.
MOV DX, OFFSET M
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 8
JNE QUIT
MOV ESI, 1
MOV EDI, 1
MOVZX EAX, row
MOV ECX, ESI
MOV EBP, 1
DEC ECX
L1:
calcoffset EBP, EBP
MOV EDX, M[EAX]
MOV e, EDX
INC ESI
MOV ESI, EBP
MOV EDI, EBP
calcoffset ESI, EBP
MOV EDX, M[EAX]
MOV ep1, EDX
;calc scale to fpu
FINIT
FLD e
FLD ep1
FDIV
FST scale
JMP L2
RETURN: JMP L1
L2:
calcoffset ESI, EDI
MOV EDX, M[EAX]
MOV mrc, EDX
;fpu to calc mrc*scale+e
FINIT
FLD mrc
FLD scale
FMUL
FCHS
FLD e
FADD
FST mrc
INC EDI
MOVZX EDX, col
CMP EDI, EDX
JBE L2
INC ESI
MOVZX EDX, row
CMP ESI, EDX
JBE L2
JMP RETURN
MOV AX, 3D02h
MOV DX, OFFSET OUTPUT
INT 21H
MOV BX, AX
MOV CX, LENGTHOF M
MOV DX, LENGTHOF M
MOV AH, 40h
INT 21H
MOV AH, 3Eh
INT 21H
QUIT: .EXIT
MAIN ENDP
END
in the END directive, you should reference the entry point
END MAIN
i am not sure what the .STARTUP directive does - never used it
i suppose it loads the DS register with the _DATA segment
so, it probably generates code that looks like this
mov ax,@data
mov ds,ax
however, when a 16-bit EXE loads, the DS and ES registers contain the PSP (Program Segment Prefix) Segment
it may be a good idea to store this segment value for later reference
mov PspSeg,es ;PspSeg is a word variable
the PSP is a 256-byte segment of information specific to the program execution
it holds things like a pointer to the environment table, parsed filenames, and so on
the last 128 bytes of the PSP hold the command line tail
at PSP:80h, there is a byte value telling you the length of the command line tail string
at PSP:81h is the actual command line tail - it is typically terminated with a carriage return
The safe, simple way for a beginner to get a maximum-size memory buffer is to release the excess memory as above and then allocate a maximum-size block with the Allocate Memory function (Interrupt 21h Function 48h). With the way Microsoft designed the function you call it twice, passing a size larger than the largest possible, -1 is handy, in BX on the first call, and then use the size of the largest available block, returned in BX, in the next call. No need to understand memory control blocks, load maps, etc. Running under the Windows XP NTVDM with a default configuration and a relatively small test app I can allocate 629600 bytes.
And it's possible to use a linear index to access the buffer in whatever element size you need, translating the index to a segment-offset address for each access. Reloading a segment register for each access will slow the code down, but it's simple and easy to do and I would guess that the access would still be much faster than random access to a disk file.
Memory is not an issue for our project, according to the instructor, I just need to make sure I get a working command tail so I can start testing.
I think most applications ignore the command tail length in the byte at 80h and just scan for the trailing CR. The attachment contains a demo that manipulates the command tail and does a dump of the entire PSP. Since most DOS functions that take null-terminated string arguments expect the strings to be in the default data segment, the demo copies the command tail from the PSP to the default data segment.
you're probably right, Michael
although, i remember writing some parsing loops that used the count
i also used LODSB and LOOP, so don't let Hutch see this post - lol
;DS = PSP segment
mov si,80h ;PSPTailLen
lodsb ;SI now points to the tail
cbw
xchg ax,cx
loop00: lodsb
;
;parsing code
;
loop loop00
Hi Dave,
In my code I have a check for a command tail. The ES segment
register points to the PSP on program load. And the carriage
return that terminates the command line is not part of the count.
MOV BL,ES:[80H] ; Length of cmd tail
XOR BH,BH ; Length byte -> word
XOR CX,CX ; Zero tail length
CMP BL,1 ; must be non-zero
JB FN2_3
Just a quick and easy sanity check.
Hi Michael,
If you want to allocate memory, you can skip the deallocation
steps if you use a linker option to limit the memory allocated to
the program when it is loaded. Oh, that seems very version
dependent. Just checked to see the spelling, and some versions
don't support it. Anyway, if supported, the /CPARMAXALLOC or /CP:
option will limit the memory allocated to a program. /CP:1 will
let the linker limit the program's memory to only what it needs
to load properly. Then you can allocate memory as you mentioned.
Just a short cut.
Regards,
Steve N.
This is my final code before we have to test it today and show our instructor that it works. I don't have matlab on my laptop so I'm going to post it up here for anyone to look at if they want. Just want to know if there are any errors I haven't corrected before we get into the lab today. Thanks again for all your help everyone.
.MODEL SMALL ;Defines memory model as small which uses separate segments for code and data
.386 ;Microprocessor number
.STACK ;Stack segment defined as 1024 by default
.DATA ;Begins definition of the data type used in this project
mrc DD ?
scale DD ?
D DD ?
row DB ?
col DB ?
e DD ?
ep1 DD ?
M DD 10000 DUP(?)
INPUT DB "input", 0
OUTPUT DB "output", 0
IHANDLE DW ?
OHANDLE DW ?
;-------------------------------------------------------------------------------------
;calcoffset takes two input variables and calculates the equation: (op2-1)*op1+(op1-1)
;The value is returned into M[EAX]
;-------------------------------------------------------------------------------------
calcoffset MACRO op1, op2
PUSH ESI
PUSH EDI
MOV ESI, op1
MOV EDI, op2
DEC EDI
MUL EDI
ADD EAX, ESI
DEC EAX ;M[EAX]
POP EDI
POP ESI
ENDM
;------------------------------------------------------------------------------------
.CODE
MAIN PROC FAR
.STARTUP
;Program:
PUSHAD
MOV EAX, 0h
MOV AH, 62h
INT 21H
MOV ES, BX
MOV SI, 81h
CMP BYTE PTR ES: [SI-1], 1
JBE NO_TAIL
MOVZX ECX, BYTE PTR ES:[SI-1]
L0: MOV DL, ES:[SI]
INT 21H
INC SI
LOOP L0
NO_TAIL: MOV DL, 0Ah
INT 21H
MOV DL, 0Dh
INT 21H
MOV BP, 0
MOV SI, 0
MOV AX, 3D00h ;Open input file
MOV DX, OFFSET INPUT
INT 21H
MOV IHANDLE, AX
MOV AX, 3D01h ;Open output file
MOV DX, OFFSET OUTPUT
INT 21H
MOV OHANDLE, AX
MOV BX, IHANDLE
MOV CX,2 ;Want to read two bytes.
MOV DX, OFFSET D
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX,2
MOV CX,8 ;Want to read eight bytes.
MOV DX, OFFSET M
MOV AH, 3FH ;Read
INT 21H
JC QUIT
CMP AX, 8
JNE QUIT
MOV ESI, 1
MOV EDI, 1
MOVZX EAX, row
MOV ECX, ESI
MOV EBP, 1
DEC ECX
L1:
calcoffset EBP, EBP
MOV EDX, M[EAX]
MOV e, EDX
INC ESI
MOV ESI, EBP
MOV EDI, EBP
calcoffset ESI, EBP
MOV EDX, M[EAX]
MOV ep1, EDX
;calc scale to fpu
FINIT
FLD e
FLD ep1
FDIV
FST scale
JMP L2
RETURN: JMP L1
L2:
calcoffset ESI, EDI
MOV EDX, M[EAX]
MOV mrc, EDX
;fpu to calc mrc*scale+e
FINIT
FLD mrc
FLD scale
FMUL
FCHS
FLD e
FADD
FST mrc
INC EDI
MOVZX EDX, col
CMP EDI, EDX
JBE L2
INC ESI
MOVZX EDX, row
CMP ESI, EDX
JBE L2
JMP RETURN
MOV AH, 40h
MOV BX, OHANDLE
MOV CX, LENGTHOF M
MOV DX, OFFSET OUTPUT
INT 21H
MOV AH, 3Eh
MOV BX, IHANDLE
INT 21H
MOV BX, OHANDLE
INT 21H
QUIT: .EXIT
MAIN ENDP
END
right - as i said before, the DS and ES registers point to the PSP at start-up
so, before i set the DS register, i would set the ES register to the local data segment
DS is still pointing to the PSP
so LODSB gets a byte from the command line tail and STOSB stores it in the data segment "parsed buffer"
Brett...
at the end of the program source....
END MAIN
the END directive should reference the entry point
I always miss little obvious things when it comes to code, thanks :t