2 * Copyright (c) 2015, 2017 ARM Limited
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.
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.
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.
37 * Authors: Andreas Sandberg
40 #include "dev/pixelpump.hh"
42 const DisplayTimings
DisplayTimings::vga(
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
)
58 DisplayTimings::serialize(CheckpointOut
&cp
) const
60 SERIALIZE_SCALAR(width
);
61 SERIALIZE_SCALAR(height
);
63 SERIALIZE_SCALAR(hBackPorch
);
64 SERIALIZE_SCALAR(hFrontPorch
);
65 SERIALIZE_SCALAR(hSync
);
67 SERIALIZE_SCALAR(vBackPorch
);
68 SERIALIZE_SCALAR(vFrontPorch
);
69 SERIALIZE_SCALAR(vSync
);
73 DisplayTimings::unserialize(CheckpointIn
&cp
)
75 UNSERIALIZE_SCALAR(width
);
76 UNSERIALIZE_SCALAR(height
);
78 UNSERIALIZE_SCALAR(hBackPorch
);
79 UNSERIALIZE_SCALAR(hFrontPorch
);
80 UNSERIALIZE_SCALAR(hSync
);
82 UNSERIALIZE_SCALAR(vBackPorch
);
83 UNSERIALIZE_SCALAR(vFrontPorch
);
84 UNSERIALIZE_SCALAR(vSync
);
88 BasePixelPump::BasePixelPump(EventManager
&em
, ClockDomain
&pxl_clk
,
90 : EventManager(em
), Clocked(pxl_clk
), Serializable(),
91 pixelChunk(pixel_chunk
),
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)
104 BasePixelPump::~BasePixelPump()
109 BasePixelPump::serialize(CheckpointOut
&cp
) const
111 SERIALIZE_SCALAR(line
);
112 SERIALIZE_SCALAR(_posX
);
113 SERIALIZE_SCALAR(_underrun
);
115 SERIALIZE_OBJ(_timings
);
118 for (PixelEvent
*event
: pixelEvents
)
119 event
->serializeSection(cp
, event
->name());
123 BasePixelPump::unserialize(CheckpointIn
&cp
)
125 UNSERIALIZE_SCALAR(line
);
126 UNSERIALIZE_SCALAR(_posX
);
127 UNSERIALIZE_SCALAR(_underrun
);
129 UNSERIALIZE_OBJ(_timings
);
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());
140 BasePixelPump::updateTimings(const DisplayTimings
&timings
)
142 panic_if(active(), "Trying to update timings in active PixelPump\n");
146 // Resize the frame buffer if needed
147 if (_timings
.width
!= fb
.width() || _timings
.height
!= fb
.height())
148 fb
.resize(timings
.width
, timings
.height
);
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();
156 BasePixelPump::start()
158 schedule(evBeginLine
, clockEdge());
163 BasePixelPump::stop()
165 if (evVSyncEnd
.scheduled())
166 deschedule(evVSyncEnd
);
168 if (evHSyncBegin
.scheduled())
169 deschedule(evHSyncBegin
);
171 if (evHSyncEnd
.scheduled())
172 deschedule(evHSyncEnd
);
174 if (evBeginLine
.scheduled())
175 deschedule(evBeginLine
);
177 if (evRenderPixels
.scheduled())
178 deschedule(evRenderPixels
);
182 BasePixelPump::beginLine()
186 if (line
>= _timings
.linesPerFrame()) {
191 if (line
== _timings
.lineVSyncStart()) {
193 } else if (line
== _timings
.lineVBackPorchStart()) {
197 const Cycles
h_sync_begin(0);
198 schedule(evHSyncBegin
, clockEdge(h_sync_begin
));
200 const Cycles
h_sync_end(h_sync_begin
+ _timings
.hSync
);
201 schedule(evHSyncEnd
, clockEdge(h_sync_end
));
204 if (line
>= _timings
.lineFirstVisible() &&
205 line
< _timings
.lineFrontPorchStart()) {
207 const Cycles
h_first_visible(h_sync_end
+ _timings
.hBackPorch
);
208 schedule(evRenderPixels
, clockEdge(h_first_visible
));
211 schedule(evBeginLine
, clockEdge(_timings
.cyclesPerLine()));
215 BasePixelPump::renderPixels()
217 // Try to handle multiple pixels at a time; doing so reduces the
218 // accuracy of the underrun detection but lowers simulation
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());
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",
231 onUnderrun(_posX
, pos_y
);
232 pixel
= underrun_pixel
;
234 fb
.pixel(_posX
, pos_y
) = pixel
;
237 // Fill remaining pixels with a dummy pixel value if we ran out of
239 for (; _posX
< x_end
; ++_posX
)
240 fb
.pixel(_posX
, pos_y
) = underrun_pixel
;
242 // Schedule a new event to handle the next block of pixels
243 if (_posX
< _timings
.width
) {
244 schedule(evRenderPixels
, clockEdge(Cycles(pxl_count
)));
246 if (pos_y
== _timings
.height
- 1)
252 BasePixelPump::renderFrame()
257 // Signal vsync end and render the frame
258 line
= _timings
.lineVBackPorchStart();
261 // We only care about the visible screen area when rendering the
263 for (line
= _timings
.lineFirstVisible();
264 line
< _timings
.lineFrontPorchStart();
275 line
= _timings
.lineFrontPorchStart() - 1;
278 // Signal vsync until the next frame begins
279 line
= _timings
.lineVSyncStart();
284 BasePixelPump::renderLine()
286 const unsigned pos_y(posY());
288 Pixel
pixel(0, 0, 0);
289 for (_posX
= 0; _posX
< _timings
.width
; ++_posX
) {
290 if (!nextPixel(pixel
)) {
291 panic("Unexpected underrun in BasePixelPump (%u, %u)\n",
294 fb
.pixel(_posX
, pos_y
) = pixel
;
299 BasePixelPump::PixelEvent::PixelEvent(
300 const char *name
, BasePixelPump
*_parent
, CallbackType _func
)
301 : Event(), Drainable(),
302 _name(name
), parent(*_parent
), func(_func
),
306 parent
.pixelEvents
.push_back(this);
310 BasePixelPump::PixelEvent::drain()
314 return DrainState::Drained
;
318 BasePixelPump::PixelEvent::drainResume()
325 BasePixelPump::PixelEvent::serialize(CheckpointOut
&cp
) const
327 assert(!scheduled());
328 Event::serialize(cp
);
329 SERIALIZE_SCALAR(suspended
);
330 SERIALIZE_SCALAR(relativeTick
);
334 BasePixelPump::PixelEvent::unserialize(CheckpointIn
&cp
)
336 Event::unserialize(cp
);
337 UNSERIALIZE_SCALAR(suspended
);
338 UNSERIALIZE_SCALAR(relativeTick
);
339 assert(!scheduled());
343 BasePixelPump::PixelEvent::suspend()
349 relativeTick
= when() - curTick();
350 parent
.deschedule(this);
354 BasePixelPump::PixelEvent::resume()
356 assert(!scheduled());
358 parent
.schedule(this, relativeTick
+ curTick());