On 24 May 2007 06:28:23 -0700, Andy
Luotto <
[email protected]> wrote:
>I partially get it: what do you mean for 'self-clocked at infinite
>frequency'? A code example will be grat
Try this. NO GUARANTEES - it's something I tried for fun
a couple of years ago, and it has never been used on a
serious project. However, I'm reasonably confident it's OK.
// analog.v
// Jonathan Bromley, Doulos Ltd, 5 April 2006
//
// This file contains two modules "analog_out" and "analog_in"
// that allow a multi-bit value to be conveyed over a single-bit
// Verilog net. In this way, analog behaviour can be modelled
// in Verilog and the quasi-analog signal values can be carried
// across a single-bit wire without needing to change the netlist.
//
// Values are transmitted bit-serially using a cyclic code. This
// cyclic coding scheme makes use of three Verilog logic values
// 1'b0, 1'b1 and 1'bX to encode bit values 0 and 1 with a
// guarantee of a signal change for each bit symbol. Each bit
// symbol is conveyed in zero time, making use of the delta-delay
// behaviour of Verilog non-blocking assignment. Consequently,
// each multi-bit value can be conveyed in zero time at the moment
// when the value changes.
//
// When the value to be conveyed is not changing, the wire is
// allowed to float to 1'bZ. This also makes it easy to arrange
// multiple drivers on a line.
//
// When the value to be conveyed has any unknown bits, the wire
// is held at 1'bX.
//
// The detailed coding scheme is as follows:
// 1. The line idles at 1'bZ.
// 2. Data is transmitted most-significant bit first.
// 3. Each of the following transitions on the line
// encodes a '0' bit:
// 0->1 1->X X->0 Z->0
// Note that the Z->0 transition can occur only as the first
// (most significant) bit of a word.
// 4. Each of the following transitions on the line
// encodes a '1' bit:
// 0->X X->1 1->0 Z->1
// Again, note that Z->1 can occur only as the first bit of a word.
// 5. Any transition to Z marks the end of the word, and does not
// encode any data bit.
// 6. The transition 0->X, or a line held at X, indicates that
// an unknown value is being conveyed. When the unknown value
// is removed and a known integer value is applied, the line will
// first make a transition from X to Z before making the Z->0
// or Z->1 transition indicating the first bit of the new value.
//
// When instantiating the analog_in and analog_out modules, it is
// necessary to parameterise them for the bit-width of the value.
// However, the most-significant bit first coding scheme means that
// if an analog_in module is connected to an analog_out module with
// a different bit width parameter, values are copied from one to
// the other using standard Verilog copy semantics: when a wide
// value is copied to a narrow target, most-significant bits are
// ignored; when a narrow value is copied to a wide target, the
// value is left-extended. The analog_in receiver module can be
// parameterised for signedness, to determine whether left-extension
// is sign-extension or zero-extension. Note that this signedness
// parameter is used only if a narrow transmitter (analog_out) sends
// values to a wide receiver (analog_in). Both modules default to
// 32-bit width; the receiver defaults to unsigned left-extension.
`timescale 1ns/1ps
//__________________________________________________ _ analog_out ___
//
module analog_out(value, pin);
parameter bits = 32;
input [bits-1:0] value;
output pin;
reg pin;
reg [bits-1:0] buffer;
integer i;
task drive;
input pin_val;
begin
pin <= pin_val;
wait (pin === pin_val);
end
endtask // drive
always begin : sender
drive(1'bz);
@value begin
// Send a new value
if (^value === 1'bx) begin
// Value is unknown - drive to X
drive(1'bx);
end else begin
buffer = value;
for (i = bits-1; i>=0; i=i-1) begin
case ({pin, buffer[i]})
2'b00, 2'bX1, 2'bZ1 : drive(1'b1);
2'bX0, 2'b11, 2'bZ0 : drive(1'b0);
2'b10, 2'b01 : drive(1'bx);
endcase
end // for (bits)
end // send a numeric value
end // sender
end
endmodule
//__________________________________________________ __ analog_in ___
//
module analog_in(pin, value);
parameter bits = 32;
parameter Signed = 0;
input pin;
output [bits-1:0] value;
reg [bits-1:0] value;
reg old_pin;
reg [bits-1:0] buffer;
initial begin
buffer = {bits{1'bx}};
forever @pin begin
case ({old_pin, pin})
2'bZ0 : // first bit = 0
buffer = {bits{1'b0}};
2'bZ1 : // first bit = 1
buffer = {{bits-1{Signed!=0}}, 1'b1};
2'b01, 2'b1X, 2'bX0 : // bit=0
buffer = {buffer, 1'b0};
2'b0X, 2'bX1, 2'b10 : // bit=1
buffer = {buffer, 1'b1};
2'bZX : // word=x
buffer = {bits{1'bx}};
default /* ?Z */ : // completed
begin
value = buffer;
buffer = 0;
end
endcase
old_pin = pin;
end // forever @pin
end // initial
endmodule
//__________________________________________________ _ analog_mux ___
//
// This module is offered as a simple example of an analog behavioural
// model that can be created using the analog_in and analog_out
modules.
// It models an analog multiplexer with two analog inputs 'i0' and
'i1',
// a digital selector input 'sel', and an analog output 'y'.
//
module analog_mux(i0, i1, sel, y);
parameter width = 32, Signed = 0;
input i0, i1, sel;
output y;
wire [width-1:0] v0, v1, vy;
analog_in #(width, Signed) a0(i0, v0);
analog_in #(width, Signed) a1(i1, v1);
assign vy = sel? v1 : v0 ;
analog_out #width ay(vy, y);
endmodule
///////////////////////////////////////////////////////////
// analog_tf.v
//
// See detailed comments in file 'analog.v'.
//
// This is a very simple test fixture for the analog_out and
// analog_in modules. It connects a 6-bit analog transmitter
// to both a 4-bit and an 8-bit receiver, and checks that
// the received values always match the transmitted values.
module analog_tf;
wire sig;
reg [5:0] tx6;
wire [7:0] rx8;
wire [3:0] rx4;
integer ok4, ok8, er4, er8;
event stim;
analog_out #6 Tx6(tx6, sig);
analog_in #4 Rx4(sig, rx4);
analog_in #8 Rx8(sig, rx8);
initial begin: test
integer seed, val;
repeat(100) #10 begin
if ($dist_uniform(seed, 0, 20))
tx6 = $dist_uniform(seed, 0, 63);
else
tx6 = 6'bx;
-> stim;
end
#10
$display("Done: 8bit ok=%0d, err=%0d; 4bit ok=%0d, err=%0d.",
ok8, er8, ok4, er4);
end
initial begin : checker
reg [7:0] tx8;
reg unknown;
ok4 = 0;
ok8 = 0;
er4 = 0;
er8 = 0;
forever #1 begin
// Trick to get 1'bX if tx6 contains any X/Z bits, else 1'b0
unknown = ^tx6;
unknown = unknown ^ unknown;
tx8 = { {2{unknown}}, tx6}; // Extend with 0 or X as necessary
if (rx8 === tx8)
ok8 = ok8 + 1;
else begin
er8 = er8 + 1;
$display("fail: rx8=%b, tx6=%b", rx8, tx6);
end
if (rx4 === tx6[3:0])
ok4 = ok4 + 1;
else begin
er4 = er4 + 1;
$display("fail: rx4=%b, tx6=%b", rx4, tx6);
end
@stim;
end
end
endmodule
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
[email protected]
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.