/*
* Copyright (c) 2015, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Andreas Sandberg
*/
#ifndef __DEV_PIXELPUMP_HH__
#define __DEV_PIXELPUMP_HH__
#include "base/framebuffer.hh"
#include "sim/clocked_object.hh"
struct BasePixelPumpParams;
struct DisplayTimings : public Serializable
{
/**
* Create a display timing configuration struct
*
* @param width Width of the visible area of the screen.
* @param height Height of the visible area of the screen.
* @param hfp Horizontal front porch in pixel clocks.
* @param h_sync Horizontal sync in pixel clocks.
* @param hbp Horizontal back porch in pixel clocks.
* @param vfp Vertical front porch in scan lines.
* @param v_sync Vertical sync in scan lines.
* @param vbp Vertical back porch in scan lines.
*/
DisplayTimings(unsigned width, unsigned height,
unsigned hbp, unsigned h_sync, unsigned hfp,
unsigned vbp, unsigned v_sync, unsigned vfp);
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
/** How many pixel clocks are required for one line? */
Cycles cyclesPerLine() const {
return Cycles(hSync + hBackPorch + width + hBackPorch);
}
/** How many pixel clocks are required for one frame? */
Cycles cyclesPerFrame() const {
return Cycles(cyclesPerLine() * linesPerFrame());
}
/** Calculate the first line of the vsync signal */
unsigned lineVSyncStart() const {
return 0;
}
/** Calculate the first line of the vertical back porch */
unsigned lineVBackPorchStart() const {
return lineVSyncStart() + vSync;
}
/** Calculate the first line of the visible region */
unsigned lineFirstVisible() const {
return lineVBackPorchStart() + vBackPorch;
}
/** Calculate the first line of the back porch */
unsigned lineFrontPorchStart() const {
return lineFirstVisible() + height;
}
/** Calculate the total number of lines in a frame */
unsigned linesPerFrame() const {
return lineFrontPorchStart() + vFrontPorch;
}
/** Display width in pixels */
unsigned width;
/** Display height in pixels */
unsigned height;
/** Horizontal back porch in pixels */
unsigned hBackPorch;
/** Horizontal front porch in pixels */
unsigned hFrontPorch;
/** Horizontal sync signal length in pixels */
unsigned hSync;
/** Vertical back porch in lines */
unsigned vBackPorch;
/** Vertical front porch in lines */
unsigned vFrontPorch;
/** Vertical sync signal in lines */
unsigned vSync;
static const DisplayTimings vga;
};
/**
* Timing generator for a pixel-based display.
*
* Pixels are ordered relative to the top left corner of the
* display. Scan lines appear in the following order:
*
* - Vertical Sync (starting at line 0)
*
- Vertical back porch
*
- Visible lines
*
- Vertical front porch
*
*
* Pixel order within a scan line:
*
* - Horizontal Sync
*
- Horizontal Back Porch
*
- Visible pixels
*
- Horizontal Front Porch
*
*/
class BasePixelPump
: public EventManager, public Clocked,
public Serializable
{
public:
BasePixelPump(EventManager &em, ClockDomain &pxl_clk,
unsigned pixel_chunk);
virtual ~BasePixelPump();
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
public: // Public API
/** Update frame size using display timing */
void updateTimings(const DisplayTimings &timings);
/** Render an entire frame in KVM execution mode */
void renderFrame();
/** Starting pushing pixels in timing mode */
void start();
/** Immediately stop pushing pixels */
void stop();
/** Get a constant reference of the current display timings */
const DisplayTimings &timings() const { return _timings; }
/** Is the pixel pump active and refreshing the display? */
bool active() const { return evBeginLine.active(); }
/** Did a buffer underrun occur within this refresh interval? */
bool underrun() const { return _underrun; }
/** Is the current line within the visible range? */
bool visibleLine() const {
return line >= _timings.lineFirstVisible() &&
line < _timings.lineFrontPorchStart();
}
/** Current pixel position within the visible area */
unsigned posX() const { return _posX; }
/** Current pixel position within the visible area */
unsigned posY() const {
return visibleLine() ? line - _timings.lineFirstVisible() : 0;
}
/** Output frame buffer */
FrameBuffer fb;
protected: // Callbacks
/**
* Get the next pixel from the scan line buffer.
*
* @param p Output pixel value, undefined on underrun
* @return true on success, false on buffer underrun
*/
virtual bool nextPixel(Pixel &p) = 0;
/** First pixel clock of the first VSync line. */
virtual void onVSyncBegin() {};
/**
* Callback on the first pixel of the line after the end VSync
* region (typically the first pixel of the vertical back porch).
*/
virtual void onVSyncEnd() {};
/**
* Start of the HSync region.
*
* @note This is called even for scan lines outside of the visible
* region.
*/
virtual void onHSyncBegin() {};
/**
* Start of the first pixel after the HSync region.
*
* @note This is called even for scan lines outside of the visible
* region.
*/
virtual void onHSyncEnd() {};
/**
* Buffer underrun occurred on a frame.
*
* This method is called once if there is buffer underrun while
* refreshing the display. The underrun state is reset on the next
* refresh.
*
* @param x Coordinate within the visible region.
* @param y Coordinate within the visible region.
*/
virtual void onUnderrun(unsigned x, unsigned y) {};
/** Finished displaying the visible region of a frame */
virtual void onFrameDone() {};
private: // Params
/** Maximum number of pixels to handle per render callback */
const unsigned pixelChunk;
private:
/**
* Callback helper class with suspend support.
*
* Unlike a normal EventWrapper, this class suspends an event on
* drain() and restarts it at drainResume(). The suspend operation
* stores the tick relative to curTick() and then deschedules the
* event. The resume operation schedules the event at curTick()
* plus the relative tick stored when the event was suspended.
*/
class PixelEvent : public Event, public Drainable
{
typedef void (BasePixelPump::* CallbackType)();
public:
PixelEvent(const char *name, BasePixelPump *parent, CallbackType func);
DrainState drain() override;
void drainResume() override;
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
const std::string name() const override { return _name; }
void process() override {
(parent.*func)();
}
bool active() const { return scheduled() || suspended; }
private:
void suspend();
void resume();
const std::string _name;
BasePixelPump &parent;
const CallbackType func;
bool suspended;
Tick relativeTick;
};
void beginLine();
void renderPixels();
/** Fast and event-free line rendering function */
void renderLine();
/** Convenience vector when doing operations on all events */
std::vector pixelEvents;
PixelEvent evVSyncBegin;
PixelEvent evVSyncEnd;
PixelEvent evHSyncBegin;
PixelEvent evHSyncEnd;
PixelEvent evBeginLine;
PixelEvent evRenderPixels;
DisplayTimings _timings;
/**
* Current line (including back porch, front porch, and vsync)
* within a frame.
*/
unsigned line;
/** X-coordinate within the visible region of a frame */
unsigned _posX;
/** Did a buffer underrun occur within this refresh interval? */
bool _underrun;
};
#endif // __DEV_PIXELPUMP_HH__