Add NRZI support
This adds support for encoding and decoding nrzi data. Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
f18acfc0b0
commit
c6f95ce26f
2
Makefile
2
Makefile
|
@ -63,7 +63,7 @@ endef
|
||||||
%.post.fst: rtl/%.post.vvp tb/%.py FORCE
|
%.post.fst: rtl/%.post.vvp tb/%.py FORCE
|
||||||
$(run-vvp)
|
$(run-vvp)
|
||||||
|
|
||||||
MODULES := pcs pmd
|
MODULES := pcs pmd nrzi_encode nrzi_decode
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: $(addsuffix .fst,$(MODULES)) $(addsuffix .post.fst,$(MODULES))
|
test: $(addsuffix .fst,$(MODULES)) $(addsuffix .post.fst,$(MODULES))
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "common.vh"
|
||||||
|
|
||||||
|
module nrzi_decode (
|
||||||
|
input clk,
|
||||||
|
input [1:0] nrzi,
|
||||||
|
input [1:0] nrzi_valid,
|
||||||
|
output reg [1:0] nrz,
|
||||||
|
output reg [1:0] nrz_valid
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [1:0] nrz_next;
|
||||||
|
reg nrzi_last;
|
||||||
|
reg nrzi_last_next;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
nrz_next[0] = nrzi[1] ^ nrzi[0];
|
||||||
|
nrz_next[1] = nrzi[1] ^ nrzi_last;
|
||||||
|
|
||||||
|
nrzi_last_next = nrzi_last;
|
||||||
|
if (nrzi_valid != 0)
|
||||||
|
nrzi_last_next = nrzi[1];
|
||||||
|
if (nrzi_valid & 2)
|
||||||
|
nrzi_last_next = nrzi[0];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
nrzi_last <= nrzi_last_next;
|
||||||
|
nrz_valid <= nrzi_valid;
|
||||||
|
nrz <= nrz_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
`DUMP(0)
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,25 @@
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "common.vh"
|
||||||
|
|
||||||
|
module nrzi_encode (
|
||||||
|
input clk,
|
||||||
|
input nrz,
|
||||||
|
output reg nrzi
|
||||||
|
);
|
||||||
|
|
||||||
|
reg nrzi_next;
|
||||||
|
initial nrzi = 1;
|
||||||
|
|
||||||
|
always @(*)
|
||||||
|
nrzi_next = nrz ^ nrzi;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
nrzi <= nrzi_next;
|
||||||
|
|
||||||
|
`DUMP(0)
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,45 @@
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
import cocotb
|
||||||
|
from cocotb.clock import Clock
|
||||||
|
from cocotb.regression import TestFactory
|
||||||
|
from cocotb.triggers import FallingEdge, RisingEdge, Timer
|
||||||
|
|
||||||
|
from .util import compare_lists, timeout, send_recovered_bits, with_valids
|
||||||
|
|
||||||
|
def nrzi_decode(bits):
|
||||||
|
last = 1
|
||||||
|
for bit in bits:
|
||||||
|
yield bit ^ last
|
||||||
|
last = bit
|
||||||
|
|
||||||
|
@timeout(10, 'us')
|
||||||
|
async def test_rx(decoder, valids):
|
||||||
|
decoder.nrzi_valid.value = 0
|
||||||
|
await Timer(1)
|
||||||
|
await cocotb.start(Clock(decoder.clk, 8, units='ns').start())
|
||||||
|
|
||||||
|
ins = [random.randrange(2) for _ in range(1000)]
|
||||||
|
await cocotb.start(send_recovered_bits(decoder.clk, decoder.nrzi,
|
||||||
|
decoder.nrzi_valid, ins, valids))
|
||||||
|
|
||||||
|
outs = []
|
||||||
|
await RisingEdge(decoder.clk)
|
||||||
|
for _ in ins:
|
||||||
|
await RisingEdge(decoder.clk)
|
||||||
|
valid = decoder.nrz_valid.value
|
||||||
|
if valid == 0:
|
||||||
|
pass
|
||||||
|
elif valid == 1:
|
||||||
|
outs.append(decoder.nrz[1].value)
|
||||||
|
else:
|
||||||
|
outs.append(decoder.nrz[1].value)
|
||||||
|
outs.append(decoder.nrz[0].value)
|
||||||
|
|
||||||
|
# Ignore the first bit, since it is influenced by the initial value
|
||||||
|
compare_lists(list(nrzi_decode(ins))[1:], outs[1:])
|
||||||
|
|
||||||
|
with_valids(globals(), test_rx)
|
|
@ -0,0 +1,38 @@
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-Only
|
||||||
|
# Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
import cocotb
|
||||||
|
from cocotb.clock import Clock
|
||||||
|
from cocotb.triggers import FallingEdge, RisingEdge, Timer
|
||||||
|
|
||||||
|
from .util import compare_lists
|
||||||
|
|
||||||
|
def nrzi_encode(bits):
|
||||||
|
last = 1
|
||||||
|
for bit in bits:
|
||||||
|
yield (last := last ^ bit)
|
||||||
|
|
||||||
|
@cocotb.test(timeout_time=100, timeout_unit='us')
|
||||||
|
async def text_encode(encoder):
|
||||||
|
ins = [random.randrange(2) for _ in range(1000)]
|
||||||
|
encoder.nrz.value = ins[0]
|
||||||
|
await Timer(1)
|
||||||
|
await cocotb.start(Clock(encoder.clk, 8, units='ns').start())
|
||||||
|
|
||||||
|
async def send_nrz():
|
||||||
|
for bit in ins:
|
||||||
|
await FallingEdge(encoder.clk)
|
||||||
|
encoder.nrz.value = bit
|
||||||
|
await cocotb.start(send_nrz())
|
||||||
|
|
||||||
|
outs = []
|
||||||
|
await RisingEdge(encoder.clk)
|
||||||
|
await RisingEdge(encoder.clk)
|
||||||
|
for _ in ins:
|
||||||
|
await RisingEdge(encoder.clk)
|
||||||
|
outs.append(encoder.nrzi.value)
|
||||||
|
|
||||||
|
# Ignore the first bit, since it is influenced by the initial value
|
||||||
|
compare_lists(list(nrzi_encode(ins[1:])), outs[1:])
|
Loading…
Reference in New Issue