OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [tests/] [rtl/] [TestDivisionAlgorithm.cpp] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
// Copyright Jamie Iles, 2017
2
//
3
// This file is part of s80x86.
4
//
5
// s80x86 is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// s80x86 is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with s80x86.  If not, see <http://www.gnu.org/licenses/>.
17
 
18
#include <string>
19
#include <vector>
20
 
21
#include <gtest/gtest.h>
22
 
23
template <typename T1, typename T2>
24
struct DivTest {
25
    T1 v1;
26
    T2 v2;
27
    T2 quotient;
28
    T2 remainder;
29
};
30
 
31
using Div8Params = struct DivTest<uint16_t, uint8_t>;
32
using Div16Params = struct DivTest<uint32_t, uint16_t>;
33
using IDiv8Params = struct DivTest<int16_t, int8_t>;
34
using IDiv16Params = struct DivTest<int32_t, int16_t>;
35
 
36
template <typename T>
37
struct SignMagnitude {
38
    bool is_negative;
39
    T magnitude;
40
};
41
 
42
template <typename UT, typename ST>
43
SignMagnitude<UT> twos_comp_to_sm(UT v)
44
{
45
    SignMagnitude<UT> r;
46
 
47
    r.is_negative = v < 0;
48
 
49
    const ST mask = static_cast<ST>(v) >> ((sizeof(ST) * 8) - 1);
50
    r.magnitude = (static_cast<UT>(v) + mask) ^ mask;
51
 
52
    return r;
53
}
54
 
55
// Non-restoring division
56
std::tuple<uint16_t, uint16_t> divide(uint32_t dividend,
57
                                      uint16_t divisor,
58
                                      bool is_signed = false)
59
{
60
    int64_t P;
61
    uint32_t D;
62
    SignMagnitude<uint32_t> dividend_sm =
63
        twos_comp_to_sm<uint32_t, int32_t>(dividend);
64
    SignMagnitude<uint16_t> divisor_sm =
65
        twos_comp_to_sm<uint16_t, int16_t>(divisor);
66
 
67
    if (!is_signed) {
68
        P = static_cast<int64_t>(dividend);
69
        D = static_cast<uint32_t>(divisor) << 16;
70
    } else {
71
        P = static_cast<int64_t>(dividend_sm.magnitude);
72
        D = static_cast<uint32_t>(divisor_sm.magnitude) << 16;
73
    }
74
 
75
    uint16_t q = 0;
76
 
77
    for (int i = 15; i >= 0; --i) {
78
        if (P >= 0) {
79
            q |= (1 << i);
80
            P = (2 * P) - D;
81
        } else {
82
            P = (2 * P) + D;
83
        }
84
    }
85
 
86
    q -= ~q;
87
 
88
    if (P < 0) {
89
        --q;
90
        P += D;
91
    }
92
 
93
    return std::tuple<uint16_t, uint16_t>(q, P >> 16);
94
}
95
 
96
// Non-restoring division
97
std::tuple<int16_t, int16_t> idivide(int32_t dividend, int16_t divisor)
98
{
99
    int16_t quotient, remainder;
100
    std::tie(quotient, remainder) = divide(
101
        static_cast<uint32_t>(dividend), static_cast<uint16_t>(divisor), true);
102
 
103
    if ((dividend < 0 && divisor >= 0) || (dividend >= 0 && divisor < 0))
104
        quotient = -quotient;
105
    if (dividend < 0)
106
        remainder = -remainder;
107
 
108
    return std::tuple<int16_t, int16_t>(quotient, remainder);
109
}
110
 
111
class DivisionAlg16 : public ::testing::TestWithParam<Div16Params>
112
{
113
};
114
TEST_P(DivisionAlg16, Result)
115
{
116
    uint16_t quotient, remainder;
117
 
118
    std::tie(quotient, remainder) = divide(GetParam().v1, GetParam().v2);
119
    EXPECT_EQ(quotient, GetParam().quotient);
120
    EXPECT_EQ(remainder, GetParam().remainder);
121
}
122
INSTANTIATE_TEST_CASE_P(Div,
123
                        DivisionAlg16,
124
                        ::testing::Values(Div16Params{100, 20, 5, 0},
125
                                          Div16Params{500, 250, 2, 0},
126
                                          Div16Params{10, 3, 3, 1},
127
                                          Div16Params{128000, 10, 12800, 0},
128
                                          Div16Params{130000, 65000, 2, 0},
129
                                          Div16Params{0x109, 0xe90b, 0, 265}));
130
 
131
class IDivisionAlg16 : public ::testing::TestWithParam<IDiv16Params>
132
{
133
};
134
TEST_P(IDivisionAlg16, Result)
135
{
136
    int16_t quotient, remainder;
137
 
138
    std::tie(quotient, remainder) = idivide(GetParam().v1, GetParam().v2);
139
    EXPECT_EQ(quotient, GetParam().quotient);
140
    EXPECT_EQ(remainder, GetParam().remainder);
141
}
142
INSTANTIATE_TEST_CASE_P(IDiv,
143
                        IDivisionAlg16,
144
                        ::testing::Values(IDiv16Params{10, 3, 3, 1},
145
                                          IDiv16Params{10, -3, -3, 1},
146
                                          IDiv16Params{-10, -3, 3, -1},
147
                                          IDiv16Params{-10, 3, -3, -1}));

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.