News:

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

Main Menu

[First timer]Window will not show up

Started by carre89, November 21, 2012, 07:33:52 AM

Previous topic - Next topic

carre89

 :shock:.....
Alrite I'll see you guys tomorrow.... I'll clean up the code up a bit tomorrow..

qWord

#31
- function prototypes are declared using PROTO:
function name [C|STDCALL|...] [PUBLIC|PRIVATE] [arg1]:TYPE,[arg2]:TYPE,...
(note that all prototypes/procs are public by default)

- If you want to split a declaration in several lines, use '\':
foo proto \ ; comment 1
arg1:type \ ; comment 2
arg2:type ; xyz


- a procedure/function body is declared with:
fncName PROC [C|SDTCALL|...] [PUBLIC|PRIVAT]] [uses reg-list] arg1:type,arg2:type,...
; code
fncName ENDP


- your code use a structure before it is declared
- Your header structure is no proper for a modular program.(?)
- use DWORD instead of all that bytes parameters and variables
- do not use structures as function argument**
- do not use LOOP
- you can't use 16 bit registers as pointers
- use a IDE that is designed for MASM
- You should stay away from this project until you have learned the basics...

MREAL macros - when you need floating point arithmetic while assembling!

dedndave

i spent a little time on it, today - got the hard part done   :P

carre89

So I imported your code into visual studio and I am getting a linking error;

"error LNK2019: unresolved external symbol _generateMineField@12 referenced in function _WinMain@0"

Edit - nevermind, I think I figured it out.


qWord

Well, I was not sure if you want a modular program (that how your org. code look like) or a "all in one file by includes"-project.
You can either configure VS thus minefield.asm get assembled as a module, or modify the file so that it can be included in main.asm.
MREAL macros - when you need floating point arithmetic while assembling!

carre89

I am reading up on it right now. I want to have the minefield procedures in one source file and the painting and main in the other. I think I am prototyping incorrectting. How would you organize the program?

carre89

I am looking at your code and I am trying to figure out what is happening. Could someone step through the code and explain what is happening? I made comments next to the instructions that I am confused about.

;-----------------------------------------------------
; do not use BYTE for arguments (MASM bug)
generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL dwSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)             

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM         ; What is m2m instruction?

mov edx,NOC
imul edx,NOR
lea edx,[edx*2]                                                        ; As I understand this calculates the row size in bytes. Since each cell is a DWORD, wouldn't you multiply it by 4?
mov dwSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)                ; Not sure what is happening here.

; fill array with "random" data
mov edi,eax
fn RandomBytes,dwSize,edi                                    ; Do we need to do this? Can we set each cell to zero first?
xor ecx,ecx                                                               ; I see you are doing this several times through the program. Why do you need to do this? If you xor the reg with itself ;   
                                                                                         ; isn't the answer the same?
.while ecx < dwSize
.if WORD ptr [edi+ecx] < 0ffffh/3                      ; where did you move the field pointer to the esi?
mov BYTE ptr [edi+ecx+1],CLOSED
.elseif WORD ptr [edi+ecx] < 0ffffh*2/3
mov BYTE ptr [edi+ecx+1],OPENED
.else
mov BYTE ptr [edi+ecx+1],FLAGGED
.endif
add ecx,2                                                  ; Why are adding 2? I thought each cell is 4 bytes in size.
.endw

m2m [esi].MineFieldStruct.RowSize, NOC

Invoke calcArea,[esi].MineFieldStruct


COMMENT !
;don't care about this yet <- bullshit

Invoke setUpMines,
ADDR mf
!

mov eax,esi

ret
generateMineField endp


EDIT: -----------------------------------

I revised the generateMineField proc to the best of my ability but now it's crashing the program.

generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL rowSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM

mov edx,NOC
imul edx,NOR
lea edx,[edx*4] ; NOC*4 - Calculates rowsize in bytes
mov rowSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)

xor ecx,ecx
.while ecx < rowSize
mov BYTE ptr [edi+ecx+1],CLOSED
add ecx,4
.endw

