News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Reduced Row-Echelon Form of a Matrix Help

Started by brettc431, April 18, 2013, 12:35:02 AM

Previous topic - Next topic

FORTRANS

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.

brettc431

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?

dedndave

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

qWord

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:
MREAL macros - when you need floating point arithmetic while assembling!

brettc431

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 . . .

dedndave

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

brettc431

We haven't been taught .DOSSEG or SS:Stacksize so if we had it in our project, he'd start asking questions lol

dedndave

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

MichaelW

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.

Well Microsoft, here's another nice mess you've gotten us into.

FORTRANS

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.

brettc431

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

dedndave

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

MichaelW

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.
Well Microsoft, here's another nice mess you've gotten us into.

brettc431

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.

MichaelW

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.
Well Microsoft, here's another nice mess you've gotten us into.