Annotation of tme/ic/mk48txx.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.