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-2021 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 
31 namespace 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 
65 void 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 
79 void 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 
135 uint8_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
156 int 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
168 void 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
182 bool 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
199 void 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)
211 void 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
Definition: canvas.cpp:36