Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1546b10
commit c099049
Showing
4 changed files
with
389 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from migen.fhdl.std import * | ||
|
||
def saturate(i, o, minimum, maximum): | ||
return [ | ||
If(i > maximum, | ||
o.eq(maximum) | ||
).Elif(i < minimum, | ||
o.eq(minimum) | ||
).Else( | ||
o.eq(i) | ||
) | ||
] | ||
|
||
def coef(value, cw=None): | ||
return int(value * 2**cw) if cw is not None else value | ||
|
||
def sd_ntsc_coefs(dw, cw=None): | ||
return { | ||
"ca" : coef(0.2568, cw), | ||
"cb" : coef(0.0979, cw), | ||
"cc" : coef(0.5910, cw), | ||
"cd" : coef(0.5772, cw), | ||
"yoffset" : 2**(dw-4), | ||
"coffset" : 2**(dw-1), | ||
"ymax" : 235*2**(dw-8), | ||
"cmax" : 235*2**(dw-8), | ||
"ymin" : 2**dw-1, | ||
"cmin" : 2**dw-1 | ||
} | ||
|
||
def hd_pal_coefs(dw, cw=None): | ||
return { | ||
"ca" : coef(0.1819, cw), | ||
"cb" : coef(0.0618, cw), | ||
"cc" : coef(0.6495, cw), | ||
"cd" : coef(0.5512, cw), | ||
"yoffset" : 2**(dw-4), | ||
"coffset" : 2**(dw-1), | ||
"ymax" : 2**dw-1, | ||
"cmax" : 2**dw-1, | ||
"ymin" : 0, | ||
"cmin" : 0 | ||
} | ||
|
||
def yuv_coefs(dw, cw=None): | ||
return { | ||
"ca" : coef(0.299, cw), | ||
"cb" : coef(0.114, cw), | ||
"cc" : coef(0.877283, cw), | ||
"cd" : coef(0.492111, cw), | ||
"yoffset" : 2**(dw-4), | ||
"coffset" : 2**(dw-1), | ||
"ymax" : 2**(dw)-1, | ||
"cmax" : 2**(dw)-1, | ||
"ymin" : 0, | ||
"cmin" : 0 | ||
} | ||
|
||
def ycbcr_layout(dw): | ||
return [("y", dw), ("cb", dw), ("cr", dw)] | ||
|
||
def rgb_layout(dw): | ||
return [("r", dw), ("g", dw), ("b", dw)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# rgb2ycbcr | ||
# (XAPP930 migen implementation) | ||
|
||
from migen.fhdl.std import * | ||
from migen.genlib.record import * | ||
from migen.flow.actor import * | ||
|
||
from hdl.csc.common import * | ||
|
||
|
||
datapath_latency = 7 | ||
|
||
|
||
@DecorateModule(InsertCE) | ||
class RGB2YCbCrDatapath(Module): | ||
def __init__(self, rgb_w, ycbcr_w, coef_w, coefs): | ||
self.sink = sink = Record(rgb_layout(rgb_w)) | ||
self.source = source = Record(ycbcr_layout(ycbcr_w)) | ||
|
||
# # # | ||
|
||
# delay rgb signals | ||
rgb_delayed = [Sink(rgb_layout(rgb_w))] | ||
for i in range(datapath_latency): | ||
rgb_n = Record(rgb_layout(rgb_w)) | ||
for name in ["r", "g", "b"]: | ||
self.comb += getattr(rgb_n, name).eq(getattr(rgb_delayed[-1], name)) | ||
rgb_delayed.append(rgb_n) | ||
|
||
# Hardware implementation: | ||
# y = ca*(r-g) + g + cb*(b-g) + yoffset | ||
# cb = cc*(r-y) + coffset | ||
# cr = cd*(b-y) + coffset | ||
|
||
# clk 0 | ||
# (r-g) & (b-g) | ||
r_minus_g = Signal((rgb_w + 1, True)) | ||
b_minus_g = Signal((rgb_w + 1, True)) | ||
self.sync += [ | ||
r_minus_g.eq(sink.r - sink.g), | ||
b_minus_g.eq(sink.b - sink.g) | ||
] | ||
|
||
# clk 1 | ||
# ca*(r-g) & cb*(b-g) | ||
ca_mult_rg = Signal((rgb_w + coef_w + 1, True)) | ||
cb_mult_bg = Signal((rgb_w + coef_w + 1, True)) | ||
self.sync += [ | ||
ca_mult_rg.eq(r_minus_g * coefs["ca"]), | ||
cb_mult_bg.eq(b_minus_g * coefs["cb"]) | ||
] | ||
|
||
# clk 2 | ||
# ca*(r-g) + cb*(b-g) | ||
carg_plus_cbbg = Signal((rgb_w + coef_w + 2, True)) | ||
self.sync += [ | ||
carg_plus_cbbg.eq(ca_mult_rg + cb_mult_bg) | ||
] | ||
|
||
# clk 3 | ||
# yraw = ca*(r-g) + cb*(b-g) + g | ||
yraw = Signal((rgb_w + 3, True)) | ||
self.sync += [ | ||
yraw.eq(carg_plus_cbbg[coef_w:] + rgb_delayed[2].g) | ||
] | ||
|
||
# clk 4 | ||
# r - yraw | ||
# b - yraw | ||
b_minus_yraw = Signal((rgb_w + 4, True)) | ||
r_minus_yraw = Signal((rgb_w + 4, True)) | ||
yraw_r0 = Signal((rgb_w + 3, True)) | ||
self.sync += [ | ||
b_minus_yraw.eq(rgb_delayed[3].b - yraw), | ||
r_minus_yraw.eq(rgb_delayed[3].r - yraw), | ||
yraw_r0.eq(yraw) | ||
] | ||
|
||
# clk 5 | ||
# cc*yraw | ||
# cd*yraw | ||
cc_mult_ryraw = Signal((rgb_w + coef_w + 4, True)) | ||
cd_mult_byraw = Signal((rgb_w + coef_w + 4, True)) | ||
yraw_r1 = Signal((rgb_w + 3, True)) | ||
self.sync += [ | ||
cc_mult_ryraw.eq(b_minus_yraw * coefs["cc"]), | ||
cd_mult_byraw.eq(r_minus_yraw * coefs["cd"]), | ||
yraw_r1.eq(yraw_r0) | ||
] | ||
|
||
# clk 6 | ||
# y = (yraw + yoffset) | ||
# cb = (cc*(r - yraw) + coffset) | ||
# cr = (cd*(b - yraw) + coffset) | ||
y = Signal((rgb_w + 3, True)) | ||
cb = Signal((rgb_w + 4, True)) | ||
cr = Signal((rgb_w + 4, True)) | ||
self.sync += [ | ||
y.eq(yraw_r1 + coefs["yoffset"]), | ||
cb.eq(cc_mult_ryraw[coef_w:] + coefs["coffset"]), | ||
cr.eq(cd_mult_byraw[coef_w:] + coefs["coffset"]) | ||
] | ||
|
||
# clk 7 | ||
# saturate | ||
self.sync += [ | ||
saturate(y, source.y, coefs["ymin"], coefs["ymax"]), | ||
saturate(cb, source.cb, coefs["cmin"], coefs["cmax"]), | ||
saturate(cr, source.cr, coefs["cmin"], coefs["cmax"]) | ||
] | ||
|
||
|
||
class RGB2YCbCr(PipelinedActor, Module): | ||
def __init__(self, rgb_w=8, ycbcr_w=8, coef_w=8, mode="HD"): | ||
self.sink = sink = Sink(rgb_layout(rgb_w)) | ||
self.source = source = Source(ycbcr_layout(ycbcr_w)) | ||
PipelinedActor.__init__(self, datapath_latency) | ||
|
||
# # # | ||
|
||
if mode in ["SD", "NTSC"]: | ||
coefs = sd_ntsc_coefs(ycbcr_w, coef_w) | ||
elif mode in ["HD", "PAL"]: | ||
coefs = hd_pal_coefs(ycbcr_w, coef_w) | ||
elif mode in ["YUV"]: | ||
coefs = yuv_coefs(ycbcr_w, coef_w) | ||
else: | ||
ValueError | ||
|
||
# datapath | ||
self.submodules.datapath = RGB2YCbCrDatapath(rgb_w, ycbcr_w, coef_w, coefs) | ||
self.comb += self.datapath.ce.eq(self.pipe_ce) | ||
for name in ["r", "g", "b"]: | ||
self.comb += getattr(self.datapath.sink, name).eq(getattr(sink, name)) | ||
for name in ["y", "cb", "cr"]: | ||
self.comb += getattr(source, name).eq(getattr(self.datapath.source, name)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import random | ||
import copy | ||
|
||
from migen.fhdl.std import * | ||
from migen.flow.actor import Sink, Source | ||
from migen.genlib.record import * | ||
|
||
|
||
def seed_to_data(seed, random=True): | ||
if random: | ||
return (seed * 0x31415979 + 1) & 0xffffffff | ||
else: | ||
return seed | ||
|
||
|
||
def comp(p1, p2): | ||
r = True | ||
for x, y in zip(p1, p2): | ||
if x != y: | ||
r = False | ||
return r | ||
|
||
|
||
def check(p1, p2): | ||
p1 = copy.deepcopy(p1) | ||
p2 = copy.deepcopy(p2) | ||
if isinstance(p1, int): | ||
return 0, 1, int(p1 != p2) | ||
else: | ||
if len(p1) >= len(p2): | ||
ref, res = p1, p2 | ||
else: | ||
ref, res = p2, p1 | ||
shift = 0 | ||
while((ref[0] != res[0]) and (len(res) > 1)): | ||
res.pop(0) | ||
shift += 1 | ||
length = min(len(ref), len(res)) | ||
errors = 0 | ||
for i in range(length): | ||
if ref.pop(0) != res.pop(0): | ||
errors += 1 | ||
return shift, length, errors | ||
|
||
|
||
def randn(max_n): | ||
return random.randint(0, max_n-1) | ||
|
||
|
||
class Packet(list): | ||
def __init__(self, init=[]): | ||
self.ongoing = False | ||
self.done = False | ||
for data in init: | ||
self.append(data) | ||
|
||
|
||
class PacketStreamer(Module): | ||
def __init__(self, description, last_be=None): | ||
self.source = Source(description) | ||
self.last_be = last_be | ||
|
||
# # # | ||
|
||
self.packets = [] | ||
self.packet = Packet() | ||
self.packet.done = True | ||
|
||
def send(self, packet): | ||
packet = copy.deepcopy(packet) | ||
self.packets.append(packet) | ||
return packet | ||
|
||
def send_blocking(self, packet): | ||
packet = self.send(packet) | ||
while not packet.done: | ||
yield | ||
|
||
def do_simulation(self, selfp): | ||
if len(self.packets) and self.packet.done: | ||
self.packet = self.packets.pop(0) | ||
if not self.packet.ongoing and not self.packet.done: | ||
selfp.source.stb = 1 | ||
if self.source.description.packetized: | ||
selfp.source.sop = 1 | ||
selfp.source.data = self.packet.pop(0) | ||
self.packet.ongoing = True | ||
elif selfp.source.stb == 1 and selfp.source.ack == 1: | ||
if self.source.description.packetized: | ||
selfp.source.sop = 0 | ||
if len(self.packet) == 1: | ||
selfp.source.eop = 1 | ||
if self.last_be is not None: | ||
selfp.source.last_be = self.last_be | ||
else: | ||
selfp.source.eop = 0 | ||
if self.last_be is not None: | ||
selfp.source.last_be = 0 | ||
if len(self.packet) > 0: | ||
selfp.source.stb = 1 | ||
selfp.source.data = self.packet.pop(0) | ||
else: | ||
self.packet.done = True | ||
selfp.source.stb = 0 | ||
|
||
|
||
class PacketLogger(Module): | ||
def __init__(self, description): | ||
self.sink = Sink(description) | ||
|
||
# # # | ||
|
||
self.packet = Packet() | ||
|
||
def receive(self): | ||
self.packet.done = False | ||
while not self.packet.done: | ||
yield | ||
|
||
def do_simulation(self, selfp): | ||
selfp.sink.ack = 1 | ||
if selfp.sink.stb: | ||
if self.sink.description.packetized: | ||
if selfp.sink.sop: | ||
self.packet = Packet() | ||
self.packet.append(selfp.sink.data) | ||
else: | ||
self.packet.append(selfp.sink.data) | ||
if selfp.sink.eop: | ||
self.packet.done = True | ||
else: | ||
self.packet.append(selfp.sink.data) | ||
|
||
|
||
class AckRandomizer(Module): | ||
def __init__(self, description, level=0): | ||
self.level = level | ||
|
||
self.sink = Sink(description) | ||
self.source = Source(description) | ||
|
||
self.run = Signal() | ||
|
||
self.comb += \ | ||
If(self.run, | ||
Record.connect(self.sink, self.source) | ||
).Else( | ||
self.source.stb.eq(0), | ||
self.sink.ack.eq(0), | ||
) | ||
|
||
def do_simulation(self, selfp): | ||
n = randn(100) | ||
if n < self.level: | ||
selfp.run = 0 | ||
else: | ||
selfp.run = 1 | ||
|
Oops, something went wrong.