Jump to content

Recommended Posts

13 minutes ago, dhe said:

Bump Bumpedy Bump Bump

... Bump Bump.

 

I hit a wall with comprehension of the code and went on to native code generation, a slightly less brain numbing exercise.

Thanks for the reminder.

On 12/10/2020 at 2:08 PM, Vorticon said:

I took a break from this project a couple of months ago as I kept hitting a wall with the evaluation function and the computer play was laughable. 

I may have to rethink a few algorithms...

Don't give up! :]

  • Like 1
  • 3 years later...

After a very long hiatus (per my notes I started this project on 3/14/2015), I've decided to take a fresh look at it, starting by scrapping my entire existing code base and re-thinking my approach.

My initial attempt was a brute force method, coupled with a very primitive evaluation function and no assembly support, resulting in what is essentially an unplayable chess engine.

I'm still far from certain that the end result will be any better, but we shall see!

I am still coding this in UCSD Pascal, but this time around I will be using assembly language support routine for time-critical parts as I am now far more proficient in UCSD Pascal than I was nearly 10 years ago.

 

So first focus is going to be on improving the speed and efficiency of move generation. This is usually a very time consuming and involved process where the computer will test the movement potential of each piece on the board in order to prep for move evaluation. After doing some research, I was very seduced by the idea of using bitboards to represent the playing board.

Bitboards are essentially 64-bit numbers representing the 64 board positions, which can be manipulated with logical operations (NOT, OR, AND, XOR, RSHIFT, LSHIFT) in various ways to quickly determine valid moves, captures etc... This is a rather involved process, but this excellent link will clearly explain the underlying concepts: https://pages.cs.wisc.edu/~psilord/blog/data/chess-pages/index.html

 

Now there is an obvious problem here, which is that our humble TI cannot handle 64-bit integers, but it can natively handle 16-bit ones, so all I had to do was break up the bitboard into 4 16-bit sections represented by an a 4-dimension integer array like so:

 

type
 bitboard = array[0..3] of integer;
var
 bit : bitboard;

 

Obviously this does slow things down a bit, but I believe the gains in efficiency will more than make up for this. Having decided on bitboards, I now needed to come up with routines to perform the necessary logical operations mentioned above in assembly. The source listings below show the bitboard operations module in assembly and the bittest program to verify functionality:

Spoiler
;bitboard logical operations routines
;bitboard is an array[0..3] of integer

        .proc bitnot,2
;complements a bitboard
;usage: bitnot(var bitboard1[0], bitboard2[0])
;the complement of bitboard1 will be stored in bitboard2

        .def    procret
        mov     r11,@procret
        mov     *r10+,r6        ;get pointer to bitboard2
        mov     *r10,r5         ;get pointer to bitboard1
        mov     *r5+,r4         ;protect content of bitboard1
        inv     r4              ;complement bitboard1
        mov     r4,*r6+         ;store in bitboard2
        mov     *r5+,r4
        inv     r4
        mov     r4,*r6+
        mov     *r5+,r4
        inv     r4
        mov     r4,*r6+
        mov     *r5,r4
        inv     r4
        mov     r4,*r6
        mov     @procret,r11
        b       *r11
        
procret .word

        .proc   bitand,3
;logically AND 2 bitboards
;usage: bitand(var bitboard1, bitboard2, bitboard3)
;bitboard1 and bitboard2 are ANDed and the result placed in bitboard3

        .ref    procret
        mov     r11,@procret
        mov     *r10+,r7        ;get pointer to bitboard3
        mov     *r10+,r6        ;get pointer to bitboard2
        mov     *r10,r5         ;get pointer to bitboard1
        mov     *r5+,r3         ;protect contents of bitboard1 and bitboard2
        mov     *r6+,r4
        inv     r3              ;AND bitboard1 with bitboard 2
        szc     r3,r4           ;inv then szc = and
        mov     r4,*r7+         ;save result in bitboard3
        mov     *r5+,r3
        mov     *r6+,r4
        inv     r3
        szc     r3,r4
        mov     r4,*r7+
        mov     *r5+,r3
        mov     *r6+,r4
        inv     r3
        szc     r3,r4
        mov     r4,*r7+
        mov     *r5,r3
        mov     *r6,r4
        inv     r3
        szc     r3,r4
        mov     r4,*r7
        mov     @procret,r11
        b       *r11

        .proc   bitor,3
