FabGL
ESP32 Display Controller and Graphics Library
PIC8259.cpp
1/*
2 Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3 Copyright (c) 2019-2022 Fabrizio Di Vittorio.
4 All rights reserved.
5
6
7* Please contact fdivitto2013@gmail.com if you need a commercial license.
8
9
10* This library and related software is available under GPL v3.
11
12 FabGL is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 FabGL is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with FabGL. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26
27#include "PIC8259.h"
28
29
30
31namespace fabgl {
32
33
34
35#define ICW1_IC4 0x01 // 1 = ICW4 needed
36#define ICW1_SNGL 0x02 // 1 = single mode, 0 = cascade mode
37#define ICW1_LTIM 0x08 // 1 = level trig imput, 0 = edge trig input
38
39#define ICW4_PM 0x01 // 1 = x86, 0 = 8085
40#define ICW4_AEOI 0x02 // 1 = auto EOI, 0 = normal EOI
41#define ICW4_MS 0x04 // valid when ICW4_BUF = 1: 0 = buffered mode slave, 1 = buffered mode master
42#define ICW4_BUF 0x08 // 1 = buffered mode, 0 = non buffered mode
43#define ICW4_SFNM 0x10 // 1 = special fully nested mode
44
45#define OCW2_EOI 0x20 // 1 = EOI command
46#define OCW2_SL 0x40 // 1 = with EOI means Specific, with R means Set Priority
47#define OCW2_R 0x80 // 1 = with EOI means Rotate, with SL means Set Priority
48
49#define OCW3_RIS 0x01 // 1 = with OCW3_RR means Read IS register, 0 = with OCW3_RR means Read IR register
50#define OCW3_RR 0x02 // 1 = OCW3_RIS specifies which register to read, 0 = no action
51#define OCW3_POLL 0x04 // 1 = poll command
52#define OCW3_SMM 0x08 // valid when OCW3_ESMM = 1: 0 = reset special mask, 1 = set special mask
53
54#define PORT0_ICW1 0x10 // 1 = presenting ICW1 on port 0, 0 = presenting OCW2 or OCW3 on port 0
55#define PORT0_OCW3 0x08 // 1 = presenting OCW3 on port 0, 0 = presenting OCW2 on port 0
56
57
58// m_state meaning
59#define STATE_READY 0x00 // waiting for ICW1/OCW2/OCW3 on port 0, OCW1 on port 1
60#define STATE_WAITING_ICW2 0X01 // waiting for ICW2 on port 1
61#define STATE_WAITING_ICW3 0X02 // waiting for ICW3 on port 2
62#define STATE_WAITING_ICW4 0X04 // waiting for ICW4 on port 3
63
64
65void PIC8259::reset()
66{
67 m_state = STATE_READY;
68 m_readISR = false;
69 m_IRR = 0x00;
70 m_IMR = 0xff;
71 m_ISR = 0x00;
72 m_autoEOI = false;
73 m_baseVector = 0x00;
74 m_pendingInterrupt = false;
75 m_pendingIR = 0;
76}
77
78
79void PIC8259::write(int addr, uint8_t value)
80{
81 switch (addr) {
82
83 case 0:
84 if (value & PORT0_ICW1) {
85 // getting ICW1
86 //printf("ICW1 <= %02X\n", value);
87 //printf(" LTIM=%d ADI=%d SNGL=%d IC4=%d\n", (bool)(value & 0x08), (bool)(value & 0x04), (bool)(value & 0x02), (bool)(value & 0x01));
88 m_state = STATE_WAITING_ICW2;
89 m_state |= value & ICW1_IC4 ? STATE_WAITING_ICW4 : 0;
90 m_state |= value & ICW1_SNGL ? 0 : STATE_WAITING_ICW3;
91 } else if (value & PORT0_OCW3) {
92 // getting OCW3
93 //printf("OCW3 <= %02X\n", value);
94 //printf(" ESMM=%d SMM=%d P=%d RR=%d RIS=%d\n", (bool)(value & 0x40), (bool)(value & 0x20), (bool)(value & 0x04), (bool)(value & 0x02), (bool)(value & 0x01));
95 if (value & OCW3_RR)
96 m_readISR = value & OCW3_RIS;
97 } else {
98 // getting OCW2
99 //printf("OCW2 <= %02X\n", value);
100 //printf(" R=%d SL=%d EOI=%d L210=%d\n", (bool)(value & 0x80), (bool)(value & 0x40), (bool)(value & 0x20), value & 7);
101 if (value & OCW2_EOI) {
102 // perform EOI
103 performEOI();
104 }
105 }
106 break;
107
108 case 1:
109 if (m_state & STATE_WAITING_ICW2) {
110 // getting ICW2
111 //printf("ICW2 <= %02X\n", value);
112 m_baseVector = value & 0xf8;
113 m_state &= ~STATE_WAITING_ICW2;
114 } else if (m_state & STATE_WAITING_ICW3) {
115 // getting ICW3
116 //printf("ICW3 <= %02X\n", value);
117 // not supported, nothing to do
118 m_state &= ~STATE_WAITING_ICW3;
119 } else if (m_state & STATE_WAITING_ICW4) {
120 // getting ICW4
121 //printf("ICW4 <= %02X\n", value);
122 //printf(" SFNM=%d BUF=%d M/S=%d AEOI=%d uPM=%d\n", (bool)(value & 0x10), (bool)(value & 0x08), (bool)(value & 0x04), (bool)(value & 0x02), (bool)(value & 0x01));
123 m_autoEOI = value & ICW4_AEOI;
124 m_state &= ~STATE_WAITING_ICW4;
125 } else {
126 // getting OCW1
127 //printf("OCW1 <= %02X\n", value);
128 m_IMR = value;
129 }
130 break;
131 }
132}
133
134
135uint8_t PIC8259::read(int addr)
136{
137 switch (addr) {
138
139 case 0:
140 //printf("%02X <= %s\n", m_readISR ? m_ISR : m_IRR, m_readISR ? "ISR" : "IRR");
141 return m_readISR ? m_ISR : m_IRR;
142
143 case 1:
144 //printf("%02X <= IMR\n", m_IMR);
145 return m_IMR;
146
147 default:
148 return 0;
149
150 }
151}
152
153
154// ret: 0..7
155// 256 = no bit set
156int PIC8259::getHighestPriorityBitNum(uint8_t value)
157{
158 if (value) {
159 for (int i = 0; i < 8; ++i)
160 if ((value >> i) & 1)
161 return i;
162 }
163 return 256;
164}
165
166
167// set as pending interrupt the higher priority bit in M_IRR
168void PIC8259::setPendingInterrupt()
169{
170 int highestInt = getHighestPriorityBitNum(m_IRR & ~m_IMR);
171 int servicingInt = getHighestPriorityBitNum(m_ISR);
172 //printf("PIC8259::setPendingInterrupt(), highestInt=%d, servicingInt=%d\n", highestInt, servicingInt);
173 if (highestInt < servicingInt) {
174 // interrupt in IRR has higher priority than the servicing one
175 m_pendingInterrupt = true;
176 m_pendingIR = highestInt;
177 }
178}
179
180
181// Device->8259: a device reports interrupt to 8259
182bool PIC8259::signalInterrupt(int intnum)
183{
184 //printf("PIC8259::signalInterrupt(%d)\n", intnum);
185 bool success = false;
186 intnum &= 7;
187 // already servicing?
188 if ((m_ISR & (1 << intnum)) == 0) {
189 // no, request interrupt
190 m_IRR |= 1 << intnum;
191 setPendingInterrupt();
192 success = true;
193 }
194 return success;
195}
196
197
198// CPU->8259: CPU acks the pending interrupt to 8259
199void PIC8259::ackPendingInterrupt()
200{
201 //printf("PIC8259::ackPendingInterrupt(), pending IR = %d\n", m_pendingIR);
202 int pendmsk = 1 << m_pendingIR;
203 m_ISR |= pendmsk; // set interrupt bit in ISR
204 m_IRR &= ~pendmsk; // reset interrupt bit in IRR
205 m_pendingInterrupt = false;
206 //printf(" ISR=%02X IRR=%02X\n", m_ISR, m_IRR);
207}
208
209
210// application reports EOI (of the higher interrupt)
211void PIC8259::performEOI()
212{
213 //printf("PIC8259::performEOI()\n");
214 // reset servicing int
215 int servicingInt = getHighestPriorityBitNum(m_ISR);
216 m_ISR &= ~(1 << servicingInt);
217 // is there another interrupt to ask for ack?
218 setPendingInterrupt();
219}
220
221
222} // namespace fabgl