1/* 2 * Copyright (c) 2015, 2017 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#ifndef __DEV_PIXELPUMP_HH__ 41#define __DEV_PIXELPUMP_HH__ 42 43#include "base/framebuffer.hh" 44#include "sim/clocked_object.hh" 45 46struct BasePixelPumpParams; 47 48struct DisplayTimings : public Serializable 49{ 50 /** 51 * Create a display timing configuration struct 52 * 53 * @param width Width of the visible area of the screen. 54 * @param height Height of the visible area of the screen. 55 * @param hfp Horizontal front porch in pixel clocks. 56 * @param h_sync Horizontal sync in pixel clocks. 57 * @param hbp Horizontal back porch in pixel clocks. 58 * @param vfp Vertical front porch in scan lines. 59 * @param v_sync Vertical sync in scan lines. 60 * @param vbp Vertical back porch in scan lines. 61 */ 62 DisplayTimings(unsigned width, unsigned height, 63 unsigned hbp, unsigned h_sync, unsigned hfp, 64 unsigned vbp, unsigned v_sync, unsigned vfp); 65 66 void serialize(CheckpointOut &cp) const override; 67 void unserialize(CheckpointIn &cp) override; 68 69 /** How many pixel clocks are required for one line? */ 70 Cycles cyclesPerLine() const { 71 return Cycles(hSync + hBackPorch + width + hBackPorch); 72 } 73 74 /** How many pixel clocks are required for one frame? */ 75 Cycles cyclesPerFrame() const { 76 return Cycles(cyclesPerLine() * linesPerFrame()); 77 } 78 79 /** Calculate the first line of the vsync signal */ 80 unsigned lineVSyncStart() const { 81 return 0; 82 } 83 84 /** Calculate the first line of the vertical back porch */ 85 unsigned lineVBackPorchStart() const { 86 return lineVSyncStart() + vSync; 87 } 88 89 /** Calculate the first line of the visible region */ 90 unsigned lineFirstVisible() const { 91 return lineVBackPorchStart() + vBackPorch; 92 } 93 94 /** Calculate the first line of the back porch */ 95 unsigned lineFrontPorchStart() const { 96 return lineFirstVisible() + height; 97 } 98 99 /** Calculate the total number of lines in a frame */ 100 unsigned linesPerFrame() const { 101 return lineFrontPorchStart() + vFrontPorch; 102 } 103 104 /** Display width in pixels */ 105 unsigned width; 106 /** Display height in pixels */ 107 unsigned height; 108 109 /** Horizontal back porch in pixels */ 110 unsigned hBackPorch; 111 /** Horizontal front porch in pixels */ 112 unsigned hFrontPorch; 113 /** Horizontal sync signal length in pixels */ 114 unsigned hSync; 115 116 /** Vertical back porch in lines */ 117 unsigned vBackPorch; 118 /** Vertical front porch in lines */ 119 unsigned vFrontPorch; 120 /** Vertical sync signal in lines */ 121 unsigned vSync; 122 123 static const DisplayTimings vga; 124}; 125 126/** 127 * Timing generator for a pixel-based display. 128 * 129 * Pixels are ordered relative to the top left corner of the 130 * display. Scan lines appear in the following order: 131 * <ol> 132 * <li>Vertical Sync (starting at line 0) 133 * <li>Vertical back porch 134 * <li>Visible lines 135 * <li>Vertical front porch 136 * </ol> 137 * 138 * Pixel order within a scan line: 139 * <ol> 140 * <li>Horizontal Sync 141 * <li>Horizontal Back Porch 142 * <li>Visible pixels 143 * <li>Horizontal Front Porch 144 * </ol> 145 */ 146class BasePixelPump 147 : public EventManager, public Clocked, 148 public Serializable 149{ 150 public: 151 BasePixelPump(EventManager &em, ClockDomain &pxl_clk, 152 unsigned pixel_chunk); 153 virtual ~BasePixelPump(); 154 155 void serialize(CheckpointOut &cp) const override; 156 void unserialize(CheckpointIn &cp) override; 157 158 public: // Public API 159 /** Update frame size using display timing */ 160 void updateTimings(const DisplayTimings &timings); 161 162 /** Render an entire frame in KVM execution mode */ 163 void renderFrame(); 164 165 /** Starting pushing pixels in timing mode */ 166 void start(); 167 168 /** Immediately stop pushing pixels */ 169 void stop(); 170 171 /** Get a constant reference of the current display timings */ 172 const DisplayTimings &timings() const { return _timings; } 173 174 /** Is the pixel pump active and refreshing the display? */ 175 bool active() const { return evBeginLine.active(); } 176 177 /** Did a buffer underrun occur within this refresh interval? */ 178 bool underrun() const { return _underrun; } 179 180 /** Is the current line within the visible range? */ 181 bool visibleLine() const { 182 return line >= _timings.lineFirstVisible() && 183 line < _timings.lineFrontPorchStart(); 184 } 185 186 /** Current pixel position within the visible area */ 187 unsigned posX() const { return _posX; } 188 189 /** Current pixel position within the visible area */ 190 unsigned posY() const { 191 return visibleLine() ? line - _timings.lineFirstVisible() : 0; 192 } 193 194 /** Output frame buffer */ 195 FrameBuffer fb; 196 197 protected: // Callbacks 198 /** 199 * Get the next pixel from the scan line buffer. 200 * 201 * @param p Output pixel value, undefined on underrun 202 * @return true on success, false on buffer underrun 203 */ 204 virtual bool nextPixel(Pixel &p) = 0; 205 206 /** First pixel clock of the first VSync line. */ 207 virtual void onVSyncBegin() {}; 208 209 /** 210 * Callback on the first pixel of the line after the end VSync 211 * region (typically the first pixel of the vertical back porch). 212 */ 213 virtual void onVSyncEnd() {}; 214 215 /** 216 * Start of the HSync region. 217 * 218 * @note This is called even for scan lines outside of the visible 219 * region. 220 */ 221 virtual void onHSyncBegin() {}; 222 223 /** 224 * Start of the first pixel after the HSync region. 225 * 226 * @note This is called even for scan lines outside of the visible 227 * region. 228 */ 229 virtual void onHSyncEnd() {}; 230 231 /** 232 * Buffer underrun occurred on a frame. 233 * 234 * This method is called once if there is buffer underrun while 235 * refreshing the display. The underrun state is reset on the next 236 * refresh. 237 * 238 * @param x Coordinate within the visible region. 239 * @param y Coordinate within the visible region. 240 */ 241 virtual void onUnderrun(unsigned x, unsigned y) {}; 242 243 /** Finished displaying the visible region of a frame */ 244 virtual void onFrameDone() {}; 245 246 private: // Params 247 /** Maximum number of pixels to handle per render callback */ 248 const unsigned pixelChunk; 249 250 private: 251 /** 252 * Callback helper class with suspend support. 253 * 254 * Unlike a normal EventWrapper, this class suspends an event on 255 * drain() and restarts it at drainResume(). The suspend operation 256 * stores the tick relative to curTick() and then deschedules the 257 * event. The resume operation schedules the event at curTick() 258 * plus the relative tick stored when the event was suspended. 259 */ 260 class PixelEvent : public Event, public Drainable 261 { 262 typedef void (BasePixelPump::* CallbackType)(); 263 264 public: 265 PixelEvent(const char *name, BasePixelPump *parent, CallbackType func); 266 267 DrainState drain() override; 268 void drainResume() override; 269 270 void serialize(CheckpointOut &cp) const override; 271 void unserialize(CheckpointIn &cp) override; 272 273 const std::string name() const override { return _name; } 274 void process() override { 275 (parent.*func)(); 276 } 277 278 bool active() const { return scheduled() || suspended; } 279 280 private: 281 void suspend(); 282 void resume(); 283 284 const std::string _name; 285 BasePixelPump &parent; 286 const CallbackType func; 287 288 bool suspended; 289 Tick relativeTick; 290 }; 291 292 void beginLine(); 293 void renderPixels(); 294 295 /** Fast and event-free line rendering function */ 296 void renderLine(); 297 298 /** Convenience vector when doing operations on all events */ 299 std::vector<PixelEvent *> pixelEvents; 300 301 PixelEvent evVSyncBegin; 302 PixelEvent evVSyncEnd; 303 PixelEvent evHSyncBegin; 304 PixelEvent evHSyncEnd; 305 PixelEvent evBeginLine; 306 PixelEvent evRenderPixels; 307 308 DisplayTimings _timings; 309 310 /** 311 * Current line (including back porch, front porch, and vsync) 312 * within a frame. 313 */ 314 unsigned line; 315 /** X-coordinate within the visible region of a frame */ 316 unsigned _posX; 317 318 /** Did a buffer underrun occur within this refresh interval? */ 319 bool _underrun; 320}; 321 322#endif // __DEV_PIXELPUMP_HH__ 323