FabGL
ESP32 Display Controller and Graphics Library
PIT8253.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 <string.h>
28
29#include "PIT8253.h"
30
31
32
33namespace fabgl {
34
35
36
37PIT8253::PIT8253()
38{
39}
40
41
42PIT8253::~PIT8253()
43{
44}
45
46
47void PIT8253::reset()
48{
49 for (int i = 0; i < 3; ++i) {
50 memset(&m_timer[i], 0, sizeof(TimerInfo));
51 m_timer[i].mode = 3;
52 m_timer[i].RLMode = 3;
53 m_timer[i].latch = -1;
54 m_timer[i].LSBToggle = true;
55 }
56 m_lastTickTime = esp_timer_get_time();
57}
58
59
60void PIT8253::write(int reg, uint8_t value)
61{
62 // just in case ticks are needed
63 tick();
64
65 int timerIndex;
66
67 if (reg == 3) {
68
69 // write control register
70 timerIndex = (value >> 6) & 0x03;
71
72 int RLMode = (value >> 4) & 0x03;
73
74 if (RLMode == 0) {
75 // counter latching operation (doesn't change BCD or mode)
76 m_timer[timerIndex].latch = m_timer[timerIndex].count;
77 m_timer[timerIndex].LSBToggle = true;
78 m_timer[timerIndex].ctrlSet = false;
79 //printf("%lld, PIT8253: write ctrl reg, %02X (timer=%d, latched=%04X)\n", esp_timer_get_time(), value, timerIndex, m_timer[timerIndex].latch);
80 } else {
81 // read / load
82 m_timer[timerIndex].mode = (value >> 1) & 0x07;
83 m_timer[timerIndex].BCD = (value & 1) == 1;
84 m_timer[timerIndex].RLMode = RLMode;
85 m_timer[timerIndex].ctrlSet = true;
86 if (RLMode == 3)
87 m_timer[timerIndex].LSBToggle = true;
88 //printf("%lld, PIT8253: write ctrl reg, %02X (timer=%d, mode=%d)\n", esp_timer_get_time(), value, timerIndex, m_timer[timerIndex].mode);
89 }
90
91 if (value >> 6 == 3)
92 printf("8253, read back. Required 8254?\n");
93
94 } else {
95
96 // write timers registers
97 timerIndex = reg;
98 bool writeLSB = false;
99
100 switch (m_timer[timerIndex].RLMode) {
101 case 1:
102 writeLSB = true;
103 break;
104 case 3:
105 writeLSB = m_timer[timerIndex].LSBToggle;
106 m_timer[timerIndex].LSBToggle = !m_timer[timerIndex].LSBToggle;
107 break;
108 }
109
110 if (writeLSB) {
111 // LSB
112 //printf("%lld, PIT8253: timer %d write LSB, %02X\n", esp_timer_get_time(), timerIndex, value);
113 m_timer[timerIndex].resetHolding = (m_timer[timerIndex].resetHolding & 0xFF00) | value;
114 } else {
115 // MSB
116 //printf("%lld, PIT8253: timer %d write MSB, %02X\n", esp_timer_get_time(), timerIndex, value);
117 m_timer[timerIndex].resetHolding = (m_timer[timerIndex].resetHolding & 0x00FF) | (((int)value) << 8);
118 m_timer[timerIndex].resetCount = m_timer[timerIndex].resetHolding;
119 if (m_timer[timerIndex].ctrlSet) {
120 m_timer[timerIndex].count = (uint16_t)(m_timer[timerIndex].resetCount - 1);
121 m_timer[timerIndex].ctrlSet = false;
122 }
123 }
124
125 // OUT: with mode 0 it starts low, other modes it starts high
126 changeOut(timerIndex, m_timer[timerIndex].mode != 0);
127
128 }
129
130}
131
132
133uint8_t PIT8253::read(int reg)
134{
135 // just in case ticks are needed
136 tick();
137
138 uint8_t value = 0;
139
140 if (reg < 3) {
141 // read timers registers
142 int timerIndex = reg;
143
144 int readValue = m_timer[timerIndex].latch != -1 ? m_timer[timerIndex].latch : m_timer[timerIndex].count;
145
146 bool readLSB = false;
147 if (m_timer[timerIndex].RLMode == 1) {
148 readLSB = true;
149 } else if (m_timer[timerIndex].RLMode == 3) {
150 readLSB = m_timer[timerIndex].LSBToggle;
151 m_timer[timerIndex].LSBToggle = !m_timer[timerIndex].LSBToggle;
152 }
153
154 if (readLSB) {
155 value = readValue & 0xFF;
156 } else {
157 value = (readValue >> 8) & 0xFF;
158 m_timer[timerIndex].latch = -1;
159 }
160 //printf("read reg %d => %02X (%04X)\n", reg, value, readValue);
161 }
162
163 return value;
164}
165
166
167void PIT8253::setGate(int timerIndex, bool value)
168{
169 // just in case ticks are needed
170 tick();
171
172 switch (m_timer[timerIndex].mode) {
173 case 0:
174 case 2:
175 case 3:
176 // running when gate is high
177 m_timer[timerIndex].running = value;
178 break;
179 case 1:
180 case 5:
181 // switch to running when gate changes to high
182 if (m_timer[timerIndex].gate == false && value == true)
183 m_timer[timerIndex].running = true;
184 break;
185 }
186 switch (m_timer[timerIndex].mode) {
187 case 2:
188 case 3:
189 if (value == false)
190 changeOut(timerIndex, true);
191 break;
192 }
193 if (!m_timer[timerIndex].gate && value)
194 m_timer[timerIndex].count = m_timer[timerIndex].resetCount;
195 m_timer[timerIndex].gate = value;
196 //printf("setGate(%d, %d) [gate=%d running=%d]\n", timerIndex, value, m_timer[timerIndex].gate, m_timer[timerIndex].running);
197}
198
199
200void PIT8253::changeOut(int timer, bool value)
201{
202 if (value != m_timer[timer].out) {
203 //printf("timer %d, out = %d\n", timer, value);
204 m_timer[timer].out = value;
205 m_changeOut(m_context, timer);
206 }
207}
208
209
210void PIT8253::tick()
211{
212 uint64_t now = esp_timer_get_time();
213 int ticks = (int) ((now - m_lastTickTime) * 1000 / (1000000000 / PIT_TICK_FREQ));
214 //printf("ticks=%d (now=%lld last=%lld now-last=%lld)\n", ticks, now, m_lastTickTime, now-m_lastTickTime);
215 if (ticks == 0)
216 return;
217 m_lastTickTime = now;
218
219 if (ticks > 65535)
220 printf("Too much ticks! (%d)\n", ticks);
221
222 for (int timerIndex = 0; timerIndex < 3; ++timerIndex) {
223
224 if (m_timer[timerIndex].running) {
225
226 // modes 4 or 5, end of ending low pulse?
227 if (m_timer[timerIndex].mode >= 4 && m_timer[timerIndex].out == false) {
228 // mode 4, end of low pulse
229 changeOut(timerIndex, true);
230 m_timer[timerIndex].running = false;
231 m_timer[timerIndex].count = 65535;
232 continue;
233 }
234
235 m_timer[timerIndex].count -= ticks;
236
237 // in mode 3 each tick subtract 2 instead of 1
238 if (m_timer[timerIndex].mode == 3)
239 m_timer[timerIndex].count -= ticks;
240
241 if (m_timer[timerIndex].count <= 0) {
242 // count terminated
243 if (m_timer[timerIndex].resetCount == 0) {
244 m_timer[timerIndex].count += 65536;
245 } else {
246 m_timer[timerIndex].count += m_timer[timerIndex].resetCount;
247 }
248 switch (m_timer[timerIndex].mode) {
249 case 0:
250 // at the end OUT goes high
251 changeOut(timerIndex, true);
252 break;
253 case 1:
254 // at the end OUT goes high
255 changeOut(timerIndex, true);
256 break;
257 case 2:
258 changeOut(timerIndex, false);
259 break;
260 case 3:
261 changeOut(timerIndex, !m_timer[timerIndex].out);
262 break;
263 }
264 } else {
265 // count running
266 switch (m_timer[timerIndex].mode) {
267 case 1:
268 // OUT is low while running
269 changeOut(timerIndex, false);
270 break;
271 case 2:
272 changeOut(timerIndex, true);
273 break;
274 case 4:
275 case 5:
276 // start low pulse
277 changeOut(timerIndex, false);
278 break;
279 }
280 }
281
282 }
283
284 //if (m_timer[timerIndex].running) printf("running: timer %d [count = %04X, ticks = %d]\n", timerIndex, m_timer[timerIndex].count, ticks);
285 }
286}
287
288
289} // namespace fabgl