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