1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
#include <assert.h>
#include "vl.h"
#define CE1 0x0100
#define CE2 0x0200
#define RE 0x0400
#define WE 0x0800
#define ALE 0x1000
#define CLE 0x2000
#define RDY1 0x4000
#define RDY2 0x8000
#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
typedef enum { WAIT, READ1, READ2, READ3 } state_t;
typedef struct {
uint8_t *flash_contents;
state_t state;
uint32_t address;
uint8_t address_cycle;
} tc58128_dev;
static tc58128_dev tc58128_devs[2];
#define FLASH_SIZE (16*1024*1024)
void init_dev(tc58128_dev * dev, char *filename)
{
int ret, blocks;
dev->state = WAIT;
dev->flash_contents = qemu_mallocz(FLASH_SIZE);
memset(dev->flash_contents, 0xff, FLASH_SIZE);
if (!dev->flash_contents) {
fprintf(stderr, "could not alloc memory for flash\n");
exit(1);
}
if (filename) {
/* Load flash image skipping the first block */
ret = load_image(filename, dev->flash_contents + 528 * 32);
if (ret < 0) {
fprintf(stderr, "ret=%d\n", ret);
fprintf(stderr, "qemu: could not load flash image %s\n",
filename);
exit(1);
} else {
/* Build first block with number of blocks */
blocks = (ret + 528 * 32 - 1) / (528 * 32);
dev->flash_contents[0] = blocks & 0xff;
dev->flash_contents[1] = (blocks >> 8) & 0xff;
dev->flash_contents[2] = (blocks >> 16) & 0xff;
dev->flash_contents[3] = (blocks >> 24) & 0xff;
fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
filename);
}
}
}
void handle_command(tc58128_dev * dev, uint8_t command)
{
switch (command) {
case 0xff:
fprintf(stderr, "reset flash device\n");
dev->state = WAIT;
break;
case 0x00:
fprintf(stderr, "read mode 1\n");
dev->state = READ1;
dev->address_cycle = 0;
break;
case 0x01:
fprintf(stderr, "read mode 2\n");
dev->state = READ2;
dev->address_cycle = 0;
break;
case 0x50:
fprintf(stderr, "read mode 3\n");
dev->state = READ3;
dev->address_cycle = 0;
break;
default:
fprintf(stderr, "unknown flash command 0x%02x\n", command);
assert(0);
}
}
void handle_address(tc58128_dev * dev, uint8_t data)
{
switch (dev->state) {
case READ1:
case READ2:
case READ3:
switch (dev->address_cycle) {
case 0:
dev->address = data;
if (dev->state == READ2)
dev->address |= 0x100;
else if (dev->state == READ3)
dev->address |= 0x200;
break;
case 1:
dev->address += data * 528 * 0x100;
break;
case 2:
dev->address += data * 528;
fprintf(stderr, "address pointer in flash: 0x%08x\n",
dev->address);
break;
default:
/* Invalid data */
assert(0);
}
dev->address_cycle++;
break;
default:
assert(0);
}
}
uint8_t handle_read(tc58128_dev * dev)
{
#if 0
if (dev->address % 0x100000 == 0)
fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
#endif
return dev->flash_contents[dev->address++];
}
/* We never mark the device as busy, so interrupts cannot be triggered
XXXXX */
int tc58128_cb(uint16_t porta, uint16_t portb,
uint16_t * periph_pdtra, uint16_t * periph_portadir,
uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
{
int dev;
if ((porta & CE1) == 0)
dev = 0;
else if ((porta & CE2) == 0)
dev = 1;
else
return 0; /* No device selected */
if ((porta & RE) && (porta & WE)) {
/* Nothing to do, assert ready and return to input state */
*periph_portadir &= 0xff00;
*periph_portadir |= RDY(dev);
*periph_pdtra |= RDY(dev);
return 1;
}
if (porta & CLE) {
/* Command */
assert((porta & WE) == 0);
handle_command(&tc58128_devs[dev], porta & 0x00ff);
} else if (porta & ALE) {
assert((porta & WE) == 0);
handle_address(&tc58128_devs[dev], porta & 0x00ff);
} else if ((porta & RE) == 0) {
*periph_portadir |= 0x00ff;
*periph_pdtra &= 0xff00;
*periph_pdtra |= handle_read(&tc58128_devs[dev]);
} else {
assert(0);
}
return 1;
}
static sh7750_io_device tc58128 = {
RE | WE, /* Port A triggers */
0, /* Port B triggers */
tc58128_cb /* Callback */
};
int tc58128_init(struct SH7750State *s, char *zone1, char *zone2)
{
init_dev(&tc58128_devs[0], zone1);
init_dev(&tc58128_devs[1], zone2);
return sh7750_register_io_device(s, &tc58128);
}
|