/* Mac Plus real time clock * * Doesn't do much yet ... eventually needs a backbus interface * to save/restore PRAM to the PIC. Not much I can do about the * actual RTC tho. * * * NOTE: * * The HW ref manual seems to indicate that the RTC chip latches * on raising clock but SW should latch on falling clock. However * that isn't what the ROM does. * * The actual transfer done by the ROM looks like: * * * Byte send: * - Direction set to output, value 111 (disabled, clock & data high) * - Set enabled and clock to 0 * 8 times: - Set value bit and clock to 0 * - Set clock to 1 * * So the transfer "completes" with clock high after sending the last bit, * the next transfer is then either a read or a write. In the later case, * the ROM goes back to the same routine above, which means it continues * clocking bits without a significant "hickup". * * For a read however, what happens next is: * * - Set direction to input (at this point clock is still high) * - Clear data (no effect as direction is input) and clock * 8 times: - Set clock to 0 * - Set clock to 1 * - Read bit * - Set direction to output * * Finally disable chip. * * You will notice that this is quite bogus since there's no way * for the RTC chip to know after a read when to stop driving the * data line before the Mac sets the direction back to output, * so there -will- be some contention... oops. This isn't a problem * for us though as we use separate signals. */ module rtc(input sysclk, input reset, output reg onesec, input data_in, output data_out, input data_clock, input _data_enable); parameter divider = 23'h7a1200; /* Sysclk is 16Mhz, to generate a 1-sec pulse, we need * a 23-bit counter */ reg [22:0] cnt; reg oldclk; wire dstrobe; wire gotbyte; reg [7:0] rdata; reg [7:0] shift; reg [7:0] addr; reg dir; reg ckaddr; reg [2:0] bitcnt; localparam rtc_state_cmd = 0; localparam rtc_state_read = 1; localparam rtc_state_write = 2; localparam rtc_state_cmd2 = 3; reg [1:0] state; /* Generate one second tick */ always@(posedge sysclk or posedge reset) begin if (reset) begin cnt <= divider; onesec <= 0; end else begin if (cnt == 0) begin onesec <= ~onesec; cnt <= divider; end else cnt <= cnt - 1; end end /* Data clock edge detect buffer */ always@(posedge sysclk or posedge reset) begin if (reset) oldclk <= 1; else oldclk <= data_clock; end assign dstrobe = data_clock & ~oldclk & ~_data_enable; `ifdef __foo__ /* Shift bit counter */ always@(posedge sysclk or posedge reset) begin if (reset) begin bitcnt <= 7; end else begin if (_data_enable) bitcnt <= 7; else if (dstrobe) bitcnt <= bitcnt - 1; end end assign gotbyte = (bitcnt == 0) && dstrobe; /* Shift register */ always@(posedge sysclk or posedge reset) begin if (reset) shift <= 0; else begin if (_data_enable) shift <= 0; else if (dstrobe) begin if (state == rtc_state_read && bitcnt == 3'b111) shift <= rdata; else shift <= { shift[6:0], data_in }; end end end assign data_out = shift[7]; /* Latch/decode command byte into address, ckaddr and dir */ always@(posedge sysclk or posedge reset) begin if (reset) begin addr <= 0; dir <= 0; ckaddr <= 0; end else if (gotbyte) begin if (state == rtc_state_cmd) begin dir <= shift[7]; addr <= shift; end else if (state == rtc_state_cmd2) addr <= { addr[2:0], shift[6:2] }; end end /* State machine */ always@(posedge sysclk or posedge reset) begin if (reset) begin state <= rtc_state_cmd; end else begin if (_data_enable) state <= rtc_state_cmd; else if (gotbyte) begin if (state == rtc_state_cmd) begin if (shift[6:3] == 4'b1111) state <= rtc_state_cmd2; else if (shift[7]) state <= rtc_state_read; else state <= rtc_state_write; end else if (state == rtc_state_cmd2) begin if (addr[7]) state <= rtc_state_read; else state <= rtc_state_write; end else state <= rtc_state_cmd; end end end /* Read machine */ always@(posedge sysclk or posedge reset) begin if (reset) begin rdata <= 0; end else begin end end `endif endmodule