// ds1822_driver.v
// "Fire and Forget" Dallas 1-Wire[TM] driver
// $Id$
// Larry Doolittle, LBNL
// llc-suite Copyright (c) 2004, The Regents of the University of
// California, through Lawrence Berkeley National Laboratory (subject
// to receipt of any required approvals from the U.S. Dept. of Energy).
// All rights reserved.
// Your use of this software is pursuant to a "BSD-style" open
// source license agreement, the text of which is in license.txt
// (md5sum a1e0e81c78f6eba050b0e96996f49fd5) that should accompany
// this file. If the license agreement is not there, or if you
// have questions about the license, please contact Berkeley Lab's
// Technology Transfer Department at TTD@lbl.gov referring to
// "llc-suite (LBNL Ref CR-1988)"
// Initial coding August 2003
// Synthesizes by both Xilinx XST and Icarus
// XST reports 46 slices, 70 MHz on XC2S150-5
// Simulates correctly against model DS2401
`timescale 1ns / 1ns
// OWP and owp stand for 1-Wire Pin
module ds1822_driver
(
inout DS_DFE, // pin 0
inout DS_FCM, // pin 1
inout DS_RFO, // pin 2
inout DS_AFE, // pin 3
output [15:0] read_data, // register DS1822_DATA
input host_clk, // interconnect
input host_we, // interconnect
input data_sel, // select DS1822_DATA
input cntl_sel, // select DS1822_CNTL
input [15:0] host_data, // interconnect
input rst // interconnect
);
`define OWP0 DS_DFE
`define OWP1 DS_FCM
`define OWP2 DS_RFO
`define OWP3 DS_AFE
// most of the host interface logic
// also see the run logic, and the FIFO control
reg [7:0] control_reg;
wire data_load = host_we & data_sel;
wire control_load = host_we & cntl_sel;
always @(posedge host_clk or posedge rst) if (rst) begin
control_reg <= 0;
end else begin
if (control_load) control_reg <= host_data[7:0];
end
wire send_reset = control_reg[7];
wire broadcast = control_reg[6];
wire [1:0] ow_address = control_reg[5:4];
wire [3:0] fifo_addr = control_reg[3:0];
// Tune this divider to generate proper pulse widths.
// This version good for 25 MHz host_clk
reg [6:0] divider;
reg tick;
always @(posedge host_clk or posedge rst) if (rst) begin
divider <= 0;
tick <= 0;
end else begin
divider <= divider + 1'b1;
tick <= (divider == 0);
end
// handle the 1-Wire pins as outputs
reg drive;
assign `OWP0 = (drive & (ow_address==2'd0 | broadcast)) ? 1'b0 : 1'bz ;
assign `OWP1 = (drive & (ow_address==2'd1 | broadcast)) ? 1'b0 : 1'bz ;
assign `OWP2 = (drive & (ow_address==2'd2 | broadcast)) ? 1'b0 : 1'bz ;
assign `OWP3 = (drive & (ow_address==2'd3 | broadcast)) ? 1'b0 : 1'bz ;
// handle the 1-Wire pins as inputs
reg owpd0, owpd1, owpd2, owpd3;
always @(posedge host_clk) if (tick) begin
owpd0 <= `OWP0;
owpd1 <= `OWP1;
owpd2 <= `OWP2;
owpd3 <= `OWP3;
end
wire ow_in = ~ow_address[1] ? ( ~ow_address[0] ? owpd0 : owpd1 )
: ( ~ow_address[0] ? owpd2 : owpd3 ) ;
// state machine that runs this mess
reg [3:0] count;
reg [6:0] bit_count;
reg [7:0] shifter;
reg run, shift_in;
wire zero_count = (count == 4'd0);
wire indata_count = (count == 4'd3);
wire end_of_count = (count == 4'd13);
wire byte_mark = (bit_count[2:0] == 3'd7);
wire reset_low = (bit_count[6:3] == 4'd0) & send_reset & run;
wire reset_high = (bit_count[6:3] == 4'd1) & send_reset;
wire xmit_complete = (bit_count[6:3] == fifo_addr) & byte_mark;
wire [7:0] next_shifter = {shift_in,shifter[7:1]};
wire shift_out = shifter[0];
wire [7:0] fifo_read;
always @(posedge host_clk or posedge rst) if (rst) begin
run <= 0;
count <= 0;
drive <= 0;
shift_in <= 0;
bit_count <= 0;
shifter <= 0;
end else begin
if (control_load | tick & end_of_count & xmit_complete)
run <= control_load & host_data[15];
if (tick) begin
count <= (run & ~end_of_count) ? (count + 1) : 0;
drive <= run & ~reset_high & (reset_low |
~end_of_count & (zero_count | ~shift_out));
end
if (tick & indata_count) shift_in <= ow_in;
if (tick & end_of_count) begin
bit_count <= xmit_complete ? 0 : (bit_count + 1);
shifter <= byte_mark ? fifo_read : next_shifter;
end
end
wire byte_shift = data_load | tick & end_of_count & byte_mark;
wire [7:0] byte_data = data_load ? host_data : next_shifter;
// FIFO that holds up to 128 bits of data, both outgoing and incoming
srl16x8e byte_fifo(
.CLK(host_clk), .CE(byte_shift),
.Q(fifo_read), .D(byte_data),
.A0(fifo_addr[0]), .A1(fifo_addr[1]),
.A2(fifo_addr[2]), .A3(fifo_addr[3])
);
// results presented to the host
// should add the 1-Wire presence bit
assign read_data = {run,7'b0,fifo_read};
endmodule