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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [sim/] [Timer.h] - 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
#pragma once
19
 
20
#include <cassert>
21
#include <stdexcept>
22
 
23
#include <boost/serialization/list.hpp>
24
#include <boost/serialization/string.hpp>
25
#include <boost/serialization/version.hpp>
26
 
27
#include "CPU.h"
28
#include "PIC.h"
29
#include <stdint.h>
30
 
31
class BadTimer : public std::runtime_error
32
{
33
public:
34
    explicit BadTimer(const char *what) : std::runtime_error(what)
35
    {
36
    }
37
};
38
 
39
#define assert_timer(expr) \
40
    if (!(expr))           \
41
        throw BadTimer("Invalid timer config: " #expr);
42
 
43
static const auto cycles_per_tick = 50000000 / (65536 * 18.2);
44
 
45
class TimerTick : public IOPorts
46
{
47
public:
48
    explicit TimerTick(PIC *pic)
49
        : IOPorts(0x0040, 2),
50
          pic(pic),
51
          access(0),
52
          operating_mode(0),
53
          count(0),
54
          latched(false),
55
          latched_val(0),
56
          access_low(false),
57
          reload(0),
58
          enabled(false)
59
    {
60
    }
61
 
62
    void write8(uint16_t port_num, unsigned offs, uint8_t v)
63
    {
64
        if (port_num == 2 && offs == 1)
65
            write_mode(v);
66
        else if (port_num == 0 && offs == 0)
67
            write_reload(v);
68
    }
69
 
70
    uint8_t read8(uint16_t port_num, unsigned offs)
71
    {
72
        if (port_num != 0 && offs != 0)
73
            return 0;
74
 
75
        auto counter_val = this->latched ? this->latched_val : read_counter();
76
        if (access_low) {
77
            access_low = false;
78
            return counter_val;
79
        } else {
80
            latched = false;
81
            return counter_val >> 8;
82
        }
83
    }
84
 
85
    void tick(unsigned cycles)
86
    {
87
        if (!enabled)
88
            return;
89
 
90
        if (count <= cycles) {
91
            if (operating_mode == 2) {
92
                pic->raise_irq(0);
93
                do_reload();
94
            }
95
        } else {
96
            count -= cycles;
97
        }
98
    }
99
 
100
private:
101
    PIC *pic;
102
    uint8_t access;
103
    uint8_t operating_mode;
104
    uint32_t count;
105
    bool latched;
106
    uint16_t latched_val;
107
    bool access_low;
108
    uint16_t reload;
109
    bool enabled;
110
 
111
    uint16_t read_counter() const
112
    {
113
        return count / cycles_per_tick;
114
    }
115
 
116
    void do_reload()
117
    {
118
        count = (((static_cast<uint32_t>(reload) & 0xffff) - 1) & 0xffff) *
119
                cycles_per_tick;
120
    }
121
 
122
    friend class boost::serialization::access;
123
    template <class Archive>
124
    void serialize(Archive &ar, const unsigned int __unused version)
125
    {
126
        // clang-format off
127
        ar & access;
128
        ar & operating_mode;
129
        ar & latched;
130
        ar & latched_val;
131
        ar & access_low;
132
        ar & reload;
133
        ar & count;
134
        ar & enabled;
135
        // clang-format on
136
    }
137
 
138
    void write_mode(uint8_t v)
139
    {
140
        auto channel = v >> 6;
141
        auto access = (v >> 4) & 0x3;
142
        auto is_bcd = v & 0x1;
143
 
144
        // Ignore DRAM refresh and sound
145
        if (channel != 0)
146
            return;
147
 
148
        this->access = access;
149
        if (this->access != 0) {
150
            operating_mode = (v >> 1) & 0x7;
151
            assert_timer(operating_mode == 2);
152
 
153
            enabled = false;
154
        }
155
        assert_timer(is_bcd == 0);
156
 
157
        access_low = this->access != 2;
158
        if (access == 0 && !this->latched) {
159
            this->latched_val = read_counter();
160
            this->latched = true;
161
        }
162
    }
163
 
164
    void write_reload(uint8_t v)
165
    {
166
        if (this->access_low) {
167
            reload &= ~0xff;
168
            reload |= v;
169
            access_low = false;
170
        } else {
171
            reload &= ~0xff00;
172
            reload |= static_cast<uint16_t>(v) << 8;
173
            enabled = true;
174
            do_reload();
175
        }
176
    }
177
};

powered by: WebSVN 2.1.0

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