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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [sim/] [Simulator.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 <algorithm>
19
#include <cassert>
20
#include <chrono>
21
#include <ctime>
22
#include <fstream>
23
#include <iostream>
24
#include <map>
25
#include <sstream>
26
#include <unistd.h>
27
 
28
#include <boost/program_options.hpp>
29
#include <boost/archive/text_oarchive.hpp>
30
#include <boost/archive/text_iarchive.hpp>
31
 
32
#include "CGA.h"
33
#include "CPU.h"
34
#include "Display.h"
35
#include "Keyboard.h"
36
#include "SoftwareCPU.h"
37
#include "RTLCPU.h"
38
#include "PIC.h"
39
#include "UART.h"
40
#include "SPI.h"
41
#include "Timer.h"
42
 
43
bool trace = false;
44
 
45
namespace tty
46
{
47
const std::string green = "\x1b[32m";
48
const std::string normal = "\x1b[39;49;0m";
49
const std::string bold = "\x1b[1m";
50
};
51
 
52
class SDRAMConfigRegister : public IOPorts
53
{
54
public:
55
    SDRAMConfigRegister() : IOPorts(0xfffc, 1)
56
    {
57
    }
58
 
59
    virtual ~SDRAMConfigRegister()
60
    {
61
    }
62
 
63
    void write8(uint16_t __unused port_num,
64
                unsigned __unused offs,
65
                uint8_t __unused v)
66
    {
67
    }
68
    uint8_t read8(uint16_t __unused port_num, unsigned offs)
69
    {
70
        return offs == 0 ? 0x1 : 0;
71
    }
72
};
73
 
74
template <typename T>
75
class Simulator
76
{
77
public:
78
    Simulator<T>(const std::string &bios_path,
79
                 const std::string &disk_image_path,
80
                 bool detached);
81
    void run();
82
 
83
private:
84
    void load_bios(const std::string &bios_path);
85
    void process_io();
86
    void trace_insn(uint16_t cs, uint16_t ip, size_t instr_len);
87
    friend class boost::serialization::access;
88
    template <class Archive>
89
    void serialize(Archive &ar, const unsigned int __unused version)
90
    {
91
        // clang-format off
92
        ar & cpu;
93
        ar & uart;
94
        ar & spi;
95
        ar & timer;
96
        ar & cga;
97
        ar & pic;
98
        // clang-format on
99
    }
100
 
101
    T cpu;
102
    SDRAMConfigRegister sdram_config_register;
103
    UART uart;
104
    SPI spi;
105
    TimerTick timer;
106
    CGA cga;
107
    Keyboard kbd;
108
    PIC pic;
109
    bool got_exit;
110
    bool detached;
111
};
112
 
113
template <typename T>
114
Simulator<T>::Simulator(const std::string &bios_path,
115
                        const std::string &disk_image_path,
116
                        bool detached)
117
    : cpu("simulator"),
118
      spi(disk_image_path),
119
      timer(&this->pic),
120
      cga(this->cpu.get_memory()),
121
      kbd(&this->pic),
122
      pic(&this->cpu),
123
      got_exit(false),
124
      detached(detached)
125
{
126
    cpu.add_ioport(&sdram_config_register);
127
    cpu.add_ioport(&uart);
128
    cpu.add_ioport(&spi);
129
    cpu.add_ioport(&timer);
130
    cpu.add_ioport(&cga);
131
    cpu.add_ioport(&kbd);
132
    cpu.add_ioport(&pic);
133
    cpu.reset();
134
    load_bios(bios_path);
135
}
136
 
137
template <typename T>
138
void Simulator<T>::load_bios(const std::string &bios_path)
139
{
140
    std::cout << tty::bold << tty::green << "Loading bios: " << bios_path
141
              << tty::normal << "\r\n";
142
 
143
    std::ifstream bios(bios_path, std::ios::binary);
144
    for (unsigned offs = 0; !bios.eof(); ++offs) {
145
        char v;
146
        bios.read(&v, 1);
147
        cpu.write_mem8(0xfc00, offs, v);
148
    }
149
 
150
    cpu.write_mem8(0xf000, 0xfffe, 0xff);
151
    cpu.write_mem8(0xf000, 0x0002, 0xff);
152
    cpu.write_mem8(0xf000, 0x0000, 8);
153
 
154
    cpu.write_reg(CS, 0xffff);
155
    cpu.write_reg(IP, 0x0000);
156
}
157
 
158
template <typename T>
159
void Simulator<T>::process_io()
160
{
161
    char c;
162
    if (read(STDIN_FILENO, &c, 1) == 1) {
163
        if (c == 0x1d)
164
            got_exit = true;
165
        else
166
            uart.add_char(c);
167
    }
168
 
169
    SDL_Event e;
170
    if (SDL_PollEvent(&e)) {
171
        if (e.type == SDL_QUIT)
172
            got_exit = true;
173
        else if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP)
174
            kbd.process_event(e);
175
    }
176
}
177
 
