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