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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [sim/] [RTLCPU/] [Core.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 <stdexcept>
19
#include <fstream>
20
#include <VerilogDriver.h>
21
#include <VRTLCPU.h>
22
#include <boost/algorithm/string/replace.hpp>
23
 
24
#include "svdpi.h"
25
 
26
#include "Memory.h"
27
#include "RegisterFile.h"
28
#include "CPU.h"
29
#include "RTLCPU.h"
30
 
31
union reg_converter {
32
    uint16_t v16;
33
    uint8_t v8[2];
34
};
35
 
36
static const int max_cycles_per_step = 100000000;
37
 
38
double cur_time_stamp = 0;
39
double sc_time_stamp()
40
{
41
    return cur_time_stamp;
42
}
43
 
44
template <bool debug_enabled>
45
RTLCPU<debug_enabled>::RTLCPU(const std::string &test_name)
46
    : VerilogDriver<VRTLCPU, debug_enabled>(test_name),
47
      SimCPU(test_name),
48
      mem_in_progress(false),
49
      io_in_progress(false),
50
      mem_latency(0),
51
      test_name(test_name),
52
      is_stopped(true)
53
{
54
    this->dut.debug_seize = 1;
55
    this->reset();
56
 
57
    this->periodic(ClockSetup, [&] { this->mem_access(); });
58
    this->periodic(ClockSetup, [&] { this->io_access(); });
59
    this->periodic(ClockCapture, [&] {
60
        auto dev = &this->mem;
61
        if (this->dut.q_m_access && !this->dut.d_io && this->dut.q_m_wr_en) {
62
            if (this->dut.q_m_bytesel & (1 << 0))
63
                dev->template write<uint8_t>(this->dut.q_m_addr << 1,
64
                                             this->dut.q_m_data_out & 0xff);
65
            if (this->dut.q_m_bytesel & (1 << 1))
66
                dev->template write<uint8_t>(
67
                    (this->dut.q_m_addr << 1) + 1,
68
                    (this->dut.q_m_data_out >> 8) & 0xff);
69
        }
70
    });
71
    this->periodic(ClockCapture, [&] {
72
        if (this->dut.io_m_access && this->dut.d_io && this->dut.io_m_wr_en &&
73
            !io_in_progress) {
74
            if (!this->io.count(this->dut.io_m_addr << 1))
75
                return;
76
            auto addr = this->dut.io_m_addr << 1;
77
            auto p = this->io[this->dut.io_m_addr << 1];
78
            if (this->dut.io_m_bytesel == 0x3)
79
                p->write16(addr - p->get_base(), this->dut.io_m_data_out);
80
            else if (this->dut.io_m_bytesel & (1 << 0))
81
                p->write8(addr - p->get_base(), 0, this->dut.io_m_data_out);
82
            else if (this->dut.io_m_bytesel & (1 << 1))
83
                p->write8(addr - p->get_base(), 1,
84
                          this->dut.io_m_data_out >> 8);
85
        }
86
    });
87
    this->periodic(ClockCapture,
88
                   [&] { this->is_stopped = this->dut.debug_stopped; });
89
    this->periodic(ClockSetup, [&] {
90
        if (this->int_in_progress || !this->pending_irq) {
91
            this->dut.intr = 0;
92
            return;
93
        }
94
 
95
        if (this->dut.inta) {
96
            auto irq_num = this->pending_irq;
97
            this->pending_irq = 0;
98
            ack_int(irq_num);
99
        } else {
100
            int irq_num = this->pending_irq;
101
            this->dut.intr = 1;
102
            this->dut.irq = irq_num;
103
        }
104
    });
105
    this->periodic(ClockCapture, [&] {
106
        if (this->dut.inta)
107
            this->int_in_progress = false;
108
    });
109
}
110
 
111
template <bool debug_enabled>
112
int RTLCPU<debug_enabled>::debug_run_proc(
113
    unsigned addr,
114
    std::function<void(unsigned long)> io_callback)
115
{
116
    this->after_n_cycles(0, [&] {
117
        this->dut.debug_addr = addr;
118
        this->dut.debug_run = 1;
119
        this->after_n_cycles(1, [&] { this->dut.debug_run = 0; });
120
    });
121
 
122
    int cycle_count = 0;
123
 
124
    // Start the procedure running.
125
    while (debug_is_stopped()) {
126
        this->cycle();
127
        ++cycle_count;
128
    }
129
 
130
    // wait for completion
131
    cycle_count = 0;
132
    while (!debug_is_stopped()) {
133
        this->cycle();
134
 
135
        auto addr = get_microcode_address();
136
        // Dispatch address and debug idle don't count
137
        if (addr != 0x100 && addr != 0x102)
138
            ++cycle_count;
139
 
140
        io_callback(this->cur_cycle());
141
    }
142
 
143
    if (cycle_count >= max_cycles_per_step)
144
        throw std::runtime_error("execution timeout");
145
 
146
    return cycle_count;
147
}
148
 
149
template <bool debug_enabled>
150
int RTLCPU<debug_enabled>::debug_step(
151
    std::function<void(unsigned long)> io_callback)
152
{
153
    assert(is_stopped);
154
 
155
    return debug_run_proc(0x00, io_callback);
156
}
157
 
158
template <bool debug_enabled>
159
void RTLCPU<debug_enabled>::debug_detach()
160
{
161
    this->after_n_cycles(0, [&] {
162
        this->dut.debug_seize = 0;
163
        this->dut.debug_addr = 0;
164
        this->dut.debug_run = 1;
165
        this->after_n_cycles(1, [&] { this->dut.debug_run = 0; });
166
    });
167
}
168
 
169
template <bool debug_enabled>
170
void RTLCPU<debug_enabled>::start_instruction()
171
{
172
    assert(is_stopped);
173
 
174
    // Give the FIFO sufficient time to fill so that we go straight to the
175
    // instruction and can detect the first real yield.
176
    this->cycle((mem_latency + 1) * 128);
177
 
178
    this->after_n_cycles(0, [&] {
179
        this->dut.debug_addr = 0;
180
        this->dut.debug_run = 1;
181
        this->after_n_cycles(1, [&] { this->dut.debug_run = 0; });
182
    });
183
 
184
    while (debug_is_stopped())
185
        this->cycle();
186
}
187
 
188
template <bool debug_enabled>
189
void RTLCPU<debug_enabled>::complete_instruction()
190
{
191
    while (!debug_is_stopped())
192
        this->cycle();
193
}
194
 
195
template <bool debug_enabled>
196
bool RTLCPU<debug_enabled>::int_yield_ready()
197
{
198
    svSetScope(svGetScopeFromName("TOP.RTLCPU.Core.Microcode"));
199
 
200
    return this->dut.get_ext_int_yield();
201
}
202
 
203
template <bool debug_enabled>
204
void RTLCPU<debug_enabled>::write_coverage()
205
{
206
#ifdef COVERAGE
207
    auto filename = (boost::format("microcode_%s.mcov") % test_name).str();
208
    boost::replace_all(filename, "/", "_");
209
    std::ofstream cov;
210
    cov.open("coverage/" + filename);
211
 
212
    svSetScope(svGetScopeFromName("TOP.RTLCPU.Core.Microcode"));
213
    auto num_bins = this->dut.get_microcode_num_instructions();
214
    for (auto i = 0; i < num_bins; ++i) {
215
        auto count = this->dut.get_microcode_coverage_bin(i);
216
        cov << std::hex << i << ":" << count << std::endl;
217
    }
218
    cov.close();
219
#endif
220
}
221
 
222
template <bool debug_enabled>
223
void RTLCPU<debug_enabled>::reset()
224
{
225
    this->dut.nmi = 0;
226
    this->dut.intr = 0;
227
 
228
    pending_irq = 0;
229
    int_in_progress = false;
230
 
231
    VerilogDriver<VRTLCPU, debug_enabled>::reset();
232
 
233
    while (get_microcode_address() != 0x102)
234
        this->cycle();
235
}
236
 
237
template <bool debug_enabled>
238
void RTLCPU<debug_enabled>::write_reg(GPR regnum, uint16_t val)
239
{
240
    if (regnum == IP)
241
        write_ip(val);
242
    else if (regnum >= ES && regnum <= DS)
243
        write_sr(regnum, val);
244
    else
245
        write_gpr(regnum, val);
246
}
247
 
248
template <bool debug_enabled>
249
void RTLCPU<debug_enabled>::write_sr(GPR regnum, uint16_t val)
250
{
251
    debug_write_data(val);
252
    debug_run_proc(0x13 + static_cast<int>(regnum));
253
}
254
 
255
template <bool debug_enabled>
256
void RTLCPU<debug_enabled>::debug_write_data(uint16_t val)
257
{
258
    this->after_n_cycles(0, [&] {
259
        this->dut.debug_wr_en = 1;
260
        this->dut.debug_wr_val = val;
261
        this->after_n_cycles(1, [&] { this->dut.debug_wr_en = 0; });
262
    });
263
    this->cycle();
264
}
265
 
266
template <bool debug_enabled>
267
void RTLCPU<debug_enabled>::write_ip(uint16_t val)
268
{
269
    assert(is_stopped);
270
 
271
    debug_write_data(val);
272
    debug_run_proc(0x11);
273
}
274
 
275
template <bool debug_enabled>
276
void RTLCPU<debug_enabled>::write_gpr(GPR regnum, uint16_t val)
277
{
278
    if (regnum < NUM_16BIT_REGS) {
279
        debug_write_data(val);
280
        debug_run_proc(0x13 + static_cast<int>(regnum));
281
    } else {
282
        auto regsel = (regnum - AL) & 0x3;
283
        reg_converter conv;
284
        conv.v16 = this->read_reg(static_cast<GPR>(regsel));
285
 
286
        conv.v8[regnum >= AH] = val;
287
 
288
        debug_write_data(conv.v16);
289
        debug_run_proc(0x13 + static_cast<int>(regsel));
290
    }
291
}
292
 
293
template <bool debug_enabled>
294
uint16_t RTLCPU<debug_enabled>::read_reg(GPR regnum) const
295
{
296
    if (regnum == IP)
297
        return read_ip();
298
    else if (regnum >= ES && regnum <= DS)
299
        return read_sr(regnum);
300
    else
301
        return read_gpr(regnum);
302
}
303
 
304
template <bool debug_enabled>
305
uint16_t RTLCPU<debug_enabled>::read_ip() const
306
{
307
    assert(this->dut.debug_stopped);
308
    const_cast<RTLCPU<debug_enabled> *>(this)->debug_run_proc(0x0f);
309
 
310
    return this->dut.debug_val;
311
}
312
 
313
template <bool debug_enabled>
314
uint16_t RTLCPU<debug_enabled>::read_gpr(GPR regnum) const
315
{
316
    if (regnum < NUM_16BIT_REGS) {
317
        const_cast<RTLCPU<debug_enabled> *>(this)->debug_run_proc(
318
            0x03 + static_cast<int>(regnum));
319
 
320
        return this->dut.debug_val;
321
    }
322
 
323
    auto regsel = static_cast<int>(regnum - AL) & 0x3;
324
    const_cast<RTLCPU<debug_enabled> *>(this)->debug_run_proc(
325
        0x03 + static_cast<int>(regsel));
326
 
327
    reg_converter conv;
328
    conv.v16 = this->dut.debug_val;
329
 
330
    return conv.v8[regnum >= AH];
331
}
332
 
333
template <bool debug_enabled>
334
uint16_t RTLCPU<debug_enabled>::read_sr(GPR regnum) const
335
{
336
    const_cast<RTLCPU<debug_enabled> *>(this)->debug_run_proc(
337
        0x03 + static_cast<int>(regnum));
338
 
339
    return this->dut.debug_val;
340
}
341
 
342
template <bool debug_enabled>
343
size_t RTLCPU<debug_enabled>::get_and_clear_instr_length()
344
{
345
    svSetScope(svGetScopeFromName("TOP.RTLCPU.Core"));
346
 
347
    return static_cast<size_t>(this->dut.get_and_clear_instr_length());
348
}
349
 
350
template <bool debug_enabled>
351
size_t RTLCPU<debug_enabled>::step()
352
{
353
    return step_with_io(null_io);
354
}
355
 
356
template <bool debug_enabled>
357
size_t RTLCPU<debug_enabled>::step_with_io(
358
    std::function<void(unsigned long)> io_callback)
359
{
360
    this->get_and_clear_instr_length();
361
 
362
    this->debug_step(io_callback);
363
 
364
    return this->get_and_clear_instr_length();
365
}
366
 
367
template <bool debug_enabled>
368
void RTLCPU<debug_enabled>::cycle_cpu_with_io(
369
    std::function<void(unsigned long)> io_callback)
370
{
371
    this->cycle();
372
 
373
    io_callback(this->cur_cycle());
374
}
375
 
376
template <bool debug_enabled>
377
void RTLCPU<debug_enabled>::idle(int count)
378
{
379
    this->cycle(count);
380
}
381
 
382
template <bool debug_enabled>
383
int RTLCPU<debug_enabled>::time_step()
384
{
385
    return this->debug_step(null_io);
386
}
387
 
388
template <bool debug_enabled>
389
void RTLCPU<debug_enabled>::write_flags(uint16_t val)
390
{
391
    debug_write_data(val);
392
    debug_run_proc(0x12);
393
}
394
 
395
template <bool debug_enabled>
396
uint16_t RTLCPU<debug_enabled>::read_flags() const
397
{
398
    const_cast<RTLCPU<debug_enabled> *>(this)->debug_run_proc(0x10);
399
 
400
    return this->dut.debug_val;
401
}
402
 
403
template <bool debug_enabled>
404
bool RTLCPU<debug_enabled>::has_trapped()
405
{
406
    auto int_cs = this->mem.template read<uint16_t>(VEC_INT + 2);
407
    auto int_ip = this->mem.template read<uint16_t>(VEC_INT + 0);
408
 
409
    return read_sr(CS) == int_cs && read_ip() == int_ip;
410
}
411
 
412
template <bool debug_enabled>
413
void RTLCPU<debug_enabled>::mem_access()
414
{
415
    if (this->dut.reset || !this->dut.q_m_access || this->dut.d_io ||
416
        mem_in_progress)
417
        return;
418
 
419
    this->after_n_cycles(0, [&] {
420
        auto v = this->mem.template read<uint16_t>(this->dut.q_m_addr << 1);
421
        this->dut.q_m_data_in = v;
422
    });
423
    mem_in_progress = true;
424
    this->after_n_cycles(mem_latency, [&] {
425
        this->dut.q_m_ack = 1;
426
        this->after_n_cycles(1, [&] {
427
            this->dut.q_m_ack = 0;
428
            mem_in_progress = false;
429
        });
430
    });
431
}
432
 
433
template <bool debug_enabled>
434
void RTLCPU<debug_enabled>::io_access()
435
{
436
    if (this->dut.reset || !this->dut.io_m_access || !this->dut.d_io ||
437
        io_in_progress)
438
        return;
439
 
440
    this->after_n_cycles(0, [&] {
441
        if (!this->io.count(this->dut.io_m_addr << 1)) {
442
            this->dut.io_m_data_in = 0;
443
            return;
444
        }
445
 
446
        auto addr = this->dut.io_m_addr << 1;
447
        auto p = this->io[this->dut.io_m_addr << 1];
448
        if (this->dut.io_m_bytesel == 0x3)
449
            this->dut.io_m_data_in = p->read16(addr - p->get_base());
450
        else if (this->dut.io_m_bytesel & 0x1)
451
            this->dut.io_m_data_in = p->read8(addr - p->get_base(), 0);
452
        else if (this->dut.io_m_bytesel & 0x2)
453
            this->dut.io_m_data_in = p->read8(addr - p->get_base(), 1) << 8;
454
    });
455
    io_in_progress = true;
456
    this->after_n_cycles(mem_latency, [&] {
457
        this->dut.io_m_ack = 1;
458
        this->after_n_cycles(1, [&] {
459
            this->dut.io_m_ack = 0;
460
            io_in_progress = false;
461
        });
462
    });
463
}
464
 
465
template <bool debug_enabled>
466
uint16_t RTLCPU<debug_enabled>::get_microcode_address()
467
{
468
    svSetScope(svGetScopeFromName("TOP.RTLCPU.Core.Microcode"));
469
 
470
    return this->dut.get_microcode_address();
471
}
472
 
473
template <bool debug_enabled>
474
void RTLCPU<debug_enabled>::write_mem8(uint16_t segment,
475
                                       uint16_t addr,
476
                                       uint8_t val)
477
{
478
    auto prev_ds = read_reg(DS);
479
 
480
    write_reg(DS, segment);
481
    write_mar(addr);
482
    write_mdr(val);
483
    debug_run_proc(0x23); // Write mem 8
484
    write_reg(DS, prev_ds);
485
}
486
 
487
template <bool debug_enabled>
488
void RTLCPU<debug_enabled>::write_mem16(uint16_t segment,
489
                                        uint16_t addr,
490
                                        uint16_t val)
491
{
492
    auto prev_ds = read_reg(DS);
493
 
494
    write_reg(DS, segment);
495
    write_mar(addr);
496
    write_mdr(val);
497
    debug_run_proc(0x24); // Write mem 16
498
    write_reg(DS, prev_ds);
499
}
500
 
501
template <bool debug_enabled>
502
void RTLCPU<debug_enabled>::write_vector8(uint16_t segment,
503
                                          uint16_t addr,
504
                                          const std::vector<uint8_t> &v)
505
{
506
    auto prev_ds = read_reg(DS);
507
 
508
    write_reg(DS, segment);
509
 
510
    write_mar(addr);
511
    for (auto &b : v) {
512
        write_mdr(b);
513
        debug_run_proc(0x23); // Write mem 8
514
    }
515
 
516
    write_reg(DS, prev_ds);
517
}
518
 
519
template <bool debug_enabled>
520
void RTLCPU<debug_enabled>::write_vector16(uint16_t segment,
521
                                           uint16_t addr,
522
                                           const std::vector<uint16_t> &v)
523
{
524
    auto prev_ds = read_reg(DS);
525
 
526
    write_reg(DS, segment);
527
 
528
    write_mar(addr);
529
    for (auto &b : v) {
530
        write_mdr(b);
531
        debug_run_proc(0x24); // Write mem 16
532
    }
533
 
534
    write_reg(DS, prev_ds);
535
}
536
 
537
template <bool debug_enabled>
538
void RTLCPU<debug_enabled>::write_mem32(uint16_t segment,
539
                                        uint16_t addr,
540
                                        uint32_t val)
541
{
542
    write_mem16(segment, addr, val & 0xffff);
543
    write_mem16(segment, addr + 2, val >> 16);
544
}
545
 
546
template <bool debug_enabled>
547
void RTLCPU<debug_enabled>::write_mar(uint16_t v)
548
{
549
    debug_write_data(v);
550
    debug_run_proc(0x1f);
551
}
552
 
553
template <bool debug_enabled>
554
void RTLCPU<debug_enabled>::write_mdr(uint16_t v)
555
{
556
    debug_write_data(v);
557
    debug_run_proc(0x20);
558
}
559
 
560
template <bool debug_enabled>
561
uint8_t RTLCPU<debug_enabled>::read_mem8(uint16_t segment, uint16_t addr)
562
{
563
    auto prev_ds = read_reg(DS);
564
 
565
    write_reg(DS, segment);
566
    write_mar(addr);
567
    debug_run_proc(0x21); // Read mem 8
568
 
569
    uint8_t val = this->dut.debug_val;
570
 
571
    write_reg(DS, prev_ds);
572
 
573
    return val;
574
}
575
 
576
template <bool debug_enabled>
577
uint16_t RTLCPU<debug_enabled>::read_mem16(uint16_t segment, uint16_t addr)
578
{
579
    auto prev_ds = read_reg(DS);
580
 
581
    write_reg(DS, segment);
582
    write_mar(addr);
583
    debug_run_proc(0x22); // Read mem 16
584
 
585
    uint16_t val = this->dut.debug_val;
586
 
587
    write_reg(DS, prev_ds);
588
 
589
    return val;
590
}
591
 
592
template <bool debug_enabled>
593
uint32_t RTLCPU<debug_enabled>::read_mem32(uint16_t segment, uint16_t addr)
594
{
595
    return read_mem16(segment, addr) |
596
           (static_cast<uint32_t>(read_mem16(segment, addr + 2)) << 16);
597
}
598
 
599
template <bool debug_enabled>
600
void RTLCPU<debug_enabled>::write_io8(uint32_t addr, uint8_t val)
601
{
602
    write_mar(addr);
603
    write_mdr(val);
604
    debug_run_proc(0x27); // Write io 8
605
}
606
 
607
template <bool debug_enabled>
608
void RTLCPU<debug_enabled>::write_io16(uint32_t addr, uint16_t val)
609
{
610
    write_mar(addr);
611
    write_mdr(val);
612
    debug_run_proc(0x28); // Write io 16
613
}
614
 
615
template <bool debug_enabled>
616
uint8_t RTLCPU<debug_enabled>::read_io8(uint32_t addr)
617
{
618
    write_mar(addr);
619
    debug_run_proc(0x25); // Read io 8
620
 
621
    return this->dut.debug_val;
622
}
623
 
624
template <bool debug_enabled>
625
uint16_t RTLCPU<debug_enabled>::read_io16(uint32_t addr)
626
{
627
    write_mar(addr);
628
    debug_run_proc(0x26); // Read io 16
629
 
630
    return this->dut.debug_val;
631
}
632
 
633
template RTLCPU<verilator_debug_enabled>::RTLCPU(const std::string &);
634
template void RTLCPU<verilator_debug_enabled>::idle(int count);
635
template int RTLCPU<verilator_debug_enabled>::time_step();

powered by: WebSVN 2.1.0

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