178
template <typename T>
179
void Simulator<T>::run()
180
{
181
    auto start_time = std::chrono::system_clock::now();
182
 
183
    if (detached)
184
        cpu.debug_detach();
185
 
186
    unsigned long last_cycle = 0;
187
    while (!got_exit) {
188
        auto io_callback = [&](unsigned long cycle_num) {
189
            if (cycle_num % 1000000 == 0)
190
                cga.update();
191
            if (cycle_num % 1000 == 0)
192
                process_io();
193
            timer.tick((cycle_num - last_cycle) + 1);
194
            last_cycle = cycle_num;
195
        };
196
 
197
        if (detached)
198
            cpu.cycle_cpu_with_io(io_callback);
199
        else {
200
            auto cs = cpu.read_reg(CS);
201
            auto ip = cpu.read_reg(IP);
202
            auto instr_len = cpu.step_with_io(io_callback);
203
 
204
            if (trace)
205
                trace_insn(cs, ip, instr_len);
206
        }
207
    }
208
 
209
    auto end_time = std::chrono::system_clock::now();
210
 
211
    std::chrono::duration<double> elapsed_seconds = end_time - start_time;
212
 
213
    std::cout << tty::bold << tty::green << "\r\nOperating frequency: "
214
              << (cpu.cycle_count() / 1000000.0) / elapsed_seconds.count()
215
              << "MHz\r\n"
216
              << tty::normal;
217
}
218
 
219
template <typename T>
220
void Simulator<T>::trace_insn(uint16_t cs, uint16_t ip, size_t instr_len)
221
{
222
    std::cout << "[" << std::hex << cs << ":" << ip << "] ";
223
    auto bytes = cpu.read_vector8(cs, ip, instr_len);
224
 
225
    auto flags = std::cout.flags();
226
 
227
    for (auto b : bytes)
228
        std::cout << std::hex << std::setfill('0') << std::setw(2)
229
                  << static_cast<unsigned>(b) << " ";
230
 
231
    std::cout.flags(flags);
232
    std::cout << "\r\n";
233
}
234
 
235
template <typename T>
236
static void run_sim(const std::string &bios_image,
237
                    const std::string &disk_image,
238
                    const bool detached,
239
                    const std::string &save,
240
                    const std::string &restore)
241
{
242
    T sim(bios_image, disk_image, detached);
243
 
244
    if (restore != "") {
245
        std::ifstream ifs(restore);
246
        boost::archive::text_iarchive ia(ifs);
247
        ia >> sim;
248
    }
249
 
250
    sim.run();
251
 
252
    if (save != "") {
253
        std::ofstream ofs(save);
254
        {
255
            boost::archive::text_oarchive oa(ofs);
256
            oa << sim;
257
        }
258
    }
259
}
260
 
261
int main(int argc, char **argv)
262
{
263
    namespace po = boost::program_options;
264
    std::string bios_image;
265
    std::string disk_image;
266
    std::string restore;
267
    std::string save;
268
    std::string backend = "SoftwareCPU";
269
    bool detached;
270
 
271
    po::options_description desc("Options");
272
    // clang-format off
273
    desc.add_options()
274
        ("help,h", "print this usage information and exit")
275
        ("backend,b", po::value<std::string>(&backend),
276
         "the simulator backend module to use, either SoftwareCPU or RTLCPU, default SoftwareCPU")
277
        ("restore,r", po::value<std::string>(&restore),
278
         "restore file to load from")
279
        ("save,s", po::value<std::string>(&save),
280
         "save file to write from")
281
        ("detached,d",
282
         "run the simulation in free-running mode")
283
        ("trace,t",
284
         "trace all instructions as they are executed")
285
        ("bios", po::value<std::string>(&bios_image)->required(),
286
         "the bios image to use")
287
        ("diskimage", po::value<std::string>(&disk_image)->required(),
288
         "the boot disk image");
289
    // clang-format on
290
 
291
    po::positional_options_description positional;
292
    positional.add("bios", 1);
293
    positional.add("diskimage", 1);
294
 
295
    po::variables_map variables_map;
296
    try {
297
        po::store(po::command_line_parser(argc, argv)
298
                      .options(desc)
299
                      .positional(positional)
300
                      .run(),
301
                  variables_map);
302
        if (variables_map.count("help")) {
303
            std::cout << desc << std::endl;
304
            return 0;
305
        }
306
 
307
        detached = variables_map.count("detached");
308
        trace = variables_map.count("trace");
309
 
310
        po::notify(variables_map);
311
    } catch (boost::program_options::required_option &e) {
312
        std::cerr << "Error: missing arguments " << e.what() << std::endl;
313
        return 1;
314
    } catch (boost::program_options::error &e) {
315
        std::cerr << "Error: " << e.what() << std::endl;
316
        return 2;
317
    }
318
 
319
    if (backend == "SoftwareCPU") {
320
        run_sim<Simulator<SoftwareCPU>>(bios_image, disk_image, detached, save,
321
                                        restore);
322
    } else if (backend == "RTLCPU") {
323
        run_sim<Simulator<RTLCPU<verilator_debug_enabled>>>(
324
            bios_image, disk_image, detached, save, restore);
325
    } else {
326
        std::cerr << "Error: invalid simulation backend \"" << backend << "\""
327
                  << std::endl;
328
        return 3;
329
    }
330
 
331
    return 0;
332
}

powered by: WebSVN 2.1.0

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