// http://lists.freepascal.org/lists/fpc-devel/2008-June/013919.html

uses SysUtils;
{$ASSERTIONS ON}
type
    bit = 0..1;
    t6bit = 0..63;

    ByteBoundary = bitpacked record
        bit0 : bit;
        bit1_8 : byte;
        bit9_15 : t6bit;
    end;

    TestByteBoundary = record
        case boolean of
            false : (AsWord : word);
            true : (AsBits : ByteBoundary);
    end;


procedure TestBits(b0 : bit; b1_8 : byte; b9_15 : t6bit);
var
    Test : TestByteBoundary;
    w : word;
begin
{$ifdef fpc_little_endian}
    w :=  b0 + b1_8 shl 1 + b9_15 shl 9;
{$else}
    w := b0 shl (16-1) + b1_8 shl (15-8) + b9_15 shl 1; 
{$endif}
    with Test, asBits do begin
        bit0 := b0;
        bit1_8 := b1_8;
        bit9_15 := b9_15;
{$ifdef fpc_little_endian}
        Writeln('Test : $', b0, ' + $', IntToHex(b1_8,2), ' << 1 + $',IntToHex(b9_15,2),' << 9');
        write('  Expected : $',IntToHex(w,4),' Got : $',IntToHex((AsWord and $7fff),4));
        if w = (Asword and $7fff) then
{$else}
        Writeln('Test : $', b0, '<< 15 + $', IntToHex(b1_8,2), ' << 6 + $',IntToHex(b9_15,2),' << 1');
        write('  Expected : $',IntToHex(w,4),' Got : $',IntToHex((AsWord and $fffe),4));
        if w = (Asword and $fffe) then
{$endif}
            writeln(' OK')
        else
          begin
            writeln(' <--- Fail');
            halt(1);
          end;
    end;
end;


procedure testproc;
var
    Test : TestByteBoundary;
begin

   Test.AsBits.bit0 := 0;
   Test.AsBits.bit1_8 := $FF;
   Test.AsBits.bit9_15 := 0;
   writeln(IntToHex(Test.AsWord,4));



   TestBits($1, $80, $00);
   TestBits($1, $FE, $00);
   TestBits($1, $FF, $00);


  // These work
   Test.AsBits.bit0 := 1;
   Test.AsBits.bit1_8 := $80;
   Test.AsBits.bit9_15 := 0;