Invoke calcArea,[esi].MineFieldStruct

mov eax,esi

ret
generateMineField endp

dedndave

m2m is a macro - not an instruction
it is a "memory-to-memory" move
for intel processors, there is no instruction for doing this in a single opcode
there are a few obscure ways to copy the contents of memory from one location to another in a single instruction
MOVS is an example, but it requires that ESI and EDI are pointers to these addresses
i believe the macro PUSH's the source content on the stack, then POP's it into the destination

mov edx,NOC
imul edx,NOR
lea edx,[edx*2]  ; As I understand this calculates the row size in bytes. Since each cell is a DWORD, wouldn't you multiply it by 4?

this code calculates the total number of squares or cells (rows times columns)
i didn't think you could use IMUL with a memory operand - don't know where i got that idea - lol

mov [esi].MineFieldStruct.Field, alloc(edx)   ; Not sure what is happening here.
the first instruction of the routine sets ESI to the base address of an allocated memory (alloc) block
(alloc is another macro used to allocate memory)
this is a structure that is defined previously in the source
mov esi,alloc(SIZEOF MineFieldStruct)
don't know whose code this is, but i probably wouldn't have used allocated memory for the structure - lol
anyways, if you look at the MineFieldStruct definition, one of the members is named "Field"
so - a second allocated block (used for the grid or field array) is pointed to by this value

working on the other questions in following posts...

qWord

Quote from: dedndave on November 30, 2012, 06:41:18 AMi didn't think you could use IMUL with a memory operand
Yes, we can!  :P
Quote from: dedndave on November 30, 2012, 06:41:18 AM
mov esi,alloc(SIZEOF MineFieldStruct)
don't know whose code this is, but i probably wouldn't have used allocated memory for the structure - lol
thats my quick modification of his clumsy HLL to ASM port. The reason for this was that he tries to pass all structures and arrays by value in and out of functions. I was simply too lazy to correct that in this case...

MREAL macros - when you need floating point arithmetic while assembling!

dedndave

ok - looking at both code snippets, i am a bit confused - lol

i hesitate to critique code written by qWord, because i know he usually writes great stuff   :biggrin:

first, i would not use allocated memory to hold the structure
it is a small amount of memory - more efficient to put it in the uninitialized data section

the same holds true for the grid array, actually
you can only get so many squares on the screen
because the squares are 32x32 pixels, i would think 8 Kb would be plenty for any grid (1 byte per cell)
this prevents allocating, freeing, and reallocating memory over and over
even if you use 1 dword per cell, 32 Kb isn't too much for uninitialized data

if you don't want to put it in uninitialized data, allocate it once at the beginning of the program
and free it once at the end - make it big enough to handle all practical array sizes

as for the random thing...
when a block of memory is allocated using the "alloc" macro, it is zeroed for you
      alloc MACRO bytecount
        invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,bytecount
        EXITM <eax>
      ENDM


if you use the uninitialized data area, you will want to zero it before each use
after that, you want to randomly fill it with mines
so - you generate a random offset into the array
if that cell isn't already a mine, make it a mine
if it is already a mine - go back and get another random index
repeat that until the requested number of mines are assigned to cells

qWord

BTW: I assumed that a cell is represented by 16 bits.
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

i am writing a program for this
i am using a single byte for each square   :P

carre89

So right now I am focusing on getting generateMineField PROC and setUpMines PROC working correctly. Here's what I have right now.


;-----------------------------------------------------
; do not use BYTE for arguments (MASM bug)
generateMineField PROC uses esi edi\
NOC:DWORD, \ ; number of columns in grid - has to be less than 255
NOR:DWORD, \ ; number of rows in grid - has to be less than 255
NOM:DWORD ; number of mines

;
; Generates a minefield
; Returns: EAX = address of MineField Struct
;-----------------------------------------------------
LOCAL pmf:ptr MineFieldStruct
LOCAL gridSize:DWORD

