/* =============================================================== (C) 2004 Bird Computer All rights reserved. bc6526tod.v Version 1.0 6526 Time Of Day compatible core. Please read the Licensing Agreement (license.html file). Use of this file is subject to the license agreement. You are free to use and modify this code for non-commercial or evaluation purposes. If you do modify the code, please state the origin and note that you have modified the code. This source file may be used without restriction, but not distributed, provided this copyright statement remains present in the file. Any derivative work must also contain the original copyright notice and the following disclaimer. NO WARRANTY. THIS Work, IS PROVIDEDED "AS IS" WITH NO WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED. The user must assume the entire risk of using the Work. IN NO EVENT SHALL BIRD COMPUTER OR ITS PRINCIPALS OR OFFICERS BE LIABLE FOR ANY INCIDENTAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES WHATSOEVER RELATING TO THE USE OF THIS WORK, OR YOUR RELATIONSHIP WITH BC. IN ADDITION, IN NO EVENT DOES BIRD COMPUTER AUTHORIZE YOU TO USE THE WORK IN APPLICATIONS OR SYSTEMS WHERE THE WORK'S FAILURE TO PERFORM CAN REASONABLY BE EXPECTED TO RESULT IN A SIGNIFICANT PHYSICAL INJURY, OR IN LOSS OF LIFE. ANY SUCH USE BY YOU IS ENTIRELY AT YOUR OWN RISK, AND YOU AGREE TO HOLD BC HARMLESS FROM ANY CLAIMS OR LOSSES RELATING TO SUCH UNAUTHORIZED USE. Reg 0 read/write time 10ths 1 read/write time seconds 2 read/write time minutes 3 read/write time hours 4 read time / write alarm 10ths 5 read time / write alarm seconds 6 read time / write alarm minutes 7 read time / write alarm hours Spartan2e 152 LUTs 71 MHz ================================================================ */ module bc6526tod(rst, clk, ce, rdy, tod, tod_freq, cs, wr, addr, din, dout, alarm, midnight); input rst; // reset input clk; // system clock input ce; // clock enable output rdy; // ready output input tod; // time of day clock input (may be async) input tod_freq; // frequency select 1=50Hz,0=60Hz input cs; // chip select input wr; // 1=write input [2:0] addr; // register address input [7:0] din; // data input output [7:0] dout; // data output reg [7:0] dout; output alarm; // alarm match output midnight; reg tod_en; reg [2:0] tod_pre; // tod prescaler /5 or /6 reg [3:0] tod_10ths; reg [6:0] tod_secs; reg [6:0] tod_mins; reg [4:0] tod_hours; reg tod_ampm; // read latches reg [3:0] todl_10ths; reg [6:0] todl_secs; reg [6:0] todl_mins; reg [4:0] todl_hours; reg todl_ampm; reg latch_tod; reg [3:0] alm_10ths; reg [6:0] alm_secs; reg [6:0] alm_mins; reg [4:0] alm_hours; reg alm_ampm; assign rdy = cs; // Synchronize external tod signal wire tods; sync2s sync0(.rst(rst), .clk(clk), .i(tod), .o(tods)); // Edge detect the incoming tod signal. wire tod_edge; edge_det ed_tod(.rst(rst), .clk(clk), .ce(ce), .i(tods), .pe(tod_edge), .ne()); // Output alarm pulse on match wire isAlarm = {alm_10ths,alm_secs,alm_mins,alm_hours,alm_ampm}=={tod_10ths,tod_secs,tod_mins,tod_hours,tod_ampm}; edge_det ed_alarm(.rst(rst), .clk(clk), .ce(ce), .i(isAlarm), .pe(alarm), .ne() ); // Output pulse at midnight wire isMidnight = {tod_ampm,tod_hours,tod_mins,tod_secs,tod_10ths} == {1'b0,5'd12,7'd0,7'd0,4'd0}; edge_det ed_midnight(.rst(rst), .clk(clk), .ce(ce), .i(isMidnight), .pe(midnight), .ne() ); // register reads // - the tod is always read - alarm cant be read always @(addr or todl_10ths or todl_secs or todl_mins or todl_hours or todl_ampm) begin case(addr[1:0]) 2'd0: dout <= {4'b0,todl_10ths}; 2'd1: dout <= {1'b0,todl_secs}; 2'h2: dout <= {1'b0,todl_mins}; 2'h3: dout <= {todl_ampm,2'b0,todl_hours}; endcase end always @(posedge clk) if (rst) begin tod_pre <= 0; tod_10ths <= 0; tod_secs <= 0; tod_mins <= 0; tod_hours <= 5'h12; tod_ampm <= 0; tod_en <= 1; alm_10ths <= 0; alm_secs <= 0; alm_mins <= 0; alm_hours <= 0; alm_ampm <= 0; end else if (ce) begin // Handle register updates if (cs & wr) begin case(addr) // write to 10ths enables clock 3'h0: begin tod_10ths <= din; tod_en <= 1; end 3'h1: tod_secs <= din; 3'h2: tod_mins <= din; // Write to hours disables clock 3'h3: begin tod_ampm <= din[7]; tod_hours <= din; tod_en <= 0; end 3'h4: alm_10ths <= din; 3'h5: alm_secs <= din; 3'h6: alm_mins <= din; 3'h7: begin alm_ampm <= din[7]; alm_hours <= din; end endcase end // clock updates if (tod_en & tod_edge) begin if (tod_pre=={2'b10,~tod_freq}) begin tod_pre <= 0; if (tod_10ths==4'd9) begin tod_10ths <= 4'd0; if (tod_secs[3:0]==4'd9) begin tod_secs[3:0] <= 4'd0; if (tod_secs[6:4]==3'h5) begin tod_secs[6:4] <= 3'd0; if (tod_mins[3:0]==4'd9) begin tod_mins[3:0] <= 4'd0; if (tod_mins[6:4]==3'd5) begin tod_mins[6:4] <= 0; if (tod_hours==5'h11) begin tod_ampm <= ~tod_ampm; tod_hours[3:0] <= tod_hours[3:0] + 1; end else if (tod_hours==5'h12) tod_hours <= 5'h1; else if (tod_hours[3:0]==4'd9) tod_hours <= 5'h10; else tod_hours[3:0] <= tod_hours[3:0] + 1; end else tod_mins[6:4] <= tod_mins[6:4] + 1; end else tod_mins[3:0] <= tod_mins[3:0] + 1; end else tod_secs[6:4] <= tod_secs[6:4] + 1; end else tod_secs[3:0] <= tod_secs[3:0] + 1; end else tod_10ths <= tod_10ths + 1; end else tod_pre <= tod_pre + 1; end end // TOD is latched on every clock cycle, unless a read of the hours register // occurs, then the previously latched value is held until a read of the // 10ths register always @(posedge clk) if (rst) begin todl_10ths <= 0; todl_secs <= 0; todl_mins <= 0; todl_hours <= 0; todl_ampm <= 0; end else if (latch_tod) begin todl_10ths <= tod_10ths; todl_secs <= tod_secs; todl_mins <= tod_mins; todl_hours <= tod_hours; todl_ampm <= tod_ampm; end // TOD latch control always @(posedge clk) if (rst) latch_tod <= 1; else begin if (cs & ce & ~wr & addr[1:0]==2'd3) // hours reg latch_tod <= 0; if (cs & ce & ~wr & addr[1:0]==2'd0) // 10ths reg latch_tod <= 1; end endmodule