;logicaly OR two bitboards
;usage: bitor(bitboard1, bitboard2, bitboard3)
;bitboard1 and bitboard2 are ORed and the result placed in bitboard3

        .ref    procret
        mov     r11,@procret
        mov     *r10+,r7        ;get pointer to bitboard3
        mov     *r10+,r6        ;get pointer to bitboard2
        mov     *r10,r5         ;get pointer to bitboard1
        mov     *r6+,r3         ;protect contents of bitboard2
        soc     *r5+,r3         ;or bitboard1 and bitboard2
        mov     r3,*r7+         ;store result in bitboard3
        mov     *r6+,r3
        soc     *r5+,r3
        mov     r3,*r7+
        mov     *r6+,r3
        soc     *r5+,r3
        mov     r3,*r7+
        mov     *r6,r3
        soc     *r5,r3
        mov     r3,*r7
        mov     @procret,r11
        b       *r11

        .proc   bitxor,3
;logically XOR two bitboards
;usage: bitxor(var bitboard1, bitboard2, bitboard3)
;bitboard1 and bitboard2 are XORed and the result placed in bitboard3

        .ref    procret
        mov     r11,@procret
        mov     *r10+,r7        ;get pointer to bitboard3
        mov     *r10+,r6        ;get pointer to bitboard2
        mov     *r10,r5         ;get pointer to bitboard1
        mov     *r6+,r4         ;xor bitboard1 and bitboard2
        xor     *r5+,r4
        mov     r4,*r7+         ;store result in bitboard3
        mov     *r6+,r4
        xor     *r5+,r4
        mov     r4,*r7+
        mov     *r6+,r4
        xor     *r5+,r4
        mov     r4,*r7+
        mov     *r6,r4
        xor     *r5,r4
        mov     r4,*r7
        mov     @procret,r11
        b       *r11
        
        .proc   rshift,3
;logically right shift a bitboard
;usage: rshift(var bitboard1, bitboard2; intnum)
;bitboard1 is logically right shifted intnum times
;the result is placed in bitboard2

        .ref    procret
        mov     r11,@procret
        mov     *r10+,r5        ;get number of shifts
        mov     *r10+,r7        ;get pointer to bitboard2
        mov     *r10,r6         ;get pointer to bitboard1
        mov     *r6+,r1         ;transfer bitboard1 to regs 1-4
        mov     *r6+,r2
        mov     *r6+,r3
        mov     *r6,r4
nxtshft srl     r4,1            ;right shift r4-r1 sequentially 1 position
        srl     r3,1
        jnc     notset1         ;transfer carry bit to next register if set
        ori     r4,8000h
notset1 srl     r2,1
        jnc     notset2
        ori     r3,8000h
notset2 srl     r1,1
        jnc     notset3
        ori     r2,8000h
notset3 dec     r5              ;done with shifts?
        jne     nxtshft
        mov     r1,*r7+         ;save shifted bitboard1 to bitboard2
        mov     r2,*r7+
        mov     r3,*r7+
        mov     r4,*r7
        mov     @procret,r11
        b       *r11
        
        .proc   lshift,3
;logically left shift a bitboard
;usage: lshift(var bitboard1, bitboard2; intnum)
;bitboard1 is logically left shifted intnum times
;the result is placed in bitboard2
        
        .ref    procret
        mov     r11,@procret
        mov     *r10+,r5        ;get number of shifts
        mov     *r10+,r7        ;get pointer to bitboard2
        mov     *r10,r6         ;get pointer to bitboard1
        mov     *r6+,r1         ;transfer bitboard1 to r1-r4
        mov     *r6+,r2
        mov     *r6+,r3
        mov     *r6,r4
