Need MSVC with assembler file help

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

So guys how about some lines of assembler. In the piece structure is a doubly linked list t->p[j].prv and t->p[j].nxt. This is how the pieces are traversed during move generation. With captured pieces being unlinked during makemove and then relinked in during move takeback. t->p[0] is not a piece. It is just where to find the first piece. t->p[20] serves the same for black. Also t->p[19] and t->p[39] have a piece type that will cause the assembler code to terminate the MoveGen function. So basically I need the code to follow the t->p[j].nxt links. If it is not too much trouble! :D

I'll create a minimal sample code so if someone wants they can compile the code. I'll be right back.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

Double.c

Code: Select all

typedef struct {
  int prv;
  int nxt;
} piece_s;

typedef struct {
  int board[64];
  piece_s piece[40];
} thread_s;

extern MoveGen(thread_s *);

main() {
  int i;

  thread_s *t = (thread_s *)malloc(sizeof(thread_s));

  for (i = 0; i < 20; i++) {
    t->piece[i].prv = i - 1;
    t->piece[i].nxt = i + 1;
    t->piece[i + 20].prv = i + 19;
    t->piece[i + 20].nxt = i + 21;
  }

  i = MoveGen(t);
}
Linked.asm

Code: Select all

.386

.model flat

.data

.code

public c MoveGen

MoveGen:

  push ebp
  mov  ebp, esp
  mov  ebx, [ebp+8]

  ; code to traverse t->piece[].nxt

  mov  esp, ebp
  pop  ebp
  ret

end
This is written for MSVS 2017 community. To use asm files the build dependencies must include masm. So on the solution explorer window right click on the name of the solution and choose "build dependencies" and check the masm( .targets ...) box. If this is done after Linked.asm is added then its properties will have to be changed to include it in the build.

P.S. This is all I need. I'll be able to write all the rest of the code without needing help! :D
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Need MSVC with assembler file help

Post by mar »

Michael Sherwin wrote: Sat Mar 16, 2019 6:18 pm Linked.asm

Code: Select all

.386

.model flat

.data

.code

public c MoveGen

MoveGen:

  push ebp
  mov  ebp, esp
  mov  ebx, [ebp+8]

  ; code to traverse t->piece[].nxt

  mov  esp, ebp
  pop  ebp
  ret

end
Let's try:

Code: Select all

ebx = thread_s *

lea esi,[ebx + 4*64 + 4]
// esi = &thread->piece[0].nxt

// edx = current index
xor edx, edx

// you may want to align the loop here, but I don't know how to do it in masm
traverse_loop:
mov edx,[esi + edx*8]
; edx = current_index



jmp traverse_loop

No idea if I made a mistake somewhere. Anyway, I very much doubt you can beat modern compilers here. You end up with non-portable code.
I understand you do this for fun though :)
Martin Sedlak
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Need MSVC with assembler file help

Post by mar »

Michael Sherwin wrote: Sat Mar 16, 2019 6:18 pm Double.c

Code: Select all

typedef struct {
  int prv;
  int nxt;
} piece_s;

typedef struct {
  int board[64];
  piece_s piece[40];
} thread_s;
Looking at this, I think you're missing an important piece of information, namely how to map to board index.
You could either embed it into piece_s or use another array, say int board_index[40];
Embedding it may be better and also more compact:

Code: Select all

typedef struct {
	int8_t prv;
	int8_t nxt;
	int8_t idx;
	int8_t pad;
}
Alternatively, the list could be an array of 64 mapping to board index directly, with separate head for white and black.
Martin Sedlak
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

mar wrote: Sat Mar 16, 2019 8:22 pm
Michael Sherwin wrote: Sat Mar 16, 2019 6:18 pm Linked.asm

Code: Select all

.386

.model flat

.data

.code

public c MoveGen

MoveGen:

  push ebp
  mov  ebp, esp
  mov  ebx, [ebp+8]

  ; code to traverse t->piece[].nxt

  mov  esp, ebp
  pop  ebp
  ret

end
Let's try:

Code: Select all

ebx = thread_s *

lea esi,[ebx + 4*64 + 4]
// esi = &thread->piece[0].nxt

// edx = current index
xor edx, edx

