Commit e4bca6f3 authored by Chris Higgs's avatar Chris Higgs
Browse files

Refactored interfaces into a distinct file for clarity

parent 59abbb76
Loading
Loading
Loading
Loading

tb/interfaces.py

0 → 100644
+101 −0
Original line number Original line Diff line number Diff line
"""
A driver and monitor to abstract the interface to the JPEG encoder
"""

import io
from PIL import Image

import cocotb
from cocotb.triggers import RisingEdge, ReadOnly
from cocotb.drivers import Driver
from cocotb.monitors import Monitor

_jpeg_header = open("header.bin", "r").read()

class JpegMonitor(Monitor):

    def __init__(self, dut, **kwargs):
        self.dut = dut
        Monitor.__init__(self, **kwargs)

    @cocotb.coroutine
    def _monitor_recv(self):
        """Creates an Image object from the output of the DUT"""
        data = ""

        clkedge = RisingEdge(self.dut.clk)
        ro = ReadOnly()
        while True:
            yield clkedge
            yield ro
            if self.dut.data_ready.value:
                data += self.dut.JPEG_bitstream.value.buff
            if self.dut.eof_data_partial_ready.value:
                f_obj = io.BytesIO(_jpeg_header + data + "\xff\xd9")
                img = Image.open(f_obj)
                self.log.info("Recovered image %s of %dx%d in mode %s" % (
                    img.format, img.size[0], img.size[1], img.mode))
                yield clkedge
                self._recv(img)
                data = ""


class ImageDriver(Driver):

    def __init__(self, dut):
        self.dut = dut
        Driver.__init__(self)

    @cocotb.coroutine
    def _driver_send(self, image, **kwargs):
        """
        Send an image into the DUT.  Image should be in RGB format and a 
        multiple of 8 pixels in both width and height

        Args:

            image (PIL.Image)   image to send into the dut
        """
        if image.mode != "RGB":
            raise TypeError("Require an format RGB image")

        width, height = image.size
        dut = self.dut                         # Local reference to save lookup
        clk_edge = RisingEdge(dut.clk)         # Recycle objects for efficiency

        yield clk_edge                         # Reset the dut first
        dut.rst <= 1
        yield clk_edge
        dut.rst <= 0
        dut.end_of_file_signal <= 0

        pixels = image.load()

        for y in xrange(0,height,8):
            for x in xrange(0,width,8):
                dut.enable <= 1

                self.log.debug("Sending block X% 4d/% 4d, Y% 4d/% 4d" % (
                        x, width, y, height))

                if y >= height-8 and x >= width-8:
                    dut.end_of_file_signal <= 1

                for y_block in xrange(8):
                    for x_block in xrange(8):
                        # If the image isn't a multiple of 8 pixels we 
                        # repeat the edge values (see Readme.doc)
                        x_ofs = min(x+x_block, width-1)
                        y_ofs = min(y+y_block, height-1)

                        r,g,b = pixels[x_ofs, y_ofs]
                        dut.data_in <= (b<<16 | g<<8 | r)
                        yield clk_edge
                        dut.end_of_file_signal <= 0

                for i in xrange(33):
                    yield clk_edge

                dut.enable <= 0
                yield clk_edge
+3 −95
Original line number Original line Diff line number Diff line
@@ -5,109 +5,17 @@ and check that the output is sufficiently similar to the input.
NB Limited to 96x96 images since we're using a static JPEG header.
NB Limited to 96x96 images since we're using a static JPEG header.
"""
"""
import os
import os
import io

import logging
import logging
from itertools import izip
from itertools import izip
from PIL import Image
from PIL import Image


import cocotb
import cocotb
from cocotb.result import TestFailure
from cocotb.result import TestFailure
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, ReadOnly

from cocotb.drivers import Driver
from cocotb.monitors import Monitor
from cocotb.regression import TestFactory
from cocotb.regression import TestFactory
from cocotb.clock import Clock


_jpeg_header = open("header.bin", "r").read()
from interfaces import ImageDriver, JpegMonitor

class JpegMonitor(Monitor):

    def __init__(self, dut, **kwargs):
        self.dut = dut
        Monitor.__init__(self, **kwargs)

    @cocotb.coroutine
    def _monitor_recv(self):
        """Creates an Image object from the output of the DUT"""
        data = ""

        clkedge = RisingEdge(self.dut.clk)
        ro = ReadOnly()
        while True:
            yield clkedge
            yield ro
            if self.dut.data_ready.value:
                data += self.dut.JPEG_bitstream.value.buff
            if self.dut.eof_data_partial_ready.value:
                f_obj = io.BytesIO(_jpeg_header + data + "\xff\xd9")
                img = Image.open(f_obj)
                self.log.info("Recovered image %s of %dx%d in mode %s" % (
                    img.format, img.size[0], img.size[1], img.mode))
                yield clkedge
                self._recv(img)
                data = ""


class ImageDriver(Driver):

    def __init__(self, dut):
        self.dut = dut
        Driver.__init__(self)

    @cocotb.coroutine
    def _driver_send(self, image, **kwargs):
        """
        Send an image into the DUT.  Image should be in RGB format and a 
        multiple of 8 pixels in both width and height

        Args:

            image (PIL.Image)   image to send into the dut
        """
        if image.mode != "RGB":
            raise TypeError("Require an format RGB image")

        width, height = image.size
        dut = self.dut                         # Local reference to save lookup
        clk_edge = RisingEdge(dut.clk)         # Recycle objects for efficiency

        yield clk_edge                         # Reset the dut first
        dut.rst <= 1
        yield clk_edge
        dut.rst <= 0
        dut.end_of_file_signal <= 0

        pixels = image.load()

        for y in xrange(0,height,8):
            for x in xrange(0,width,8):
                dut.enable <= 1

                self.log.debug("Sending block X% 4d/% 4d, Y% 4d/% 4d" % (
                        x, width, y, height))

                if y >= height-8 and x >= width-8:
                    dut.end_of_file_signal <= 1

                for y_block in xrange(8):
                    for x_block in xrange(8):
                        # If the image isn't a multiple of 8 pixels we 
                        # repeat the edge values (see Readme.doc)
                        x_ofs = min(x+x_block, width-1)
                        y_ofs = min(y+y_block, height-1)

                        r,g,b = pixels[x_ofs, y_ofs]
                        dut.data_in <= (b<<16 | g<<8 | r)
                        yield clk_edge
                        dut.end_of_file_signal <= 0

                for i in xrange(33):
                    yield clk_edge

                dut.enable <= 0
                yield clk_edge



def compare(i1, i2):
def compare(i1, i2):
    """
    """