newshft sla     r1,1            ;left shift r1-r4 in sequence 1 position
        sla     r2,1
        jnc     nocar1          ;transfer carry bit to previous register if set
        ori     r1,0001h
nocar1  sla     r3,1
        jnc     nocar2
        ori     r2,0001h
nocar2  sla     r4,1
        jnc     nocar3
        ori     r3,0001h
nocar3  dec     r5              ;done with shifts?
        jne     newshft
        mov     r1,*r7+         ;save shifted bitboard1 to bitboard2
        mov     r2,*r7+
        mov     r3,*r7+
        mov     r4,*r7
        mov     @procret,r11
        b       *r11
        
        .end

 

 

Spoiler
{test program for bitboard manipulation}

program bittest;

type
 bitboard = array[0..3] of integer;

var
 bit1, bit2, bitres : bitboard;
 i : integer;
 
procedure bitnot(var b1, br : integer); external;
procedure bitand(var b1, b2, br : integer); external;
procedure bitor(var b1, b2, br : integer); external;
procedure bitxor(var b1, b2, br : integer); external;
procedure rshift(var b1, br: integer; n : integer); external;
procedure lshift(var b1, br: integer; n : integer); external;

procedure bitdisp(var bitres : bitboard; n : integer);
{if n = 1 then bitboard display is shifted by 12 columns}

type
 byte = 0..255;

 dual = record
  case boolean of
   true : (value : integer);
   false : (bytes : packed array[0..1] of byte);
  end;

var
 i, j, k, y, bitpos : integer;
 bitval : dual;
 
begin
 bitpos := 256;
 y := 0;
 if n = 1 then
  begin
   y := 3;
   gotoxy(11, y);
  end;
 for i := 0 to 3 do
  begin
   bitval.value := bitres[i];
    for j := 0 to 1 do
     begin
      for k := 0 to 7 do
       begin
        bitpos := bitpos div 2;
        if ord (odd(bitval.bytes[j]) and odd(bitpos)) <> 0 then
         write('1')
        else
         write('0');
       end;
      y := succ(y);
      if n = 1 then 
       gotoxy(11, y)
      else
       writeln;
      bitpos := 256;
     end;
  end;
end; (* bitdisp *)

begin
 page(output);
 {test NOT functionality}
 for i := 0 to 3 do
  bit1[i] := 0;
  
 writeln('testing NOT functionality');
 writeln;
 writeln('initial bitboard:');
 bitdisp(bit1, 0);
 writeln;

 bitnot(bit1[0], bitres[0]);
 writeln('after NOT operation:');
 bitdisp(bitres, 0);
 readln;
 page(output);
 
 {test AND functionality}
 writeln('testing AND functionality');
 for i := 0 to 3 do
  begin
   bit1[i] := -1;
   bit2[i] := 0;
  end;

 writeln;
 writeln('initial bitboards:');
 bitdisp(bit1, 0);
 bitdisp(bit2, 1);

 bitand(bit1[0], bit2[0], bitres[0]);
 writeln;
 writeln('after AND operation:');
 bitdisp(bitres, 0);
 readln;
 page(output);
 
 {test OR functionality}
 writeln('testing OR functionality');
 writeln;
 for i := 0 to 3 do
  begin
   bit1[i] := -1;
   bit2[i] := 0;
  end;
  
 writeln('initial bitboards:');
 bitdisp(bit1, 0);
 bitdisp(bit2, 1);
 writeln;
 
 bitor(bit1[0], bit2[0], bitres[0]);
 writeln('after OR operation:');
 bitdisp(bitres, 0);
 readln;
 page(output);
 
 {test XOR functionality}
 writeln('testing XOR functionality');
 writeln;
 for i := 0 to 3 do
  begin 
   bit1[i] :=-1;
   bit2[i] := 0;
  end;
  
 writeln('initial bitboards:');
 bitdisp(bit1, 0);
 bitdisp(bit2, 1);
 writeln;
 
 bitxor(bit1[0], bit2[0], bitres[0]);
 writeln('after XOR operation:');
 bitdisp(bitres, 0);
 readln;
 page(output);
 
 {test right shift functionality}
 writeln('testing right shift functionality');
 writeln;
 for i := 0 to 3 do
  bit1[i] := -1;
  
 writeln('initial bitboard:');
 bitdisp(bit1, 0);
 writeln;
 
 rshift(bit1[0], bitres[0], 9);
 writeln('after right shift 9:');
 bitdisp(bitres, 0);
 readln;
 page(output);
 
 {test left shift functionality}
 writeln('testing left shift functionality');
 writeln;
 for i:=0 to 3 do
  bit1[i] := -1;
  
 writeln('initial bitboard');
 bitdisp(bit1, 0);
 writeln;
 
 lshift(bit1[0], bitres[0], 9);
 writeln('after left shift 9');
 bitdisp(bitres, 0);
 readln;
 page(output);