{$ifdef fpc_little_endian}
   assert((Test.AsWord and $7fff) = $0101, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $0101');

   Test.AsBits.bit1_8 := $FE;
   assert((Test.AsWord and $7fff) = $01FD, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $01FD');

   // DOES NOT WORK ...
   Test.AsBits.bit1_8 := 255;
   assert((Test.AsWord and $7fff) = $01FF, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $01FF');

   // Rest OK
   Test.AsWord := 0;
   Test.AsBits.bit9_15 := 1;
   assert((Test.AsWord and $7fff) = $0200, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $0200');

   Test.AsBits.bit9_15 := 32;
   assert((Test.AsWord and $7fff) = $4000, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $4000');

   Test.AsBits.bit9_15 := 62;
   assert((Test.AsWord and $7fff) = $7C00, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $7C00');

   Test.AsBits.bit9_15 := 63;   // Correct
   assert((Test.AsWord and $7fff) = $7E00, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $7E00');

   Test.AsBits.bit0 := 1;
   Test.AsBits.bit1_8 := 255;
   Test.AsBits.bit9_15 := 63;
   assert((Test.AsWord and $7fff) = $7FFF, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $7FFF');
{$else}
   assert((Test.AsWord and $fffe) = $c000, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $C001');

   Test.AsBits.bit1_8 := $FE;
   assert((Test.AsWord and $fffe) = $FF00, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $FF00');

   // DOES NOT WORK ...
   Test.AsBits.bit1_8 := 255;
   assert((Test.AsWord and $fffe) = $FF80, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $FF80');

   // Rest OK
   Test.AsWord := 0;
   Test.AsBits.bit9_15 := 1;
   assert((Test.AsWord and $fffe) = $0002, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $0002');

   Test.AsBits.bit9_15 := 32;
   assert((Test.AsWord and $fffe) = $0040, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $0040');

   Test.AsBits.bit9_15 := 62;
   assert((Test.AsWord and $fffe) = $007C, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $007C');

   Test.AsBits.bit9_15 := 63;   // Correct
   assert((Test.AsWord and $fffe) = $007E, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $007E');

   Test.AsBits.bit0 := 1;
   Test.AsBits.bit1_8 := 255;
   Test.AsBits.bit9_15 := 63;
   assert((Test.AsWord and $fffe) = $FFFE, 'Is: ' + IntToHex(Test.AsWord,4) + ' Should be $FFFE');
{$endif}
end;


var
    Test : TestByteBoundary;
begin

    with Test, AsBits do begin



       bit0 := 0;
       bit1_8 := $FF;
       bit9_15 := 0;
       writeln(IntToHex(AsWord,4));



       TestBits($1, $80, $00);
       TestBits($1, $FE, $00);
       TestBits($1, $FF, $00);
       TestBits($0, $00, $01);


      // These work
       bit0 := 1;
       bit1_8 := $80;
       bit9_15 := 0;

{$ifdef fpc_little_endian}
       assert((AsWord and $7fff) = $0101, 'Is: ' + IntToHex(Asword,4) + ' Should be $0101');

       bit1_8 := $FE;
       assert((AsWord and $7fff) = $01FD, 'Is: ' + IntToHex(Asword,4) + ' Should be $01FD');

       // DOES NOT WORK ...
       bit1_8 := 255;
       assert((AsWord and $7fff) = $01FF, 'Is: ' + IntToHex(Asword,4) + ' Should be $01FF');

       // Rest OK
       AsWord := 0;
       bit9_15 := 1;
       assert((AsWord and $7fff) = $0200, 'Is: ' + IntToHex(Asword,4) + ' Should be $0200');

       bit9_15 := 32;
       assert((AsWord and $7fff) = $4000, 'Is: ' + IntToHex(Asword,4) + ' Should be $4000');

       bit9_15 := 62;
       assert((AsWord and $7fff) = $7C00, 'Is: ' + IntToHex(Asword,4) + ' Should be $7C00');

       bit9_15 := 63;   // Correct
       assert((AsWord and $7fff) = $7E00, 'Is: ' + IntToHex(Asword,4) + ' Should be $7E00');

       bit0 := 1;
       bit1_8 := 255;
       bit9_15 := 63;
       assert((AsWord and $7fff) = $7FFF, 'Is: ' + IntToHex(Asword,4) + ' Should be $7FFF');
{$else}
       assert((AsWord and $fffe) = $c000, 'Is: ' + IntToHex(Asword,4) + ' Should be $C000');

       bit1_8 := $FE;
       assert((AsWord and $fffe) = $FF00, 'Is: ' + IntToHex(Asword,4) + ' Should be $FF00');

       // DOES NOT WORK ...
       bit1_8 := 255;
       assert((AsWord and $fffe) = $FF80, 'Is: ' + IntToHex(Asword,4) + ' Should be $FF80');

       // Rest OK
       AsWord := 0;
       bit9_15 := 1;
       assert((AsWord and $fffe) = $0002, 'Is: ' + IntToHex(Asword,4) + ' Should be $0002');

       bit9_15 := 32;
       assert((AsWord and $fffe) = $0040, 'Is: ' + IntToHex(Asword,4) + ' Should be $0040');

       bit9_15 := 62;
       assert((AsWord and $fffe) = $007C, 'Is: ' + IntToHex(Asword,4) + ' Should be $007C');

       bit9_15 := 63;   // Correct
       assert((AsWord and $fffe) = $007E, 'Is: ' + IntToHex(Asword,4) + ' Should be $007E');

       bit0 := 1;
       bit1_8 := 255;
       bit9_15 := 63;
       assert((AsWord and $fffe) = $FFFE, 'Is: ' + IntToHex(Asword,4) + ' Should be $FFFE');
{$endif}

    end;
    testproc;
end.

