How to preserve an array or string in x86 - arrays
I'm programming the game "15 puzzle game" in x86 using tasm asm/dosbox. I want to "save" or "preserve" my array called 'a' that is being declared in my data segment, so that after I swap the bytes around using upArrow, downArrow, etc... and then I press 'n' for new game, I can set my array 'a' back to it's original state as it was declared in my data segment. Here is my code:
.MODEL TINY
.386
.DATA
PROMPT DB "Enter q to quit, arrow keys to move, n to restart (new game) HAPPY HOLIDAYS!! :)$"
;this is board preset A
a DB 201,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,187,
DB 186,255,48,50,255,186,255,48,49,255,186,255,48,51,255,186,255,48,52,255,186,255,48,53,255,186,255,48,54,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,48,55,255,186,255,48,56,255,186,255,48,57,255,186,255,49,48,255,186,255,49,49,255,186,255,49,50,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,49,51,255,186,255,49,52,255,186,255,49,53,255,186,255,49,54,255,186,255,49,55,255,186,255,255,255,255,186,
DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185,
DB 186,255,49,56,255,186,255,49,57,255,186,255,50,48,255,186,255,50,49,255,186,255,50,50,255,186,255,50,51,255,186,
DB 200,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,188,"$"
col DB 0
row DB 0
board DB 0
.CODE
org 100h
MAIN PROC
;initialize display step 0
MOV AH, 00h
MOV AL, 03h
INT 10h
MOV AX, 0B800h
MOV ES, AX
XOR di,di
;initialize configuration and dislay prompt step 1
newGame:
call initConfig
;display board step 2
;wait for key step 3
game:
;print board
call printBoard1
;get cursor x y
call SetCursor
MOV AH, 0
INT 16H
MOV BL, AL
;up arrow
CMP AH, 48h
jz upArrow
;down arrow
CMP AH, 50h
jz downArrow
;right arrow
CMP AH, 4dh
jz rightArrow
;left arrow
CMP AH, 4bh
jz leftArrow
;lowercase q
CMP AL, 71h
jz EXIT
;uppercase q
CMP AL, 51h
jz EXIT
;lowercase n
CMP AL, 6eh
jz newGame
;uppercase n
CMP AL, 4eh
jz newGame
jmp game
MAIN ENDP
EXIT:
MOV AH, 4CH ; return control to DOS
INT 21H
SetCursor:
mov dl, col
mov dh, row
mov bh, 0
mov ah, 02h
int 10h
ret
getStrlen:
lodsb
cmp al, 24h
je strlen_end
inc bx
jmp getStrlen
strlen_end:
ret
loadAndDisplayStr:
lodsb
stosw
dec cx
jne loadAndDisplayStr
ret
printBoard1:
MOV board, 1
xor dx,dx
xor ax,ax
mov cx, 9
myloop1:
push cx
lea si, a
add si, dx
mov cx, 31
mov di, ax
push ax
mov ah, 4
call loadAndDisplayStr
pop ax
add ax, 160
add dx, 32
pop cx
dec cx
jnz myloop1
ret
upArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub row, 2
mul row
add al, col
mov di, ax
mov ax, 32
add row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub row, 2
jmp game
downArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add row, 2
mul row
add al, col
mov di, ax
mov ax, 32
sub row, 2
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add row, 2
jmp game
leftArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
sub col, 5
mul row
add al, col
mov di, ax
mov ax, 32
add col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
sub col, 5
jmp game
rightArrow:
xor si, si
xor di, di
lea bx, a
mov ax, 32
add col, 5
mul row
add al, col
mov di, ax
mov ax, 32
sub col, 5
mul row
add al, col
mov si, ax
mov dx, [bx+si]
xchg dx, [bx+di]
xchg [bx+si], dx
add col, 5
jmp game
initConfig:
;put the cursor at 00
mov col, 27
mov row, 5
;gets strlen of prompt and stores it in BX
lea si, PROMPT
xor bx, bx
call getStrlen
;display prompt
lea si, PROMPT
mov cx, bx
mov ah, 2
mov di, 5a0h
call loadAndDisplayStr
ret
END MAIN
The way I see it is there are 2 ways of doing this. One way would be to create an empty array, and every time the user makes a move (up/down/left/right) I can push this to a stack, and then when the user hits 'n' for new game, I just pop through that stack and reverse all the moves.
Another alternative would be to create 2 identical boards (arrays/string) 'a' and 'b', and then the user would manipulate board 'a' till they decide to hit 'n' for a new game, and then I would some how set 'a' = 'b'
There's no magic way, you just have to copy the array like you would in C.
I'd suggest having one master copy of the data that you keep clean / untouched, never ever writing into it.
Allocate uninitialized space for the working game state somewhere, e.g. on the stack or in the BSS1.
At the start of every game (including the first one), copy the preset whole array to the scratch space for the current game. (e.g. with rep movsb or rep movsw after setting CX, SI, and DI. ES and DS segment regs are already equal segment because of .model tiny. i.e. implement a memcpy however you like.)
So you don't need to write the initializer data twice or anything like that, and only one copy of it needs to be in the file.
And no you don't need any exchanging, just a block copy. Get the assembler to calculate the size of the whole thing by putting a label at the end, or put datasize = $ - a right after the end of a to get the size in bytes.
Footnote 1: See #MichaelPetch's comment for details on how to declare a label in the .data? segment so you can use normal label/symbol syntax. Like gamestate datasize dup(?), where datasize is an = or equ constant you got the assembler to calculate earlier from the size of the preset.
I think .data? is just space past the end of where DOS loads your .com file, and you can use space from there out to near the end of a 64k segment where the program-loader put your stack. (Unlike the .bss under a modern OS is not zeroed to start with. That's fine for this, you want to write the space you use before you read/modify it anyway.)
#DavidWohlferd also suggests you could re-read part of the executable from disk, with DOS file open/read system calls. That could be the start of a save-game mechanism. In its simplest form, if the first n bytes of your program are all read-only (code and constant data) apart from this game-state array, you could read the first n bytes of the raw .com file into memory at ds:100h (or cs or es, it's all the same in a tiny memory model). Overwriting instructions with themselves (like a jmp rel16 over the data) is fine.
Related
Printing an array but specific values highlighted {emu8086}
I want to print this array but also highlight specific characters from said array. This is my code: include 'emu8086.inc' .data animales1 db 'BUBRPQYFODFZXIQ' db 'MSVDJVQDTLOEATF' db 'RCZPIFYGAZLPMFN' db 'LVWKFFBKDXHFIUW' db 'AOSEFQEMOOTGQUR' db 'ELLWTGNJJKAJISJ' db 'OVCOXLUEQTSDDSP' db 'UEAEMTNYOLVYMGI' db 'ORREPOMJZGYPHAI' db 'IFTLCBJFVOYHLUB' db 'WTOWZQFRAXQRLMR' db 'KGNYIIHHHKFUKIJ' db 'XMLSACGMVXEYSIT' db 'TSOESQVSEQRFNPU' db 'ODDQMDFWRGETDLY' lenguajes2 db 'SLKFMBCULKVYUIM' db 'TWCDQFYIVIKUXKB' db 'GNIWEQBOSYEMDTJ' db 'WDHFZZPUIEDERYQ' db 'KMTGTKAKROMUSUV' db 'BELBLLTUVJQHCRW' db 'UPLUBYJKNUXORLF' db 'SGMAOOEENBOGIWR' db 'JVSTLPTEGPPNPJW' db 'YINCASSEMBLYTTU' db 'CHWTIOIWORDZDRV' db 'BRZCNRAVRWAMUNU' db 'KOMCOUKNGQEPQVS' db 'XXRXJUJUBEXVGGA' db 'MNKJQKZAACVCLDW' char db 'a' flag db 0 ;Pez= 12,27,42 ;Ave= 76,92,108 indx db 5,11,26,41,45 dup (' ') .stack .code .start up mov ax,0000h mov bx,0000h mov cx,0000h mov dx,0000h lea si, animales1 ;call valueInArray call printArrays printArrays proc mov bx,0000h printArray: mov dx,0000h mov ah, 02h mov dl,byte ptr[si+bx] call valueinArray cmp flag,1 jz printSpecial int 21h mov dl, 20h int 21h add bx, 1 add cl, 1 cmp cl,15 jz nextRow jnz printArray nextRow: call nwLine add ch,1 mov cl, 00h cmp ch,15 jz finproc jnz printArray printSpecial: lea di,char mov byte ptr[di],dl push ax push bx push cx push dx mov bp, offset char mov dh,00h mov al, 1 mov bh, 0 mov bl, 1111_0000b mov cx, 1; calculate message size. mov dx,0000h mov ah, 13h int 10h mov dl, 20h mov ah, 02h int 21h pop dx pop cx pop bx pop ax add bx, 1 add cl, 1 cmp cl,15 jz nextRow jnz printArray finproc: ret printArrays endp nwLine PROC MOV AH,02h MOV DX,0Ah; imprime asscii 10 (nueva linea) INT 21h MOV DX,0Dh; imprime asscii 13 (retorno de carro) INT 21h RET nwLine ENDP valueInArray proc mov flag, 0 mov di,0001h iterar: mov dh, indx[di] cmp dh,20h jz finvalueproc cmp bl,dh jz found add di,1 jmp iterar found: mov flag,1 jmp finvalueproc: finvalueproc: ret valueInArray endp exit: end As you can see, the array 'indx' have the positions of the chars (The first number is the effective lenght of said array) that I want to highlight so I check if bx is in the position of said character to print it highlighted. I have two problems at the moment, the first one is the highlighted characters are printing in a kinda random position and that messes up the rest, but I think I know why the position of the highlighted character that prints is wrong, because the interrupt that I use uses dh and dl as positioners but I do not know how to make it so it continues the flow of the rest. The second problem is that the character that prints is wrong, if you run it and check the variable char, it has an 'Z' but it prints a 'T'. I really need help. Pretty please. :(
indx db 5,11,26,41,45 dup (' ') It could be that this line is not what you think it is! Reading your explanation I think you really meant: indx db 5, 11, 26, 41, 45, ' ' That is the length of the array which is 5, then followed by 4 offsets to the highlighted characters and 1 space character as a list terminator. the first one is the highlighted characters are printing in a kinda random position and that messes up the rest, but I think I know why the position of the highlighted character that prints is wrong, because the interrupt that I use uses dh and dl as positioners but I do not know how to make it so it continues the flow of the rest. Because your code to output the highlighted character uses mov dx,0000h, the BIOS function 13h places the character in the upperleft corner of the screen and the other, 'normal' characters will continue from there. All you have to do is to ask BIOS where the cursor is at that moment using function 03h: Replace mov cx, 1; calculate message size. mov dx,0000h mov ah, 13h int 10h by mov ah, 03h ; BIOS.GetCursorAndConfiguration int 10h ; -> CX DX mov cx, 1 ; message size mov ah, 13h ; BIOS.WriteString int 10h Function 13h fetches from ES:BP. Did you setup the ES segment register? The second problem is that the character that prints is wrong, if you run it and check the variable char, it has an 'Z' but it prints a 'T'. Probably resolving the first problem will also resolve the second one. There's a better, less convoluted way to output your highlighted character. printSpecial: push ax push bx push cx mov cx, 1 ; ReplicationCount mov bx, 00F0h ; DisplayPage 0, Attribute BlackOnBrightWhite (11110000b) mov al, dl ; Character mov ah, 09h ; BIOS.WriteCharacterAndAttribute int 10h mov ah, 0Eh ; BIOS.TeletypeCharacter int 10h pop cx pop bx pop ax ... Function 09h will write your character with the colors that you need, and then function 0Eh will advance the cursor normally.
How to sort an array using stack in assembly
I want to sort an array while using the stack: so first things first I pushed it all into the stack. then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array. but something isn't right and about halfway there it got messed up (DI is one index below than what it should really be) data segment a db 5h,12h,6h,4h,9h len equ $-a loop_counter db len min_index dw 0 min db ? ends stack segment dw 128 dup(0) ends code segment ;TODO: Locate min in stack xchg it with top element copy to array and pop it :| start: mov ax, data mov ds, ax mov bx,0 mov cx,0 mov cl,loop_counter push_arr_to_stack: mov al,a[bx] push ax inc bx loop push_arr_to_stack mov bx,len-1 mov ax,0 mov cl,loop_counter mov bp,sp mov ax,[bp] mov bx,[bp] mov di,0 mov dx,0 mov si,2 mov di_check,len-loop_counter find_min_to_arr: cmp bx,ax jb new_min mov bx,[bp+si] add si,2 loop find_min_to_arr mov min,al xchg a[di],al jmp pop_min new_min: mov ax,bx mov bx,[bp+si] mov min_index,si sub min_index,2 add si,2 dec cx jmp find_min_to_arr pop_min: mov dx,[bp] xchg di,min_index mov [bp+di],dx xchg di,min_index pop dx mov dx,0 inc di mov si,0 cmp di,len je b dec loop_counter mov cl,loop_counter jmp find_min_to_arr b: mov ax, 4c00h ; exit to operating system. int 21h ends end start
first I pushed it all into the stack. This part is fine although for speed reasons you should forget about loop .. and replace it with dec cx followed by jnz .. then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array. Here your code gets very complicated and it contains many errors. Also the code does not perform true swapping between the located minimum and the element at the top of the stack. I tried amending your code but as is often the case, it is beyond repair. Below is my rewrite that you should study, not just copy! I have defined the loop_counter a word variable because that's easier. Additionally I kept it in the DX register that was sitting there doing nothing... Pushing it all into the stack mov bx, dx push_arr_to_stack: mov al, a[bx-1] push ax dec bx jnz push_arr_to_stack I push the array in reverse so the stack has the elements in the same order as the original array. This is not necessary for the task, but it is simpler and it leaves the BX register at zero for use below. Locating the minimum in the stack Again: mov bp, sp xor si, si mov al, [bp+si] ; Chosen minimum mov di, si ; Remember its position mov cx, dx dec cx ; N elements = N-1 compares jz .c .a: add si, 2 cmp al, [bp+si] jbe .b mov al, [bp+si] ; New minimum mov di, si ; Remember its position .b: dec cx jnz .a Swapping it with the top element .c: xchg al, [bp] mov [bp+di], al Popping it out and moving it back to the array pop ax mov a[bx], al inc bx dec dx jnz Again The important thing here is that the above exactly does what the task description said.
TASM assembly array being funky and not working
Basically.... I'm trying to make a snake game in TASM assembly. currently, main problem is the fact that the array of the snake game (a 400 cell array of bytes) is being completely funky. example: when i try to put it later on in the DATASEG (like being one of the last vars defined) and i try to paint the array for the start of the game, it loads up as if some random cells have value different than 0 (they should not). another problem is when i change the value of 1 random cell to generate an apple, it sometimes goes and paints 2 apples, meaning something went awry... This is how i defined my array: GameArray db 400 dup(0) This is how i mov array: mov bx, offset GameArray also, the timer just doesn't seem to work. what i have right now in the code are just the functions and the attempt at seeing if the timer works: `.286 IDEAL model small stack 100h DATASEG GameArray db 400 dup(0) ;20x20 array for the snake game. need to be first variable for some reason, or cell values are jumbled up. wierd... ApplePresent db 0 ;incase 2 or more cells with applevalue, disregard the later cells and make them empty squares seconds db 99 ;variable for timer to check in how many miliseconds there is change. One db 1 ;used as number '1' as word so bx which array is moved to will have no problems. AppleValue db 255 ;used as number '256' as word so bx which array is moved to will have no problems. Zero db 0 ;used as number '0' as word so bx which array is moved to will have no problems. PointGained db 0 ;Boolean var to check if point was gained in the movement. if so, snake will be grown. NumCell dw 0 ;NumCell represents the cell in the array which the snake's head will be going to. Score db 0 ;keeps score of the game. xArr dw 10 ;x coordinate of head (value 5 at start) at start of game. (x of array) yArr dw 9 ;y coordinate of head (value 5 at start) at start of game. (y of array) SnakeHead db 5 ;SnakeHead value will be copied to element of array snake head will go to. xDraw dw ? ;x coordinate for drawing screen yDraw dw ? ;y coordinate for drawing screen xDrawlim dw ? ;x coordinate for drawing screen limit of box yDrawlim dw ? ;y coordinate for drawing screen limit of box Direction db 1 ;1 = right, 2 = up, 3 = left, 4 = down. gets value from last click of WASD keys Clock equ es:6ch ;looks at clock memory segment. CODESEG proc ApplesFix ;FUnction to fix if there are 2 or more cells with value of 255 in them. if so, reset the value of the array cell to 0. pusha mov bx, offset GameArray mov ax, 400 ApplesFixLoop: mov cl, [AppleValue] cmp [bx], cl je IncrementApplePresent inc bx dec ax jnz ApplesFixLoop jmp EndFix IncrementApplePresent: inc [ApplePresent] cmp [ApplePresent],1 jg FixCell inc bx dec ax jnz ApplesFixLoop jmp EndFix FixCell: mov cl, [Zero] mov [bx], cl inc bx dec ax jnz ApplesFixLoop EndFix: popa ret endp ApplesFix proc RandApple pusha ;pushes all registers. never knew the command so only using it now. push [Numcell] RandGen: mov [NumCell],0 mov ax, 40h mov es, ax mov cx, 10 mov bx, 0 random_loop_apple: mov ax, [Clock] mov ah, [byte cs:bx] xor al, ah and al, 11111111b xor ah, ah mov [NumCell], ax add [NumCell], 11 loop random_loop_apple mov bx, offset GameArray add bx, [NumCell] mov cl, [Zero] cmp [bx], cl je GenerateApple jmp RandGen GenerateApple: mov cl, [AppleValue] mov [bx], cl pop [Numcell] popa ret endp RandApple proc KeyPress ;function which gets key press from WASD and will change var 'Direction' according to it. push ax mov ah, 1d int 21h Wait_for_Data: cmp al, 87;'W' je MovingUp cmp al, 65;'A' je MovingLeft cmp al, 83;'S' je MovingDown cmp al, 68;'D' je MovingRight jmp Wait_for_Data MovingUp: mov [Direction], 2d jmp EndKeyPress MovingLeft: mov [Direction], 3d jmp EndKeyPress MovingDown: mov [Direction], 4d jmp EndKeyPress MovingRight: mov [Direction], 1d jmp EndKeyPress EndKeyPress: pop ax ret endp KeyPress proc MoveHead ;Head value will be copied into the array cell which snake moves to. pusha mov bx, offset GameArray add bx, [NumCell] mov cl, [SnakeHead] mov [bx], cl popa ret endp MoveHead proc DirectionSnake ;proc for changing x,y values of array to know which square head value will be copied to. cmp [Direction], 1d je MoveRight cmp [Direction], 2d je MoveUp cmp [Direction], 3d je MoveLeft cmp [Direction], 4d je MoveDown MoveRight: add [xArr] ,1d cmp [xArr], 19d jg OtherSideRight jmp EndDirectionSnake MoveUp: sub [yArr], 1d cmp [yArr], 0d jb OtherSideUp ;function for making snake head appear at the highest layer if snake goes down out of boundaries. (same with labels of same name, just for different function) jmp EndDirectionSnake MoveLeft: sub [xArr], 1d cmp [xArr], 0d jb OtherSideLeft jmp EndDirectionSnake MoveDown: add [yArr], 1d cmp [yArr], 19d jg OtherSideDown jmp EndDirectionSnake OtherSideRight: mov [xArr], 0d jmp EndDirectionSnake OtherSideUp: mov [yArr], 19d jmp EndDirectionSnake OtherSideLeft: mov [xArr], 19d jmp EndDirectionSnake OtherSideDown: mov [yArr], 0d EndDirectionSnake: ret endp DirectionSnake proc findHeadXY ;find xy coordinate of the cell in array which head will be going to push ax ;preserving value of ax by pushing him into stack and popping him at the end of function. mov ax, [xArr] mov [NumCell], ax ;NumCell represents the cell in the array which the snake's head will be going to. mov ax, [yArr] FindArrayCelly: ;label for loop of finding the array cell's y value that snake head is going to be copied into. add [NumCell], 20d sub ax, 1d jnz FindArrayCelly pop ax ret endp findHeadXY proc MoveAction ;function will find whats inside the cell snake head will be going to and see if snake eats apple and moves, regular movement or lose. push bx push cx mov bx, offset GameArray add bx, [NumCell] ;goes to the cell which the snake head will be moving to. mov cl, [AppleValue] cmp [bx], cl je SnakeEatsApple mov cl, [Zero] cmp [bx], cl je SnakeMoves jmp GameLost SnakeEatsApple: add [Score], 1d ;if apple is eaten score is increased by 1. mov [PointGained], 1d ;sets boolean to 1 meaning 'True', snake will lengthen cmp [Score], 255d je GameWon call MoveHead SnakeMoves: call MoveHead GameLost: mov ax, 0c00h ;replicating exit interrupt. int 21h GameWon: mov ax, 0c00h ;replicating exit interrupt. int 21h EndMoveAction: pop cx pop bx ret endp MoveAction proc BlackSquare ;when array element has value which is 0, draw white square push cx push dx mov cx,[xDraw] mov dx,[yDraw] mov al, 15d loopboxB: mov bh,0h mov ah,0ch int 10h inc cx cmp cx,[xDrawlim] jne loopboxB mov cx,[xDraw] inc dx cmp dx,[yDrawlim] jne loopboxB pop dx pop cx ret endp BlackSquare proc SnakeSquare ;when array element has value which is not 0 or 256, draw green square (green color) push cx push dx mov cx,[xDraw] mov dx,[yDraw] mov al, 2d ;al assigned different value for different color loopboxS: mov bh,0h mov ah,0ch int 10h inc cx cmp cx,[xDrawlim] jne loopboxS mov cx,[xDraw] inc dx cmp dx,[yDrawlim] jne loopboxS pop dx pop cx ret endp SnakeSquare proc AppleSquare ;when array element has value which is 256, draw yellow square push cx push dx mov cx,[xDraw] mov dx,[yDraw] mov al, 14d ;al assigned different value for different color loopboxA: mov bh,0h mov ah,0ch int 10h inc cx cmp cx,[xDrawlim] jne loopboxA mov cx,[xDraw] inc dx cmp dx,[yDrawlim] jne loopboxA pop dx pop cx ret endp AppleSquare proc DrawScreen ;draws screen according to value in array elements. pusha mov bx, offset GameArray mov ax, 0d mov [xDraw], 121d ;starting values for painting screen mov [ydraw], 101d mov [xDrawlim], 130d mov [yDrawlim], 110d CheckElementValue: mov cl, [Zero] cmp [bx], cl je CallBlackSquare ;goes to label to call function BlackSquare mov cl, [AppleValue] cmp [bx], cl ;cx is copying AppleValue since comparing memory (var) to memory (array which is copied in bx) is illegal. je CallAppleSquare ;goes to label to call function AppleSquare jmp CallSnakeSquare ;goes to label to call function SnakeSquare CallBlackSquare: call BlackSquare add [xDraw], 10d add [xDrawlim], 10d inc ax cmp ax, 400d je EndDrawingScreen add bx,1 cmp [xDrawlim], 330d je DropLine jmp CheckElementValue MidJumP: jmp CheckElementValue CallAppleSquare: call AppleSquare add [xDraw], 10d add [xDrawlim], 10d inc ax cmp ax, 400d je EndDrawingScreen add bx,1 cmp [xDrawlim], 330d je DropLine jmp CheckElementValue CallSnakeSquare: call SnakeSquare add [xDraw], 10d add [xDrawlim], 10d inc ax cmp ax, 400d je EndDrawingScreen add bx,1 cmp [xDrawlim], 330d je DropLine jmp CheckElementValue DropLine: add [yDraw], 10d add [yDrawlim], 10d mov [xDraw], 121d mov [xDrawlim], 130d cmp [yDrawlim], 310d jne MidJumP EndDrawingScreen: popa ret endp DrawScreen proc CycleChange ;the procedure reduces all cells in array which value is greater than 0 by 1, so tail of the snake will get erased after new head is formed. pusha mov bx, offset GameArray mov ax, 400d CheckArray: cmp [word ptr bx], 0 ;checks current element of array looked at and checks if equal to 0. need to add that will not reduce value if its 256 as well. jne DecreaseCellValue add bx, 1d dec ax jz EndCycleChange DecreaseCellValue: mov cl, [One] sub [bx], cl add bx, 1d dec ax jmp CheckArray EndCycleChange: popa ret endp CycleChange proc ResetArray ;restore all array values to 0. pusha mov bx, offset GameArray mov ax, 400d ResetArrayL: mov cl, [Zero] mov [byte ptr bx], cl inc bx dec ax jnz ResetArrayL popa ret endp ResetArray start: mov ax, #data mov ds, ax GameStart: mov bx, offset GameArray add bx, 210 push cx mov cx, [word ptr SnakeHead] GenerateSnake: ;puts snake of length 5 in the array. mov [word ptr bx], cx inc bx loop GenerateSnake GenerateStartingApple: call RandApple ;Puts apple randomly in cell of array before starting the game. call ApplesFix mov ax,012h int 10h ;640 x 480 16 colors. graphic mode interrupt. secstart: call DrawScreen mov ah,02ch ; Get current second int 021h mov bh,dh ; Store current second readloop: mov ah,02ch ; Get new time. Seconds are stored in dh int 021h sub dh,1 ; Subtract 1 from new second. Giving 1 Secs for input. GoBackCheck: ;if no key has been pressed, until second is over input from keyboard will be checked. cmp bh,dh je SecondPassed ; Exit when DH is finally equal to BH. mov ah,06h ; Function 06h of INT 021 will directly read from the Stdin/Stdout mov dl,0ffh ; Move 0ff into the DL register to read from the keyboard int 21h jz GoBackCheck ; If the zero flag of the FLAGS register is set, no key was pressed. call KeyPress jmp GoBackCheck SecondPassed: ;here snake moves and checks if you lost/won game. call findHeadXY call MoveHead GoBack: jmp secstart exit: mov ax, 0c00h int 21h END start`
Asm Assembler - CX loop never executes
I have a vector and I have to put in the AX register the sum of the numbers that are greater than 50 ( > 50 ). I do not understand why my loop does not work when I run it. First it compares 100 with 50, jumps at adunare , add 100 to AX but then it exits the loop and terminates the program. .MODEL SMALL .STACK 10h .DATA vect DB 100,70,3,10,60,200,30 len DB 7 .CODE begin: mov ax,#DATA mov ds,ax mov ax,0 mov cl,len mov ch,0 mov si, -1 bucla: inc si cmp vect[si],50 ja adunare jb mic adunare: add ax, word ptr vect[si] mic: loop bucla mov ah,4ch int 21h END begin
.STACK 10h With such a small stack the debugger could very well terminate your program as soon as an interrupt occurs, leaving you thinking that the loop doesn't execute. Specify a larger stack. 256 bytes is a reasonable minimum. adunare: add ax, word ptr vect[si] To add the byte at vect[si] to the word in AX, you have several options: using an intermediate register like zx485 suggested clearing the extra register: xor dx, dx mov dl, vect[si] add ax, dx extending from byte to word in one instruction: movzx dx, vect[si] add ax, dx without an extra register but using a cascaded addition: add al, vect[si] adc ah, 0 cmp vect[si],50 ja adunare jb mic adunare: add ax, word ptr vect[si] mic: loop bucla You can write this simpler and if the number 50 were present in the array, it would erroneously be added to the sum. Besides the above and below conditions there's also the equal condition to take care of. cmp vect[si], 50 jna mic add al, vect[si] adc ah, 0 mic: loop bucla For perfection you could dismiss the loop instruction (it has a reputation for being slow) and use instead dec cx jnz bucla. This in turn gives you the opportunity to not having to zero CH and rather use dec cl jnz bucla. Everything together: xor ax, ax ; This makes AX=0 mov cl, len mov si, -1 bucla: inc si cmp vect[si], 50 jna mic add al, vect[si] adc ah, 0 mic: dec cl jnz bucla mov ah, 4ch ; DOS.Terminate (exitcode is in AL) int 21h I've tested a good number of variations. This is a faster version of the loop: xor ax, ax ; This makes AX=0 xor si, si mov cl, len bucla: cmp vect[si], 50 jna mic xor dx, dx mov dl, vect[si] add ax, dx mic: inc si dec cl jnz bucla
Assembly two-dimensional array of pixels
How could I do something like this in assembly? DOS 16bit graphic mode int start_x=1, start_y=1; for(int i=0; i<8; i++){ for(int j=0; j<8; j++){ if(T34[i][j]==1) put_colour_pixel(start_x+i, start_y+j); else put_black_pixel(start_x+i, start_y+j); } } :edit: So my loops pretty work. How to connect it to table with 0 and 1. mov ax, 10 ; Y start line mov bx, 20 ; X start line mov dl, 4 ; colour (red) mov cx, 5 ; loop top counter top: add ax, 1 push cx ;loop top counter mov cx, 10 inside: add bx, 1 push ax push bx push cx call putpixel pop cx pop bx pop ax loop inside mov bx, 20 ;next line X go to start X pop cx ;loop top counter loop top ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// My new code: segment .data segment .code ..start: mov ax, 13h int 10h ; switch to 320x200 mode mov ax, 0a000h ; The offset to video memory mov es, ax ; We load it to ES through AX, ; because immediate operation ; is not allowed on ES ;;;;;;;;;;;;;;;;;;;;;; mov di, T34 mov si, 8 ;------------------------------------ P1: mov bp, 8 ;---------------- P2: cmp BYTE[di], 1 jnz short NOHIT NOHIT: ; increase the x position push ax push bx push cx mov ax,si ;Y mov bx,bp ;X mov dl, 1 ; here I should take '0' or '1' from table call putpixel pop cx pop bx pop ax inc di ; increase offset address of array dec bp jnz P2 ;------------- ; increase the y position + substract 8 from x position dec si jnz P1 ;------------------------------------ ;;;;;;;;;;;;;;;;;;;;;;;;; xor ah, ah int 16h ; keyboard (wait for key) mov ax, 3 int 10h ; go to text mode mov ax, 4c00h int 21h ; return to DOS, exit code 0 ;;;;;;;;;;;;;;;;;;;;; putpixel: push dx ; mul changes dx too mov cx, 320 mul cx ; multiply Y (ax) by 320 (one row) add ax, bx ; and add X (bx) (result= dx:ax) mov di, ax pop dx mov [es:di], dl ; store color/pixel ret ;;;;;;;;;;;;;;;;;;;;;; T34 DB 1,1,1,1,1,1,1,1 DB 1,0,0,0,0,0,0,0 DB 1,0,0,0,0,0,0,0 DB 1,0,0,0,0,0,0,0 DB 1,1,1,1,1,1,1,1 DB 1,0,0,0,0,0,0,0 DB 1,0,0,0,0,0,0,0 DB 1,1,1,1,1,1,1,1 I have changed order and now it is drawing square in left corner (as I expected). Did I change order rigth? I suppose that letter will be spinned, but it is not problem for me. I can fix it later. Now I should go to '0' or '1' in table and set color. Which register have "0" or "1"? So mostly I have problem with colour. I have try this, but I have error. I have try set colour black (0) or blue (1) push dx mov ax, bp ; X*8 mov cx,8 mul cx add ax, si ; X*8 +Y add ax, di ; tab0 + X*8+Y mov dl, ax; here is error, here I set the colour pop dx So I don't know how to fix it :( I have try different possibilities and northing work.
mov di, T34 mov si, 8 ;------------------------------------ P1: mov bp, 8 ;---------------- P2: cmp BYTE[di], 1 jnz short NOHIT ; save used REGISTER ; load register with the X,Y position and color call putpixel ; get back the saved Register NOHIT: ; increase the x position inc di ; increase offset address of array dec bp ; decrease counter and set zeroflag if register is zero jnz P2 ; jump if zeroflag is not set ;------------- ; increase the y position + substract 8 from x position dec si jnz P1 ;------------------------------------ It is also possible to start the counters for the loops with 0 for to increase the counter, but then we need a compare instruction for to leave the loop, if we want to run the loop from 0 to 8. The offset addresses inside of the array are pointed independent with no relationship to the counters. With a little modifying (put an additional jump instruction in the code and a second call) it is also possible to set a black pixel if the byte of the array is 0. But i think this simple form of a nested loop is easier to understand in the first time. Edit: Now it is compatible for NASM. Edit2: Maybe it is more simple to store the x,y coordinates into a known ram location for modifying and reloading inside of a loop, if many parameters are in use. Our ram location: Color DB ? ; define byte X_Pos DW ? ; define word Y_Pos DW ? Examples for to show how to access a memory location (default segment is DS): mov [X_Pos], ax mov [X_Pos], bx mov [Color], dl mov ax, [X_Pos] mov bx, [Y_Pos] mov dl, [Color] mov WORD[X_Pos], 10 inc WORD[X_Pos] sub WORD[X_Pos], 8 mov BYTE[Color], 4 inc BYTE[Color] Edit3: mov dl, ax; here is error, here I set the colour It is not possible to mix an 8 bit register with a 16 Bit register. Note: AX = AL+AH DX = DL+DH Existing instruction are: mov dl, al mov dl, ah mov dx, ax movzx dl, ax