end.

 

So that seems to work quite well. I should mention that while displaying the bitboards is slow, the operations themselves are very fast.

The next issue related to bitboards is that many bitboards will need to be generated and stored in order to properly represent the state of the game, so I will likely need to leverage the SAMS card for this. Luckily I did develop a SAMS module for UCSD Pascal previously (see the Pascal thread), so that should help. 

More to come :)

 

 

  • Like 7
2 minutes ago, TheBF said:

Maybe you could just shoe-horn a small LLM into SAMS and let it learn by itself. :)

 

You do some very neat things with this old machine, I must say.

That's where the fun is! 

I have actually mulled over the idea of creating a machine learning algorithm to have the TI teach itself chess, but only very superficially, and I suspect that would require pretty large memory space where even a 1MB SAMS might not be enough. Once my move generator is complete, it might be something worth re-visiting. The key here would be to have a good evaluation function to start with. 

 

My overall goal for this project is to eventually have a chess engine that could beat Video Chess 100% of the time at its highest level. We'll see how far I get...

  • Like 3

 

 

I've finished the initialization program which generates the 112 base bitboards (896 bytes) for the game and which will run ahead of the main program. These bitboards will be used to generate many more bitboards on the fly as the game progresses for move generation, attack tables etc... using the logical operators discussed earlier. All these tables reside in the SAMS card, and below is a test program which generates the baseboards, saves them to the SAMS, then reads them back and displays them. The rendering is slow but the underlying bitboard operations are pretty speedy.

 

 

 

 

  • Like 7
  • 2 weeks later...

OK the base bitboards generation is now complete, including pre-generated movement squares for each type of piece of every board square, i.e. 64 bitboards per piece. The whole thing takes about 1 minute to complete and occupies 4.5K of SAMS space (full page and 512 bytes of subsequent page). I plan to allocate 512K for a hash table and 256K for an opening library, targeting a 1M SAMS card.

I am essentially trading memory for efficiency and speed. This is what the SAMS card was born to do :)

Next is coming up with a good evaluation function, the hardest aspect of chess engine programming. How does one approximate the intuitive thinking of a human? Lots of research ahead...

 

 

 

  • Like 6

You are aware of that if you have to integers, a and b, the inversion of a will end up in b if you do

 

b := ord(not(odd(a)));

 

Lines like

c := ord(odd(a) and odd(b));

are also allowed.

 

You should also be aware of the moveleft, moveright and fillchar intrinsics availalbe in Pascal. There's also scan that may be useful.

Doing your own assembly is of course good too, and can be even faster, but these commands may make it possible to test things on Pascal level without sacrificing too much speed.

 

Explanation: In UCSD Pascal, the function odd does nothing more than return the state of the least significant bit and allow you to treat the operator as a logical value.

In a similar way, the function ord applied to a logical value does nothing  more than allow you to treat it as an integer.

In neither case are the values themselves changed.

  • Like 2
11 hours ago, Vorticon said:

I plan to allocate 512K for a hash table and 256K for an opening library, targeting a 1M SAMS card.

I don't know what your hashing method will be but text books say making the size of the hash table a prime number will reduce collisions.

  • Like 1
