Annotation of tme/ic/mm58167.c, revision 1.1.1.4

1.1.1.4 ! root        1: /* $Id: mm58167.c,v 1.8 2009/08/29 21:22:47 fredette Exp $ */
1.1       root        2: 
1.1.1.2   root        3: /* ic/mm58167.c - implementation of National Semiconductor MM58167 emulation: */
1.1       root        4: 
                      5: /*
                      6:  * Copyright (c) 2003 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>
1.1.1.4 ! root       37: _TME_RCSID("$Id: mm58167.c,v 1.8 2009/08/29 21:22:47 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/generic/bus-device.h>
                     41: #include <tme/ic/mm58167.h>
                     42: #include <time.h>
1.1.1.2   root       43: #include <sys/time.h>
1.1       root       44: 
                     45: /* macros: */
                     46: 
                     47: /* register addresses: */
                     48: #define TME_MM58167_REG_MSEC_XXX       (0)
                     49: #define TME_MM58167_REG_CSEC           (1)
                     50: #define TME_MM58167_REG_SEC            (2)
                     51: #define TME_MM58167_REG_MIN            (3)
                     52: #define TME_MM58167_REG_HOUR           (4)
                     53: #define TME_MM58167_REG_WDAY           (5)
                     54: #define TME_MM58167_REG_DAY            (6)
                     55: #define TME_MM58167_REG_MON            (7)
                     56: #define TME_MM58167_REG_STATUS         (20)
                     57: #define TME_MM58167_REG_GO             (21)
                     58: #define TME_MM58167_REG_BANK_SZ                (24)
                     59: 
                     60: /* bits in the status register: */
                     61: #define TME_MM58167_STATUS_RIPPLING    TME_BIT(0)      
                     62: 
                     63: #define TME_MM58167_LOG_HANDLE(mm) (&(mm)->tme_mm58167_element->tme_element_log_handle)
                     64: 
                     65: /* structures: */
                     66: 
                     67: struct tme_mm58167 {
                     68: 
                     69:   /* our simple bus device header: */
                     70:   struct tme_bus_device tme_mm58167_device;
                     71: #define tme_mm58167_element tme_mm58167_device.tme_bus_device_element
                     72: 
                     73:   /* our socket: */
                     74:   struct tme_mm58167_socket tme_mm58167_socket;
                     75: #define tme_mm58167_addr_shift tme_mm58167_socket.tme_mm58167_socket_addr_shift
                     76: #define tme_mm58167_port_least_lane tme_mm58167_socket.tme_mm58167_socket_port_least_lane
                     77: 
                     78:   /* the mutex protecting the chip: */
                     79:   tme_mutex_t tme_mm58167_mutex;
                     80: 
1.1.1.2   root       81:   /* the last time sampled.  the tv_usec field is actually a value in
                     82:      milliseconds, since we divide it by 1000 right after
                     83:      gettimeofday() returns: */
                     84:   struct timeval tme_mm58167_sampled_time;
1.1       root       85: 
                     86:   /* the struct tm for the last time sampled: */
                     87:   struct tm tme_mm58167_sampled_tm;
                     88: 
                     89:   /* the status register: */
                     90:   tme_uint8_t tme_mm58167_status;
                     91: };
                     92: 
                     93: /* the mm58167 bus router: */
                     94: static const tme_bus_lane_t tme_mm58167_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = {
                     95:   
                     96:   /* [gen]  initiator port size: 8 bits
                     97:      [gen]  initiator port least lane: 0: */
                     98:   /* D7-D0 */  TME_BUS_LANE_ROUTE(0),
                     99: };
                    100: 
                    101: /* the mm58167 bus cycle handler: */
                    102: static int
                    103: _tme_mm58167_bus_cycle(void *_mm58167, struct tme_bus_cycle *cycle_init)
                    104: {
                    105:   struct tme_mm58167 *mm58167;
1.1.1.4 ! root      106:   tme_bus_addr32_t address, mm58167_address_last;
1.1       root      107:   tme_uint8_t buffer, value;
                    108:   struct tme_bus_cycle cycle_resp;
                    109:   unsigned int reg;
1.1.1.2   root      110:   struct timeval now;
                    111:   time_t _now;
1.1       root      112:   struct tm *now_tm;
                    113:   int reg_is_bcd;
                    114: 
                    115:   /* recover our data structure: */
                    116:   mm58167 = (struct tme_mm58167 *) _mm58167;
                    117: 
                    118:   /* the requested cycle must be within range: */
                    119:   mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last;
                    120:   assert(cycle_init->tme_bus_cycle_address <= mm58167_address_last);
                    121:   assert(cycle_init->tme_bus_cycle_size <= (mm58167_address_last - cycle_init->tme_bus_cycle_address) + 1);
                    122: 
                    123:   /* get the register being accessed: */
                    124:   address = cycle_init->tme_bus_cycle_address;
                    125:   reg = address >> mm58167->tme_mm58167_addr_shift;
                    126:   reg_is_bcd = (reg <= TME_MM58167_REG_MON);
                    127: 
                    128:   /* lock the mutex: */
                    129:   tme_mutex_lock(&mm58167->tme_mm58167_mutex);
                    130: 
1.1.1.2   root      131:   /* sample the time, and drop from microsecond accuracy to
                    132:      millisecond accuracy: */
                    133:   gettimeofday(&now, NULL);
                    134:   now.tv_usec /= 1000;
                    135: 
                    136:   /* if the seconds value has changed, convert it, and an update is
                    137:      rippling through the system: */
                    138:   if (now.tv_sec
                    139:       != mm58167->tme_mm58167_sampled_time.tv_sec) {
1.1       root      140:     mm58167->tme_mm58167_status |= TME_MM58167_STATUS_RIPPLING;
1.1.1.2   root      141:     _now = now.tv_sec;
                    142:     now_tm = gmtime_r(&_now, &mm58167->tme_mm58167_sampled_tm);
1.1       root      143:     if (now_tm != &mm58167->tme_mm58167_sampled_tm) {
                    144:       mm58167->tme_mm58167_sampled_tm = *now_tm;
                    145:     }
                    146:   }
                    147: 
1.1.1.2   root      148:   /* otherwise, if the centiseconds value has changed, an update
                    149:      is also rippling through the system: */
                    150:   else if ((now.tv_usec / 10)
                    151:           != (mm58167->tme_mm58167_sampled_time.tv_usec / 10)) {
                    152:     mm58167->tme_mm58167_status |= TME_MM58167_STATUS_RIPPLING;
                    153:   }
                    154: 
                    155:   /* save the sampled time: */
                    156:   mm58167->tme_mm58167_sampled_time = now;
                    157: 
                    158:   /* get the converted time: */
                    159:   now_tm = &mm58167->tme_mm58167_sampled_tm;
                    160:     
1.1       root      161:   /* if this is a write: */
                    162:   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
                    163: 
                    164:     /* run the bus cycle: */
                    165:     cycle_resp.tme_bus_cycle_buffer = &buffer;
                    166:     cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router;
                    167:     cycle_resp.tme_bus_cycle_address = 0;
                    168:     cycle_resp.tme_bus_cycle_buffer_increment = 1;
                    169:     cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ;
                    170:     cycle_resp.tme_bus_cycle_size = sizeof(buffer);
                    171:     cycle_resp.tme_bus_cycle_port = 
                    172:       TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane,
                    173:                         TME_BUS8_LOG2);
                    174:     tme_bus_cycle_xfer(cycle_init, &cycle_resp);
                    175:     value = buffer;
                    176:     
                    177:     /* log this write: */
                    178:     tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK,
                    179:            (TME_MM58167_LOG_HANDLE(mm58167),
                    180:             "reg %d write %02x",
                    181:             reg, value));
                    182: 
                    183:     /* otherwise, ignore writes for now: */
                    184:   }
                    185: 
                    186: 
                    187:   /* otherwise, this is a read: */
                    188:   else {
                    189:     assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
                    190:     
                    191:     /* dispatch on the register: */
                    192:     switch (reg) {
                    193:     case TME_MM58167_REG_MSEC_XXX:
1.1.1.2   root      194:       value = (now.tv_usec % 10) * 10;
                    195:       break;
1.1       root      196:     case TME_MM58167_REG_CSEC:
1.1.1.2   root      197:       value = (now.tv_usec / 10);
1.1       root      198:       break;
                    199:     case TME_MM58167_REG_SEC:
                    200:       value = now_tm->tm_sec;
                    201:       break;
                    202:     case TME_MM58167_REG_MIN:
                    203:       value = now_tm->tm_min;
                    204:       break;
                    205:     case TME_MM58167_REG_HOUR:
                    206:       value = now_tm->tm_hour;
                    207:       break;
                    208:     case TME_MM58167_REG_WDAY:
                    209:       value = now_tm->tm_wday;
                    210:       break;
                    211:     case TME_MM58167_REG_DAY:
                    212:       value = now_tm->tm_mday;
                    213:       break;
                    214:     case TME_MM58167_REG_MON:
                    215:       value = now_tm->tm_mon + 1;
                    216:       break;
                    217:     case TME_MM58167_REG_STATUS:
                    218:       value = mm58167->tme_mm58167_status;
                    219:       mm58167->tme_mm58167_status = 0;
                    220:       break;
                    221:     default:
                    222:       abort();
                    223:     }
                    224: 
                    225:     /* if needed, convert this value to BCD: */
                    226:     if (reg_is_bcd) {
                    227:       value = (value % 10) + ((value / 10) << 4);
                    228:     }
                    229: 
                    230:     /* log this read: */
                    231:     tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK,
                    232:            (TME_MM58167_LOG_HANDLE(mm58167),
                    233:             "reg %d read %02x",
                    234:             reg, value));
                    235: 
                    236:     /* run the bus cycle: */
                    237:     buffer = value;
                    238:     cycle_resp.tme_bus_cycle_buffer = &buffer;
                    239:     cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router;
                    240:     cycle_resp.tme_bus_cycle_address = 0;
                    241:     cycle_resp.tme_bus_cycle_buffer_increment = 1;
                    242:     cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE;
                    243:     cycle_resp.tme_bus_cycle_size = sizeof(buffer);
                    244:     cycle_resp.tme_bus_cycle_port = 
                    245:       TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane,
                    246:                         TME_BUS8_LOG2);
                    247:     tme_bus_cycle_xfer(cycle_init, &cycle_resp);
                    248:   }
                    249:     
                    250:   /* unlock the mutex: */
                    251:   tme_mutex_unlock(&mm58167->tme_mm58167_mutex);
                    252: 
                    253:   /* no faults: */
                    254:   return (TME_OK);
                    255: }
                    256: 
                    257: /* the mm58167 TLB filler: */
                    258: static int
                    259: _tme_mm58167_tlb_fill(void *_mm58167, struct tme_bus_tlb *tlb, 
                    260:                     tme_bus_addr_t address, unsigned int cycles)
                    261: {
                    262:   struct tme_mm58167 *mm58167;
1.1.1.4 ! root      263:   tme_bus_addr32_t mm58167_address_last;
1.1       root      264: 
                    265:   /* recover our data structure: */
                    266:   mm58167 = (struct tme_mm58167 *) _mm58167;
                    267: 
                    268:   /* the address must be within range: */
                    269:   mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last;
                    270:   assert(address <= mm58167_address_last);
                    271: 
                    272:   /* initialize the TLB entry: */
                    273:   tme_bus_tlb_initialize(tlb);
                    274: 
                    275:   /* this TLB entry can cover the whole device: */
1.1.1.3   root      276:   tlb->tme_bus_tlb_addr_first = 0;
                    277:   tlb->tme_bus_tlb_addr_last = mm58167_address_last;
1.1       root      278: 
                    279:   /* allow reading and writing: */
                    280:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    281: 
                    282:   /* our bus cycle handler: */
                    283:   tlb->tme_bus_tlb_cycle_private = mm58167;
                    284:   tlb->tme_bus_tlb_cycle = _tme_mm58167_bus_cycle;
                    285: 
                    286:   return (TME_OK);
                    287: }
                    288: 
                    289: /* the new mm58167 function: */
                    290: TME_ELEMENT_NEW_DECL(tme_ic_mm58167) {
                    291:   const struct tme_mm58167_socket *socket;
                    292:   struct tme_mm58167 *mm58167;
                    293:   struct tme_mm58167_socket socket_real;
                    294:   tme_bus_addr_t address_mask;
                    295: 
                    296:   /* dispatch on our socket version: */
                    297:   socket = (const struct tme_mm58167_socket *) extra;
                    298:   if (socket == NULL) {
                    299:     tme_output_append_error(_output, _("need an ic socket"));
                    300:     return (ENXIO);
                    301:   }
                    302:   switch (socket->tme_mm58167_socket_version) {
                    303:   case TME_MM58167_SOCKET_0:
                    304:     socket_real = *socket;
                    305:     break;
                    306:   default: 
                    307:     tme_output_append_error(_output, _("socket type"));
                    308:     return (EOPNOTSUPP);
                    309:   }
                    310:     
                    311:   /* we take no arguments: */
                    312:   if (args[1] != NULL) {
                    313:     tme_output_append_error(_output,
                    314:                            "%s %s, %s %s",
                    315:                            args[1],
                    316:                            _("unexpected"),
                    317:                            _("usage:"),
                    318:                            args[0]);
                    319:     return (EINVAL);
                    320:   }
                    321: 
                    322:   /* start the mm58167 structure: */
                    323:   mm58167 = tme_new0(struct tme_mm58167, 1);
                    324:   tme_mutex_init(&mm58167->tme_mm58167_mutex);
                    325:   mm58167->tme_mm58167_socket = socket_real;
                    326: 
                    327:   /* figure our address mask, up to the nearest power of two: */
1.1.1.2   root      328:   address_mask = TME_MM58167_REG_BANK_SZ << mm58167->tme_mm58167_addr_shift;
1.1       root      329:   if (address_mask & (address_mask - 1)) {
                    330:     for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1));
                    331:     address_mask <<= 1;
                    332:   }
                    333:   address_mask -= 1;
                    334: 
                    335:   /* initialize our simple bus device descriptor: */
                    336:   mm58167->tme_mm58167_device.tme_bus_device_element = element;
                    337:   mm58167->tme_mm58167_device.tme_bus_device_tlb_fill = _tme_mm58167_tlb_fill;
                    338:   mm58167->tme_mm58167_device.tme_bus_device_address_last = address_mask;
                    339: 
                    340:   /* fill the element: */
                    341:   element->tme_element_private = mm58167;
                    342:   element->tme_element_connections_new = tme_bus_device_connections_new;
                    343: 
                    344:   return (TME_OK);
                    345: }

unix.superglobalmegacorp.com

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