From 66a04f7356a45926406e6fe6bbc01d540eec4205 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 15 Oct 2016 19:28:16 +0300 Subject: [PATCH] Microwire EEPROM (9346) --- flashrom.cpp | 221 ++++++++++++++++++++++++++++++++++++++++++++- include/flashrom.h | 11 ++- 2 files changed, 230 insertions(+), 2 deletions(-) diff --git a/flashrom.cpp b/flashrom.cpp index 696c782e..63571caa 100644 --- a/flashrom.cpp +++ b/flashrom.cpp @@ -1,7 +1,9 @@ /* * UAE - The Un*x Amiga Emulator * -* Simple 29F010 flash ROM chip emulator +* Simple 29Fxxx flash ROM chip emulator +* I2C EEPROM (24C08) +* MICROWIRE EEPROM (9346) * * (c) 2014 Toni Wilen */ @@ -20,6 +22,223 @@ #define FLASH_LOG 0 #define EEPROM_LOG 0 +/* MICROWIRE EEPROM */ + +struct eeprom93xx_eeprom_t { + uint8_t tick; + uint8_t address; + uint8_t command; + uint8_t writeable; + + uint8_t eecs; + uint8_t eesk; + uint8_t eedo; + + uint8_t addrbits; + uint16_t size; + uint16_t data; + uint16_t contents[256]; + + uae_u8 *memory; + struct zfile *zf; +}; + +static const char *opstring[] = { "extended", "write", "read", "erase" }; + +void eeprom93xx_write(void *eepromp, int eecs, int eesk, int eedi) +{ + eeprom93xx_eeprom_t *eeprom = (eeprom93xx_eeprom_t*)eepromp; + uint8_t tick = eeprom->tick; + uint8_t eedo = eeprom->eedo; + uint16_t address = eeprom->address; + uint8_t command = eeprom->command; + + //write_log("CS=%u SK=%u DI=%u DO=%u, tick = %u\n", eecs, eesk, eedi, eedo, tick); + + if (!eeprom->eecs && eecs) { + /* Start chip select cycle. */ + //write_log("Cycle start, waiting for 1st start bit (0)\n"); + tick = 0; + command = 0x0; + address = 0x0; + } + else if (eeprom->eecs && !eecs) { + /* End chip select cycle. This triggers write / erase. */ + if (eeprom->writeable) { + uint8_t subcommand = address >> (eeprom->addrbits - 2); + if (command == 0 && subcommand == 2) { + /* Erase all. */ + for (address = 0; address < eeprom->size; address++) { + eeprom->contents[address] = 0xffff; + } + } + else if (command == 3) { + /* Erase word. */ + eeprom->contents[address] = 0xffff; + } + else if (tick >= 2 + 2 + eeprom->addrbits + 16) { + if (command == 1) { + /* Write word. */ + eeprom->contents[address] &= eeprom->data; + } + else if (command == 0 && subcommand == 1) { + /* Write all. */ + for (address = 0; address < eeprom->size; address++) { + eeprom->contents[address] &= eeprom->data; + } + } + } + } + /* Output DO is tristate, read results in 1. */ + eedo = 1; + } + else if (eecs && !eeprom->eesk && eesk) { + /* Raising edge of clock shifts data in. */ + if (tick == 0) { + /* Wait for 1st start bit. */ + if (eedi == 0) { + //write_log("Got correct 1st start bit, waiting for 2nd start bit (1)\n"); + tick++; + } + else { + //write_log("wrong 1st start bit (is 1, should be 0)\n"); + tick = 2; + //~ assert(!"wrong start bit"); + } + } + else if (tick == 1) { + /* Wait for 2nd start bit. */ + if (eedi != 0) { + //write_log("Got correct 2nd start bit, getting command + address\n"); + tick++; + } + else { + ;//write_log("1st start bit is longer than needed\n"); + } + } + else if (tick < 2 + 2) { + /* Got 2 start bits, transfer 2 opcode bits. */ + tick++; + command <<= 1; + if (eedi) { + command += 1; + } + } + else if (tick < 2 + 2 + eeprom->addrbits) { + /* Got 2 start bits and 2 opcode bits, transfer all address bits. */ + tick++; + address = ((address << 1) | eedi); + if (tick == 2 + 2 + eeprom->addrbits) { + //write_log("%s command, address = 0x%02x (value 0x%04x)\n", opstring[command], address, eeprom->contents[address]); + if (command == 2) { + eedo = 0; + } + address = address % eeprom->size; + if (command == 0) { + /* Command code in upper 2 bits of address. */ + switch (address >> (eeprom->addrbits - 2)) { + case 0: + //write_log("write disable command\n"); + eeprom->writeable = 0; + break; + case 1: + //write_log("write all command\n"); + break; + case 2: + //write_log("erase all command\n"); + break; + case 3: + //write_log("write enable command\n"); + eeprom->writeable = 1; + break; + } + } + else { + /* Read, write or erase word. */ + eeprom->data = eeprom->contents[address]; + } + } + } + else if (tick < 2 + 2 + eeprom->addrbits + 16) { + /* Transfer 16 data bits. */ + tick++; + if (command == 2) { + /* Read word. */ + eedo = ((eeprom->data & 0x8000) != 0); + } + eeprom->data <<= 1; + eeprom->data += eedi; + } + else { + ;//write_log("additional unneeded tick, not processed\n"); + } + } + /* Save status of EEPROM. */ + eeprom->tick = tick; + eeprom->eecs = eecs; + eeprom->eesk = eesk; + eeprom->eedo = eedo; + eeprom->address = address; + eeprom->command = command; +} + +uae_u16 eeprom93xx_read(void *eepromp) +{ + eeprom93xx_eeprom_t *eeprom = (eeprom93xx_eeprom_t*)eepromp; + /* Return status of pin DO (0 or 1). */ + //write_log("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo); + return eeprom->eedo; +} + +uae_u8 eeprom93xx_read_byte(void *eepromp, int offset) +{ + eeprom93xx_eeprom_t *eeprom = (eeprom93xx_eeprom_t*)eepromp; + if (offset & 1) + return eeprom->contents[offset / 2]; + else + return eeprom->contents[offset / 2] >> 8; +} + +void *eeprom93xx_new(const uae_u8 *memory, int nwords, struct zfile *zf) +{ + /* Add a new EEPROM (with 16, 64 or 256 words). */ + eeprom93xx_eeprom_t *eeprom; + uint8_t addrbits; + + switch (nwords) { + case 16: + case 64: + addrbits = 6; + break; + case 128: + case 256: + addrbits = 8; + break; + default: + return NULL; + } + + eeprom = (eeprom93xx_eeprom_t *)xcalloc(eeprom93xx_eeprom_t, 1); + eeprom->size = nwords; + eeprom->addrbits = addrbits; + for (int i = 0; i < nwords; i++) { + eeprom->contents[i] = (memory[i * 2 + 0] << 8) | memory[i * 2 + 1]; + } + /* Output DO is tristate, read results in 1. */ + eeprom->eedo = 1; + write_log("eeprom = 0x%p, nwords = %u\n", eeprom, nwords); + return eeprom; +} + +void eeprom93xx_free(void *eepromp) +{ + eeprom93xx_eeprom_t *eeprom = (eeprom93xx_eeprom_t*)eepromp; + + /* Destroy EEPROM. */ + write_log("eeprom = 0x%p\n", eeprom); + xfree(eeprom); +} + /* I2C EEPROM */ #define NVRAM_PAGE_SIZE 16 diff --git a/include/flashrom.h b/include/flashrom.h index 15859538..3b4c89c8 100644 --- a/include/flashrom.h +++ b/include/flashrom.h @@ -13,7 +13,7 @@ uae_u32 flash_read(void *fdv, uaecptr addr); bool flash_active(void *fdv, uaecptr addr); int flash_size(void *fdv); -/* EPROM */ +/* I2C EEPROM */ #define BITBANG_I2C_SDA 0 #define BITBANG_I2C_SCL 1 @@ -27,4 +27,13 @@ int eeprom_i2c_set(void *i2c, int line, int level); #define FLASHROM_EVERY_OTHER_BYTE_ODD 2 #define FLASHROM_PARALLEL_EEPROM 4 +/* MICROWIRE EEPROM */ + +void eeprom93xx_write(void *eepromp, int eecs, int eesk, int eedi); +uae_u16 eeprom93xx_read(void *eepromp); +void *eeprom93xx_new(const uae_u8 *memory, int nwords, struct zfile *zf); +void eeprom93xx_free(void *eepromp); +uae_u8 eeprom93xx_read_byte(void *eepromp, int offset); + + #endif /* UAE_FLASHROM_H */ -- 2.47.3