From 232a029ffb1355690eddad470b995138573f5485 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 29 Jan 2017 12:17:36 +0100 Subject: m24cxx: Fix I2C implementation Signed-off-by: Michael Buesch --- libtoprammer/chips/m24cxxdip8.py | 149 ++++---- libtoprammer/fpga/bin/m24c16dip8.bit | Bin 24787 -> 24787 bytes libtoprammer/fpga/common/i2c.v | 234 ++++++++++++ libtoprammer/fpga/src/m24c16dip8/m24c16dip8.ucf | 62 --- libtoprammer/fpga/src/m24c16dip8/m24c16dip8.v | 483 ++++-------------------- libtoprammer/fpga/src/m24c16dip8/warning.filter | 1 + 6 files changed, 386 insertions(+), 543 deletions(-) create mode 100644 libtoprammer/fpga/common/i2c.v delete mode 100644 libtoprammer/fpga/src/m24c16dip8/m24c16dip8.ucf create mode 100644 libtoprammer/fpga/src/m24c16dip8/warning.filter diff --git a/libtoprammer/chips/m24cxxdip8.py b/libtoprammer/chips/m24cxxdip8.py index 85a58cf..44ab3c2 100644 --- a/libtoprammer/chips/m24cxxdip8.py +++ b/libtoprammer/chips/m24cxxdip8.py @@ -3,7 +3,7 @@ # # M24C16 I2C based serial EEPROM # -# Copyright (c) 2011 Michael Buesch +# Copyright (c) 2011-2017 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,13 +24,9 @@ from libtoprammer.chip import * class Chip_m24cXXdip8_common(Chip): - CMD_DEVSEL_READ = 0 - CMD_DEVSEL_WRITE = 1 - CMD_SETADDR = 2 - CMD_DATA_READ = 3 - CMD_DATA_READ_STOP = 4 - CMD_DATA_WRITE = 5 - CMD_DATA_WRITE_STOP = 6 + I2C_BASE_ADDR = 0x50 << 1 + I2C_READ = 0x01 + I2C_WRITE = 0x00 def __init__(self, eepromSize): Chip.__init__(self, @@ -57,27 +53,34 @@ class Chip_m24cXXdip8_common(Chip): self.__chipTurnOn() image = "" - count = 0 prevAddr = None self.progressMeterInit("Reading EEPROM", self.eepromSize) for addr in range(0, self.eepromSize): self.progressMeter(addr) if prevAddr is None or (prevAddr & 0xFF00) != (addr & 0xFF00): - self.__setAddress(addr, writeMode=False) - self.__runCommand(self.CMD_DEVSEL_WRITE) - self.__runCommand(self.CMD_SETADDR) - self.__runCommand(self.CMD_DEVSEL_READ) - self.__runCommand(self.CMD_DATA_READ_STOP) + self.__setAddressExtension(addr, writeMode=False) + # Begin sequential random read + self.__runI2C(data=self.I2C_BASE_ADDR | self.currentAddrExt | self.I2C_WRITE, + read=False, do_start=True, do_stop=False) + self.__expectACK() + self.__runI2C(data=addr & 0xFF, + read=False, do_start=False, do_stop=False) + self.__expectACK() + self.__runI2C(data=self.I2C_BASE_ADDR | self.currentAddrExt | self.I2C_READ, + read=False, do_start=True, do_stop=False) + self.__expectACK() prevAddr = addr + # Sequential random read + if addr >= self.eepromSize - 1: + # Last byte + self.__runI2C(read=True, do_start=False, do_stop=True) + self.__expectNACK() else: - self.__runCommand(self.CMD_DEVSEL_READ) - self.__runCommand(self.CMD_DATA_READ_STOP) + self.__runI2C(read=True, do_start=False, do_stop=False, + drive_ack=True) + self.__expectACK() self.__readData() - count += 1 - if count == self.top.getBufferRegSize(): - image += self.top.cmdReadBufferReg(count) - count = 0 - image += self.top.cmdReadBufferReg(count) + image += self.top.cmdReadBufferReg(1) self.progressMeterFinish() return image @@ -93,18 +96,24 @@ class Chip_m24cXXdip8_common(Chip): for addr in range(0, len(image)): self.progressMeter(addr) if prevAddr is None or (prevAddr & 0xFFF0) != (addr & 0xFFF0): - self.__setAddress(addr, writeMode=True) - self.__runCommand(self.CMD_DEVSEL_WRITE, busyWait=True) - self.__runCommand(self.CMD_SETADDR, busyWait=True) - self.__setData(byte2int(image[addr])) - self.__runCommand(self.CMD_DATA_WRITE, busyWait=True) + self.__setAddressExtension(addr, writeMode=True) + self.__runI2C(data=self.I2C_BASE_ADDR | self.currentAddrExt | self.I2C_WRITE, + read=False, do_start=True, do_stop=False) + self.__expectACK() + self.__runI2C(data=addr & 0xFF, + read=False, do_start=False, do_stop=False) + self.__expectACK() prevAddr = addr + if (addr & 0xF) == 0xF: + self.__runI2C(data=byte2int(image[addr]), + read=False, do_start=False, do_stop=True) + self.__expectACK() + self.top.cmdDelay(0.005) # Max write time else: - self.__setData(byte2int(image[addr])) - if (addr & 0xF) == 0xF: - self.__runCommand(self.CMD_DATA_WRITE_STOP, busyWait=True) - else: - self.__runCommand(self.CMD_DATA_WRITE, busyWait=True) + self.__runI2C(data=byte2int(image[addr]), + read=False, do_start=False, do_stop=False) + self.__expectACK() + self.progressMeterFinish() def __readData(self): @@ -113,56 +122,39 @@ class Chip_m24cXXdip8_common(Chip): def __setData(self, dataByte): self.top.cmdFPGAWrite(1, dataByte & 0xFF) - def __setAddress(self, address, writeMode): - # Address base - self.__setData(address) - # Address extension + def __setAddressExtension(self, address, writeMode): sizeMask = self.eepromSize - 1 assert(sizeMask & ~0x7FF == 0) - addrExt = address & 0x700 & sizeMask - if self.currentAddrExt != addrExt or\ - self.currentWriteMode != writeMode: - self.currentAddrExt = addrExt - self.currentWriteMode = writeMode - if sizeMask & 0x0100: - E0 = addrExt & 0x0100 - E0_en = 0 - else: - E0 = 0 - E0_en = 1 - if sizeMask & 0x0200: - E1 = addrExt & 0x0200 - E1_en = 0 - else: - E1 = 0 - E1_en = 1 - if sizeMask & 0x0400: - E2 = addrExt & 0x0400 - E2_en = 0 - else: - E2 = 0 - E2_en = 1 - if writeMode: - WC = 0 - else: - WC = 1 + addrExt = ((address & 0x700 & sizeMask) >> 8) << 1 + + if self.currentWriteMode != writeMode: + E0 = E1 = E2 = 0 + E0_en = not (sizeMask & 0x0100) + E1_en = not (sizeMask & 0x0200) + E2_en = not (sizeMask & 0x0400) + WC = not writeMode self.__setControlPins(E0=E0, E0_en=E0_en, E1=E1, E1_en=E1_en, E2=E2, E2_en=E2_en, WC=WC) + self.currentAddrExt = addrExt + self.currentWriteMode = writeMode - def __runCommand(self, command, busyWait=False): - self.top.cmdFPGAWrite(0, command & 0xFF) - if busyWait: - self.__busyWait() + def __runI2C(self, data=None, read=False, do_start=False, do_stop=False, drive_ack=False): + if data is not None: + self.__setData(data) else: - # We do not read busy flags, but wait long enough for - # the operation to finish. This is safe for eeprom read. - self.top.cmdDelay(0.00009) + self.__setData(0) + command = (0x01 if read else 0) |\ + (0x02 if do_start else 0) |\ + (0x04 if do_stop else 0) |\ + (0x08 if drive_ack else 0) + self.top.cmdFPGAWrite(0, command) + self.__busyWait() def __isBusy(self): - (busy0, busy1) = self.__getStatusFlags() - return busy0 != busy1 + (busy, ack) = self.__getStatusFlags() + return busy def __busyWait(self): for i in range(0, 100): @@ -174,9 +166,18 @@ class Chip_m24cXXdip8_common(Chip): def __getStatusFlags(self): self.top.cmdFPGARead(1) stat = self.top.cmdReadBufferReg8() - busy0 = bool(stat & 0x01) - busy1 = bool(stat & 0x02) - return (busy0, busy1) + busy = bool(stat & 0x01) + ack = not bool(stat & 0x02) + self.lastAck = ack + return (busy, ack) + + def __expectACK(self): + if not self.lastAck: + self.throwError("Expected I2C ACK, but received NACK") + + def __expectNACK(self): + if self.lastAck: + self.throwError("Expected I2C NACK, but received ACK") def __setControlPins(self, E0, E0_en, E1, E1_en, E2, E2_en, WC): value = 0 diff --git a/libtoprammer/fpga/bin/m24c16dip8.bit b/libtoprammer/fpga/bin/m24c16dip8.bit index be6fb81..6786f5d 100644 Binary files a/libtoprammer/fpga/bin/m24c16dip8.bit and b/libtoprammer/fpga/bin/m24c16dip8.bit differ diff --git a/libtoprammer/fpga/common/i2c.v b/libtoprammer/fpga/common/i2c.v new file mode 100644 index 0000000..593398c --- /dev/null +++ b/libtoprammer/fpga/common/i2c.v @@ -0,0 +1,234 @@ +/* + * TOP2049 Open Source programming suite + * + * FPGA bottomhalf I2C bus implementation + * + * Copyright (c) 2011-2017 Michael Buesch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +module i2c_module(clock, nreset, + scl_out, scl_out_en, scl_in, + sda_out, sda_out_en, sda_in, + write_byte, read_byte, read_mode, + ack, drive_ack, + do_start, do_stop, + finished); + input clock; + input nreset; + output scl_out; + output scl_out_en; + input scl_in; + output sda_out; + output sda_out_en; + input sda_in; + input [7:0] write_byte; + output [7:0] read_byte; + input read_mode; + output ack; + input drive_ack; + input do_start; + input do_stop; + output finished; + + reg [1:0] start_state; + reg [1:0] data_state; + reg [0:0] ack_state; + reg [0:0] stop_state; + reg [3:0] bit_index; + + reg sda_out_reg; + reg sda_out_en_reg; + reg [1:0] scl_out_reg; + reg scl_out_en_reg; + reg scl_running; + reg [7:0] read_byte_reg; + reg ack_reg; + reg finished_reg; + + wire [1:0] scl_pos; + assign scl_pos = (scl_out_reg + 1) & 3; + parameter SCL_HILO = 0; + parameter SCL_LO = 1; + parameter SCL_LOHI = 2; + parameter SCL_HI = 3; + + wire [7:0] write_byte_wire; + assign write_byte_wire[0] = write_byte[7]; + assign write_byte_wire[1] = write_byte[6]; + assign write_byte_wire[2] = write_byte[5]; + assign write_byte_wire[3] = write_byte[4]; + assign write_byte_wire[4] = write_byte[3]; + assign write_byte_wire[5] = write_byte[2]; + assign write_byte_wire[6] = write_byte[1]; + assign write_byte_wire[7] = write_byte[0]; + assign read_byte[0] = read_byte_reg[7]; + assign read_byte[1] = read_byte_reg[6]; + assign read_byte[2] = read_byte_reg[5]; + assign read_byte[3] = read_byte_reg[4]; + assign read_byte[4] = read_byte_reg[3]; + assign read_byte[5] = read_byte_reg[2]; + assign read_byte[6] = read_byte_reg[1]; + assign read_byte[7] = read_byte_reg[0]; + assign sda_out = sda_out_reg; + assign sda_out_en = sda_out_en_reg; + assign scl_out = scl_out_reg[1]; + assign scl_out_en = scl_out_en_reg; + assign ack = ack_reg; + assign finished = finished_reg; + + initial begin + start_state <= 0; + data_state <= 0; + ack_state <= 0; + stop_state <= 0; + bit_index <= 0; + + sda_out_reg <= 1; + sda_out_en_reg <= 0; + scl_out_reg <= SCL_HI; + scl_out_en_reg <= 1; + scl_running <= 0; + read_byte_reg <= 0; + ack_reg <= 0; + finished_reg <= 0; + end + +//TODO clock stretching + + always @(posedge clock or negedge nreset) begin + if (nreset == 0) begin + /* Reset */ + start_state <= 0; + data_state <= 0; + ack_state <= 0; + stop_state <= 0; + + bit_index <= 0; + + sda_out_reg <= 1; + sda_out_en_reg <= 0; + scl_out_reg <= SCL_HI; + scl_out_en_reg <= 1; + scl_running <= 0; + read_byte_reg <= 0; + ack_reg <= 0; + + finished_reg <= 0; + end else begin + +// if (scl_running) begin + scl_out_reg <= scl_out_reg + 1; +// end else begin +// scl_out_reg <= SCL_HI; +// end + + if (do_start && start_state != 2) begin + /* Send start condition */ + finished_reg <= 0; + scl_running <= 1; + sda_out_en_reg <= 1; + case (start_state) + 0: begin + /* Begin with SDA=hi */ + sda_out_reg <= 1; + if (scl_pos == SCL_LOHI) begin + start_state <= 1; + end + end + 1: begin + /* Start condition latch */ + if (scl_pos == SCL_HI) begin + sda_out_reg <= 0; + start_state <= 2; + end + end + endcase + end else if (data_state != 2) begin + /* Data transfer */ + finished_reg <= 0; + scl_running <= 1; + sda_out_en_reg <= !read_mode; + case (data_state) + 0: begin + if (scl_pos == SCL_LO) begin + if (read_mode) begin + sda_out_reg <= 0; + end else begin + sda_out_reg <= write_byte_wire[bit_index & 7]; + end + data_state <= 1; + end + end + 1: begin + if (scl_pos == SCL_HI) begin + bit_index <= bit_index + 1; + if (read_mode) begin + read_byte_reg[bit_index & 7] <= sda_in; + end + if (bit_index >= 7) begin + data_state <= 2; + end else begin + data_state <= 0; + end + end + end + endcase + end else if (ack_state != 1) begin + /* Read ACK bit */ + finished_reg <= 0; + scl_running <= 1; + case (ack_state) + 0: begin + if (scl_pos == SCL_LO) begin + sda_out_en_reg <= drive_ack; + sda_out_reg <= 0; + end else if (scl_pos == SCL_HI) begin + ack_reg <= sda_in; + ack_state <= 1; + end + end + endcase + end else if (do_stop && stop_state != 1) begin + /* Send stop condition */ + finished_reg <= 0; + sda_out_en_reg <= 1; + case (stop_state) + 0: begin + if (scl_pos == SCL_HI) begin + sda_out_reg <= 1; + stop_state <= 1; + end + end + endcase + end else begin + if (scl_pos == SCL_HILO) begin + start_state <= 0; + data_state <= 0; + ack_state <= 0; + stop_state <= 0; + + bit_index <= 0; + + finished_reg <= 1; +// scl_running <= 0; + end else begin + finished_reg <= 0; + end + end + end + end +endmodule diff --git a/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.ucf b/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.ucf deleted file mode 100644 index a550c07..0000000 --- a/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.ucf +++ /dev/null @@ -1,62 +0,0 @@ -NET "data<0>" LOC = P30; -NET "data<1>" LOC = P31; -NET "data<2>" LOC = P32; -NET "data<3>" LOC = P34; -NET "data<4>" LOC = P40; -NET "data<5>" LOC = P41; -NET "data<6>" LOC = P43; -NET "data<7>" LOC = P44; - -NET "read" LOC = P45; -NET "write" LOC = P39; -NET "osc_in" LOC = P46; -NET "ale_in" LOC = P36; - -NET "zif<1>" LOC = P21; -NET "zif<2>" LOC = P19; -NET "zif<3>" LOC = P17; -NET "zif<4>" LOC = P15; -NET "zif<5>" LOC = P10; -NET "zif<6>" LOC = P8; -NET "zif<7>" LOC = P6; -NET "zif<8>" LOC = P4; -NET "zif<9>" LOC = P98; -NET "zif<10>" LOC = P96; -NET "zif<11>" LOC = P93; -NET "zif<12>" LOC = P86; -NET "zif<13>" LOC = P83; -NET "zif<14>" LOC = P81; -NET "zif<15>" LOC = P74; -NET "zif<16>" LOC = P71; -NET "zif<17>" LOC = P69; -NET "zif<18>" LOC = P67; -NET "zif<19>" LOC = P65; -NET "zif<20>" LOC = P60; -NET "zif<21>" LOC = P58; -NET "zif<22>" LOC = P56; -NET "zif<23>" LOC = P54; -NET "zif<24>" LOC = P47; -NET "zif<25>" LOC = P53; -NET "zif<26>" LOC = P55; -NET "zif<27>" LOC = P57; -NET "zif<28>" LOC = P59; -NET "zif<29>" LOC = P62; -NET "zif<30>" LOC = P66; -NET "zif<31>" LOC = P68; -NET "zif<32>" LOC = P70; -NET "zif<33>" LOC = P72; -NET "zif<34>" LOC = P80; -NET "zif<35>" LOC = P82; -NET "zif<36>" LOC = P84; -NET "zif<37>" LOC = P87; -NET "zif<38>" LOC = P95; -NET "zif<39>" LOC = P97; -NET "zif<40>" LOC = P3; -NET "zif<41>" LOC = P5; -NET "zif<42>" LOC = P7; -NET "zif<43>" LOC = P9; -NET "zif<44>" LOC = P13; -NET "zif<45>" LOC = P16; -NET "zif<46>" LOC = P18; -NET "zif<47>" LOC = P20; -NET "zif<48>" LOC = P22; diff --git a/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.v b/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.v index 68c6f41..7b82fe0 100644 --- a/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.v +++ b/libtoprammer/fpga/src/m24c16dip8/m24c16dip8.v @@ -4,7 +4,7 @@ * M24C16 I2C based serial EEPROM * FPGA bottomhalf implementation * - * Copyright (c) 2011 Michael Buesch + * Copyright (c) 2011-2017 Michael Buesch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,204 +21,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* The runtime ID and revision. */ -`define RUNTIME_ID 16'h000B -`define RUNTIME_REV 16'h01 +`include "common.vh" +`include "i2c.v" -module i2c_module(clock, scl, sda_out, sda_out_en, sda_in, - write_byte, read_byte, read_mode, - do_start, expect_ack, do_stop, - finished); - input clock; - output scl; - output sda_out; - output sda_out_en; - input sda_in; - input [7:0] write_byte; - output [7:0] read_byte; - input read_mode; - input do_start; - input expect_ack; - input do_stop; - output finished; - - reg [1:0] start_state; - reg [1:0] data_state; - reg [1:0] ack_state; - reg [1:0] stop_state; - reg [2:0] bit_index; - - reg sda_out; - reg sda_out_en; - reg scl; - reg [7:0] read_byte; - reg finished; - - initial begin - start_state <= 0; - data_state <= 0; - ack_state <= 0; - stop_state <= 0; - bit_index <= 7; - - sda_out <= 0; - sda_out_en <= 0; - scl <= 0; - read_byte <= 0; - finished <= 0; - end - - always @(posedge clock) begin - if (do_start && start_state != 3) begin - /* Send start condition */ - finished <= 0; - sda_out_en <= 1; - case (start_state) - 0: begin - /* Start SCL high */ - scl <= 1; - sda_out <= 1; - start_state <= 1; - end - 1: begin - /* Start condition latch */ - sda_out <= 0; - start_state <= 2; - end - 2: begin - /* Start SCL low */ - scl <= 0; - start_state <= 3; - end - endcase - end else if (data_state != 3) begin - /* Data transfer */ - finished <= 0; - if (read_mode) begin /* Read */ - sda_out_en <= 0; - sda_out <= 0; - case (data_state) - 0: begin - scl <= 1; - data_state <= 1; - end - 1: begin - read_byte[bit_index] <= sda_in; - data_state <= 2; - end - 2: begin - scl <= 0; - if (bit_index == 0) begin - /* Done reading byte */ - bit_index <= 7; - data_state <= 3; - end else begin - bit_index <= bit_index - 1; - data_state <= 0; - end - end - endcase - end else begin /* Write */ - sda_out_en <= 1; - case (data_state) - 0: begin - sda_out <= write_byte[bit_index]; - scl <= 0; - data_state <= 1; - end - 1: begin - scl <= 1; - data_state <= 2; - end - 2: begin - scl <= 0; - if (bit_index == 0) begin - /* Done writing byte */ - bit_index <= 7; - data_state <= 3; - end else begin - bit_index <= bit_index - 1; - data_state <= 0; - end - end - endcase - end - end else if (expect_ack && ack_state != 2) begin - /* Wait for ACK from chip */ - finished <= 0; - sda_out_en <= 0; - case (ack_state) - 0: begin - scl <= 1; - ack_state <= 1; - end - 1: begin - scl <= 0; - if (sda_in == 0) begin - /* Got it */ - ack_state <= 2; - end else begin - ack_state <= 0; - end - end - endcase - end else if (do_stop && stop_state != 2) begin - /* Send stop condition */ - finished <= 0; - sda_out_en <= 1; - case (stop_state) - 0: begin - scl <= 1; - sda_out <= 0; - stop_state <= 1; - end - 1: begin - sda_out <= 1; - stop_state <= 2; - end - endcase - end else begin - /* Reset */ - start_state <= 0; - data_state <= 0; - ack_state <= 0; - stop_state <= 0; - - finished <= 1; - end - end -endmodule - -module m24c16dip8(data, ale_in, write, read, osc_in, zif); - inout [7:0] data; - input ale_in; - input write; - input read; - input osc_in; /* 24MHz oscillator */ - inout [48:1] zif; - - /* Interface to the microcontroller */ - wire read_oe; /* Read output-enable */ - reg [7:0] address; /* Cached address value */ - reg [7:0] read_data; /* Cached read data */ - - /* Programmer API and statemachine */ - reg [1:0] cmd_busy; /* bit0 != bit1 >= busy */ - reg [3:0] command; +`BOTTOMHALF_BEGIN(m24c16dip8, 11, 1) reg [7:0] data_buffer; - `define IS_BUSY (cmd_busy[0] != cmd_busy[1]) /* Is running command? */ - `define SET_FINISHED cmd_busy[1] <= cmd_busy[0] /* Set command-finished */ - - /* Programmer commands */ - parameter CMD_DEVSEL_READ = 0; - parameter CMD_DEVSEL_WRITE = 1; - parameter CMD_SETADDR = 2; - parameter CMD_DATA_READ = 3; - parameter CMD_DATA_READ_STOP = 4; - parameter CMD_DATA_WRITE = 5; - parameter CMD_DATA_WRITE_STOP = 6; - /* Chip signals */ reg chip_e0; /* E0 */ reg chip_e0_en; /* E0 enable */ @@ -227,55 +35,46 @@ module m24c16dip8(data, ale_in, write, read, osc_in, zif); reg chip_e2; /* E2 */ reg chip_e2_en; /* E2 enable */ reg chip_wc; /* /WC */ - wire chip_scl; /* I2C SCL */ + wire chip_scl_out; /* I2C SCL out */ + wire chip_scl_out_en; /* I2C SCL out enable*/ wire chip_sda_out; /* I2C SDA out */ wire chip_sda_out_en; /* I2C SDA out enable */ parameter ZIF_SDA = 25; - - wire low, high; /* Constant lo/hi */ - assign low = 0; - assign high = 1; + parameter ZIF_SCL = 26; /* I2C interface */ reg i2c_clock; + reg i2c_nreset; reg [7:0] i2c_write_byte; wire [7:0] i2c_read_byte; reg i2c_read; /* 1=> Read mode */ + wire i2c_ack; + reg i2c_drive_ack; reg i2c_do_start; - reg i2c_expect_ack; reg i2c_do_stop; wire i2c_finished; - reg [1:0] i2c_running; + reg i2c_running; i2c_module i2c( .clock(i2c_clock), - .scl(chip_scl), + .nreset(i2c_nreset), + .scl_out(chip_scl_out), + .scl_out_en(chip_scl_out_en), + .scl_in(zif[ZIF_SCL]), .sda_out(chip_sda_out), .sda_out_en(chip_sda_out_en), .sda_in(zif[ZIF_SDA]), .write_byte(i2c_write_byte), .read_byte(i2c_read_byte), .read_mode(i2c_read), + .ack(i2c_ack), + .drive_ack(i2c_drive_ack), .do_start(i2c_do_start), - .expect_ack(i2c_expect_ack), .do_stop(i2c_do_stop), .finished(i2c_finished) ); - /* The delay counter. Based on the 24MHz input clock. */ - reg [15:0] delay_count; - wire osc; - IBUF osc_ibuf(.I(osc_in), .O(osc)); - - `define DELAY_1P5US delay_count <= 36 - 1 /* 1.5 microseconds */ - - initial begin - address <= 0; - read_data <= 0; - delay_count <= 0; - - cmd_busy <= 0; - command <= 0; + `INITIAL_BEGIN data_buffer <= 0; chip_e0 <= 0; @@ -287,212 +86,82 @@ module m24c16dip8(data, ale_in, write, read, osc_in, zif); chip_wc <= 0; i2c_clock <= 0; + i2c_nreset <= 0; i2c_write_byte <= 0; i2c_read <= 0; + i2c_drive_ack <= 0; i2c_do_start <= 0; - i2c_expect_ack <= 0; i2c_do_stop <= 0; i2c_running <= 0; - end + `INITIAL_END - always @(posedge osc) begin - if (delay_count == 0 && `IS_BUSY) begin + `ASYNCPROC_BEGIN + if (`CMD_IS_RUNNING) begin if (i2c_running) begin - if (i2c_finished && i2c_running == 2) begin + if (i2c_finished && i2c_clock) begin i2c_running <= 0; - `SET_FINISHED; + `CMD_FINISH end else begin - i2c_running <= 2; i2c_clock <= ~i2c_clock; - `DELAY_1P5US; + `UDELAY(250) end end else begin - case (command) - CMD_DEVSEL_READ: begin - i2c_write_byte[7] <= 1; - i2c_write_byte[6] <= 0; - i2c_write_byte[5] <= 1; - i2c_write_byte[4] <= 0; - i2c_write_byte[3] <= chip_e2; - i2c_write_byte[2] <= chip_e1; - i2c_write_byte[1] <= chip_e0; - i2c_write_byte[0] <= 1; /* Read */ - i2c_clock <= 0; - i2c_read <= 0; - i2c_do_start <= 1; - i2c_expect_ack <= 1; - i2c_do_stop <= 0; - i2c_running <= 1; - end - CMD_DEVSEL_WRITE: begin - i2c_write_byte[7] <= 1; - i2c_write_byte[6] <= 0; - i2c_write_byte[5] <= 1; - i2c_write_byte[4] <= 0; - i2c_write_byte[3] <= chip_e2; - i2c_write_byte[2] <= chip_e1; - i2c_write_byte[1] <= chip_e0; - i2c_write_byte[0] <= 0; /* Write */ - i2c_clock <= 0; - i2c_read <= 0; - i2c_do_start <= 1; - i2c_expect_ack <= 1; - i2c_do_stop <= 0; - i2c_running <= 1; - end - CMD_SETADDR: begin - i2c_write_byte <= data_buffer; - i2c_clock <= 0; - i2c_read <= 0; - i2c_do_start <= 0; - i2c_expect_ack <= 1; - i2c_do_stop <= 0; - i2c_running <= 1; - end - CMD_DATA_READ: begin - i2c_clock <= 0; - i2c_read <= 1; - i2c_do_start <= 0; - i2c_expect_ack <= 1; - i2c_do_stop <= 0; - i2c_running <= 1; - end - CMD_DATA_READ_STOP: begin - i2c_clock <= 0; - i2c_read <= 1; - i2c_do_start <= 0; - i2c_expect_ack <= 0; - i2c_do_stop <= 1; - i2c_running <= 1; - end - CMD_DATA_WRITE: begin - i2c_write_byte <= data_buffer; - i2c_clock <= 0; - i2c_read <= 0; - i2c_do_start <= 0; - i2c_expect_ack <= 1; - i2c_do_stop <= 0; - i2c_running <= 1; - end - CMD_DATA_WRITE_STOP: begin - i2c_write_byte <= data_buffer; - i2c_clock <= 0; - i2c_read <= 0; - i2c_do_start <= 0; - i2c_expect_ack <= 1; - i2c_do_stop <= 1; - i2c_running <= 1; - end - endcase - end - end else begin - if (delay_count != 0) begin - delay_count <= delay_count - 1; + i2c_write_byte <= data_buffer; + i2c_read <= `CMD_NR[0]; + i2c_do_start <= `CMD_NR[1]; + i2c_do_stop <= `CMD_NR[2]; + i2c_drive_ack <= `CMD_NR[3]; + i2c_clock <= 0; + i2c_running <= 1; + i2c_nreset <= 1; end end - end + `ASYNCPROC_END - always @(posedge write) begin - case (address) - 8'h10: begin /* Run command */ - command <= data; - cmd_busy[0] <= ~cmd_busy[1]; + `DATAWRITE_BEGIN + `ADDR(0): begin /* Run command */ + `CMD_RUN(in_data) end - 8'h11: begin /* Write to data buffer */ - data_buffer[7:0] <= data[7:0]; + `ADDR(1): begin /* Write to data buffer */ + data_buffer[7:0] <= in_data[7:0]; end - 8'h12: begin /* Set control pins */ - chip_e0 <= data[0]; - chip_e0_en <= data[1]; - chip_e1 <= data[2]; - chip_e1_en <= data[3]; - chip_e2 <= data[4]; - chip_e2_en <= data[5]; - chip_wc <= data[6]; + `ADDR(2): begin /* Set control pins */ + chip_e0 <= in_data[0]; + chip_e0_en <= in_data[1]; + chip_e1 <= in_data[2]; + chip_e1_en <= in_data[3]; + chip_e2 <= in_data[4]; + chip_e2_en <= in_data[5]; + chip_wc <= in_data[6]; end - endcase - end + `DATAWRITE_END - always @(negedge read) begin - case (address) - 8'h10: begin /* Read data buffer */ - read_data <= i2c_read_byte; + `DATAREAD_BEGIN + `ADDR(0): begin /* Read data buffer */ + out_data <= i2c_read_byte; end - 8'h11: begin /* Status read */ - read_data[0] <= cmd_busy[0]; - read_data[1] <= cmd_busy[1]; + `ADDR(1): begin /* Status read */ + out_data[0] <= `CMD_IS_RUNNING; + out_data[1] <= i2c_ack; end - - 8'hFD: read_data <= `RUNTIME_ID & 16'hFF; - 8'hFE: read_data <= (`RUNTIME_ID >> 8) & 16'hFF; - 8'hFF: read_data <= `RUNTIME_REV; - endcase - end - - wire ale; - IBUFG ale_ibufg(.I(ale_in), .O(ale)); - - always @(negedge ale) begin - address <= data; - end - - assign read_oe = !read && address[4]; - - bufif0(zif[1], low, low); - bufif0(zif[2], low, low); - bufif0(zif[3], low, low); - bufif0(zif[4], low, low); - bufif0(zif[5], low, low); - bufif0(zif[6], low, low); - bufif0(zif[7], low, low); - bufif0(zif[8], low, low); - bufif0(zif[9], low, low); - bufif0(zif[10], low, low); - bufif0(zif[11], low, low); - bufif0(zif[12], low, low); - bufif0(zif[13], low, low); - bufif0(zif[14], low, low); - bufif0(zif[15], low, low); - bufif0(zif[16], low, low); - bufif0(zif[17], low, low); - bufif0(zif[18], low, low); - bufif0(zif[19], low, low); - bufif0(zif[20], low, low); - bufif0(zif[21], chip_e0, !chip_e0_en); /* E0 */ - bufif0(zif[22], chip_e1, !chip_e1_en); /* E1 */ - bufif0(zif[23], chip_e2, !chip_e2_en); /* E2 */ - bufif0(zif[24], low, low); /* VSS */ - bufif0(zif[25], chip_sda_out, !chip_sda_out_en); /* SDA */ - bufif0(zif[26], chip_scl, low); /* SCL */ - bufif0(zif[27], chip_wc, low); /* /WC */ - bufif0(zif[28], high, low); /* VCC */ - bufif0(zif[29], low, low); - bufif0(zif[30], low, low); - bufif0(zif[31], low, low); - bufif0(zif[32], low, low); - bufif0(zif[33], low, low); - bufif0(zif[34], low, low); - bufif0(zif[35], low, low); - bufif0(zif[36], low, low); - bufif0(zif[37], low, low); - bufif0(zif[38], low, low); - bufif0(zif[39], low, low); - bufif0(zif[40], low, low); - bufif0(zif[41], low, low); - bufif0(zif[42], low, low); - bufif0(zif[43], low, low); - bufif0(zif[44], low, low); - bufif0(zif[45], low, low); - bufif0(zif[46], low, low); - bufif0(zif[47], low, low); - bufif0(zif[48], low, low); - - bufif1(data[0], read_data[0], read_oe); - bufif1(data[1], read_data[1], read_oe); - bufif1(data[2], read_data[2], read_oe); - bufif1(data[3], read_data[3], read_oe); - bufif1(data[4], read_data[4], read_oe); - bufif1(data[5], read_data[5], read_oe); - bufif1(data[6], read_data[6], read_oe); - bufif1(data[7], read_data[7], read_oe); -endmodule + `DATAREAD_END + + `ZIF_UNUSED(1) `ZIF_UNUSED(2) `ZIF_UNUSED(3) `ZIF_UNUSED(4) + `ZIF_UNUSED(5) `ZIF_UNUSED(6) `ZIF_UNUSED(7) `ZIF_UNUSED(8) + `ZIF_UNUSED(9) `ZIF_UNUSED(10) `ZIF_UNUSED(11) `ZIF_UNUSED(12) + `ZIF_UNUSED(13) `ZIF_UNUSED(14) `ZIF_UNUSED(15) `ZIF_UNUSED(16) + `ZIF_UNUSED(17) `ZIF_UNUSED(18) `ZIF_UNUSED(19) `ZIF_UNUSED(20) + `ZIF_BUF1(21, chip_e0, chip_e0_en) /* E0 */ + `ZIF_BUF1(22, chip_e1, chip_e1_en) /* E1 */ + `ZIF_BUF1(23, chip_e2, chip_e2_en) /* E2 */ + `ZIF_BUF1(24, low, high) /* VSS */ + `ZIF_BUF1(25, chip_sda_out, chip_sda_out_en) /* SDA */ + `ZIF_BUF1(26, chip_scl_out, chip_scl_out_en) /* SCL */ + `ZIF_BUF1(27, chip_wc, high) /* /WC */ + `ZIF_BUF1(28, high, high) /* VCC */ + `ZIF_UNUSED(29) `ZIF_UNUSED(30) `ZIF_UNUSED(31) `ZIF_UNUSED(32) + `ZIF_UNUSED(33) `ZIF_UNUSED(34) `ZIF_UNUSED(35) `ZIF_UNUSED(36) + `ZIF_UNUSED(37) `ZIF_UNUSED(38) `ZIF_UNUSED(39) `ZIF_UNUSED(40) + `ZIF_UNUSED(41) `ZIF_UNUSED(42) `ZIF_UNUSED(43) `ZIF_UNUSED(44) + `ZIF_UNUSED(45) `ZIF_UNUSED(46) `ZIF_UNUSED(47) `ZIF_UNUSED(48) +`BOTTOMHALF_END diff --git a/libtoprammer/fpga/src/m24c16dip8/warning.filter b/libtoprammer/fpga/src/m24c16dip8/warning.filter new file mode 100644 index 0000000..6218ade --- /dev/null +++ b/libtoprammer/fpga/src/m24c16dip8/warning.filter @@ -0,0 +1 @@ +The\svalue\sinit\sof\sthe\sFF/Latch\si2c_nreset\shinder\sthe\sconstant\scleaning\sin\sthe\sblock -- cgit v1.2.3