/* * 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: *
    *
  1. Vertical Sync (starting at line 0) *
  2. Vertical back porch *
  3. Visible lines *
  4. Vertical front porch *
* * Pixel order within a scan line: *
    *
  1. Horizontal Sync *
  2. Horizontal Back Porch *
  3. Visible pixels *
  4. 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__