3 hours ago, TheBF said:

I don't know what your hashing method will be but text books say making the size of the hash table a prime number will reduce collisions.

I only have a high level concept of the move hash tables at this point but I did come across that. Priority for now is to design the evaluation function and search algorithms. The hash tables' impact will really be on efficiency of search but not on quality of play, so they are on a lower priority. Baby steps :)

  • Like 3
4 hours ago, apersson850 said:

You are aware of that if you have to integers, a and b, the inversion of a will end up in b if you do

 

b := ord(not(odd(a)));

 

Lines like

c := ord(odd(a) and odd(b));

are also allowed.

 

You should also be aware of the moveleft, moveright and fillchar intrinsics availalbe in Pascal. There's also scan that may be useful.

Doing your own assembly is of course good too, and can be even faster, but these commands may make it possible to test things on Pascal level without sacrificing too much speed.

 

Explanation: In UCSD Pascal, the function odd does nothing more than return the state of the least significant bit and allow you to treat the operator as a logical value.

In a similar way, the function ord applied to a logical value does nothing  more than allow you to treat it as an integer.

In neither case are the values themselves changed.

Yup I use ORD in my bitboard display function that way. Strange way of doing things but it works. There is a good explanation in the Advanced UCSD Pascal Programming book.

  • Like 2

It was invented due to the desire to be able to use UCSD Pascal as a language to write an operating system with. That requires some special functions, like bitwise logical operations, things they wanted to include into the language without modifying it more than necessary.

  • Like 2

As I was working on the move generation algorithm, I came across a thorny problem:

With bitboards, generating movement lists is relatively easy. Retrieve the pre-generated movement bitboard for the piece of interest on the square it is on, XOR it with the automatically maintained bitboard of all the pieces of the same color, and the result is a bitboard with all the legal squares that piece can move to, including captures. However, with the sliding pieces (rook, bishop and queen) it's not quite so simple. For example, below is the movement bitboard for a queen in the middle of the board:

 

 

 

 

1

 

 

 

1

1

 

 

1

 

 

1

 

 

1

 

1

 

1

 

 

 

 

1

1

1

 

 

 

1

1

1

Q

1

1

1

1

 

 

1

1

1

 

 

 

 

1

 

1

 

1

 

 

1

 

 

1

 

 

1

 

 

Here is the bitboard of all the pieces of the same color (blocking pieces)

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

XORing these 2 bitboards together gives us this bitboard:

 

 

 

 

1

 

 

 

1

1

 

 

 

 

 

1

 

 

1

 

1

 

1

 

 

 

 

 

1

1

 

 

 

1

1

1

Q

1

1

1

 

 

 

1

1

1

 

 

 

 

 

 

1

 

1

 

 

1

 

 

1

 

 

1

 

 

You can immediately see that the movement rays continue beyond where the blocking pieces were unless they are on the edge of the board, and that was definitely not trivial to fix. While there was a way to do this in straight Pascal, it was way too slow and I ended up coding a ray trimming routine in assembly. One of the difficulties was due to the fact that a bitboard is represented by an array of 4 words, and it was necessary to be able to figure out which byte and offset to that byte a particular bit of interest was located across the entire array. Luckily this was not too dissimilar to accessing the individual pixels on the bitmap screen, which I had ample experience with previously, so that helped. Here's what the final movement bitboard would look like in this case:

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

1

 

 

 

 

1

 

1

 

 

 

 

 

1

1

 

 

 

1

1

1

Q

1

1

1

 

 

 

1

1

1

 

 

 

 

 

 

1

 

1

 

 

 

 

 

1

 

 

1

 

 

Regardless, it is not hard to see how useful and efficient bitboards are in chess...

 

  • Like 4

Preliminary move generation test: the program can generate all the legal moves for all the pieces on both sides (2 ply or 1 turn) in 4.25 seconds. Not bad... Mind you this is likely to get (much) longer once we add an evaluation function into the mix and we go deeper into the search tree, but it's an encouraging result which is already significantly faster than the miserable original iteration of this project. I'm attaching the disk image in case someone wants to browse the source files, but it's probably going to be difficult to follow at this stage.

 

