pixelpump.cc revision 11012:f2ca575d27fd
1/* 2 * Copyright (c) 2015 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 * Authors: Andreas Sandberg 38 */ 39 40#include "dev/pixelpump.hh" 41 42const DisplayTimings DisplayTimings::vga( 43 640, 480, 44 48, 96, 16, 45 33, 2, 10); 46 47 48DisplayTimings::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 57void 58DisplayTimings::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 72void 73DisplayTimings::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 88BasePixelPump::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 104BasePixelPump::~BasePixelPump() 105{ 106} 107 108void 109BasePixelPump::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 122void 123BasePixelPump::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 140void 141BasePixelPump::start(const DisplayTimings &timings) 142{ 143 _timings = timings; 144 145 // Resize the frame buffer if needed 146 if (_timings.width != fb.width() || _timings.height != fb.height()) 147 fb.resize(timings.width, timings.height); 148 149 // Set the current line past the last line in the frame. This 150 // triggers the new frame logic in beginLine(). 151 line = _timings.linesPerFrame(); 152 schedule(evBeginLine, clockEdge()); 153} 154 155void 156BasePixelPump::stop() 157{ 158 if (evVSyncEnd.scheduled()) 159 deschedule(evVSyncEnd); 160 161 if (evHSyncBegin.scheduled()) 162 deschedule(evHSyncBegin); 163 164 if (evHSyncEnd.scheduled()) 165 deschedule(evHSyncEnd); 166 167 if (evBeginLine.scheduled()) 168 deschedule(evBeginLine); 169 170 if (evRenderPixels.scheduled()) 171 deschedule(evRenderPixels); 172} 173 174void 175BasePixelPump::beginLine() 176{ 177 _posX = 0; 178 line++; 179 if (line >= _timings.linesPerFrame()) { 180 _underrun = false; 181 line = 0; 182 } 183 184 if (line == _timings.lineVSyncStart()) { 185 onVSyncBegin(); 186 } else if (line == _timings.lineVBackPorchStart()) { 187 onVSyncEnd(); 188 } 189 190 const Cycles h_sync_begin(0); 191 schedule(evHSyncBegin, clockEdge(h_sync_begin)); 192 193 const Cycles h_sync_end(h_sync_begin + _timings.hSync); 194 schedule(evHSyncEnd, clockEdge(h_sync_end)); 195 196 // Visible area 197 if (line >= _timings.lineFirstVisible() && 198 line < _timings.lineFrontPorchStart()) { 199 200 const Cycles h_first_visible(h_sync_end + _timings.hBackPorch); 201 schedule(evRenderPixels, clockEdge(h_first_visible)); 202 } 203 204 schedule(evBeginLine, clockEdge(_timings.cyclesPerLine())); 205} 206 207void 208BasePixelPump::renderPixels() 209{ 210 // Try to handle multiple pixels at a time; doing so reduces the 211 // accuracy of the underrun detection but lowers simulation 212 // overhead 213 const unsigned x_end(std::min(_posX + pixelChunk, _timings.width)); 214 const unsigned pxl_count(x_end - _posX); 215 const unsigned pos_y(posY()); 216 217 Pixel pixel(0, 0, 0); 218 const Pixel underrun_pixel(0, 0, 0); 219 for (; _posX < x_end && !_underrun; ++_posX) { 220 if (!nextPixel(pixel)) { 221 warn("Input buffer underrun in BasePixelPump (%u, %u)\n", 222 _posX, pos_y); 223 _underrun = true; 224 onUnderrun(_posX, pos_y); 225 pixel = underrun_pixel; 226 } 227 fb.pixel(_posX, pos_y) = pixel; 228 } 229 230 // Fill remaining pixels with a dummy pixel value if we ran out of 231 // data 232 for (; _posX < x_end; ++_posX) 233 fb.pixel(_posX, pos_y) = underrun_pixel; 234 235 // Schedule a new event to handle the next block of pixels 236 if (_posX < _timings.width) { 237 schedule(evRenderPixels, clockEdge(Cycles(pxl_count))); 238 } else { 239 if (pos_y == _timings.height - 1) 240 onFrameDone(); 241 } 242} 243 244BasePixelPump::PixelEvent::PixelEvent( 245 const char *name, BasePixelPump *_parent, CallbackType _func) 246 : Event(), Drainable(), 247 _name(name), parent(*_parent), func(_func), 248 suspended(false), 249 relativeTick(0) 250{ 251 parent.pixelEvents.push_back(this); 252} 253 254DrainState 255BasePixelPump::PixelEvent::drain() 256{ 257 if (scheduled()) 258 suspend(); 259 return DrainState::Drained; 260} 261 262void 263BasePixelPump::PixelEvent::drainResume() 264{ 265 if (suspended) 266 resume(); 267} 268 269void 270BasePixelPump::PixelEvent::serialize(CheckpointOut &cp) const 271{ 272 assert(!scheduled()); 273 Event::serialize(cp); 274 SERIALIZE_SCALAR(suspended); 275 SERIALIZE_SCALAR(relativeTick); 276} 277 278void 279BasePixelPump::PixelEvent::unserialize(CheckpointIn &cp) 280{ 281 Event::unserialize(cp); 282 UNSERIALIZE_SCALAR(suspended); 283 UNSERIALIZE_SCALAR(relativeTick); 284 assert(!scheduled()); 285} 286 287void 288BasePixelPump::PixelEvent::suspend() 289{ 290 assert(scheduled()); 291 assert(!suspended); 292 293 suspended = true; 294 relativeTick = when() - curTick(); 295 parent.deschedule(this); 296} 297 298void 299BasePixelPump::PixelEvent::resume() 300{ 301 assert(!scheduled()); 302 assert(suspended); 303 parent.schedule(this, relativeTick + curTick()); 304 suspended = false; 305 relativeTick = 0; 306} 307