| /* |
| * 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. |
| */ |
| |
| #ifndef __DEV_PIXELPUMP_HH__ |
| #define __DEV_PIXELPUMP_HH__ |
| |
| #include <vector> |
| |
| #include "base/framebuffer.hh" |
| #include "sim/clocked_object.hh" |
| |
| namespace gem5 |
| { |
| |
| 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: |
| * <ol> |
| * <li>Vertical Sync (starting at line 0) |
| * <li>Vertical back porch |
| * <li>Visible lines |
| * <li>Vertical front porch |
| * </ol> |
| * |
| * Pixel order within a scan line: |
| * <ol> |
| * <li>Horizontal Sync |
| * <li>Horizontal Back Porch |
| * <li>Visible pixels |
| * <li>Horizontal Front Porch |
| * </ol> |
| */ |
| 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 non-caching 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; |
| |
| /** |
| * Get the next line of pixels directly from memory. This is for use from |
| * the renderFrame which is called in non-caching mode. |
| * |
| * The default implementation falls back to calling nextPixel over and |
| * over, but a more efficient implementation could retrieve the entire line |
| * of pixels all at once using fewer access to memory which bypass any |
| * intermediate structures like an incoming FIFO. |
| * |
| * @param ps A vector iterator to store retrieved pixels into. |
| * @param line_length The number of pixels being requested. |
| * @return The number of pixels actually retrieved. |
| */ |
| virtual size_t |
| nextLine(std::vector<Pixel>::iterator ps, size_t line_length) |
| { |
| size_t count = 0; |
| while (count < line_length && nextPixel(*ps++)) |
| count++; |
| return count; |
| } |
| |
| /** 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<PixelEvent *> 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; |
| }; |
| |
| } // namespace gem5 |
| |
| #endif // __DEV_PIXELPUMP_HH__ |