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