pixelpump.cc revision 11012
111012Sandreas.sandberg@arm.com/* 211012Sandreas.sandberg@arm.com * Copyright (c) 2015 ARM Limited 311012Sandreas.sandberg@arm.com * All rights reserved 411012Sandreas.sandberg@arm.com * 511012Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall 611012Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual 711012Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating 811012Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software 911012Sandreas.sandberg@arm.com * licensed hereunder. You may use the software subject to the license 1011012Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated 1111012Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software, 1211012Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form. 1311012Sandreas.sandberg@arm.com * 1411012Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without 1511012Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are 1611012Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright 1711012Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer; 1811012Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright 1911012Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 2011012Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution; 2111012Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its 2211012Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from 2311012Sandreas.sandberg@arm.com * this software without specific prior written permission. 2411012Sandreas.sandberg@arm.com * 2511012Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2611012Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2711012Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2811012Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2911012Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3011012Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3111012Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3211012Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3311012Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3411012Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3511012Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3611012Sandreas.sandberg@arm.com * 3711012Sandreas.sandberg@arm.com * Authors: Andreas Sandberg 3811012Sandreas.sandberg@arm.com */ 3911012Sandreas.sandberg@arm.com 4011012Sandreas.sandberg@arm.com#include "dev/pixelpump.hh" 4111012Sandreas.sandberg@arm.com 4211012Sandreas.sandberg@arm.comconst DisplayTimings DisplayTimings::vga( 4311012Sandreas.sandberg@arm.com 640, 480, 4411012Sandreas.sandberg@arm.com 48, 96, 16, 4511012Sandreas.sandberg@arm.com 33, 2, 10); 4611012Sandreas.sandberg@arm.com 4711012Sandreas.sandberg@arm.com 4811012Sandreas.sandberg@arm.comDisplayTimings::DisplayTimings(unsigned _width, unsigned _height, 4911012Sandreas.sandberg@arm.com unsigned hbp, unsigned h_sync, unsigned hfp, 5011012Sandreas.sandberg@arm.com unsigned vbp, unsigned v_sync, unsigned vfp) 5111012Sandreas.sandberg@arm.com : width(_width), height(_height), 5211012Sandreas.sandberg@arm.com hBackPorch(hbp), hFrontPorch(hfp), hSync(h_sync), 5311012Sandreas.sandberg@arm.com vBackPorch(vbp), vFrontPorch(vfp), vSync(v_sync) 5411012Sandreas.sandberg@arm.com{ 5511012Sandreas.sandberg@arm.com} 5611012Sandreas.sandberg@arm.com 5711012Sandreas.sandberg@arm.comvoid 5811012Sandreas.sandberg@arm.comDisplayTimings::serialize(CheckpointOut &cp) const 5911012Sandreas.sandberg@arm.com{ 6011012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(width); 6111012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(height); 6211012Sandreas.sandberg@arm.com 6311012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(hBackPorch); 6411012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(hFrontPorch); 6511012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(hSync); 6611012Sandreas.sandberg@arm.com 6711012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(vBackPorch); 6811012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(vFrontPorch); 6911012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(vSync); 7011012Sandreas.sandberg@arm.com} 7111012Sandreas.sandberg@arm.com 7211012Sandreas.sandberg@arm.comvoid 7311012Sandreas.sandberg@arm.comDisplayTimings::unserialize(CheckpointIn &cp) 7411012Sandreas.sandberg@arm.com{ 7511012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(width); 7611012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(height); 7711012Sandreas.sandberg@arm.com 7811012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(hBackPorch); 7911012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(hFrontPorch); 8011012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(hSync); 8111012Sandreas.sandberg@arm.com 8211012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(vBackPorch); 8311012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(vFrontPorch); 8411012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(vSync); 8511012Sandreas.sandberg@arm.com} 8611012Sandreas.sandberg@arm.com 8711012Sandreas.sandberg@arm.com 8811012Sandreas.sandberg@arm.comBasePixelPump::BasePixelPump(EventManager &em, ClockDomain &pxl_clk, 8911012Sandreas.sandberg@arm.com unsigned pixel_chunk) 9011012Sandreas.sandberg@arm.com : EventManager(em), Clocked(pxl_clk), Serializable(), 9111012Sandreas.sandberg@arm.com pixelChunk(pixel_chunk), 9211012Sandreas.sandberg@arm.com pixelEvents(), 9311012Sandreas.sandberg@arm.com evVSyncBegin("evVSyncBegin", this, &BasePixelPump::onVSyncBegin), 9411012Sandreas.sandberg@arm.com evVSyncEnd("evVSyncEnd", this, &BasePixelPump::onVSyncEnd), 9511012Sandreas.sandberg@arm.com evHSyncBegin("evHSyncBegin", this, &BasePixelPump::onHSyncBegin), 9611012Sandreas.sandberg@arm.com evHSyncEnd("evHSyncEnd", this, &BasePixelPump::onHSyncEnd), 9711012Sandreas.sandberg@arm.com evBeginLine("evBeginLine", this, &BasePixelPump::beginLine), 9811012Sandreas.sandberg@arm.com evRenderPixels("evRenderPixels", this, &BasePixelPump::renderPixels), 9911012Sandreas.sandberg@arm.com _timings(DisplayTimings::vga), 10011012Sandreas.sandberg@arm.com line(0), _posX(0), _underrun(false) 10111012Sandreas.sandberg@arm.com{ 10211012Sandreas.sandberg@arm.com} 10311012Sandreas.sandberg@arm.com 10411012Sandreas.sandberg@arm.comBasePixelPump::~BasePixelPump() 10511012Sandreas.sandberg@arm.com{ 10611012Sandreas.sandberg@arm.com} 10711012Sandreas.sandberg@arm.com 10811012Sandreas.sandberg@arm.comvoid 10911012Sandreas.sandberg@arm.comBasePixelPump::serialize(CheckpointOut &cp) const 11011012Sandreas.sandberg@arm.com{ 11111012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(line); 11211012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(_posX); 11311012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(_underrun); 11411012Sandreas.sandberg@arm.com 11511012Sandreas.sandberg@arm.com SERIALIZE_OBJ(_timings); 11611012Sandreas.sandberg@arm.com SERIALIZE_OBJ(fb); 11711012Sandreas.sandberg@arm.com 11811012Sandreas.sandberg@arm.com for (PixelEvent *event : pixelEvents) 11911012Sandreas.sandberg@arm.com event->serializeSection(cp, event->name()); 12011012Sandreas.sandberg@arm.com} 12111012Sandreas.sandberg@arm.com 12211012Sandreas.sandberg@arm.comvoid 12311012Sandreas.sandberg@arm.comBasePixelPump::unserialize(CheckpointIn &cp) 12411012Sandreas.sandberg@arm.com{ 12511012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(line); 12611012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(_posX); 12711012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(_underrun); 12811012Sandreas.sandberg@arm.com 12911012Sandreas.sandberg@arm.com UNSERIALIZE_OBJ(_timings); 13011012Sandreas.sandberg@arm.com UNSERIALIZE_OBJ(fb); 13111012Sandreas.sandberg@arm.com 13211012Sandreas.sandberg@arm.com // We don't need to reschedule the event here since the event was 13311012Sandreas.sandberg@arm.com // suspended by PixelEvent::drain() and will be rescheduled by 13411012Sandreas.sandberg@arm.com // PixelEvent::drainResume(). 13511012Sandreas.sandberg@arm.com for (PixelEvent *event : pixelEvents) 13611012Sandreas.sandberg@arm.com event->unserializeSection(cp, event->name()); 13711012Sandreas.sandberg@arm.com} 13811012Sandreas.sandberg@arm.com 13911012Sandreas.sandberg@arm.com 14011012Sandreas.sandberg@arm.comvoid 14111012Sandreas.sandberg@arm.comBasePixelPump::start(const DisplayTimings &timings) 14211012Sandreas.sandberg@arm.com{ 14311012Sandreas.sandberg@arm.com _timings = timings; 14411012Sandreas.sandberg@arm.com 14511012Sandreas.sandberg@arm.com // Resize the frame buffer if needed 14611012Sandreas.sandberg@arm.com if (_timings.width != fb.width() || _timings.height != fb.height()) 14711012Sandreas.sandberg@arm.com fb.resize(timings.width, timings.height); 14811012Sandreas.sandberg@arm.com 14911012Sandreas.sandberg@arm.com // Set the current line past the last line in the frame. This 15011012Sandreas.sandberg@arm.com // triggers the new frame logic in beginLine(). 15111012Sandreas.sandberg@arm.com line = _timings.linesPerFrame(); 15211012Sandreas.sandberg@arm.com schedule(evBeginLine, clockEdge()); 15311012Sandreas.sandberg@arm.com} 15411012Sandreas.sandberg@arm.com 15511012Sandreas.sandberg@arm.comvoid 15611012Sandreas.sandberg@arm.comBasePixelPump::stop() 15711012Sandreas.sandberg@arm.com{ 15811012Sandreas.sandberg@arm.com if (evVSyncEnd.scheduled()) 15911012Sandreas.sandberg@arm.com deschedule(evVSyncEnd); 16011012Sandreas.sandberg@arm.com 16111012Sandreas.sandberg@arm.com if (evHSyncBegin.scheduled()) 16211012Sandreas.sandberg@arm.com deschedule(evHSyncBegin); 16311012Sandreas.sandberg@arm.com 16411012Sandreas.sandberg@arm.com if (evHSyncEnd.scheduled()) 16511012Sandreas.sandberg@arm.com deschedule(evHSyncEnd); 16611012Sandreas.sandberg@arm.com 16711012Sandreas.sandberg@arm.com if (evBeginLine.scheduled()) 16811012Sandreas.sandberg@arm.com deschedule(evBeginLine); 16911012Sandreas.sandberg@arm.com 17011012Sandreas.sandberg@arm.com if (evRenderPixels.scheduled()) 17111012Sandreas.sandberg@arm.com deschedule(evRenderPixels); 17211012Sandreas.sandberg@arm.com} 17311012Sandreas.sandberg@arm.com 17411012Sandreas.sandberg@arm.comvoid 17511012Sandreas.sandberg@arm.comBasePixelPump::beginLine() 17611012Sandreas.sandberg@arm.com{ 17711012Sandreas.sandberg@arm.com _posX = 0; 17811012Sandreas.sandberg@arm.com line++; 17911012Sandreas.sandberg@arm.com if (line >= _timings.linesPerFrame()) { 18011012Sandreas.sandberg@arm.com _underrun = false; 18111012Sandreas.sandberg@arm.com line = 0; 18211012Sandreas.sandberg@arm.com } 18311012Sandreas.sandberg@arm.com 18411012Sandreas.sandberg@arm.com if (line == _timings.lineVSyncStart()) { 18511012Sandreas.sandberg@arm.com onVSyncBegin(); 18611012Sandreas.sandberg@arm.com } else if (line == _timings.lineVBackPorchStart()) { 18711012Sandreas.sandberg@arm.com onVSyncEnd(); 18811012Sandreas.sandberg@arm.com } 18911012Sandreas.sandberg@arm.com 19011012Sandreas.sandberg@arm.com const Cycles h_sync_begin(0); 19111012Sandreas.sandberg@arm.com schedule(evHSyncBegin, clockEdge(h_sync_begin)); 19211012Sandreas.sandberg@arm.com 19311012Sandreas.sandberg@arm.com const Cycles h_sync_end(h_sync_begin + _timings.hSync); 19411012Sandreas.sandberg@arm.com schedule(evHSyncEnd, clockEdge(h_sync_end)); 19511012Sandreas.sandberg@arm.com 19611012Sandreas.sandberg@arm.com // Visible area 19711012Sandreas.sandberg@arm.com if (line >= _timings.lineFirstVisible() && 19811012Sandreas.sandberg@arm.com line < _timings.lineFrontPorchStart()) { 19911012Sandreas.sandberg@arm.com 20011012Sandreas.sandberg@arm.com const Cycles h_first_visible(h_sync_end + _timings.hBackPorch); 20111012Sandreas.sandberg@arm.com schedule(evRenderPixels, clockEdge(h_first_visible)); 20211012Sandreas.sandberg@arm.com } 20311012Sandreas.sandberg@arm.com 20411012Sandreas.sandberg@arm.com schedule(evBeginLine, clockEdge(_timings.cyclesPerLine())); 20511012Sandreas.sandberg@arm.com} 20611012Sandreas.sandberg@arm.com 20711012Sandreas.sandberg@arm.comvoid 20811012Sandreas.sandberg@arm.comBasePixelPump::renderPixels() 20911012Sandreas.sandberg@arm.com{ 21011012Sandreas.sandberg@arm.com // Try to handle multiple pixels at a time; doing so reduces the 21111012Sandreas.sandberg@arm.com // accuracy of the underrun detection but lowers simulation 21211012Sandreas.sandberg@arm.com // overhead 21311012Sandreas.sandberg@arm.com const unsigned x_end(std::min(_posX + pixelChunk, _timings.width)); 21411012Sandreas.sandberg@arm.com const unsigned pxl_count(x_end - _posX); 21511012Sandreas.sandberg@arm.com const unsigned pos_y(posY()); 21611012Sandreas.sandberg@arm.com 21711012Sandreas.sandberg@arm.com Pixel pixel(0, 0, 0); 21811012Sandreas.sandberg@arm.com const Pixel underrun_pixel(0, 0, 0); 21911012Sandreas.sandberg@arm.com for (; _posX < x_end && !_underrun; ++_posX) { 22011012Sandreas.sandberg@arm.com if (!nextPixel(pixel)) { 22111012Sandreas.sandberg@arm.com warn("Input buffer underrun in BasePixelPump (%u, %u)\n", 22211012Sandreas.sandberg@arm.com _posX, pos_y); 22311012Sandreas.sandberg@arm.com _underrun = true; 22411012Sandreas.sandberg@arm.com onUnderrun(_posX, pos_y); 22511012Sandreas.sandberg@arm.com pixel = underrun_pixel; 22611012Sandreas.sandberg@arm.com } 22711012Sandreas.sandberg@arm.com fb.pixel(_posX, pos_y) = pixel; 22811012Sandreas.sandberg@arm.com } 22911012Sandreas.sandberg@arm.com 23011012Sandreas.sandberg@arm.com // Fill remaining pixels with a dummy pixel value if we ran out of 23111012Sandreas.sandberg@arm.com // data 23211012Sandreas.sandberg@arm.com for (; _posX < x_end; ++_posX) 23311012Sandreas.sandberg@arm.com fb.pixel(_posX, pos_y) = underrun_pixel; 23411012Sandreas.sandberg@arm.com 23511012Sandreas.sandberg@arm.com // Schedule a new event to handle the next block of pixels 23611012Sandreas.sandberg@arm.com if (_posX < _timings.width) { 23711012Sandreas.sandberg@arm.com schedule(evRenderPixels, clockEdge(Cycles(pxl_count))); 23811012Sandreas.sandberg@arm.com } else { 23911012Sandreas.sandberg@arm.com if (pos_y == _timings.height - 1) 24011012Sandreas.sandberg@arm.com onFrameDone(); 24111012Sandreas.sandberg@arm.com } 24211012Sandreas.sandberg@arm.com} 24311012Sandreas.sandberg@arm.com 24411012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::PixelEvent( 24511012Sandreas.sandberg@arm.com const char *name, BasePixelPump *_parent, CallbackType _func) 24611012Sandreas.sandberg@arm.com : Event(), Drainable(), 24711012Sandreas.sandberg@arm.com _name(name), parent(*_parent), func(_func), 24811012Sandreas.sandberg@arm.com suspended(false), 24911012Sandreas.sandberg@arm.com relativeTick(0) 25011012Sandreas.sandberg@arm.com{ 25111012Sandreas.sandberg@arm.com parent.pixelEvents.push_back(this); 25211012Sandreas.sandberg@arm.com} 25311012Sandreas.sandberg@arm.com 25411012Sandreas.sandberg@arm.comDrainState 25511012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::drain() 25611012Sandreas.sandberg@arm.com{ 25711012Sandreas.sandberg@arm.com if (scheduled()) 25811012Sandreas.sandberg@arm.com suspend(); 25911012Sandreas.sandberg@arm.com return DrainState::Drained; 26011012Sandreas.sandberg@arm.com} 26111012Sandreas.sandberg@arm.com 26211012Sandreas.sandberg@arm.comvoid 26311012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::drainResume() 26411012Sandreas.sandberg@arm.com{ 26511012Sandreas.sandberg@arm.com if (suspended) 26611012Sandreas.sandberg@arm.com resume(); 26711012Sandreas.sandberg@arm.com} 26811012Sandreas.sandberg@arm.com 26911012Sandreas.sandberg@arm.comvoid 27011012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::serialize(CheckpointOut &cp) const 27111012Sandreas.sandberg@arm.com{ 27211012Sandreas.sandberg@arm.com assert(!scheduled()); 27311012Sandreas.sandberg@arm.com Event::serialize(cp); 27411012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(suspended); 27511012Sandreas.sandberg@arm.com SERIALIZE_SCALAR(relativeTick); 27611012Sandreas.sandberg@arm.com} 27711012Sandreas.sandberg@arm.com 27811012Sandreas.sandberg@arm.comvoid 27911012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::unserialize(CheckpointIn &cp) 28011012Sandreas.sandberg@arm.com{ 28111012Sandreas.sandberg@arm.com Event::unserialize(cp); 28211012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(suspended); 28311012Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(relativeTick); 28411012Sandreas.sandberg@arm.com assert(!scheduled()); 28511012Sandreas.sandberg@arm.com} 28611012Sandreas.sandberg@arm.com 28711012Sandreas.sandberg@arm.comvoid 28811012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::suspend() 28911012Sandreas.sandberg@arm.com{ 29011012Sandreas.sandberg@arm.com assert(scheduled()); 29111012Sandreas.sandberg@arm.com assert(!suspended); 29211012Sandreas.sandberg@arm.com 29311012Sandreas.sandberg@arm.com suspended = true; 29411012Sandreas.sandberg@arm.com relativeTick = when() - curTick(); 29511012Sandreas.sandberg@arm.com parent.deschedule(this); 29611012Sandreas.sandberg@arm.com} 29711012Sandreas.sandberg@arm.com 29811012Sandreas.sandberg@arm.comvoid 29911012Sandreas.sandberg@arm.comBasePixelPump::PixelEvent::resume() 30011012Sandreas.sandberg@arm.com{ 30111012Sandreas.sandberg@arm.com assert(!scheduled()); 30211012Sandreas.sandberg@arm.com assert(suspended); 30311012Sandreas.sandberg@arm.com parent.schedule(this, relativeTick + curTick()); 30411012Sandreas.sandberg@arm.com suspended = false; 30511012Sandreas.sandberg@arm.com relativeTick = 0; 30611012Sandreas.sandberg@arm.com} 307