hdlcd.cc revision 11090:f37a6b82f98f
12SN/A/*
211071SN/A * Copyright (c) 2010-2013, 2015 ARM Limited
311071SN/A * All rights reserved
411071SN/A *
511071SN/A * The license below extends only to copyright in the software and shall
611071SN/A * not be construed as granting a license to any other intellectual
711071SN/A * property including but not limited to intellectual property relating
811071SN/A * to a hardware implementation of the functionality of the software
911071SN/A * licensed hereunder.  You may use the software subject to the license
1011071SN/A * terms below provided that you ensure that this notice is replicated
1111071SN/A * unmodified and in its entirety in all distributions of the software,
1211071SN/A * modified or unmodified, in source code or in binary form.
1311071SN/A *
141762SN/A * Redistribution and use in source and binary forms, with or without
152SN/A * modification, are permitted provided that the following conditions are
162SN/A * met: redistributions of source code must retain the above copyright
172SN/A * notice, this list of conditions and the following disclaimer;
182SN/A * redistributions in binary form must reproduce the above copyright
192SN/A * notice, this list of conditions and the following disclaimer in the
202SN/A * documentation and/or other materials provided with the distribution;
212SN/A * neither the name of the copyright holders nor the names of its
222SN/A * contributors may be used to endorse or promote products derived from
232SN/A * this software without specific prior written permission.
242SN/A *
252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362SN/A *
372SN/A * Authors: Chris Emmons
382SN/A *          Andreas Sandberg
392665SN/A */
402665SN/A
412665SN/A#include "dev/arm/hdlcd.hh"
422SN/A
432SN/A#include "base/vnc/vncinput.hh"
442SN/A#include "base/output.hh"
452SN/A#include "base/trace.hh"
462SN/A#include "debug/Checkpoint.hh"
472SN/A#include "debug/HDLcd.hh"
4811263Sandreas.sandberg@arm.com#include "dev/arm/amba_device.hh"
4911263Sandreas.sandberg@arm.com#include "dev/arm/base_gic.hh"
50146SN/A#include "mem/packet.hh"
512SN/A#include "mem/packet_access.hh"
522SN/A#include "params/HDLcd.hh"
532SN/A#include "sim/system.hh"
542SN/A
551954SN/Ausing std::vector;
56146SN/A
578232SN/A
588232SN/A// initialize hdlcd registers
5911263Sandreas.sandberg@arm.comHDLcd::HDLcd(const HDLcdParams *p)
6011263Sandreas.sandberg@arm.com    : AmbaDmaDevice(p, 0xFFFF),
6111263Sandreas.sandberg@arm.com      // Parameters
624762SN/A      vnc(p->vnc),
638229SN/A      workaroundSwapRB(p->workaround_swap_rb),
641078SN/A      workaroundDmaLineCount(p->workaround_dma_line_count),
651078SN/A      addrRanges{RangeSize(pioAddr, pioSize)},
662SN/A      enableCapture(p->enable_capture),
672SN/A      pixelBufferSize(p->pixel_buffer_size),
682SN/A
694981SN/A      // Registers
704981SN/A      version(VERSION_RESETV),
712SN/A      int_rawstat(0), int_mask(0),
725034SN/A
735034SN/A      fb_base(0), fb_line_length(0), fb_line_count(0), fb_line_pitch(0),
745034SN/A      bus_options(BUS_OPTIONS_RESETV),
755034SN/A
762SN/A      v_sync(0), v_back_porch(0), v_data(0), v_front_porch(0),
774981SN/A      h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0),
784981SN/A      polarities(0),
794981SN/A
802SN/A      command(0),
812SN/A
822SN/A      pixel_format(0),
832SN/A      red_select(0), green_select(0), blue_select(0),
841435SN/A
851435SN/A      // Other
862SN/A      bmp(&pixelPump.fb), pic(NULL), conv(PixelConverter::rgba8888_le),
871435SN/A      pixelPump(*this, *p->pxl_clk, p->pixel_chunk)
881435SN/A{
892SN/A    if (vnc)
902SN/A        vnc->setFrameBuffer(&pixelPump.fb);
914981SN/A}
924981SN/A
934981SN/AHDLcd::~HDLcd()
944981SN/A{
954981SN/A}
964981SN/A
974981SN/Avoid
984981SN/AHDLcd::serialize(CheckpointOut &cp) const
994981SN/A{
1004981SN/A    DPRINTF(Checkpoint, "Serializing ARM HDLCD\n");
1014981SN/A
1024981SN/A    SERIALIZE_SCALAR(int_rawstat);
1034981SN/A    SERIALIZE_SCALAR(int_mask);
1044981SN/A
1054981SN/A    SERIALIZE_SCALAR(fb_base);
1064981SN/A    SERIALIZE_SCALAR(fb_line_length);
1074981SN/A    SERIALIZE_SCALAR(fb_line_count);
108633SN/A    SERIALIZE_SCALAR(fb_line_pitch);
1092SN/A    SERIALIZE_SCALAR(bus_options);
1102SN/A
1112SN/A    SERIALIZE_SCALAR(v_sync);
1122SN/A    SERIALIZE_SCALAR(v_back_porch);
1132SN/A    SERIALIZE_SCALAR(v_data);
1142SN/A    SERIALIZE_SCALAR(v_front_porch);
1151435SN/A
1161954SN/A    SERIALIZE_SCALAR(h_sync);
1171435SN/A    SERIALIZE_SCALAR(h_back_porch);
1181954SN/A    SERIALIZE_SCALAR(h_data);
11911071SN/A    SERIALIZE_SCALAR(h_front_porch);
1201435SN/A
1212SN/A    SERIALIZE_SCALAR(polarities);
1222SN/A
12310905SN/A    SERIALIZE_SCALAR(command);
124558SN/A    SERIALIZE_SCALAR(pixel_format);
12510905SN/A    SERIALIZE_SCALAR(red_select);
12610905SN/A    SERIALIZE_SCALAR(green_select);
127558SN/A    SERIALIZE_SCALAR(blue_select);
128558SN/A
129558SN/A    SERIALIZE_OBJ(pixelPump);
13010905SN/A    if (enabled())
131558SN/A        dmaEngine->serializeSection(cp, "dmaEngine");
13210905SN/A}
13310905SN/A
134558SN/Avoid
135558SN/AHDLcd::unserialize(CheckpointIn &cp)
136558SN/A{
1372566SN/A    DPRINTF(Checkpoint, "Unserializing ARM HDLCD\n");
138633SN/A
139633SN/A    UNSERIALIZE_SCALAR(int_rawstat);
140633SN/A    UNSERIALIZE_SCALAR(int_mask);
141633SN/A
142633SN/A    UNSERIALIZE_SCALAR(fb_base);
143633SN/A    UNSERIALIZE_SCALAR(fb_line_length);
144633SN/A    UNSERIALIZE_SCALAR(fb_line_count);
1452SN/A    UNSERIALIZE_SCALAR(fb_line_pitch);
1462SN/A    UNSERIALIZE_SCALAR(bus_options);
1472SN/A
1482SN/A    UNSERIALIZE_SCALAR(v_sync);
1492SN/A    UNSERIALIZE_SCALAR(v_back_porch);
150633SN/A    UNSERIALIZE_SCALAR(v_data);
151633SN/A    UNSERIALIZE_SCALAR(v_front_porch);
15211071SN/A
15311071SN/A    UNSERIALIZE_SCALAR(h_sync);
15411071SN/A    UNSERIALIZE_SCALAR(h_back_porch);
155633SN/A    UNSERIALIZE_SCALAR(h_data);
15611071SN/A    UNSERIALIZE_SCALAR(h_front_porch);
157633SN/A
158633SN/A    UNSERIALIZE_SCALAR(polarities);
159195SN/A
1602SN/A    UNSERIALIZE_SCALAR(command);
1612SN/A    UNSERIALIZE_SCALAR(pixel_format);
1622SN/A    UNSERIALIZE_SCALAR(red_select);
1632SN/A    UNSERIALIZE_SCALAR(green_select);
1642SN/A    UNSERIALIZE_SCALAR(blue_select);
1652SN/A
16611071SN/A    {
16711071SN/A        // Try to unserialize the pixel pump. It might not exist if
16811071SN/A        // we're unserializing an old checkpoint.
16911071SN/A        ScopedCheckpointSection sec(cp, "pixelPump");
17011071SN/A        if (cp.sectionExists(Serializable::currentSection()))
17111071SN/A            pixelPump.unserialize(cp);
17211071SN/A    }
17311071SN/A
17411071SN/A    if (enabled()) {
17511071SN/A        // Create the DMA engine and read its state from the
17611071SN/A        // checkpoint. We don't need to worry about the pixel pump as
17711071SN/A        // it is a proper SimObject.
17811071SN/A        createDmaEngine();
17911071SN/A        dmaEngine->unserializeSection(cp, "dmaEngine");
18011071SN/A
18111071SN/A        conv = pixelConverter();
18211071SN/A    }
1832SN/A}
1842566SN/A
1852SN/Avoid
1862SN/AHDLcd::drainResume()
187633SN/A{
1882SN/A    AmbaDmaDevice::drainResume();
1892SN/A
1902SN/A    // We restored from an old checkpoint without a pixel pump, start
191633SN/A    // an new refresh. This typically happens when restoring from old
1922SN/A    // checkpoints.
1932SN/A    if (enabled() && !pixelPump.active())
1942SN/A        pixelPump.start(displayTimings());
19511701Smichael.lebeane@amd.com
1965190SN/A    // We restored from a checkpoint and need to update the VNC server
1975190SN/A    if (pixelPump.active() && vnc)
1985190SN/A        vnc->setDirty();
199633SN/A}
200633SN/A
2017823SN/A// read registers and frame buffer
2022SN/ATick
2032SN/AHDLcd::read(PacketPtr pkt)
2042SN/A{
2052SN/A    assert(pkt->getAddr() >= pioAddr &&
206558SN/A           pkt->getAddr() < pioAddr + pioSize);
20710905SN/A
208558SN/A    const Addr daddr(pkt->getAddr() - pioAddr);
20910469SN/A    panic_if(pkt->getSize() != 4,
21010905SN/A             "Unhandled read size (address: 0x.4x, size: %u)",
2111435SN/A             daddr, pkt->getSize());
21210905SN/A
213558SN/A    const uint32_t data(readReg(daddr));
214633SN/A    DPRINTF(HDLcd, "read register 0x%04x: 0x%x\n", daddr, data);
21510905SN/A
216558SN/A    pkt->set<uint32_t>(data);
217633SN/A    pkt->makeAtomicResponse();
21810905SN/A    return pioDelay;
219574SN/A}
220574SN/A
22111071SN/A// write registers and frame buffer
22211071SN/ATick
22311071SN/AHDLcd::write(PacketPtr pkt)
22411071SN/A{
22511071SN/A    assert(pkt->getAddr() >= pioAddr &&
22611071SN/A           pkt->getAddr() < pioAddr + pioSize);
22711071SN/A
22811071SN/A    const Addr daddr(pkt->getAddr() - pioAddr);
22911071SN/A    panic_if(pkt->getSize() != 4,
230558SN/A             "Unhandled read size (address: 0x.4x, size: %u)",
231558SN/A             daddr, pkt->getSize());
232558SN/A    const uint32_t data(pkt->get<uint32_t>());
23310905SN/A    DPRINTF(HDLcd, "write register 0x%04x: 0x%x\n", daddr, data);
234558SN/A
235574SN/A    writeReg(daddr, data);
23610905SN/A
237574SN/A    pkt->makeAtomicResponse();
23811701Smichael.lebeane@amd.com    return pioDelay;
23910905SN/A}
240558SN/A
241558SN/Auint32_t
242574SN/AHDLcd::readReg(Addr offset)
24310905SN/A{
244558SN/A    switch (offset) {
245574SN/A      case Version: return version;
24610905SN/A
2475606SN/A      case Int_RawStat: return int_rawstat;
248558SN/A      case Int_Clear:
24911071SN/A        panic("HDLCD INT_CLEAR register is Write-Only\n");
25011071SN/A      case Int_Mask: return int_mask;
25111071SN/A      case Int_Status: return intStatus();
25211071SN/A
25311071SN/A      case Fb_Base: return fb_base;
25411701Smichael.lebeane@amd.com      case Fb_Line_Length: return fb_line_length;
25511071SN/A      case Fb_Line_Count: return fb_line_count;
25611071SN/A      case Fb_Line_Pitch: return fb_line_pitch;
25711071SN/A      case Bus_Options: return bus_options;
25811071SN/A
25911071SN/A      case V_Sync: return v_sync;
26011071SN/A      case V_Back_Porch: return v_back_porch;
26111071SN/A      case V_Data: return v_data;
26211071SN/A      case V_Front_Porch: return v_front_porch;
26311071SN/A      case H_Sync: return h_sync;
26411071SN/A      case H_Back_Porch: return h_back_porch;
26511071SN/A      case H_Data: return h_data;
26611071SN/A      case H_Front_Porch: return h_front_porch;
26711071SN/A      case Polarities: return polarities;
26811071SN/A
26911071SN/A      case Command: return command;
27011071SN/A      case Pixel_Format: return pixel_format;
27111071SN/A      case Red_Select: return red_select;
27211071SN/A      case Green_Select: return green_select;
27311071SN/A      case Blue_Select: return blue_select;
274558SN/A
275558SN/A      default:
2764762SN/A        panic("Tried to read HDLCD register that doesn't  exist\n", offset);
2774762SN/A    }
2782SN/A}
2794981SN/A
2802SN/Avoid
281HDLcd::writeReg(Addr offset, uint32_t value)
282{
283    switch (offset) {
284      case Version:
285        panic("HDLCD VERSION register is read-Only\n");
286
287      case Int_RawStat:
288        intRaise(value);
289        return;
290      case Int_Clear:
291        intClear(value);
292        return;
293      case Int_Mask:
294        intMask(value);
295        return;
296      case Int_Status:
297        panic("HDLCD INT_STATUS register is read-Only\n");
298        break;
299
300      case Fb_Base:
301        fb_base = value;
302        return;
303
304      case Fb_Line_Length:
305        fb_line_length = value;
306        return;
307
308      case Fb_Line_Count:
309        fb_line_count = value;
310        return;
311
312      case Fb_Line_Pitch:
313        fb_line_pitch = value;
314        return;
315
316      case Bus_Options: {
317          const BusOptsReg old_bus_options(bus_options);
318          bus_options = value;
319
320          if (bus_options.max_outstanding != old_bus_options.max_outstanding) {
321              DPRINTF(HDLcd,
322                      "Changing HDLcd outstanding DMA transactions: %d -> %d\n",
323                      old_bus_options.max_outstanding,
324                      bus_options.max_outstanding);
325
326          }
327
328          if (bus_options.burst_len != old_bus_options.burst_len) {
329              DPRINTF(HDLcd,
330                      "Changing HDLcd DMA burst flags: 0x%x -> 0x%x\n",
331                      old_bus_options.burst_len, bus_options.burst_len);
332          }
333      } return;
334
335      case V_Sync:
336        v_sync = value;
337        return;
338      case V_Back_Porch:
339        v_back_porch = value;
340        return;
341      case V_Data:
342        v_data = value;
343        return;
344      case V_Front_Porch:
345        v_front_porch = value;
346        return;
347
348      case H_Sync:
349        h_sync = value;
350        return;
351      case H_Back_Porch:
352        h_back_porch = value;
353        return;
354      case H_Data:
355        h_data = value;
356        return;
357      case H_Front_Porch:
358        h_front_porch = value;
359        return;
360
361      case Polarities:
362        polarities = value;
363        return;
364
365      case Command: {
366          const CommandReg new_command(value);
367
368          if (new_command.enable != command.enable) {
369              DPRINTF(HDLcd, "HDLCD switched %s\n",
370                      new_command.enable ? "on" : "off");
371
372              if (new_command.enable) {
373                  cmdEnable();
374              } else {
375                  cmdDisable();
376              }
377          }
378          command = new_command;
379      } return;
380
381      case Pixel_Format:
382        pixel_format = value;
383        return;
384
385      case Red_Select:
386        red_select = value;
387        return;
388      case Green_Select:
389        green_select = value;
390        return;
391      case Blue_Select:
392        blue_select = value;
393        return;
394
395      default:
396        panic("Tried to write HDLCD register that doesn't exist\n", offset);
397        return;
398    }
399}
400
401PixelConverter
402HDLcd::pixelConverter() const
403{
404    ByteOrder byte_order(
405        pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder);
406
407    /* Some Linux kernels have a broken driver that swaps the red and
408     * blue color select registers. */
409    if (!workaroundSwapRB) {
410        return PixelConverter(
411            pixel_format.bytes_per_pixel + 1,
412            red_select.offset, green_select.offset, blue_select.offset,
413            red_select.size, green_select.size, blue_select.size,
414            byte_order);
415    } else {
416        return PixelConverter(
417            pixel_format.bytes_per_pixel + 1,
418            blue_select.offset, green_select.offset, red_select.offset,
419            blue_select.size, green_select.size, red_select.size,
420            byte_order);
421    }
422}
423
424DisplayTimings
425HDLcd::displayTimings() const
426{
427    return DisplayTimings(
428        h_data.val + 1, v_data.val + 1,
429        h_back_porch.val + 1, h_sync.val + 1, h_front_porch.val + 1,
430        v_back_porch.val + 1, v_sync.val + 1, v_front_porch.val + 1);
431}
432
433void
434HDLcd::createDmaEngine()
435{
436    if (bus_options.max_outstanding == 0) {
437        warn("Maximum number of outstanding DMA transfers set to 0.");
438        return;
439    }
440
441    const uint32_t dma_burst_flags(bus_options.burst_len);
442    const uint32_t dma_burst_len(
443        dma_burst_flags ?
444        (1UL << (findMsbSet(dma_burst_flags) - 1)) :
445        MAX_BURST_LEN);
446    // Some drivers seem to set the DMA line count incorrectly. This
447    // could either be a driver bug or a specification bug. Unlike for
448    // timings, the specification does not require 1 to be added to
449    // the DMA engine's line count.
450    const uint32_t dma_lines(
451        fb_line_count + (workaroundDmaLineCount ? 1 : 0));
452
453    dmaEngine.reset(new DmaEngine(
454                        *this, pixelBufferSize,
455                        AXI_PORT_WIDTH * dma_burst_len,
456                        bus_options.max_outstanding,
457                        fb_line_length, fb_line_pitch, dma_lines));
458}
459
460void
461HDLcd::cmdEnable()
462{
463    createDmaEngine();
464    conv = pixelConverter();
465    pixelPump.start(displayTimings());
466}
467
468void
469HDLcd::cmdDisable()
470{
471    pixelPump.stop();
472    dmaEngine->abortFrame();
473}
474
475bool
476HDLcd::pxlNext(Pixel &p)
477{
478    uint8_t pixel_data[MAX_PIXEL_SIZE];
479    assert(conv.length <= sizeof(pixel_data));
480    if (dmaEngine->tryGet(pixel_data, conv.length)) {
481        p = conv.toPixel(pixel_data);
482        return true;
483    } else {
484        return false;
485    }
486}
487
488void
489HDLcd::pxlVSyncBegin()
490{
491    DPRINTF(HDLcd, "Raising VSYNC interrupt.\n");
492    intRaise(INT_VSYNC);
493}
494
495void
496HDLcd::pxlVSyncEnd()
497{
498    DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n");
499    dmaEngine->startFrame(fb_base);
500}
501
502void
503HDLcd::pxlUnderrun()
504{
505    DPRINTF(HDLcd, "Buffer underrun, stopping DMA fill.\n");
506    intRaise(INT_UNDERRUN);
507    dmaEngine->abortFrame();
508}
509
510void
511HDLcd::pxlFrameDone()
512{
513    DPRINTF(HDLcd, "Reached end of last visible line.\n");
514
515    if (dmaEngine->size()) {
516        warn("HDLCD %u bytes still in FIFO after frame: Ensure that DMA "
517             "and PixelPump configuration is consistent\n",
518             dmaEngine->size());
519        dmaEngine->dumpSettings();
520        pixelPump.dumpSettings();
521    }
522
523    if (vnc)
524        vnc->setDirty();
525
526    if (enableCapture) {
527        if (!pic) {
528            pic = simout.create(
529                csprintf("%s.framebuffer.bmp", sys->name()),
530                true);
531        }
532
533        assert(pic);
534        pic->seekp(0);
535        bmp.write(*pic);
536    }
537}
538
539void
540HDLcd::setInterrupts(uint32_t ints, uint32_t mask)
541{
542    const bool old_ints(intStatus());
543
544    int_mask = mask;
545    int_rawstat = ints;
546
547    if (!old_ints && intStatus()) {
548        gic->sendInt(intNum);
549    } else if (old_ints && !intStatus()) {
550        gic->clearInt(intNum);
551    }
552}
553
554HDLcd::DmaEngine::DmaEngine(HDLcd &_parent, size_t size,
555          unsigned request_size, unsigned max_pending,
556          size_t line_size, ssize_t line_pitch, unsigned num_lines)
557    : DmaReadFifo(
558        _parent.dmaPort, size, request_size, max_pending,
559        Request::UNCACHEABLE),
560      parent(_parent),
561      lineSize(line_size), linePitch(line_pitch), numLines(num_lines),
562      nextLineAddr(0)
563{
564}
565
566void
567HDLcd::DmaEngine::serialize(CheckpointOut &cp) const
568{
569    DmaReadFifo::serialize(cp);
570
571    SERIALIZE_SCALAR(nextLineAddr);
572    SERIALIZE_SCALAR(frameEnd);
573}
574
575void
576HDLcd::DmaEngine::unserialize(CheckpointIn &cp)
577{
578    DmaReadFifo::unserialize(cp);
579
580    UNSERIALIZE_SCALAR(nextLineAddr);
581    UNSERIALIZE_SCALAR(frameEnd);
582}
583
584void
585HDLcd::DmaEngine::startFrame(Addr fb_base)
586{
587    nextLineAddr = fb_base;
588    frameEnd = fb_base + numLines * linePitch;
589
590    startFill(nextLineAddr, lineSize);
591}
592
593void
594HDLcd::DmaEngine::abortFrame()
595{
596    nextLineAddr = frameEnd;
597    stopFill();
598    flush();
599}
600
601
602void
603HDLcd::DmaEngine::dumpSettings()
604{
605    inform("DMA line size: %u bytes", lineSize);
606    inform("DMA line pitch: %i bytes", linePitch);
607    inform("DMA num lines: %u", numLines);
608}
609
610void
611HDLcd::DmaEngine::onEndOfBlock()
612{
613    if (nextLineAddr == frameEnd)
614        // We're done with this frame. Ignore calls to this method
615        // until the next frame has been started.
616        return;
617
618    nextLineAddr += linePitch;
619    if (nextLineAddr != frameEnd)
620        startFill(nextLineAddr, lineSize);
621}
622
623void
624HDLcd::DmaEngine::onIdle()
625{
626    parent.intRaise(INT_DMA_END);
627}
628
629void
630HDLcd::PixelPump::dumpSettings()
631{
632    const DisplayTimings &t(timings());
633
634    inform("PixelPump width: %u", t.width);
635    inform("PixelPump height: %u", t.height);
636
637    inform("PixelPump horizontal back porch: %u", t.hBackPorch);
638    inform("PixelPump horizontal fron porch: %u", t.hFrontPorch);
639    inform("PixelPump horizontal fron porch: %u", t.hSync);
640
641    inform("PixelPump vertical back porch: %u", t.vBackPorch);
642    inform("PixelPump vertical fron porch: %u", t.vFrontPorch);
643    inform("PixelPump vertical fron porch: %u", t.vSync);
644}
645
646
647HDLcd *
648HDLcdParams::create()
649{
650    return new HDLcd(this);
651}
652