arch-power: Add fields for DS form instructions
[gem5.git] / src / dev / pixelpump.cc
1 /*
2 * Copyright (c) 2015, 2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "dev/pixelpump.hh"
39
40 #include "base/logging.hh"
41
42 const DisplayTimings DisplayTimings::vga(
43 640, 480,
44 48, 96, 16,
45 33, 2, 10);
46
47
48 DisplayTimings::DisplayTimings(unsigned _width, unsigned _height,
49 unsigned hbp, unsigned h_sync, unsigned hfp,
50 unsigned vbp, unsigned v_sync, unsigned vfp)
51 : width(_width), height(_height),
52 hBackPorch(hbp), hFrontPorch(hfp), hSync(h_sync),
53 vBackPorch(vbp), vFrontPorch(vfp), vSync(v_sync)
54 {
55 }
56
57 void
58 DisplayTimings::serialize(CheckpointOut &cp) const
59 {
60 SERIALIZE_SCALAR(width);
61 SERIALIZE_SCALAR(height);
62
63 SERIALIZE_SCALAR(hBackPorch);
64 SERIALIZE_SCALAR(hFrontPorch);
65 SERIALIZE_SCALAR(hSync);
66
67 SERIALIZE_SCALAR(vBackPorch);
68 SERIALIZE_SCALAR(vFrontPorch);
69 SERIALIZE_SCALAR(vSync);
70 }
71
72 void
73 DisplayTimings::unserialize(CheckpointIn &cp)
74 {
75 UNSERIALIZE_SCALAR(width);
76 UNSERIALIZE_SCALAR(height);
77
78 UNSERIALIZE_SCALAR(hBackPorch);
79 UNSERIALIZE_SCALAR(hFrontPorch);
80 UNSERIALIZE_SCALAR(hSync);
81
82 UNSERIALIZE_SCALAR(vBackPorch);
83 UNSERIALIZE_SCALAR(vFrontPorch);
84 UNSERIALIZE_SCALAR(vSync);
85 }
86
87
88 BasePixelPump::BasePixelPump(EventManager &em, ClockDomain &pxl_clk,
89 unsigned pixel_chunk)
90 : EventManager(em), Clocked(pxl_clk), Serializable(),
91 pixelChunk(pixel_chunk),
92 pixelEvents(),
93 evVSyncBegin("evVSyncBegin", this, &BasePixelPump::onVSyncBegin),
94 evVSyncEnd("evVSyncEnd", this, &BasePixelPump::onVSyncEnd),
95 evHSyncBegin("evHSyncBegin", this, &BasePixelPump::onHSyncBegin),
96 evHSyncEnd("evHSyncEnd", this, &BasePixelPump::onHSyncEnd),
97 evBeginLine("evBeginLine", this, &BasePixelPump::beginLine),
98 evRenderPixels("evRenderPixels", this, &BasePixelPump::renderPixels),
99 _timings(DisplayTimings::vga),
100 line(0), _posX(0), _underrun(false)
101 {
102 }
103
104 BasePixelPump::~BasePixelPump()
105 {
106 }
107
108 void
109 BasePixelPump::serialize(CheckpointOut &cp) const
110 {
111 SERIALIZE_SCALAR(line);
112 SERIALIZE_SCALAR(_posX);
113 SERIALIZE_SCALAR(_underrun);
114
115 SERIALIZE_OBJ(_timings);
116 SERIALIZE_OBJ(fb);
117
118 for (PixelEvent *event : pixelEvents)
119 event->serializeSection(cp, event->name());
120 }
121
122 void
123 BasePixelPump::unserialize(CheckpointIn &cp)
124 {
125 UNSERIALIZE_SCALAR(line);
126 UNSERIALIZE_SCALAR(_posX);
127 UNSERIALIZE_SCALAR(_underrun);
128
129 UNSERIALIZE_OBJ(_timings);
130 UNSERIALIZE_OBJ(fb);
131
132 // We don't need to reschedule the event here since the event was
133 // suspended by PixelEvent::drain() and will be rescheduled by
134 // PixelEvent::drainResume().
135 for (PixelEvent *event : pixelEvents)
136 event->unserializeSection(cp, event->name());
137 }
138
139 void
140 BasePixelPump::updateTimings(const DisplayTimings &timings)
141 {
142 panic_if(active(), "Trying to update timings in active PixelPump\n");
143
144 _timings = timings;
145
146 // Resize the frame buffer if needed
147 if (_timings.width != fb.width() || _timings.height != fb.height())
148 fb.resize(timings.width, timings.height);
149
150 // Set the current line past the last line in the frame. This
151 // triggers the new frame logic in beginLine().
152 line = _timings.linesPerFrame();
153 }
154
155 void
156 BasePixelPump::start()
157 {
158 schedule(evBeginLine, clockEdge());
159 }
160
161
162 void
163 BasePixelPump::stop()
164 {
165 if (evVSyncEnd.scheduled())
166 deschedule(evVSyncEnd);
167
168 if (evHSyncBegin.scheduled())
169 deschedule(evHSyncBegin);
170
171 if (evHSyncEnd.scheduled())
172 deschedule(evHSyncEnd);
173
174 if (evBeginLine.scheduled())
175 deschedule(evBeginLine);
176
177 if (evRenderPixels.scheduled())
178 deschedule(evRenderPixels);
179 }
180
181 void
182 BasePixelPump::beginLine()
183 {
184 _posX = 0;
185 line++;
186 if (line >= _timings.linesPerFrame()) {
187 _underrun = false;
188 line = 0;
189 }
190
191 if (line == _timings.lineVSyncStart()) {
192 onVSyncBegin();
193 } else if (line == _timings.lineVBackPorchStart()) {
194 onVSyncEnd();
195 }
196
197 const Cycles h_sync_begin(0);
198 schedule(evHSyncBegin, clockEdge(h_sync_begin));
199
200 const Cycles h_sync_end(h_sync_begin + _timings.hSync);
201 schedule(evHSyncEnd, clockEdge(h_sync_end));
202
203 // Visible area
204 if (line >= _timings.lineFirstVisible() &&
205 line < _timings.lineFrontPorchStart()) {
206
207 const Cycles h_first_visible(h_sync_end + _timings.hBackPorch);
208 schedule(evRenderPixels, clockEdge(h_first_visible));
209 }
210
211 schedule(evBeginLine, clockEdge(_timings.cyclesPerLine()));
212 }
213
214 void
215 BasePixelPump::renderPixels()
216 {
217 // Try to handle multiple pixels at a time; doing so reduces the
218 // accuracy of the underrun detection but lowers simulation
219 // overhead
220 const unsigned x_end(std::min(_posX + pixelChunk, _timings.width));
221 const unsigned pxl_count(x_end - _posX);
222 const unsigned pos_y(posY());
223
224 Pixel pixel(0, 0, 0);
225 const Pixel underrun_pixel(0, 0, 0);
226 for (; _posX < x_end && !_underrun; ++_posX) {
227 if (!nextPixel(pixel)) {
228 warn("Input buffer underrun in BasePixelPump (%u, %u)\n",
229 _posX, pos_y);
230 _underrun = true;
231 onUnderrun(_posX, pos_y);
232 pixel = underrun_pixel;
233 }
234 fb.pixel(_posX, pos_y) = pixel;
235 }
236
237 // Fill remaining pixels with a dummy pixel value if we ran out of
238 // data
239 for (; _posX < x_end; ++_posX)
240 fb.pixel(_posX, pos_y) = underrun_pixel;
241
242 // Schedule a new event to handle the next block of pixels
243 if (_posX < _timings.width) {
244 schedule(evRenderPixels, clockEdge(Cycles(pxl_count)));
245 } else {
246 if (pos_y == _timings.height - 1)
247 onFrameDone();
248 }
249 }
250
251 void
252 BasePixelPump::renderFrame()
253 {
254 _underrun = false;
255 line = 0;
256
257 // Signal vsync end and render the frame
258 line = _timings.lineVBackPorchStart();
259 onVSyncEnd();
260
261 // We only care about the visible screen area when rendering the
262 // frame
263 for (line = _timings.lineFirstVisible();
264 line < _timings.lineFrontPorchStart();
265 ++line) {
266
267 _posX = 0;
268
269 onHSyncBegin();
270 onHSyncEnd();
271
272 renderLine();
273 }
274
275 line = _timings.lineFrontPorchStart() - 1;
276 onFrameDone();
277
278 // Signal vsync until the next frame begins
279 line = _timings.lineVSyncStart();
280 onVSyncBegin();
281 }
282
283 void
284 BasePixelPump::renderLine()
285 {
286 const unsigned pos_y = posY();
287 const size_t _width = fb.width();
288
289 auto pixel_it = fb.pixels.begin() + _width * pos_y;
290 panic_if(nextLine(pixel_it, _width) != _width,
291 "Unexpected underrun in BasePixelPump (%u, %u)", _width, pos_y);
292 }
293
294
295 BasePixelPump::PixelEvent::PixelEvent(
296 const char *name, BasePixelPump *_parent, CallbackType _func)
297 : Event(), Drainable(),
298 _name(name), parent(*_parent), func(_func),
299 suspended(false),
300 relativeTick(0)
301 {
302 parent.pixelEvents.push_back(this);
303 }
304
305 DrainState
306 BasePixelPump::PixelEvent::drain()
307 {
308 if (scheduled())
309 suspend();
310 return DrainState::Drained;
311 }
312
313 void
314 BasePixelPump::PixelEvent::drainResume()
315 {
316 if (suspended)
317 resume();
318 }
319
320 void
321 BasePixelPump::PixelEvent::serialize(CheckpointOut &cp) const
322 {
323 assert(!scheduled());
324 Event::serialize(cp);
325 SERIALIZE_SCALAR(suspended);
326 SERIALIZE_SCALAR(relativeTick);
327 }
328
329 void
330 BasePixelPump::PixelEvent::unserialize(CheckpointIn &cp)
331 {
332 Event::unserialize(cp);
333 UNSERIALIZE_SCALAR(suspended);
334 UNSERIALIZE_SCALAR(relativeTick);
335 assert(!scheduled());
336 }
337
338 void
339 BasePixelPump::PixelEvent::suspend()
340 {
341 assert(scheduled());
342 assert(!suspended);
343
344 suspended = true;
345 relativeTick = when() - curTick();
346 parent.deschedule(this);
347 }
348
349 void
350 BasePixelPump::PixelEvent::resume()
351 {
352 assert(!scheduled());
353 assert(suspended);
354 parent.schedule(this, relativeTick + curTick());
355 suspended = false;
356 relativeTick = 0;
357 }