// you may want to align the loop here, but I don't know how to do it in masm
traverse_loop:
mov edx,[esi + edx*8]
; edx = current_index



jmp traverse_loop

No idea if I made a mistake somewhere. Anyway, I very much doubt you can beat modern compilers here. You end up with non-portable code.
I understand you do this for fun though :)

Code: Select all

.386

.model flat

.data

count  dd 10

.code

public c MoveGen

MoveGen:

  push ebp
  mov  ebp, esp
  mov  ebx, [ebp+8]
  
  lea  esi, [ebx + 260]
  xor  edx, edx
traverse_loop:
  dec  [count]
  je   done
  mov  edx, [esi + edx*8]
  jmp traverse_loop
  
done:
  mov  esp, ebp
  pop  ebp
  ret

end
When it finished ecx was 9 so this worked perfectly. Thank you very much!
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

mar wrote: Sat Mar 16, 2019 8:42 pm
Michael Sherwin wrote: Sat Mar 16, 2019 6:18 pm Double.c

Code: Select all

typedef struct {
  int prv;
  int nxt;
} piece_s;

typedef struct {
  int board[64];
  piece_s piece[40];
} thread_s;
Looking at this, I think you're missing an important piece of information, namely how to map to board index.
You could either embed it into piece_s or use another array, say int board_index[40];
Embedding it may be better and also more compact:

Code: Select all

typedef struct {
	int8_t prv;
	int8_t nxt;
	int8_t idx;
	int8_t pad;
}
Alternatively, the list could be an array of 64 mapping to board index directly, with separate head for white and black.
I'm not exactly sure that I understand. In pieces there is a .sqr to map it to the board. It would then just take a different offset to access [ebx + sqr_offset]. Of course I did not include that in the example code for simplicity.

This is actually the structure in my real code.

typedef struct {
int sqr; // the square the piece is on
int typ; // the type of piece, WP ... BK
int clr; // the side
int prv; // the previous on board piece
int nxt; // the next on board piece
int val; // the value of the piece
} ps; // piece-structure

On the other hand I like simplicity! :D So I could unwrap the piece_s structure to just include each element of the structure to be an array in the thread structure. Then I would not need the lea instruction and could just use some type of offset math with the thread pointer. Is that what your were getting at when you said simplicity? Please pardon my terminology if it was not quite right! Thanks.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Need MSVC with assembler file help

Post by mar »

Michael Sherwin wrote: Sat Mar 16, 2019 9:41 pm This is actually the structure in my real code.

typedef struct {
int sqr; // the square the piece is on
int typ; // the type of piece, WP ... BK
int clr; // the side
int prv; // the previous on board piece
int nxt; // the next on board piece
int val; // the value of the piece
} ps; // piece-structure

On the other hand I like simplicity! :D So I could unwrap the piece_s structure to just include each element of the structure to be an array in the thread structure. Then I would not need the lea instruction and could just use some type of offset math with the thread pointer. Is that what your were getting at when you said simplicity? Please pardon my terminology if it was not quite right! Thanks.
I see, so my "idx" is actually your "sqr" :)
A side note: you'll have to adjust the traversal, because a single instruction won't do anymore.

You real structure is 24 bytes long, so you'll have to do something like this:

Code: Select all

// multiply by 3
lea edx,[edx*2 + edx]
// multiply by 8 to get 24
mov edx,[esi + edx*8]
If you'd use SOA (structure of arrays), which is what you described, then you could still traverse the list with only one instruction, also being more cache friendly.
Also this way adding new members won't affect the way you address nxt, so it's probably a win-win situation.
Martin Sedlak
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

mar wrote: Sat Mar 16, 2019 10:01 pm
Michael Sherwin wrote: Sat Mar 16, 2019 9:41 pm This is actually the structure in my real code.

typedef struct {
int sqr; // the square the piece is on
int typ; // the type of piece, WP ... BK
int clr; // the side
int prv; // the previous on board piece
int nxt; // the next on board piece
int val; // the value of the piece
} ps; // piece-structure

On the other hand I like simplicity! :D So I could unwrap the piece_s structure to just include each element of the structure to be an array in the thread structure. Then I would not need the lea instruction and could just use some type of offset math with the thread pointer. Is that what your were getting at when you said simplicity? Please pardon my terminology if it was not quite right! Thanks.
I see, so my "idx" is actually your "sqr" :)
A side note: you'll have to adjust the traversal, because a single instruction won't do anymore.

