|
|
1.1 root 1: /* $Id: mk48txx.c,v 1.2 2006/11/26 16:01:49 fredette Exp $ */
2:
3: /* ic/mk48txx.c - implementation of Mostek 48Txx emulation: */
4:
5: /*
6: * Copyright (c) 2006 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: mk48txx.c,v 1.2 2006/11/26 16:01:49 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus-device.h>
41: #include <tme/ic/mk48txx.h>
42: #include <tme/misc.h>
43: #include <time.h>
44: #include <sys/time.h>
45:
46: /* macros: */
47:
48: /* the different parts: */
49: #define TME_MK48TXX_PART_02 (02)
50:
51: /* register addresses: */
52: #define TME_MK48TXX_REGS_COUNT (8) /* maximum number of registers */
53: #define TME_MK48TXX_REG_YEAR (TME_MK48TXX_REGS_COUNT - 1) /* BCD year */
54: #define TME_MK48TXX_REG_MON (TME_MK48TXX_REGS_COUNT - 2) /* BCD month */
55: #define TME_MK48TXX_REG_DAY (TME_MK48TXX_REGS_COUNT - 3) /* BCD day in month */
56: #define TME_MK48TXX_REG_WDAY (TME_MK48TXX_REGS_COUNT - 4) /* weekday */
57: #define TME_MK48TXX_REG_HOUR (TME_MK48TXX_REGS_COUNT - 5) /* BCD hour */
58: #define TME_MK48TXX_REG_MIN (TME_MK48TXX_REGS_COUNT - 6) /* BCD minutes */
59: #define TME_MK48TXX_REG_SEC (TME_MK48TXX_REGS_COUNT - 7) /* BCD seconds */
60: #define TME_MK48TXX_REG_CSR (TME_MK48TXX_REGS_COUNT - 8) /* control register */
61:
62: /* the first register implemented by a part: */
63: #define TME_MK48TXX_REG_FIRST(part) (TME_MK48TXX_REG_CSR)
64:
65: /* bits in the CSR: */
66: #define TME_MK48TXX_CSR_WRITE TME_BIT(7) /* start writing */
67: #define TME_MK48TXX_CSR_READ TME_BIT(6) /* start reading */
68:
69: /* bits in the weekday register: */
70: #define TME_MK48TXX_WDAY_FTEST TME_BIT(6) /* 512Hz frequency test */
71:
72: /* bits in the seconds register: */
73: #define TME_MK48TXX_SEC_STOP TME_BIT(7) /* all stop */
74:
75: #define TME_MK48TXX_LOG_HANDLE(am) (&(am)->tme_mk48txx_element->tme_element_log_handle)
76:
77: /* structures: */
78: struct tme_mk48txx {
79:
80: /* our simple bus device header: */
81: struct tme_bus_device tme_mk48txx_device;
82: #define tme_mk48txx_element tme_mk48txx_device.tme_bus_device_element
83:
84: /* our socket: */
85: struct tme_mk48txx_socket tme_mk48txx_socket;
86: #define tme_mk48txx_addr_shift tme_mk48txx_socket.tme_mk48txx_socket_addr_shift
87: #define tme_mk48txx_port_least_lane tme_mk48txx_socket.tme_mk48txx_socket_port_least_lane
88: #define tme_mk48txx_year_zero tme_mk48txx_socket.tme_mk48txx_socket_year_zero
89:
90: /* our mutex: */
91: tme_mutex_t tme_mk48txx_mutex;
92:
93: /* the part emulated: */
94: unsigned int tme_mk48txx_part;
95:
96: /* our timer condition: */
97: tme_cond_t tme_mk48txx_cond_timer;
98:
99: /* it's easiest to just model the chip as a chunk of memory: */
100: tme_uint8_t tme_mk48txx_regs[TME_MK48TXX_REGS_COUNT];
101:
102: /* if nonzero, the internal time-of-day needs to be updated: */
103: tme_uint8_t tme_mk48txx_tod_update;
104: };
105:
106: /* the mk48txx bus router: */
107: static const tme_bus_lane_t tme_mk48txx_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = {
108:
109: /* [gen] initiator port size: 8 bits
110: [gen] initiator port least lane: 0: */
111: /* D7-D0 */ TME_BUS_LANE_ROUTE(0),
112: };
113:
114: /* these convert values to and from BCD: */
115: static inline tme_uint8_t
116: _tme_mk48txx_bcd_out(unsigned int value)
117: {
118: return ((value % 10)
119: + ((value / 10) * 16));
120: }
121: static inline unsigned int
122: _tme_mk48txx_bcd_in(tme_uint8_t value)
123: {
124: return ((value % 16)
125: + ((value / 16) * 10));
126: }
127:
128: /* this resets an mk48txx: */
129: static void
130: _tme_mk48txx_reset(struct tme_mk48txx *mk48txx)
131: {
132:
133: /* clear the CSR: */
134: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] = 0;
135:
136: /* start the clock running normally: */
137: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_WDAY] = 0;
138: mk48txx->tme_mk48txx_regs[TME_MK48TXX_SEC_STOP] = 0;
139: }
140:
141: /* the mk48txx bus cycle handler: */
142: static int
143: _tme_mk48txx_bus_cycle(void *_mk48txx, struct tme_bus_cycle *cycle_init)
144: {
145: struct tme_mk48txx *mk48txx;
146: tme_bus_addr_t address, mk48txx_address_last;
147: tme_uint8_t buffer, value;
148: struct tme_bus_cycle cycle_resp;
149: unsigned int reg;
150: struct timeval now;
151: time_t _now;
152: struct tm *now_tm, now_tm_buffer;
153:
154: /* recover our data structure: */
155: mk48txx = (struct tme_mk48txx *) _mk48txx;
156:
157: /* the requested cycle must be within range: */
158: mk48txx_address_last = mk48txx->tme_mk48txx_device.tme_bus_device_address_last;
159: assert(cycle_init->tme_bus_cycle_address <= mk48txx_address_last);
160: assert(cycle_init->tme_bus_cycle_size <= (mk48txx_address_last - cycle_init->tme_bus_cycle_address) + 1);
161:
162: /* get the register being accessed: */
163: address = cycle_init->tme_bus_cycle_address;
164: reg = (address >> mk48txx->tme_mk48txx_addr_shift) + TME_MK48TXX_REG_FIRST(mk48txx->tme_mk48txx_part);
165:
166: /* lock the mutex: */
167: tme_mutex_lock(&mk48txx->tme_mk48txx_mutex);
168:
169: /* if the clock is not being read or written: */
170: if ((mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR]
171: & (TME_MK48TXX_CSR_READ
172: | TME_MK48TXX_CSR_WRITE)) == 0) {
173:
174: /* sample the time of day: */
175: gettimeofday(&now, NULL);
176: _now = now.tv_sec;
177: now_tm = gmtime_r(&_now, &now_tm_buffer);
178:
179: /* put the time-of-day into the registers: */
180: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_HOUR] = _tme_mk48txx_bcd_out(now_tm->tm_hour);
181: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_MIN] = _tme_mk48txx_bcd_out(now_tm->tm_min);
182: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_SEC] = _tme_mk48txx_bcd_out(now_tm->tm_sec);
183: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_MON] = _tme_mk48txx_bcd_out(now_tm->tm_mon + 1);
184: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_DAY] = _tme_mk48txx_bcd_out(now_tm->tm_mday);
185: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_YEAR]
186: = _tme_mk48txx_bcd_out((1900 + now_tm->tm_year) - mk48txx->tme_mk48txx_year_zero);
187: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_WDAY] = now_tm->tm_wday;
188: }
189:
190: /* if this is a write: */
191: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
192:
193: /* run the bus cycle: */
194: cycle_resp.tme_bus_cycle_buffer = &buffer;
195: cycle_resp.tme_bus_cycle_lane_routing = tme_mk48txx_router;
196: cycle_resp.tme_bus_cycle_address = 0;
197: cycle_resp.tme_bus_cycle_buffer_increment = 1;
198: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ;
199: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
200: cycle_resp.tme_bus_cycle_port =
201: TME_BUS_CYCLE_PORT(mk48txx->tme_mk48txx_port_least_lane,
202: TME_BUS8_LOG2);
203: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
204: value = buffer;
205:
206: /* log this write: */
207: tme_log(TME_MK48TXX_LOG_HANDLE(mk48txx), 100000, TME_OK,
208: (TME_MK48TXX_LOG_HANDLE(mk48txx),
209: "reg %d write %02x",
210: reg, value));
211:
212: /* dispatch on the register: */
213: switch (reg) {
214:
215: case TME_MK48TXX_REG_WDAY:
216:
217: /* flag that the time-of-day needs to be updated: */
218: mk48txx->tme_mk48txx_tod_update = TRUE;
219:
220: /* update the register: */
221: mk48txx->tme_mk48txx_regs[reg] = value;
222: break;
223:
224: case TME_MK48TXX_REG_HOUR:
225: case TME_MK48TXX_REG_MIN:
226: case TME_MK48TXX_REG_SEC:
227: case TME_MK48TXX_REG_MON:
228: case TME_MK48TXX_REG_DAY:
229: case TME_MK48TXX_REG_YEAR:
230:
231: /* flag that the time-of-day needs to be updated: */
232: mk48txx->tme_mk48txx_tod_update = TRUE;
233:
234: /* update the register: */
235: mk48txx->tme_mk48txx_regs[reg] = value;
236: break;
237:
238: case TME_MK48TXX_REG_CSR:
239:
240: /* update the CSR: */
241: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] = value;
242:
243: break;
244:
245: default:
246: /* ignore */
247: break;
248: }
249: }
250:
251: /* otherwise, this is a read: */
252: else {
253: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
254:
255: /* dispatch on the register: */
256: switch (reg) {
257:
258: case TME_MK48TXX_REG_HOUR:
259: case TME_MK48TXX_REG_MIN:
260: case TME_MK48TXX_REG_SEC:
261: case TME_MK48TXX_REG_MON:
262: case TME_MK48TXX_REG_DAY:
263: case TME_MK48TXX_REG_YEAR:
264: case TME_MK48TXX_REG_WDAY:
265:
266: /* read the register: */
267: value = mk48txx->tme_mk48txx_regs[reg];
268: break;
269:
270: case TME_MK48TXX_REG_CSR:
271:
272: /* read the register: */
273: value = mk48txx->tme_mk48txx_regs[reg];
274: break;
275:
276: /* undefined registers return garbage when read: */
277: default:
278: value = 0xff;
279: break;
280: }
281:
282: /* log this read: */
283: tme_log(TME_MK48TXX_LOG_HANDLE(mk48txx), 100000, TME_OK,
284: (TME_MK48TXX_LOG_HANDLE(mk48txx),
285: "reg %d read %02x",
286: reg, value));
287:
288: /* run the bus cycle: */
289: buffer = value;
290: cycle_resp.tme_bus_cycle_buffer = &buffer;
291: cycle_resp.tme_bus_cycle_lane_routing = tme_mk48txx_router;
292: cycle_resp.tme_bus_cycle_address = 0;
293: cycle_resp.tme_bus_cycle_buffer_increment = 1;
294: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE;
295: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
296: cycle_resp.tme_bus_cycle_port =
297: TME_BUS_CYCLE_PORT(mk48txx->tme_mk48txx_port_least_lane,
298: TME_BUS8_LOG2);
299: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
300: }
301:
302: /* if the time-of-day registers have been updated, and the clock
303: is running: */
304: if (mk48txx->tme_mk48txx_tod_update
305: && ((mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR]
306: & (TME_MK48TXX_CSR_READ
307: | TME_MK48TXX_CSR_WRITE)) == 0)) {
308:
309: /* XXX update the host's time-of-day clock? */
310: mk48txx->tme_mk48txx_tod_update = FALSE;
311: }
312:
313: /* unlock the mutex: */
314: tme_mutex_unlock(&mk48txx->tme_mk48txx_mutex);
315:
316: /* no faults: */
317: return (TME_OK);
318: }
319:
320: /* the mk48txx TLB filler: */
321: static int
322: _tme_mk48txx_tlb_fill(void *_mk48txx, struct tme_bus_tlb *tlb,
323: tme_bus_addr_t address, unsigned int cycles)
324: {
325: struct tme_mk48txx *mk48txx;
326: tme_bus_addr_t mk48txx_address_last;
327:
328: /* recover our data structure: */
329: mk48txx = (struct tme_mk48txx *) _mk48txx;
330:
331: /* the address must be within range: */
332: mk48txx_address_last = mk48txx->tme_mk48txx_device.tme_bus_device_address_last;
333: assert(address <= mk48txx_address_last);
334:
335: /* initialize the TLB entry: */
336: tme_bus_tlb_initialize(tlb);
337:
338: /* this TLB entry can cover the whole device: */
339: tlb->tme_bus_tlb_addr_first = 0;
340: tlb->tme_bus_tlb_addr_last = mk48txx_address_last;
341:
342: /* allow reading and writing: */
343: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
344:
345: /* our bus cycle handler: */
346: tlb->tme_bus_tlb_cycle_private = mk48txx;
347: tlb->tme_bus_tlb_cycle = _tme_mk48txx_bus_cycle;
348:
349: return (TME_OK);
350: }
351:
352: /* the new mk48txx element function: */
353: static int
354: _tme_mk48txx_new(struct tme_element *element,
355: const char * const *args,
356: const void *extra,
357: char **_output,
358: unsigned int part)
359: {
360: const struct tme_mk48txx_socket *socket;
361: struct tme_mk48txx *mk48txx;
362: struct tme_mk48txx_socket socket_real;
363: tme_bus_addr_t address_mask;
364: int arg_i;
365: int usage;
366:
367: /* dispatch on our socket version: */
368: socket = (const struct tme_mk48txx_socket *) extra;
369: if (socket == NULL) {
370: tme_output_append_error(_output, _("need an ic socket"));
371: return (ENXIO);
372: }
373: switch (socket->tme_mk48txx_socket_version) {
374: case TME_MK48TXX_SOCKET_0:
375: socket_real = *socket;
376: break;
377: default:
378: tme_output_append_error(_output, _("socket type"));
379: return (EOPNOTSUPP);
380: }
381:
382: /* check our arguments: */
383: usage = 0;
384: arg_i = 1;
385: for (;;) {
386:
387: if (0) {
388: }
389:
390: /* if we ran out of arguments: */
391: else if (args[arg_i] == NULL) {
392:
393: break;
394: }
395:
396: /* otherwise this is a bad argument: */
397: else {
398: tme_output_append_error(_output,
399: "%s %s, ",
400: args[arg_i],
401: _("unexpected"));
402: usage = TRUE;
403: break;
404: }
405: }
406:
407: if (usage) {
408: tme_output_append_error(_output,
409: "%s %s",
410: _("usage:"),
411: args[0]);
412: return (EINVAL);
413: }
414:
415: /* start the mk48txx structure: */
416: mk48txx = tme_new0(struct tme_mk48txx, 1);
417: tme_mutex_init(&mk48txx->tme_mk48txx_mutex);
418: mk48txx->tme_mk48txx_part = part;
419: mk48txx->tme_mk48txx_socket = socket_real;
420: mk48txx->tme_mk48txx_element = element;
421: _tme_mk48txx_reset(mk48txx);
422:
423: /* figure our address mask, up to the nearest power of two: */
424: address_mask = (TME_MK48TXX_REGS_COUNT - TME_MK48TXX_REG_FIRST(part)) << mk48txx->tme_mk48txx_addr_shift;
425: if (address_mask & (address_mask - 1)) {
426: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1));
427: address_mask <<= 1;
428: }
429: address_mask -= 1;
430:
431: /* initialize our simple bus device descriptor: */
432: mk48txx->tme_mk48txx_device.tme_bus_device_tlb_fill = _tme_mk48txx_tlb_fill;
433: mk48txx->tme_mk48txx_device.tme_bus_device_address_last = address_mask;
434:
435: /* fill the element: */
436: element->tme_element_private = mk48txx;
437: element->tme_element_connections_new = tme_bus_device_connections_new;
438:
439: return (TME_OK);
440: }
441:
442: TME_ELEMENT_X_NEW_DECL(tme_ic_,mk48txx,mk48t02) {
443: return (_tme_mk48txx_new(element, args, extra, _output, TME_MK48TXX_PART_02));
444: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.