qemu/hw/block/tc58128.c
<<
>>
Prefs
   1/*
   2 * TC58128 NAND EEPROM emulation
   3 *
   4 * Copyright (c) 2005 Samuel Tardieu
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice (including the next
  14 * paragraph) shall be included in all copies or substantial portions of the
  15 * Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 *
  25 * SPDX-License-Identifier: MIT
  26 */
  27#include "qemu/osdep.h"
  28#include "qemu/units.h"
  29#include "hw/sh4/sh.h"
  30#include "hw/loader.h"
  31#include "sysemu/qtest.h"
  32#include "qemu/error-report.h"
  33
  34#define CE1  0x0100
  35#define CE2  0x0200
  36#define RE   0x0400
  37#define WE   0x0800
  38#define ALE  0x1000
  39#define CLE  0x2000
  40#define RDY1 0x4000
  41#define RDY2 0x8000
  42#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
  43
  44typedef enum { WAIT, READ1, READ2, READ3 } state_t;
  45
  46typedef struct {
  47    uint8_t *flash_contents;
  48    state_t state;
  49    uint32_t address;
  50    uint8_t address_cycle;
  51} tc58128_dev;
  52
  53static tc58128_dev tc58128_devs[2];
  54
  55#define FLASH_SIZE (16 * MiB)
  56
  57static void init_dev(tc58128_dev * dev, const char *filename)
  58{
  59    int ret, blocks;
  60
  61    dev->state = WAIT;
  62    dev->flash_contents = g_malloc(FLASH_SIZE);
  63    memset(dev->flash_contents, 0xff, FLASH_SIZE);
  64    if (filename) {
  65        /* Load flash image skipping the first block */
  66        ret = load_image_size(filename, dev->flash_contents + 528 * 32,
  67                              FLASH_SIZE - 528 * 32);
  68        if (ret < 0) {
  69            if (!qtest_enabled()) {
  70                error_report("Could not load flash image %s", filename);
  71                exit(1);
  72            }
  73        } else {
  74            /* Build first block with number of blocks */
  75            blocks = DIV_ROUND_UP(ret, 528 * 32);
  76            dev->flash_contents[0] = blocks & 0xff;
  77            dev->flash_contents[1] = (blocks >> 8) & 0xff;
  78            dev->flash_contents[2] = (blocks >> 16) & 0xff;
  79            dev->flash_contents[3] = (blocks >> 24) & 0xff;
  80            fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
  81                    filename);
  82        }
  83    }
  84}
  85
  86static void handle_command(tc58128_dev * dev, uint8_t command)
  87{
  88    switch (command) {
  89    case 0xff:
  90        fprintf(stderr, "reset flash device\n");
  91        dev->state = WAIT;
  92        break;
  93    case 0x00:
  94        fprintf(stderr, "read mode 1\n");
  95        dev->state = READ1;
  96        dev->address_cycle = 0;
  97        break;
  98    case 0x01:
  99        fprintf(stderr, "read mode 2\n");
 100        dev->state = READ2;
 101        dev->address_cycle = 0;
 102        break;
 103    case 0x50:
 104        fprintf(stderr, "read mode 3\n");
 105        dev->state = READ3;
 106        dev->address_cycle = 0;
 107        break;
 108    default:
 109        fprintf(stderr, "unknown flash command 0x%02x\n", command);
 110        abort();
 111    }
 112}
 113
 114static void handle_address(tc58128_dev * dev, uint8_t data)
 115{
 116    switch (dev->state) {
 117    case READ1:
 118    case READ2:
 119    case READ3:
 120        switch (dev->address_cycle) {
 121        case 0:
 122            dev->address = data;
 123            if (dev->state == READ2)
 124                dev->address |= 0x100;
 125            else if (dev->state == READ3)
 126                dev->address |= 0x200;
 127            break;
 128        case 1:
 129            dev->address += data * 528 * 0x100;
 130            break;
 131        case 2:
 132            dev->address += data * 528;
 133            fprintf(stderr, "address pointer in flash: 0x%08x\n",
 134                    dev->address);
 135            break;
 136        default:
 137            /* Invalid data */
 138            abort();
 139        }
 140        dev->address_cycle++;
 141        break;
 142    default:
 143        abort();
 144    }
 145}
 146
 147static uint8_t handle_read(tc58128_dev * dev)
 148{
 149#if 0
 150    if (dev->address % 0x100000 == 0)
 151        fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
 152#endif
 153    return dev->flash_contents[dev->address++];
 154}
 155
 156/* We never mark the device as busy, so interrupts cannot be triggered
 157   XXXXX */
 158
 159static int tc58128_cb(uint16_t porta, uint16_t portb,
 160                      uint16_t * periph_pdtra, uint16_t * periph_portadir,
 161                      uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
 162{
 163    int dev;
 164
 165    if ((porta & CE1) == 0)
 166        dev = 0;
 167    else if ((porta & CE2) == 0)
 168        dev = 1;
 169    else
 170        return 0;               /* No device selected */
 171
 172    if ((porta & RE) && (porta & WE)) {
 173        /* Nothing to do, assert ready and return to input state */
 174        *periph_portadir &= 0xff00;
 175        *periph_portadir |= RDY(dev);
 176        *periph_pdtra |= RDY(dev);
 177        return 1;
 178    }
 179
 180    if (porta & CLE) {
 181        /* Command */
 182        assert((porta & WE) == 0);
 183        handle_command(&tc58128_devs[dev], porta & 0x00ff);
 184    } else if (porta & ALE) {
 185        assert((porta & WE) == 0);
 186        handle_address(&tc58128_devs[dev], porta & 0x00ff);
 187    } else if ((porta & RE) == 0) {
 188        *periph_portadir |= 0x00ff;
 189        *periph_pdtra &= 0xff00;
 190        *periph_pdtra |= handle_read(&tc58128_devs[dev]);
 191    } else {
 192        abort();
 193    }
 194    return 1;
 195}
 196
 197static sh7750_io_device tc58128 = {
 198    RE | WE,                    /* Port A triggers */
 199    0,                          /* Port B triggers */
 200    tc58128_cb                  /* Callback */
 201};
 202
 203int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
 204{
 205    init_dev(&tc58128_devs[0], zone1);
 206    init_dev(&tc58128_devs[1], zone2);
 207    return sh7750_register_io_device(s, &tc58128);
 208}
 209