program ablastest;

{$MODE FPC}
uses ablas, ap;

const
    NMAX = 40;
    RKindCount = 8;
    RNames : array [0..RKindCount-1] of String = (
        'DotProduct',
        'Move',
        'MoveS',
        'MoveNeg',
        'Add',
        'Sub',
        'AddS',
        'MulS');
    Eps = 1.0E-14;

procedure ProcessArrays(
    pA1: PDouble; I11, I12: Integer;
    pB1: PDouble; J11, J12: Integer;
    var V1: Double;
    pA2: PDouble; I21, I22: Integer;
    pB2: PDouble; J21, J22: Integer;
    var V2: Double;
    RKind: Integer);
var
    S: Real;
begin
    Assert(I22-I21=J22-J21, 'ProcessArrays: different sizes!');
    V1:=0;
    V2:=0;
    S:=2*RandomReal()-1;

    if RKind=0 then
    begin
        V1:=APVDotProduct(pA1, I11, I12, pB1, J11, J12);
        V2:=ASMDotProduct1(pA2+I21, pB2+J21, I22-I21+1);
    end;
    if RKind=1 then
    begin
        APVMove(pA1, I11, I12, pB1, J11, J12);
        ASMMove1(pA2+I21, pB2+J21, I22-I21+1);
    end;
    if RKind=2 then
    begin
        APVMove(pA1, I11, I12, pB1, J11, J12, S);
        ASMMoveS1(pA2+I21, pB2+J21, I22-I21+1, S);
    end;
    if RKind=3 then
    begin
        APVMoveNeg(pA1, I11, I12, pB1, J11, J12);
        ASMMoveNeg1(pA2+I21, pB2+J21, I22-I21+1);
    end;
    if RKind=4 then
    begin
        APVAdd(pA1, I11, I12, pB1, J11, J12);
        ASMAdd1(pA2+I21, pB2+J21, I22-I21+1);
    end;
    if RKind=5 then
    begin
        APVSub(pA1, I11, I12, pB1, J11, J12);
        ASMSub1(pA2+I21, pB2+J21, I22-I21+1);
    end;
    if RKind=6 then
    begin
        APVAdd(pA1, I11, I12, pB1, J11, J12, S);
        ASMAddS1(pA2+I21, pB2+J21, I22-I21+1, S);
    end;
    if RKind=7 then
    begin
        APVMul(pA1, I11, I12, S);
        ASMMulS1(pA2+I21, I22-I21+1, S);
    end;
end;

procedure TestABLAS();
var
    a1, a2: array [0..NMAX*8-1+16] of Char;
    b1, b2: array [0..NMAX*8-1+16] of Char;
    V1, V2: Double;
    pA1, pA2, pB1, pB2: PDouble;
    Shift1, Shift2:  Integer;
    SSEFlag, RKind, N, Pass, PassCount, I1, I2, I: Integer;
    WasErrors: array [0..RKindCount-1] of Boolean;
begin
    WriteLn('TESTING AP BLAS (IA-32 ASSEMBLER VERSION)');
    for RKind:=0 to RKindCount-1 do
        WasErrors[RKind]:=False;
    PassCount:=4;

    //
    // Testing
    //
    for Shift1:=0 to 15 do
        for Shift2:=0 to 15 do
        begin
            //
            // Shift pointers
            //
            pA1:=PDouble(@(a1[Shift1]));
            pA2:=PDouble(@(a2[Shift1]));
            pB1:=PDouble(@(b1[Shift2]));
            pB2:=PDouble(@(b2[Shift2]));
            for N:=0 to NMAX-8 do
                for RKind:=0 to RKindCount-1 do
                    for SSEFlag:=0 to 1 do
                        for Pass:=0 to PassCount-1 do
                        begin
                            UseSSE2IfPresent:=SSEFlag<>0;

                            //
                            // Random I1, I2
                            //
                            I1:=Random(NMAX+1-N);
                            I2:=Random(NMAX+1-N);

                            //
                            // Initialize arrays
                            //
                            for I:=0 to NMAX-1 do
                            begin
                                pA1[I]:=2*Random()-1;
                                pA2[I]:=pA1[I];
                                pB1[I]:=2*Random()-1;
                                pB2[I]:=pB1[I];
                            end;

                            //
                            // Pass to routine
                            //
                            ProcessArrays(
                                pA1, I1, I1+N-1,
                                pB1, I2, I2+N-1,
                                V1,
                                pA2, I1, I1+N-1,
                                pB2, I2, I2+N-1,
                                V2,
                                RKind);

                            //
                            // Test
                            //
                            for I:=0 to NMAX-1 do
                            begin
                                WasErrors[RKind] := WasErrors[RKind] or (Abs(pA1[I]-pA2[I])>Eps);
                                {if WasErrors[RKind] then
                                begin
                                    WriteLn('A-class error');
                                    WriteLn('N:       ', N);
                                    WriteLn('SSEFlag: ', SSEFlag);
                                    WriteLn('Shift1:  ', Shift1);
                                    WriteLn('Shift2:  ', Shift2);
                                    Exit;
                                end;}
                                WasErrors[RKind] := WasErrors[RKind] or (Abs(pB1[I]-pB2[I])>Eps);
                                {if WasErrors[RKind] then
                                begin
                                    WriteLn('B-class error');
                                    WriteLn('N:       ', N);
                                    WriteLn('SSEFlag: ', SSEFlag);
                                    WriteLn('Shift1:  ', Shift1);
                                    WriteLn('Shift2:  ', Shift2);
                                    Exit;
                                end;}
                            end;
                            WasErrors[RKind] := WasErrors[RKind] or (Abs(V1-V2)>Eps);
                                {if WasErrors[RKind] then
                                begin
                                    WriteLn('B-class error');
                                    WriteLn('N:       ', N);
                                    WriteLn('SSEFlag: ', SSEFlag);
                                    WriteLn('Shift1:  ', Shift1);
                                    WriteLn('Shift2:  ', Shift2);
                                    WriteLn('V1:  ', V1);
                                    WriteLn('V2:  ', V2);
                                    Exit;
                                end;}
                        end;
        end;

    //
    // Output results
    //
    for RKind:=0 to RKindCount-1 do
    begin
        Write(RNames[RKind]);
        for I:=0 to 25-Length(RNames[RKind]) do
            Write(' ');
        if WasErrors[RKind] then
            WriteLn('FAILED')
        else
            WriteLn('OK');
    end;
end;

begin
    TestABLAS();
end.