PHOENIX.dsk

  • Like 3

I was thinking of your work with bit tables and I remembered I found this thing in Forth to find the first bit.

Maybe it would be useful, if you coded it up in Assembler. ??

??

\ sourec: https://forth.sourceforge.net/algorithm/firstbit/index.html

\ explanation: 
\ sourec: https://forth.sourceforge.net/algorithm/firstbit/index.html

\ Let us consider the 1st set bit. 
\ On the first step, DUP 1 RSHIFT OR, it gets copied to the bit that follows it. 
\ On the 2nd step, it gets copies to the two bits that follow the two bits mentioned on the previous step. 
\ And so on. Finally, all bits below the first set bit become set. 
\ Then, 1 RSHIFT XOR clears all set bits except the very 1st one.

DECIMAL 
: FIRSTBIT ( number -- firstbit )
        DUP  1 RSHIFT OR
        DUP  2 RSHIFT OR
        DUP  4 RSHIFT OR
        DUP  8 RSHIFT OR
        DUP 16 RSHIFT OR
        DUP  1 RSHIFT XOR
;

 

  • Like 2
4 hours ago, TheBF said:

I was thinking of your work with bit tables and I remembered I found this thing in Forth to find the first bit.

Maybe it would be useful, if you coded it up in Assembler. ??

??

\ sourec: https://forth.sourceforge.net/algorithm/firstbit/index.html

\ explanation: 
\ sourec: https://forth.sourceforge.net/algorithm/firstbit/index.html

\ Let us consider the 1st set bit. 
\ On the first step, DUP 1 RSHIFT OR, it gets copied to the bit that follows it. 
\ On the 2nd step, it gets copies to the two bits that follow the two bits mentioned on the previous step. 
\ And so on. Finally, all bits below the first set bit become set. 
\ Then, 1 RSHIFT XOR clears all set bits except the very 1st one.

DECIMAL 
: FIRSTBIT ( number -- firstbit )
        DUP  1 RSHIFT OR
        DUP  2 RSHIFT OR
        DUP  4 RSHIFT OR
        DUP  8 RSHIFT OR
        DUP 16 RSHIFT OR
        DUP  1 RSHIFT XOR
;

 

Interesting. The way I implemented my bit search routine is as below, with the understanding that a bitboard is 8 bytes with the LSB of byte 7 being position 63 (right uppermost square on chess board) and MSB of byte 0 being position 0 (lower leftmost square):

 

;bitboard is at location bitbrd1
;r5 has loc, the position of desired bit in bitboard (0..63) 

bittab  .byte   128,64,32,16,8,4,2,1   ;bit mask table
bitbrd1 .block  8

bitchk  mov     r11,@subrtn2
        clr     r7              ;clear index to bittab
        mov     r5,r6           ;save loc value
        srl     r5,3            ;calculate byte displacement (loc DIV 8)
        mov     r5,r4           ;save byte displacement
        sla     r5,3            ;byte displacement * 8 = clean byte boundary
nxtbit  c       r5,r6           ;are we at loc?
        jeq     fndbit
        inc     r5              ;add a bit to the byte
        inc     r7              ;advance bit mask table index
        jmp     nxtbit
fndbit  ai      r4,bitbrd1      ;point to displacement byte in bitboard
        clr     r5
        movb    *r4,r5          ;get content of byte
        clr     r6
        movb    @bittab(r7),r6  ;select appropriate bitmask
        inv     r6              ;AND bit mask with displacement byte (INV then SZCB)
        szcb    r6,r5           ;high byte of r5 has value of displacement bit. 
                                ;a byte compare to 0 will indicate if bit is set or reset
        mov     @subrtn2,r11
        b       *r11

 

