|
CNets and General LFSR Counters |
|||
|
Home CNets and Datapaths >> << Small footprints
Usenet Postings |
Subject: XBLOX vs. "CNets", lfsr dividers, etc.
Date: 28 Nov 1995 00:00:00 GMT
newsgroups: comp.arch.fpga,comp.lsi.cad
Perhaps this is of interest. I have created an experimental set of C++
classes called "CNets" that let me specify structural (not behavioural)
designs which ultimately emit XNF primitives such as nets, gates, and
flipflops. Using this specification language I can build up higher
level modules, the most sophisticated of which is a pipelined 32-bit
RISC processor plus on-chip peripherals such as boot ROM, UART, and
DRAM controller, in ~65% of a XC4010.
I use this approach in preference to both schematic capture and to
synthesis from HDLs. It is more flexible, more powerful, and more
reusable than schematic capture and yet still allows me to precisely
and explicitly control primitive instantiation and placement, which can
be tricky using synthesis. Not to mention this approach is much more
affordable than HDL synthesis.
(By the way, "CNets" does NOT deliver FPGA device independence, but it
could be adapted to that purpose. I'm not convinced device
independence is such a panacea anyway -- for instance, either you
design to exploit distributed SRAMs and 3-state buses or you don't, and
if your current target device doesn't implement them you probably
should not require them.)
For instance, here is my universal linear feedback shift register
divider, which is known to work nicely for simple divisors like
n==(25000000/9600):
// emit an lfsr counter and decoder to divide by n
//
// See "Efficient Shift Registers, LFSR Counters, and
// Long Pseudo-Random Sequence Generators", Peter Alfke,
// Xilinx App Note, Aug. 1995
//
void lfsr_div(Net out, Net ce, Net reset, unsigned n) {
...
// choose appropriate width counter
static unsigned taps[32][4] = {
{ 0 }, { 0 }, { 0 }, { 3, 2 },
{ 4, 3 }, { 5, 3 }, { 6, 5 }, { 7, 6 },
{ 8, 6, 5, 4 }, { 9, 5 }, { 10, 7 }, { 11, 9 },
{ 12, 6, 4, 1 }, { 13, 4, 3, 1 }, { 14, 5, 3, 1 }, { 15, 14 },
{ 16, 15, 13, 4 }, { 17, 14 }, { 18, 11 }, { 19, 6, 2, 1 },
{ 20, 17 }, { 21, 19 }, { 22, 21 }, { 23, 18 },
{ 24, 23, 22, 17 }, { 25, 22 }, { 26, 6, 2, 1 }, { 27, 5, 2, 1
},
{ 28, 25 }, { 29, 27 }, { 30, 6, 4, 1, }, { 31, 28 }
};
check(n <= (1 << 30));
for (unsigned bits = 1; n >= (1U << bits); bits++)
;
check((1U << (bits-1)) <= n && n < (1U << bits));
// determine bit pattern of terminal state (after n-1 clockings of lfsr)
unsigned w = 0;
for (unsigned i = 1; i < n; i++) {
unsigned in = 0;
for (unsigned j = 0; j < 4 && taps[bits][j]; j++)
in ^= (w >> (taps[bits][j]) - 1) & 1;
w = ((w << 1) & ((1 << bits) - 1)) ^ !in;
check(w != 0);
}
// emit shift register and gates to recognize terminal state
bus(lfsr, bits+1);
out = lfsr(bits,1) == w;
lfsr[0] = gnd;
net(lfsr_in) = nomap(xnor(lfsr[taps[bits][0]], lfsr[taps[bits][1]],
lfsr[taps[bits][2]], lfsr[taps[bits][3]]));
net(lfsr_reset) = out | reset;
ff(lfsr[1], lfsr_in & ~lfsr_reset, ce);
for (i = 2; i <= bits; i++)
ff(lfsr[i], lfsr[i-1] & ~lfsr_reset, ce);
}
In case it's not perfectly obvious, :-), the last two groups of statements do
the following:
bus(lfsr, bits+1); -- declare lfsr to be a bus of bits+1 nets
out = lfsr(bits,1) == w; -- emit AND gate(s) to recognize the
word 'w' in bits (bits..1) of bus lfsr
lfsr[0] = gnd; -- set lfsr[0] to gnd, necessary for the
following XNOR to be correct when
taps[i] is 0
-- emit an XNOR of up to 4 inputs taking various taps from the lfsr
shift register flipflop outputs. 'nomap' suppresses the default FMAP:
net(lfsr_in) = nomap(xnor(lfsr[taps[bits][0]], lfsr[taps[bits][1]],
lfsr[taps[bits][2]], lfsr[taps[bits][3]]));
-- set lfsr_reset to be the OR of out and reset signals:
net(lfsr_reset) = out | reset;
-- emit a flipflop driving lfsr[1] whose D is the AND of lfsr_in and
NOT lfsr_reset and whose clock enable is 'ce':
ff(lfsr[1], lfsr_in & ~lfsr_reset, ce);
-- emit the rest of the flipflops, each of whose D input is the Q output of
the previous 'flop, qualified by not reset, and whose clock enables
are 'ce':
for (i = 2; i <= bits; i++)
ff(lfsr[i], lfsr[i-1] & ~lfsr_reset, ce);
Anyway, the salient ideas are:
* extend a real programming language with circuit specification datatypes
* employ structural specification, close to the FPGA primitive elements
Is anyone else using a similar approach?
Jan Gray
Copyright © 2000, Gray Research LLC. All rights reserved. |