lib/PackUnpack: helper to pack and unpack values for transmission
With this you can feed a stream of bytes in and get multi-byte structs out, or vice versa. Handy for hooking up stuff like debuggers to narrower serial busses.
This commit is contained in:
parent
8ab867d2d2
commit
498aeae2f4
|
@ -0,0 +1,77 @@
|
|||
package PackUnpack;
|
||||
|
||||
import Vector::*;
|
||||
import FIFOF::*;
|
||||
import SpecialFIFOs::*;
|
||||
import GetPut::*;
|
||||
import ClientServer::*;
|
||||
|
||||
// mkPacker makes a server that converts data_in values into one or
|
||||
// more data_out values, both of which must be in the Bits
|
||||
// typeclass. The packing is implemented by taking the bit
|
||||
// representation of data_in and striping it across as many data_outs
|
||||
// as needed to preserve all the bytes. If data_in is not an exact
|
||||
// multiple of data_out, the final data_out is padded with zeros.
|
||||
module mkPacker(Server#(data_in, data_out))
|
||||
provisos(Bits#(data_in, data_in_bits),
|
||||
Bits#(data_out, data_out_bits),
|
||||
Div#(data_in_bits, data_out_bits, data_out_elts),
|
||||
Min#(data_out_elts, 1, 1),
|
||||
Log#(TAdd#(data_out_elts, 1), data_out_elts_cnt),
|
||||
Add#(data_in_bits, _pad, TMul#(data_out_elts, data_out_bits)));
|
||||
let data_out_elts = valueOf(data_out_elts);
|
||||
|
||||
Reg#(Vector#(data_out_elts, data_out)) vals_out <- mkRegU();
|
||||
Reg#(UInt#(data_out_elts_cnt)) num_vals <- mkReg(0);
|
||||
FIFOF#(data_out) out <- mkBypassFIFOF();
|
||||
|
||||
rule push_out (num_vals > 0);
|
||||
out.enq(vals_out[0]);
|
||||
vals_out <= shiftOutFrom0(unpack(0), vals_out, 1);
|
||||
num_vals <= num_vals-1;
|
||||
endrule
|
||||
|
||||
interface Put request;
|
||||
method Action put(di) if (num_vals == 0);
|
||||
vals_out <= reverse(unpack(extend(pack(di))));
|
||||
num_vals <= fromInteger(data_out_elts);
|
||||
endmethod
|
||||
endinterface
|
||||
interface response = toGet(out);
|
||||
endmodule
|
||||
|
||||
// mkUnpacker makes a server that converts one or more data_in values
|
||||
// into a data_out value. Both data_in and data_out must be in the
|
||||
// Bits typeclass. The unpacking is implemented by concatenating the
|
||||
// bit representation of consecutive data_in values until enough bits
|
||||
// have been accumulated to represent one data_out. If data_out is not
|
||||
// an exact multiple of data_in, the unneeded upper bits of the final
|
||||
// data_in are discarded.
|
||||
module mkUnpacker(Server#(data_in, data_out))
|
||||
provisos(Bits#(data_in, data_in_bits),
|
||||
Bits#(data_out, data_out_bits),
|
||||
Div#(data_out_bits, data_in_bits, data_in_elts),
|
||||
Min#(data_in_elts, 1, 1),
|
||||
Log#(TAdd#(data_in_elts, 1), data_in_elts_cnt),
|
||||
Add#(data_out_bits, _pad, TMul#(data_in_elts, data_in_bits)));
|
||||
|
||||
Reg#(Vector#(data_in_elts, data_in)) vals_in <- mkRegU();
|
||||
Reg#(UInt#(data_in_elts_cnt)) num_vals <- mkReg(0);
|
||||
FIFOF#(data_out) out <- mkBypassFIFOF();
|
||||
|
||||
rule push_out (num_vals == fromInteger(valueOf(data_in_elts)));
|
||||
out.enq(unpack(truncate(pack(vals_in))));
|
||||
num_vals <= 0;
|
||||
endrule
|
||||
|
||||
interface Put request;
|
||||
method Action put(di) if (num_vals < fromInteger(valueOf(data_in_elts)));
|
||||
vals_in <= shiftInAt0(vals_in, di);
|
||||
num_vals <= num_vals+1;
|
||||
endmethod
|
||||
endinterface
|
||||
interface response = toGet(out);
|
||||
endmodule
|
||||
|
||||
endpackage
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package PackUnpack_Test;
|
||||
|
||||
import StmtFSM::*;
|
||||
import Assert::*;
|
||||
import GetPut::*;
|
||||
import ClientServer::*;
|
||||
|
||||
import PackUnpack::*;
|
||||
import Testing::*;
|
||||
|
||||
module mkTB();
|
||||
let testflags <- mkTestFlags();
|
||||
|
||||
Server#(UInt#(17), Bit#(8)) dut_pack <- mkPacker();
|
||||
Server#(Bit#(8), UInt#(17)) dut_unpack <- mkUnpacker();
|
||||
|
||||
function Action put_pack(UInt#(17) v);
|
||||
return action
|
||||
dut_pack.request.put(v);
|
||||
if (testflags.verbose)
|
||||
$display("pack.put(%0d), binary %017b", v, v);
|
||||
endaction;
|
||||
endfunction
|
||||
|
||||
function Action check_pack(Bit#(8) want);
|
||||
return action
|
||||
let got <- dut_pack.response.get();
|
||||
if (testflags.verbose)
|
||||
$display("pack.get = %0d (%08b), want %0d (%08b)", got, got, want, want);
|
||||
dynamicAssert(got == want, "got incorrect packed byte");
|
||||
|
||||
dut_unpack.request.put(got);
|
||||
if (testflags.verbose)
|
||||
$display("unpack.put(%0d), binary %08b", got, got);
|
||||
endaction;
|
||||
endfunction
|
||||
|
||||
function Action check_unpack(UInt#(17) want);
|
||||
return action
|
||||
let got <- dut_unpack.response.get();
|
||||
if (testflags.verbose)
|
||||
$display("unpack.get = %0d (%08b), want %0d (%08b)", got, got, want, want);
|
||||
dynamicAssert(got == want, "got incorrect unpacked value");
|
||||
endaction;
|
||||
endfunction
|
||||
|
||||
runTest(100,
|
||||
mkTest("PackUnpack", seq
|
||||
put_pack(115738);
|
||||
check_pack(8'b00000001);
|
||||
check_pack(8'b11000100);
|
||||
check_pack(8'b00011010);
|
||||
check_unpack(115738);
|
||||
|
||||
put_pack(0);
|
||||
check_pack(0);
|
||||
check_pack(0);
|
||||
check_pack(0);
|
||||
check_unpack(0);
|
||||
endseq));
|
||||
endmodule
|
||||
|
||||
endpackage
|
Loading…
Reference in New Issue