1/*
2 * Copyright (c) 2015 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 M5_ATTR_OVERRIDE;
67 void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
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, unsigned pixel_chunk);
152 virtual ~BasePixelPump();
153
154 void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
155 void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
154 void serialize(CheckpointOut &cp) const override;
155 void unserialize(CheckpointIn &cp) override;
156
157 public: // Public API
158 /** Starting pushing pixels using the supplied display timings. */
159 void start(const DisplayTimings &timings);
160
161 /** Immediately stop pushing pixels */
162 void stop();
163
164 /** Get a constant reference of the current display timings */
165 const DisplayTimings &timings() const { return _timings; }
166
167 /** Is the pixel pump active and refreshing the display? */
168 bool active() const { return evBeginLine.active(); }
169
170 /** Did a buffer underrun occur within this refresh interval? */
171 bool underrun() const { return _underrun; }
172
173 /** Is the current line within the visible range? */
174 bool visibleLine() const {
175 return line >= _timings.lineFirstVisible() &&
176 line < _timings.lineFrontPorchStart();
177 }
178
179 /** Current pixel position within the visible area */
180 unsigned posX() const { return _posX; }
181
182 /** Current pixel position within the visible area */
183 unsigned posY() const {
184 return visibleLine() ? line - _timings.lineFirstVisible() : 0;
185 }
186
187 /** Output frame buffer */
188 FrameBuffer fb;
189
190 protected: // Callbacks
191 /**
192 * Get the next pixel from the scan line buffer.
193 *
194 * @param p Output pixel value, undefined on underrun
195 * @return true on success, false on buffer underrun
196 */
197 virtual bool nextPixel(Pixel &p) = 0;
198
199 /** First pixel clock of the first VSync line. */
200 virtual void onVSyncBegin() {};
201
202 /**
203 * Callback on the first pixel of the line after the end VSync
204 * region (typically the first pixel of the vertical back porch).
205 */
206 virtual void onVSyncEnd() {};
207
208 /**
209 * Start of the HSync region.
210 *
211 * @note This is called even for scan lines outside of the visible
212 * region.
213 */
214 virtual void onHSyncBegin() {};
215
216 /**
217 * Start of the first pixel after the HSync region.
218 *
219 * @note This is called even for scan lines outside of the visible
220 * region.
221 */
222 virtual void onHSyncEnd() {};
223
224 /**
225 * Buffer underrun occurred on a frame.
226 *
227 * This method is called once if there is buffer underrun while
228 * refreshing the display. The underrun state is reset on the next
229 * refresh.
230 *
231 * @param x Coordinate within the visible region.
232 * @param y Coordinate within the visible region.
233 */
234 virtual void onUnderrun(unsigned x, unsigned y) {};
235
236 /** Finished displaying the visible region of a frame */
237 virtual void onFrameDone() {};
238
239 private: // Params
240 /** Maximum number of pixels to handle per render callback */
241 const unsigned pixelChunk;
242
243 private:
244 /**
245 * Callback helper class with suspend support.
246 *
247 * Unlike a normal EventWrapper, this class suspends an event on
248 * drain() and restarts it at drainResume(). The suspend operation
249 * stores the tick relative to curTick() and then deschedules the
250 * event. The resume operation schedules the event at curTick()
251 * plus the relative tick stored when the event was suspended.
252 */
253 class PixelEvent : public Event, public Drainable
254 {
255 typedef void (BasePixelPump::* CallbackType)();
256
257 public:
258 PixelEvent(const char *name, BasePixelPump *parent, CallbackType func);
259
260 DrainState drain() M5_ATTR_OVERRIDE;
261 void drainResume() M5_ATTR_OVERRIDE;
260 DrainState drain() override;
261 void drainResume() override;
262
263 void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
264 void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
263 void serialize(CheckpointOut &cp) const override;
264 void unserialize(CheckpointIn &cp) override;
265
266 const std::string name() const M5_ATTR_OVERRIDE { return _name; }
267 void process() M5_ATTR_OVERRIDE {
266 const std::string name() const override { return _name; }
267 void process() override {
268 (parent.*func)();
269 }
270
271 bool active() const { return scheduled() || suspended; }
272
273 private:
274 void suspend();
275 void resume();
276
277 const std::string _name;
278 BasePixelPump &parent;
279 const CallbackType func;
280
281 bool suspended;
282 Tick relativeTick;
283 };
284
285 void beginLine();
286 void renderPixels();
287
288 /** Convenience vector when doing operations on all events */
289 std::vector<PixelEvent *> pixelEvents;
290
291 PixelEvent evVSyncBegin;
292 PixelEvent evVSyncEnd;
293 PixelEvent evHSyncBegin;
294 PixelEvent evHSyncEnd;
295 PixelEvent evBeginLine;
296 PixelEvent evRenderPixels;
297
298 DisplayTimings _timings;
299
300 /**
301 * Current line (including back porch, front porch, and vsync)
302 * within a frame.
303 */
304 unsigned line;
305 /** X-coordinate within the visible region of a frame */
306 unsigned _posX;
307
308 /** Did a buffer underrun occur within this refresh interval? */
309 bool _underrun;
310};
311
312#endif // __DEV_PIXELPUMP_HH__