mov esi,alloc(SIZEOF MineFieldStruct)

m2m [esi].MineFieldStruct.FieldWidth, NOC
m2m [esi].MineFieldStruct.FieldHeight, NOR
m2m [esi].MineFieldStruct.NumOfMines, NOM

mov edx,NOC
imul edx,NOR
mov [esi].MineFieldStruct.FieldArea, edx ; set FieldArea to the number of cells
lea edx,[edx*4] ; Calculates gridSize in BYTES
mov gridSize,edx
mov [esi].MineFieldStruct.Field, alloc(edx)

xor ecx,ecx
; set each cell opened so I can see what is generated
.while ecx < gridSize
mov BYTE ptr [edi+ecx+2],OPENED
add ecx,4
.endw
INVOKE setUpMines esi ; Go through the grid and put in the mines at random positions

;let's focus on the setUpMines proc
;INVOKE incAdj esi ; set the numbers in each cell

mov eax,esi

ret
generateMineField endp

;-----------------------------------------------------
setUpMines PROC mf:MineFieldStruct
;
; Generates a blank minefield - every cell is zero
; Returns: Nothing
; Checks: number of mines less than number of cells and is not zero. Also needs to check if minefield has been generated
;-----------------------------------------------------
pushad ; push all registers to the stack

mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
mov esi, 0

mov si, MINE
mov cl, mf.NumOfMines
mov eax, offset mf.Field
mov ebx, TYPE mf.Field

call randomize
mineLoop:
mov edx, offset mf.Field
mov eax, mf.FieldArea
call RandomRange ; Random range generates a number from 0 to the number in the eax.[exclusive - so not
mul ebx ; multiply by cell size
add edx, eax
.IF dl == MINE
jmp mineLoop
.ELSE
mov dl, MINE
.ENDIF
loop mineLoop

popad
ret
setUpMines endp


I also attached my project if anyone wants to take a look at it. As you probably see I am getting alot of errors right now because i redid the incAdj and getcell procedures. I am going to try to fix as many errors as I can figure out and then up upload the project.

carre89


carre89

Now I have two syntax errors left
1>main.asm(534): error A2070: invalid instruction operands
@ .if x<0 || mf.FieldWidth <= x || y<0 || mf.FieldHeight <= y

getCell PROC uses esi \
mf:MineFieldStruct, \
x:DWORD, \ ; row index
y:DWORD \ ; column index
;
; returns the cell's value at x-y point specified
; if specified row and column are out of range it returns OUTBOUNDS
; Returns: EAX = cell address
;-----------------------------------------------------

; check if it's in the minefield bounds
.if x<0 || mf.FieldWidth <= x || y<0 || mf.FieldHeight <= y
mov eax, OFFBOUNDS
.else
mov eax, x
mov esi, y
mov ebx, mf.RowSize
mul ebx
add eax, mf.Field
.endif

ret
getCell endp



1>main.asm(470): error A2133: register value overwritten by INVOKE
@ invoke IncSp, mf, eax, tempX, tempY
;-----------------------------------------------------
incAdj PROC, mf:MineFieldStruct
;
;Goes through whole grid and calls IncSp for any cell that is not a mine
;-----------------------------------------------------
LOCAL tempX:BYTE ; used to keep track of current position in grid
LOCAL tempY:BYTE

mov tempX, 0
mov tempY, 0

mov ecx, 0
mov eax, 0
mov esi, mf.Field
mov ecx, mf.FieldHeight
loopY: ;go to each row
push ecx
mov ecx, mf.FieldWidth
loopX: ;go to each column in each row
mov eax, 0
mov eax,[esi]
.if al != MINE ;if the current grid spot is not a bomb
[b]invoke IncSp, mf, eax, tempX, tempY[/b]
.endif
inc tempX
add esi, 4 ;mov to next spot in grid
loop loopX
mov tempX, 0 ;reset to beginning of the col
inc tempY ;go to next col

pop ecx
loop loopY

ret
incAdj ENDP