Now your suggestion gave me an idea that is efficient and does not need assembly! In Pascal, I would select the bitboard representing the desired square to be checked (loc) and AND it with the bitboard I need to check, resulting in a cleared bitboard that preserves the value of the bit at loc. RSHIFT that bitboard 63-loc and read the value of the last byte in the bitboard, either a 0 or 1. (Technically though this is not pure Pascal since the logical bitboard ops are implemented in assembly :) )

For example, if we have that bitboard:

 

 

 

 

1

 

 

 

1

1

 

 

1

 

 

1

 

 

1

 

1

 

1

 

 

 

 

1

1

1

 

 

 

1

1

1

 

1

1

1

1

 

 

1

1

1

 

 

 

 

1

 

1

 

1

 

 

1

 

 

1

 

 

1

 

 

And we are interested in that particular bit (loc = 34) - There is a pre-generated bitboard for each square on the chess board

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ANDing the two boards yields this:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Finally RSHIFT 63-34 = 29 and we get

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

So the least significant bit in the last byte of the bitboard now has the state of the loc bit. 

 

  • Like 3
13 hours ago, Vorticon said:
;bitboard is at location bitbrd1
;r5 has loc, the position of desired bit in bitboard (0..63) 

bittab  .byte   128,64,32,16,8,4,2,1   ;bit mask table
bitbrd1 .block  8

bitchk  mov     r11,@subrtn2	NOT NEEDED, SINCE THERE'S NO BL IN THIS PROCEDURE
        clr     r7              ;clear index to bittab
        mov     r5,r6           ;save loc value
        srl     r5,3            ;calculate byte displacement (loc DIV 8)
        mov     r5,r4           ;save byte displacement
        sla     r5,3            ;byte displacement * 8 = clean byte boundary
nxtbit  c       r5,r6           ;are we at loc?
        jeq     fndbit
        inc     r5              ;add a bit to the byte
        inc     r7              ;advance bit mask table index
        jmp     nxtbit
fndbit  ai      r4,bitbrd1      ;point to displacement byte in bitboard		YOU CAN SKIP THIS INSTRUCTION
        clr     r5
        movb    *r4,r5          ;get content of byte		USE MOVB @BITBRD1(R4),R5
        clr     r6
        movb    @bittab(r7),r6  ;select appropriate bitmask
        inv     r6              ;AND bit mask with displacement byte (INV then SZCB)
        szcb    r6,r5           ;high byte of r5 has value of displacement bit. 
                                ;a byte compare to 0 will indicate if bit is set or reset
        mov     @subrtn2,r11	NOT NEEDED, SINCE THERE'S NO BL IN THIS PROCEDURE
        b       *r11

 

 

 

I had a look at that code. I entered some suggestions in CAPITAL letters. It will save you a few clock cycles, unless there's more going on around that procedure that requires your instructions to be there.

  • Like 2
6 hours ago, apersson850 said:

I had a look at that code. I entered some suggestions in CAPITAL letters. It will save you a few clock cycles, unless there's more going on around that procedure that requires your instructions to be there.

Thanks! This routine is actually a subroutine for another assembly subroutine, so saving and restoring R11 is necessary. 

5 hours ago, Gary from OPA said:

Nanochess (author of CVBasic) has done an amazing chess game in x86 and JavaScript. The AI is not bad. I wonder if some of his AI logic could be adapted to your Pascal chess.

 

 

Yes I've seen that and it's an incredible achievement. Understanding what's going on under the hood there is another matter entirely however, and probably well above my pay grade.

  • Like 1
40 minutes ago, Vorticon said:

Thanks! This routine is actually a subroutine for another assembly subroutine, so saving and restoring R11 is necessary. 

 

Not so. @apersson850 is correct. You are not changing R11 in that subroutine, so it is redundant and wasteful to save/restore it.

 

...lee

  • Like 2
12 hours ago, Lee Stewart said:

 

Not so. @apersson850 is correct. You are not changing R11 in that subroutine, so it is redundant and wasteful to save/restore it.

 

...lee

Ah I see it now since it's the last subroutine level called. I'll make change. Every saved cycle counts! Thanks.

  • Like 4

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...