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-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 <string.h>
28 
29 #include "PIT8253.h"
30 
31 
32 
33 namespace fabgl {
34 
35 
36 
37 PIT8253::PIT8253()
38 {
39 }
40 
41 
42 PIT8253::~PIT8253()
43 {
44 }
45 
46 
47 void 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 
60 void 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 
133 uint8_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 
167 void 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 
200 void 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 
210 void 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
Definition: canvas.cpp:36