I'm currently implementing Snake for university, and we have to use TASM for that.
My main game data is laid out like this (using C syntax):
struct GameLine {
uint8_t direction_bits[10]; // 2 bits per entry, the first entry is invalid since valid x positions start at one
uint8_t collision_bits[5]; // 1 bit per entry, the first entry is again invalid but has to stay zero
uint8_t aux; // padding such that GameLine is 16 bytes big, also used to store other information at times.
};
struct GameData {
struct GameLine lines[23];
} PHYSICAL_GAME_DATA;
The issue is that writing the direction bits each frame overwrites the read collision bits for large x positions (38 is the maximum position, but it happens earlier). I say "read collision bits" because I wasn't able to verify where the physical_game_data
actually resides because I don't know how to instruct the assembler (tasm
) and/or linker (tlink
) and/or debugger (td
) to show me that.
The declarations in my code are:
physical_game_data DB 368 DUP (0)
; ..., Some `EQU`s for `aux` data I'm using to store other information
game_data EQU (offset physical_game_data) - 16 ; Since 1 <= y <= 23, this allows addressing a line via `game_data + (y << 4)`
The mov
s that I'm most worried about here (there are a few more, but these are the two that make the bug visible) are these two:
; This one is for writing a new direction
mov BYTE [ds:game_data + bx], dh
; ...
; This one is for reading a collision bit to check if the player lost
mov dl, [ds:game_data + 10 + si]
Looking at those in td
however yields this:
mov [bx+05AF],dh
; ...
mov dl,[si+05B8]
The difference between 0x05AF and 0x05B8 however is 9, not 10. I've currently "fixed" the issue by adding 11 in the source code instead, which means the bug doesn't occur, but I'd rather fix this issue properly.
I'm assuming that this is me misunderstanding something about TASM or x86/x86-16 assembly, but I don't know what exactly that misunderstanding is.
Here's a complete file that exhibits this issue:
.model tiny
.286
.data
datastart:
physical_game_data DB 368 DUP (0)
; ..., Some `EQU`s for `aux` data I'm using to store other information
game_data EQU (offset physical_game_data) - 16 ; Since 1 <= y <= 23, this allows addressing a line via `game_data + (y << 4)`
.code
ORG 100h
start:
mov ax, seg datastart
mov ds, ax
; This one is for writing a new direction
mov BYTE [ds:game_data + bx], dh
; ...
; This one is for reading a collision bit to check if the player lost
mov dl, [ds:game_data + 10 + si]
; Exit
mov ax, 4C00h
int 21h
end start
Compiled using tasm MRE.ASM
, tlink MRE.OBJ
and opened with td
using td MRE.EXE
, the decompiled code reads:
mov ax,48AF
mov ds,ax
mov [bx+0103],dh
mov dl,[si+010C]
mov ax,4C00
int 21
Where, again, 0x10C - 0x103 is 9.
If it is of interest, I'm running this code under Dosbox.
Thanks!
Your problem is the BYTE keyword. In MASM mode the BYTE keyword evaluates to the size of a BYTE: 1. This is added to the expression in the square brackets []
as square brackets primarily act as an addition operator in MASM mode. You'd need to write BYTE PTR [ds:game_data + bx]
instead, although your next instruction demonstrates that you can also just leave it out.