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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [sim/] [PIC.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 <iostream>
22
 
23
#include <boost/serialization/string.hpp>
24
#include <boost/serialization/version.hpp>
25
 
26
#include "CPU.h"
27
 
28
class PIC : public IOPorts
29
{
30
private:
31
    enum State { STATE_IDLE, STATE_ICW2, STATE_ICW4 };
32
 
33
    enum CommandReadMode { STATE_READ_IRR, STATE_READ_ISR };
34
 
35
public:
36
    explicit PIC(SimCPU *cpu)
37
        : IOPorts(0x0020, 1),
38
          cpu(cpu),
39
          state(STATE_IDLE),
40
          command_read_mode(STATE_READ_IRR),
41
          mask(0),
42
          isr(0),
43
          irr(0)
44
    {
45
        cpu->set_inta_handler(
46
            [this](int irq_num) { this->inta_handler(irq_num); });
47
    }
48
 
49
    void write8(uint16_t __unused port_num, unsigned offs, uint8_t v)
50
    {
51
        if (offs == 0)
52
            write_command(v);
53
        else
54
            write_data(v);
55
    }
56
 
57
    uint8_t read8(uint16_t __unused port_num, unsigned offs)
58
    {
59
        if (offs == 0)
60
            return read_command();
61
        else
62
            return read_data();
63
    }
64
 
65
    void raise_irq(int irq_num)
66
    {
67
        if (mask & (1 << irq_num))
68
            return;
69
 
70
        irr |= (1 << irq_num);
71
 
72
        for (int i = 0; i < 8; ++i) {
73
            if ((1 << i) & isr)
74
                return;
75
 
76
            if ((1 << i) & irr) {
77
                cpu->raise_irq(vector_address + i);
78
                return;
79
            }
80
        }
81
    }
82
 
83
private:
84
    void inta_handler(int irq_num)
85
    {
86
        isr |= (1 << (irq_num - vector_address));
87
        irr &= ~(1 << (irq_num - vector_address));
88
    }
89
 
90
    void write_command(uint8_t v)
91
    {
92
        if (is_icw1(v))
93
            icw1(v);
94
        else if (is_ocw2(v))
95
            ocw2(v);
96
        else if (is_ocw3(v))
97
            ocw3(v);
98
    }
99
 
100
    uint8_t read_command()
101
    {
102
        if (command_read_mode == STATE_READ_IRR)
103
            return irr;
104
        else if (command_read_mode == STATE_READ_ISR)
105
            return isr;
106
        return 0;
107
    }
108
 
109
    uint8_t read_data()
110
    {
111
        return mask;
112
    }
113
 
114
    void write_data(uint8_t v)
115
    {
116
        switch (state) {
117
        case STATE_ICW2:
118
            vector_address = v & 0xf8;
119
            state = STATE_ICW4;
120
            return;
121
        case STATE_ICW4:
122
            assert(v == 0x01);
123
            state = STATE_IDLE;
124
            return;
125
        default: set_mask(v);
126
        }
127
    }
128
 
129
    bool is_icw1(uint8_t v)
130
    {
131
        return v & (1 << 4);
132
    }
133
 
134
    bool is_ocw2(uint8_t v)
135
    {
136
        return (v & (3 << 3)) == 0;
137
    }
138
 
139
    bool is_ocw3(uint8_t v)
140
    {
141
        return (v & (0x80 | (3 << 3))) == 0x08;
142
    }
143
 
144
    void icw1(uint8_t __unused v)
145
    {
146
        state = STATE_ICW2;
147
        // Only single PIC in edge triggered, 8086 mode supported
148
        assert((v & 0x0f) == 0x3);
149
    }
150
 
151
    void ocw2(uint8_t v)
152
    {
153
        if (v >> 5 == 1) {
154
            for (int i = 0; i < 8; ++i) {
155
                if (isr & (1 << i)) {
156
                    isr &= ~(1 << i);
157
                    return;
158
                }
159
            }
160
        } else if (v >> 5 == 3) {
161
            isr &= ~(1 << (v & 0x7));
162
        }
163
    }
164
 
165
    void ocw3(uint8_t v)
166
    {
167
        // No poll supported
168
        assert(!(v & 0x04));
169
        // No special mask
170
        assert(!(v & 0x60));
171
 
172
        if ((v & 0x3) == 2)
173
            command_read_mode = STATE_READ_IRR;
174
        else if ((v & 0x3) == 3)
175
            command_read_mode = STATE_READ_ISR;
176
    }
177
 
178
    void set_mask(uint8_t v)
179
    {
180
        mask = v;
181
    }
182
 
183
    friend class boost::serialization::access;
184
    template <class Archive>
185
    void serialize(Archive &ar, const unsigned int __unused version)
186
    {
187
        // clang-format off
188
        ar & state;
189
        ar & command_read_mode;
190
        ar & vector_address;
191
        ar & mask;
192
        ar & isr;
193
        ar & irr;
194
        // clang-format on
195
    }
196
 
197
    SimCPU *cpu;
198
    State state;
199
    CommandReadMode command_read_mode;
200
    uint8_t vector_address;
201
    uint8_t mask;
202
    uint8_t isr;
203
    uint8_t irr;
204
};

powered by: WebSVN 2.1.0

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