You real structure is 24 bytes long, so you'll have to do something like this:

Code: Select all

// multiply by 3
lea edx,[edx*2 + edx]
// multiply by 8 to get 24
mov edx,[esi + edx*8]
If you'd use SOA (structure of arrays), which is what you described, then you could still traverse the list with only one instruction, also being more cache friendly.
Also this way adding new members won't affect the way you address nxt, so it's probably a win-win situation.
So I will recode to SOA! And I'm looking into an idea. If the thread structure is mirrored in the .asm file then extern c thread_s:asm_mirror can be used. That way when the thread_s structure pointer is in ebx the the assemblers . operator can be used. :?: I don't know if an assembler structure can be used like a basic type like DWORD can be used. Thanks again!
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

My intuition was close to being correct. If one needs to access a structure in C/C++ from an assembler file the structure definition needs to be duplicated in the assembler file. Also the #pragma pack (push 1) and #pragma pack (pop) needs to encase the Cpp structure definition so Cpp packs the structure the same as masm. An extern c directive is not needed. So assuming all registers have appropriate values and a thread structure is named thread and a piece structure is named piece in assembler it seems this is the way it is done.

mov [edx], [ebx].thread.piece[edx].nxt

However, what I'm trying to figure out now is do I use edx as is or in the form edx*4 or does a calculation need to be done to get the correct value into edx or do I need to prefix something like DWORD ptr or does the assembler having the structure definition just know how to do all the calculations? What a mess, lol!
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Need MSVC with assembler file help

Post by Michael Sherwin »

Partial success.

New sample code.

Code: Select all

#pragma pack (push, 1)
typedef struct {
  int sqr;
  int typ;          // the type of piece, WP ... BK
  int clr;
  int prv;          // the previous on board piece
  int nxt;          // the next on board piece  
  int val;          // the value of the piece
} ps;               // piece-structure 

typedef struct {
  int castle;
  int epsq;
} ss;               // search-structure  

typedef struct {
  int wtm;          // white-to-move
  int ply;          // search ply
  int castle;       // castling status
  int epsq;         // capture e.p. square if any
  int fifty;
  int board[64];
  ps  p[40];        // index piece array 
  ss  s[100];       // search stack 
} ts;
#pragma pack (pop)

ts *t = new ts;

extern "C" int MoveGen(ts *);

int main() {
  int code;

  code = MoveGen(t);
  code = t->p[0].nxt;
}

Code: Select all

piece struc
  sqr dd ?
  typ dd ?          
  clr dd ?
  prv dd ?          
  nxt dd ?            
  val dd ? 
piece ends

search struc
  castle dd ?
  epsq   dd ?
search ends

t struc
  wtm    dd ?          
  ply    dd ?          
  castle dd ?       
  epsq   dd ?         
  fifty  dd ?
  board  dd 64 dup (?)
  p      piece   40 dup ({})         
  s      search 100 dup ({})
t ends



.data

.code

MoveGen proc
  xor rax, rax
  mov rdx, 0
  mov DWORD PTR[rcx].t.p[rdx].nxt, 3
  mov eax, DWORD PTR[rcx].t.p[rdx].nxt

  ret
MoveGen endp

end
I switched to C++ x64 because x32 would not work right and in C I could not debug trace the assemble file. Now for the good news. This code works. The 3 is moved. The 3 is retrieved and ends up in eax. In the C++ file int var code has 3. And when code = t->p[0].nxt is executed code still has 3. All correct. But, when I load 1 into rdx the 3 is sent somewhere and retrieved into eax just like before. However, when code = t->p[1].nxt is executed I get the big negative undefined number. I tried [rdx*4] [rdx*8] and mov rdx, 4 all with the same result. I'm so close to getting this but I'm really starting to get discouraged. Can I get a bit more help please. Or have I used up all my tokens?

Edit: I understand now what I'm doing wrong. I have to multiply edx by the number of bytes in the piece structure. I'll give that a try.

Edit2: Yes, that did it. It works perfectly now! Thanks for all the help!! :D
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through