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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [tests/] [rtl/] [TestLoadStore.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 <gtest/gtest.h>
19
#include <VLoadStore.h>
20
#include <map>
21
#include <memory>
22
 
23
#include "VerilogTestbench.h"
24
 
25
using physaddr = uint32_t;
26
 
27
class LoadStoreTestbench : public VerilogTestbench<VLoadStore>,
28
                           public ::testing::Test
29
{
30
public:
31
    enum MemWidth { WIDTH_8, WIDTH_16 };
32
 
33
    LoadStoreTestbench();
34
    void add_memory(physaddr start, const std::vector<uint8_t> &bytes);
35
    std::vector<uint16_t> get_read_values() const
36
    {
37
        return read_values;
38
    }
39
    void write_mar(physaddr address)
40
    {
41
        after_n_cycles(0, [&] {
42
            this->dut.mar_in = address;
43
            this->dut.write_mar = 1;
44
            after_n_cycles(0, [&] {
45
                this->dut.write_mar = 0;
46
                this->dut.mar_in = 0;
47
            });
48
        });
49
        cycle();
50
    }
51
    void write_mdr(physaddr address)
52
    {
53
        after_n_cycles(0, [&] {
54
            this->dut.mdr_in = address;
55
            this->dut.write_mdr = 1;
56
            after_n_cycles(1, [&] {
57
                this->dut.write_mdr = 0;
58
                this->dut.mdr_in = 0;
59
            });
60
        });
61
        cycle();
62
    }
63
    void read(MemWidth width)
64
    {
65
        access(width, false);
66
    }
67
    void write(MemWidth width)
68
    {
69
        access(width, true);
70
    }
71
    std::map<physaddr, uint8_t> mem_bytes;
72
 
73
private:
74
    void access(MemWidth width, bool write)
75
    {
76
        after_n_cycles(0, [&] {
77
            this->dut.is_8bit = width == WIDTH_8;
78
            this->dut.start = 1;
79
            this->dut.wr_en = write;
80
            after_n_cycles(1, [&] { this->dut.start = 0; });
81
        });
82
        for (auto i = 0; i < 100; ++i) {
83
            cycle();
84
            if (dut.complete)
85
                return;
86
        }
87
 
88
        FAIL() << "failed to complete memory operation" << std::endl;
89
    }
90
    std::vector<uint16_t> read_values;
91
    bool reading;
92
    bool writing;
93
};
94
 
95
LoadStoreTestbench::LoadStoreTestbench() : reading(false), writing(false)
96
{
97
    reset();
98
 
99
    periodic(ClockCapture, [&] {
100
        if (!this->dut.reset && this->dut.complete && !this->dut.wr_en)
101
            read_values.push_back(this->dut.mdr_out);
102
    });
103
    periodic(ClockSetup, [&] {
104
        if (!this->dut.reset && this->dut.m_access && !reading &&
105
            !this->dut.wr_en) {
106
            reading = true;
107
            if (mem_bytes.find(this->dut.m_addr << 1) == mem_bytes.end())
108
                FAIL() << "no memory at 0x" << std::hex << this->dut.m_addr;
109
            after_n_cycles(4, [&] {
110
                this->dut.m_data_in =
111
                    mem_bytes[this->dut.m_addr << 1] |
112
                    (mem_bytes[(this->dut.m_addr << 1) + 1] << 8);
113
                this->dut.m_ack = 1;
114
                after_n_cycles(1, [&] {
115
                    this->dut.m_ack = 0;
116
                    reading = false;
117
                });
118
            });
119
        }
120
    });
121
    periodic(ClockSetup, [&] {
122
        if (!this->dut.reset && this->dut.m_access && !writing &&
123
            this->dut.wr_en) {
124
            writing = true;
125
            after_n_cycles(4, [&] {
126
                if (this->dut.m_bytesel & 0x1)
127
                    this->mem_bytes[this->dut.m_addr << 1] =
128
                        this->dut.m_data_out & 0xff;
129
                if (this->dut.m_bytesel & 0x2)
130
                    this->mem_bytes[(this->dut.m_addr << 1) + 1] =
131
                        (this->dut.m_data_out >> 8) & 0xff;
132
                this->dut.m_ack = 1;
133
                after_n_cycles(1, [&] {
134
                    this->dut.m_ack = 0;
135
                    writing = false;
136
                });
137
            });
138
        }
139
    });
140
}
141
 
142
void LoadStoreTestbench::add_memory(physaddr start,
143
                                    const std::vector<uint8_t> &bytes)
144
{
145
    auto addr = start;
146
 
147
    for (auto b : bytes)
148
        mem_bytes[addr++] = b;
149
}
150
 
151
TEST_F(LoadStoreTestbench, SegmentCalculation)
152
{
153
    this->dut.segment = 0x800;
154
    write_mar(0x100);
155
 
156
    cycle();
157
 
158
    ASSERT_EQ(this->dut.m_addr, ((0x800 << 4) + 0x100LU) >> 1);
159
}
160
 
161
TEST_F(LoadStoreTestbench, SegmentNoWrap)
162
{
163
    this->dut.segment = 0;
164
    add_memory(0xfffe, {0xee, 0x55});
165
    add_memory(0x10000, {0xaa, 0xff});
166
 
167
    write_mar(0xffff);
168
    read(WIDTH_16);
169
 
170
    ASSERT_EQ(get_read_values(), std::vector<uint16_t>{0xaa55});
171
}
172
 
173
struct LoadParams {
174
    physaddr mar_value;
175
    LoadStoreTestbench::MemWidth width;
176
    std::vector<uint16_t> values;
177
};
178
 
179
class LoadTest : public LoadStoreTestbench,
180
                 public ::testing::WithParamInterface<LoadParams>
181
{
182
};
183
 
184
TEST_P(LoadTest, LoadMemory)
185
{
186
    auto params = GetParam();
187
 
188
    add_memory(0xff, {0xff, 0x55, 0xaa, 0xff});
189
 
190
    write_mar(params.mar_value);
191
    read(params.width);
192
 
193
    ASSERT_EQ(get_read_values(), params.values);
194
}
195
INSTANTIATE_TEST_CASE_P(
196
    Load,
197
    LoadTest,
198
    ::testing::Values(
199
        LoadParams{0x100U, LoadStoreTestbench::MemWidth::WIDTH_16, {0xaa55}},
200
        LoadParams{0x101U, LoadStoreTestbench::MemWidth::WIDTH_16, {0xffaa}},
201
        LoadParams{0x100U, LoadStoreTestbench::MemWidth::WIDTH_8, {0x55}},
202
        LoadParams{0x101U, LoadStoreTestbench::MemWidth::WIDTH_8, {0xaa}}));
203
 
204
struct StoreParams {
205
    physaddr mar_value;
206
    uint16_t mdr_value;
207
    LoadStoreTestbench::MemWidth width;
208
    std::map<physaddr, uint8_t> expected_mem;
209
};
210
 
211
class StoreTest : public LoadStoreTestbench,
212
                  public ::testing::WithParamInterface<StoreParams>
213
{
214
};
215
 
216
TEST_P(StoreTest, StoreMemory)
217
{
218
    auto params = GetParam();
219
 
220
    write_mar(params.mar_value);
221
    write_mdr(params.mdr_value);
222
 
223
    write(params.width);
224
 
225
    ASSERT_TRUE(params.expected_mem.size() == mem_bytes.size() &&
226
                std::equal(params.expected_mem.begin(),
227
                           params.expected_mem.end(), mem_bytes.begin()));
228
}
229
INSTANTIATE_TEST_CASE_P(
230
    Store,
231
    StoreTest,
232
    ::testing::Values(StoreParams{0x100U,
233
                                  0xaa55,
234
                                  LoadStoreTestbench::MemWidth::WIDTH_16,
235
                                  {{0x100, 0x55}, {0x101, 0xaa}}},
236
                      StoreParams{0x101U,
237
                                  0xaa55,
238
                                  LoadStoreTestbench::MemWidth::WIDTH_16,
239
                                  {{0x101, 0x55}, {0x102, 0xaa}}},
240
                      StoreParams{0x100U,
241
                                  0xff55,
242
                                  LoadStoreTestbench::MemWidth::WIDTH_8,
243
                                  {{0x100, 0x55}}},
244
                      StoreParams{0x101U,
245
                                  0xff55,
246
                                  LoadStoreTestbench::MemWidth::WIDTH_8,
247
                                  {{0x101, 0x55}}}));

powered by: WebSVN 2.1.0

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