Annotation of tme/generic/bus.c, revision 1.1

1.1     ! root        1: /* $Id: bus.c,v 1.3 2003/05/16 21:48:08 fredette Exp $ */
        !             2: 
        !             3: /* generic/gen-bus.c - generic bus support: */
        !             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>
        !            37: _TME_RCSID("$Id: bus.c,v 1.3 2003/05/16 21:48:08 fredette Exp $");
        !            38: 
        !            39: /* includes: */
        !            40: #include <tme/generic/bus.h>
        !            41: #include <stdlib.h>
        !            42: #include <string.h>
        !            43: 
        !            44: /* macros: */
        !            45: #define TME_BUS_LINE_RESET     (0)
        !            46: #define TME_BUS_LINE_HALT      (1)
        !            47: #define TME_BUS_LINE_INT       (2)
        !            48: 
        !            49: /* this does a binary search of the addressable connections: */
        !            50: int
        !            51: tme_bus_address_search(struct tme_bus *bus, tme_bus_addr_t address)
        !            52: {
        !            53:   int left, right, pivot;
        !            54:   struct tme_bus_connection_int *conn_int;
        !            55: 
        !            56:   /* initialize for the search: */
        !            57:   left = 0;
        !            58:   right = bus->tme_bus_addressables_count - 1;
        !            59:   
        !            60:   /* do the search: */
        !            61:   pivot = 0;
        !            62:   for (; left <= right; ) {
        !            63: 
        !            64:     /* get the pivot: */
        !            65:     pivot = (left + right) / 2;
        !            66:     conn_int = bus->tme_bus_addressables[pivot];
        !            67: 
        !            68:     /* if we have to move left: */
        !            69:     if (address < conn_int->tme_bus_connection_int_address) {
        !            70:       /* if we're done searching, pivot is already the index of the
        !            71:         first element we need to shift to the right in order to
        !            72:         insert a new element: */
        !            73:       right = pivot - 1;
        !            74:     }
        !            75: 
        !            76:     /* if we have to move right: */
        !            77:     else if (address > (conn_int->tme_bus_connection_int_address
        !            78:                        + conn_int->tme_bus_connection_int_address_last)) {
        !            79:       /* if we're done searching, pivot + 1 is the index of the
        !            80:         first element we need to shift to the right in order to
        !            81:         insert a new element: */
        !            82:       left = ++pivot;
        !            83:     }
        !            84: 
        !            85:     /* we found the addressable: */
        !            86:     else {
        !            87:       return (pivot);
        !            88:     }
        !            89:   }
        !            90: 
        !            91:   /* we failed to find an addressable that covers the address: */
        !            92:   return (-1 - pivot);
        !            93: }
        !            94: 
        !            95: /* this fills a TLB entry: */
        !            96: int
        !            97: tme_bus_tlb_fill(struct tme_bus *bus,
        !            98:                 struct tme_bus_connection_int *conn_int_asker,
        !            99:                 struct tme_bus_tlb *tlb,
        !           100:                 tme_bus_addr_t address, 
        !           101:                 unsigned int cycles)
        !           102: {
        !           103:   int pivot;
        !           104:   struct tme_bus_connection_int *conn_int;
        !           105:   struct tme_bus_connection *conn_bus_other;
        !           106:   tme_bus_addr_t sourced_address_mask, conn_address;
        !           107:   tme_bus_addr_t hole_first, hole_last;
        !           108:   struct tme_bus_tlb tlb_bus;
        !           109:   void *cycle_fault_private;
        !           110:   tme_bus_cycle_handler cycle_fault;
        !           111:   int rc;
        !           112: 
        !           113:   /* get the sourced address mask: */
        !           114:   sourced_address_mask = conn_int_asker->tme_bus_connection_int_sourced;
        !           115: 
        !           116:   /* search for this address on the bus: */
        !           117:   pivot = tme_bus_address_search(bus, sourced_address_mask | address);
        !           118: 
        !           119:   /* if this address doesn't exist: */
        !           120:   if (pivot < 0) {
        !           121: 
        !           122:     /* save the bus' fault cycle handler: */
        !           123:     cycle_fault_private = tlb->tme_bus_tlb_cycle_private;
        !           124:     cycle_fault = tlb->tme_bus_tlb_cycle;
        !           125: 
        !           126:     /* initialize the TLB entry: */
        !           127:     tme_bus_tlb_initialize(tlb);
        !           128: 
        !           129:     /* this TLB entry can cover the entire hole in the address space,
        !           130:        limited by the sourced address mask of this device: */
        !           131:     pivot = -1 - pivot;
        !           132:     hole_first = (pivot == 0
        !           133:                  ? 0
        !           134:                  : (bus->tme_bus_addressables[pivot - 1]->tme_bus_connection_int_address
        !           135:                     + bus->tme_bus_addressables[pivot - 1]->tme_bus_connection_int_address_last
        !           136:                     + 1));
        !           137:     hole_first = TME_MAX(hole_first, sourced_address_mask);
        !           138:     hole_last = (pivot == bus->tme_bus_addressables_count
        !           139:                 ? bus->tme_bus_address_mask
        !           140:                 : bus->tme_bus_addressables[pivot]->tme_bus_connection_int_address - 1);
        !           141:     hole_last = TME_MIN(hole_last,
        !           142:                        sourced_address_mask
        !           143:                        + conn_int_asker->tme_bus_connection_int_address_last);
        !           144:     TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, hole_first);
        !           145:     TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, hole_last);
        !           146: 
        !           147:     /* reads and writes are allowed: */
        !           148:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
        !           149: 
        !           150:     /* reads and writes in this region always fault: */
        !           151:     tlb->tme_bus_tlb_cycle_private = cycle_fault_private;
        !           152:     tlb->tme_bus_tlb_cycle = cycle_fault;
        !           153:     rc = TME_OK;
        !           154:   }
        !           155: 
        !           156:   /* otherwise, this address does exist: */
        !           157:   else {
        !           158:     conn_int = bus->tme_bus_addressables[pivot];
        !           159:     conn_bus_other = 
        !           160:       (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other;
        !           161: 
        !           162:     /* call the TLB fill function for the connection: */
        !           163:     conn_address = (sourced_address_mask | address) - conn_int->tme_bus_connection_int_address;
        !           164:     rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb,
        !           165:                                             conn_address, cycles);
        !           166: 
        !           167:     /* if that succeeded: */
        !           168:     if (rc == TME_OK) {
        !           169:       
        !           170:       /* create the mapping TLB entry: */
        !           171:       TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_first, 
        !           172:                       (conn_int->tme_bus_connection_int_address
        !           173:                        - sourced_address_mask));
        !           174:       TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_last, 
        !           175:                       (conn_int->tme_bus_connection_int_address
        !           176:                        + conn_int->tme_bus_connection_int_address_last
        !           177:                        - sourced_address_mask));
        !           178:       tlb_bus.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
        !           179:   
        !           180:       /* map the filled TLB entry: */
        !           181:       tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address);
        !           182:     }
        !           183:   }
        !           184: 
        !           185:   /* done: */
        !           186:   return (rc);
        !           187: }
        !           188: 
        !           189: /* this allocates a new TLB set: */
        !           190: int
        !           191: tme_bus_tlb_set_allocate(struct tme_bus *bus,
        !           192:                         struct tme_bus_connection_int *conn_int_asker,
        !           193:                         unsigned int count, unsigned int sizeof_one, 
        !           194:                         TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs)
        !           195: {
        !           196:   struct tme_bus_connection *conn_bus_other, *conn_bus_dma;
        !           197:   int conn_int_i;
        !           198:   int rc;
        !           199:   struct tme_bus_tlb *tlbs, *tlb;
        !           200:   unsigned int tlb_i;
        !           201: 
        !           202:   /* at most one of our addressable connections may provide a TLB set
        !           203:      allocator.  generally, this means that connection is
        !           204:      DMA-controller-like connection to the bus, where it may need to
        !           205:      invalidate at any later time the TLBs it fills out, due to sudden
        !           206:      changes in how the DMA region on the bus is mapped: */
        !           207:   conn_bus_dma = NULL;
        !           208:   for (conn_int_i = 0;
        !           209:        conn_int_i < bus->tme_bus_addressables_count;
        !           210:        conn_int_i++) {
        !           211:     conn_bus_other = 
        !           212:       (struct tme_bus_connection *) bus->tme_bus_addressables[conn_int_i]->tme_bus_connection_int.tme_bus_connection.tme_connection_other;
        !           213: 
        !           214:     /* if this bus connection offers a TLB set allocator, it is
        !           215:        a DMA-controller-like connection to the bus: */
        !           216:     if (conn_bus_other->tme_bus_tlb_set_allocate != NULL) {
        !           217: 
        !           218:       /* if there is more than one of these, it is likely a
        !           219:         configuration error.  if we had some way of specifying which
        !           220:         of several DMA regions a given connection will always use, we
        !           221:         could avoid this: */
        !           222:       if (conn_bus_dma != NULL) {
        !           223:        abort();
        !           224:       }
        !           225: 
        !           226:       conn_bus_dma = conn_bus_other;
        !           227:     }
        !           228:   }
        !           229: 
        !           230:   /* if there is a DMA-controller-like connection to the bus, 
        !           231:      let it allocate the TLB set: */
        !           232:   if (conn_bus_dma != NULL) {
        !           233:     rc = (*conn_bus_dma->tme_bus_tlb_set_allocate)
        !           234:       (conn_bus_dma, count, sizeof_one, _tlbs);
        !           235:   }
        !           236: 
        !           237:   /* otherwise, allocate and initialize a singleton set ourselves: */
        !           238:   else {
        !           239:     tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one);
        !           240:     tlb = tlbs;
        !           241:     for (tlb_i = 0; tlb_i < count; tlb_i++) {
        !           242:       tme_bus_tlb_invalidate(tlb);
        !           243:       tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one);
        !           244:     }
        !           245:     TME_ATOMIC_WRITE(struct tme_bus_tlb *, *_tlbs, tlbs);
        !           246:     rc = TME_OK;
        !           247:   }
        !           248:       
        !           249:   /* done: */
        !           250:   return (rc);
        !           251: }
        !           252: 
        !           253: /* this returns nonzero if the connection's address space is available: */
        !           254: int
        !           255: tme_bus_connection_ok(struct tme_bus *bus,
        !           256:                      struct tme_bus_connection_int *conn_int)
        !           257: {
        !           258:   int pivot_start, pivot_end;
        !           259: 
        !           260:   /* if this connection isn't addressable, it's always OK: */
        !           261:   if (!conn_int->tme_bus_connection_int_addressable) {
        !           262:     return (TRUE);
        !           263:   }
        !           264: 
        !           265:   /* the connection must fit on the bus: */
        !           266:   if (conn_int->tme_bus_connection_int_address_last >
        !           267:       (bus->tme_bus_address_mask
        !           268:        - conn_int->tme_bus_connection_int_address)) {
        !           269:     return (FALSE);
        !           270:   }
        !           271: 
        !           272:   /* search for anything covering the start or end of the new
        !           273:      addressable: */
        !           274:   pivot_start = 
        !           275:     tme_bus_address_search(bus, 
        !           276:                           conn_int->tme_bus_connection_int_address);
        !           277:   pivot_end =
        !           278:     tme_bus_address_search(bus,
        !           279:                           (conn_int->tme_bus_connection_int_address
        !           280:                            + conn_int->tme_bus_connection_int_address_last));
        !           281: 
        !           282:   /* both searches must have failed, and they must have stopped at the
        !           283:      same point in the sorted addressables, further indicating that no
        !           284:      addressable exists anywhere *between* the start and end of the
        !           285:      new addressable, either.  otherwise, this connection fails: */
        !           286:   if (pivot_start >= 0
        !           287:       || pivot_end >= 0
        !           288:       || pivot_start != pivot_end) {
        !           289:     return (FALSE);
        !           290:   }
        !           291: 
        !           292:   /* this connection's address space is available: */
        !           293:   return (TRUE);
        !           294: }
        !           295: 
        !           296: /* this makes a new connection: */
        !           297: int
        !           298: tme_bus_connection_make(struct tme_bus *bus,
        !           299:                        struct tme_bus_connection_int *conn_int,
        !           300:                        unsigned int state)
        !           301: {
        !           302:   int pivot;
        !           303: 
        !           304:   /* if this connection is not full, return now: */
        !           305:   if (state == TME_CONNECTION_HALF) {
        !           306:     return (TME_OK);
        !           307:   }
        !           308: 
        !           309:   /* add this connection to our list: */
        !           310:   conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_next
        !           311:     = (struct tme_connection *) bus->tme_bus_connections;
        !           312:   bus->tme_bus_connections = conn_int;
        !           313: 
        !           314:   /* if this connection is addressable, and this is connection is now
        !           315:      fully made, add it to our list of addressables: */
        !           316:   if (conn_int->tme_bus_connection_int_addressable
        !           317:       && state == TME_CONNECTION_FULL) {
        !           318:     
        !           319:     /* search for the place to insert this new addressable: */
        !           320:     pivot = tme_bus_address_search(bus, conn_int->tme_bus_connection_int_address);
        !           321:     assert(pivot < 0);
        !           322:     pivot = -1 - pivot;
        !           323:     
        !           324:     /* if we have to, grow the addressable array: */
        !           325:     if (bus->tme_bus_addressables_count
        !           326:        == bus->tme_bus_addressables_size) {
        !           327:       bus->tme_bus_addressables_size +=        (bus->tme_bus_addressables_size >> 1) + 1;
        !           328:       bus->tme_bus_addressables = tme_renew(struct tme_bus_connection_int *,
        !           329:                                            bus->tme_bus_addressables,
        !           330:                                            bus->tme_bus_addressables_size);
        !           331:     }
        !           332: 
        !           333:     /* move all of the later addressables down: */
        !           334:     memmove(&bus->tme_bus_addressables[pivot + 1],
        !           335:            &bus->tme_bus_addressables[pivot],
        !           336:            sizeof(bus->tme_bus_addressables[pivot])
        !           337:            * (bus->tme_bus_addressables_count
        !           338:               - pivot));
        !           339: 
        !           340:     /* insert this new addressable: */
        !           341:     bus->tme_bus_addressables[pivot] = conn_int;
        !           342:     bus->tme_bus_addressables_count++;
        !           343:   }
        !           344: 
        !           345:   return (TME_OK);
        !           346: }
        !           347: 
        !           348: /* this breaks a connection: */
        !           349: int
        !           350: tme_bus_connection_break(struct tme_bus *bus,
        !           351:                         struct tme_bus_connection_int *conn_int,
        !           352:                         unsigned int state)
        !           353: {
        !           354:   abort();
        !           355: }
        !           356: 
        !           357: /* this map the first bus TLB entry to be valid on another bus, according to
        !           358:    the information in the second bus TLB entry: */
        !           359: void
        !           360: tme_bus_tlb_map(struct tme_bus_tlb *tlb0, tme_bus_addr_t addr0, 
        !           361:                const struct tme_bus_tlb *tlb1, tme_bus_addr_t addr1)
        !           362: {
        !           363:   tme_bus_addr_t extra_before0, extra_after0;
        !           364:   tme_bus_addr_t extra_before1, extra_after1;
        !           365:   tme_bus_addr_t addr_offset;
        !           366:   unsigned int cycles_ok;
        !           367: 
        !           368:   /* get the address offset: */
        !           369:   addr_offset = addr1 - addr0;
        !           370: 
        !           371:   /* intersect the amount of bus address space covered: */
        !           372:   extra_before0 = addr0 - TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first);
        !           373:   extra_after0 = TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last) - addr0;
        !           374:   extra_before1 = addr1 - TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_first);
        !           375:   extra_after1 = TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_last) - addr1;
        !           376:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first, 
        !           377:                   addr1 - TME_MIN(extra_before0, extra_before1));
        !           378:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last, 
        !           379:                   addr1 + TME_MIN(extra_after0, extra_after1));
        !           380: 
        !           381:   /* intersect the kinds of bus cycles allowed: */
        !           382:   cycles_ok = (tlb0->tme_bus_tlb_cycles_ok &= tlb1->tme_bus_tlb_cycles_ok);
        !           383:   if (!(cycles_ok & TME_BUS_CYCLE_READ)) {
        !           384:     tlb0->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
        !           385:   }
        !           386:   else if (tlb0->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) {
        !           387:     tlb0->tme_bus_tlb_emulator_off_read -= addr_offset;
        !           388:   }
        !           389:   if (!(cycles_ok & TME_BUS_CYCLE_WRITE)) {
        !           390:     tlb0->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
        !           391:   }
        !           392:   else if (tlb0->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
        !           393:     tlb0->tme_bus_tlb_emulator_off_write -= addr_offset;
        !           394:   }
        !           395: 
        !           396:   /* update the address shift for the cycle handler: */
        !           397:   tlb0->tme_bus_tlb_addr_offset -= addr_offset;
        !           398: }
        !           399: 
        !           400: /* this invalidates a bus TLB entry: */
        !           401: void
        !           402: tme_bus_tlb_invalidate(struct tme_bus_tlb *tlb)
        !           403: {
        !           404:   
        !           405:   /* make the first address covered all-bits-one.  the only bus TLB
        !           406:      entries this will not invalidate are those that have a last
        !           407:      address covered of all-bits one: */
        !           408:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1);
        !           409:   
        !           410:   /* make the last address covered all-bits-zero.  this will
        !           411:      invalidate the TLB entries we didn't catch above: */
        !           412:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0);
        !           413: }
        !           414: 
        !           415: /* this initializes a bus TLB entry: */
        !           416: void
        !           417: tme_bus_tlb_initialize(struct tme_bus_tlb *tlb)
        !           418: {
        !           419:   
        !           420:   /* make the first address covered all-bits-one: */
        !           421:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1);
        !           422:   
        !           423:   /* make the last address covered all-bits-zero: */
        !           424:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0);
        !           425: 
        !           426:   /* no fast (memory) transfers allowed: */
        !           427:   tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
        !           428:   tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
        !           429:   tlb->tme_bus_tlb_rwlock = NULL;
        !           430: 
        !           431:   /* no bus cycles allowed: */
        !           432:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_UNDEF;
        !           433: 
        !           434:   /* no address offset or shift: */
        !           435:   tlb->tme_bus_tlb_addr_offset = 0;
        !           436:   tlb->tme_bus_tlb_addr_shift = 0;
        !           437: 
        !           438:   /* no bus cycle handler: */
        !           439:   tlb->tme_bus_tlb_cycle_private = NULL;
        !           440:   tlb->tme_bus_tlb_cycle = NULL;
        !           441: 
        !           442:   /* no bus fault handlers: */
        !           443:   tlb->tme_bus_tlb_fault_handler_count = 0;
        !           444: }
        !           445: 
        !           446: /* this calls a TLB entry's fault handlers: */
        !           447: int
        !           448: tme_bus_tlb_fault(struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
        !           449: {
        !           450:   unsigned int i;
        !           451: 
        !           452:   /* call all of the fault handlers: */
        !           453:   for (i = 0; i < tlb->tme_bus_tlb_fault_handler_count; i++) {
        !           454:     rc = ((*tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler)
        !           455:          (tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler_private,
        !           456:           tlb, cycle, rc));
        !           457:   }
        !           458: 
        !           459:   return (rc);
        !           460: }
        !           461: 
        !           462: /* this parses any bus address: */
        !           463: tme_bus_addr_t
        !           464: tme_bus_addr_parse_any(const char *address_string, int *_failed)
        !           465: {
        !           466:   unsigned long address;
        !           467:   char *units;
        !           468: 
        !           469:   /* catch a NULL string: */
        !           470:   if (address_string == NULL) {
        !           471:     *_failed = TRUE;
        !           472:     return (0);
        !           473:   }
        !           474: 
        !           475:   /* assume we will succeed: */
        !           476:   *_failed = FALSE;
        !           477: 
        !           478:   /* convert the string: */
        !           479:   address = strtoul(address_string, &units, 0);
        !           480:   if (units == address_string) {
        !           481:     *_failed = TRUE;
        !           482:     return (0);
        !           483:   }
        !           484: 
        !           485:   /* handle any units: */
        !           486:   if (!strcmp(units, "GB")
        !           487:       || !strcasecmp(units, "G")) {
        !           488:     return (((tme_bus_addr_t) address) * 1024 * 1024 * 1024);
        !           489:   }
        !           490:   else if (!strcmp(units, "MB")
        !           491:       || !strcasecmp(units, "M")) {
        !           492:     return (((tme_bus_addr_t) address) * 1024 * 1024);
        !           493:   }
        !           494:   else if (!strcmp(units, "KB")
        !           495:           || !strcasecmp(units, "k")) {
        !           496:     return (((tme_bus_addr_t) address) * 1024);
        !           497:   }
        !           498:   else if (*units == '\0') {
        !           499:     return ((tme_bus_addr_t) address);
        !           500:   }
        !           501:   *_failed = TRUE;
        !           502:   return (0);
        !           503: }
        !           504: 
        !           505: /* this parses a bus address that has a restricted range: */
        !           506: tme_bus_addr_t
        !           507: tme_bus_addr_parse(const char *address_string, tme_bus_addr_t failure_value)
        !           508: {
        !           509:   int failed;
        !           510:   tme_bus_addr_t address;
        !           511:   address = tme_bus_addr_parse_any(address_string, &failed);
        !           512:   return (failed ? failure_value : address);
        !           513: }
        !           514: 
        !           515: /* this transfers bytes between the two participants in a bus cycle: */
        !           516: void
        !           517: tme_bus_cycle_xfer(struct tme_bus_cycle *cycle_init, struct tme_bus_cycle *cycle_resp)
        !           518: {
        !           519:   struct tme_bus_cycle *cycle_reader, *cycle_writer;
        !           520:   int buffer_increment_mask_reader, buffer_increment_mask_writer;
        !           521:   int port_size_reader, port_size_writer;
        !           522:   int port_overlap_lane_least, port_overlap_size, port_overlap_size_lg2;
        !           523:   int lane, lane_end;
        !           524:   int lane_reader, lane_writer;
        !           525:   int lane_in_reader, lane_in_writer;
        !           526:   int lane_routing_offset_reader, lane_routing_offset_writer;
        !           527:   tme_bus_lane_t lane_routing_reader, lane_routing_writer;
        !           528:   tme_uint8_t lane_value;
        !           529:   int warn_on_lane;
        !           530:   unsigned int cycle_size_reader, cycle_size_writer;
        !           531: 
        !           532:   /* sort the initiator and responder into bus reader and bus writer: */
        !           533:   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
        !           534:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
        !           535:     cycle_reader = cycle_init;
        !           536:     cycle_writer = cycle_resp;
        !           537:   }
        !           538:   else {
        !           539:     assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
        !           540:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
        !           541:     cycle_reader = cycle_resp;
        !           542:     cycle_writer = cycle_init;
        !           543:   }
        !           544: 
        !           545:   /* get the increment masks for the reader and writer.  since
        !           546:      tme_bus_cycle_buffer_increment is always 1 or -1, this mask is
        !           547:      used to negate values without multiplication: */
        !           548:   if (cycle_reader->tme_bus_cycle_buffer_increment == -1) {
        !           549:     buffer_increment_mask_reader = -1;
        !           550:   }
        !           551:   else {
        !           552:     assert(cycle_reader->tme_bus_cycle_buffer_increment == 1);
        !           553:     buffer_increment_mask_reader = 0;
        !           554:   }
        !           555:   if (cycle_writer->tme_bus_cycle_buffer_increment == -1) {
        !           556:     buffer_increment_mask_writer = -1;
        !           557:   }
        !           558:   else {
        !           559:     assert(cycle_writer->tme_bus_cycle_buffer_increment == 1);
        !           560:     buffer_increment_mask_writer = 0;
        !           561:   }
        !           562: #define _TME_BUS_CYCLE_BUFFER_MULTIPLY(value, mask) \
        !           563:   (((value) ^ (mask)) + ((mask) & 1))
        !           564: 
        !           565:   /* get the sizes, in bytes, of the reader and writer ports: */
        !           566:   port_size_reader = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port));
        !           567:   port_size_writer = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port));
        !           568: 
        !           569:   /* determine how the writer's port and the reader's port overlap: */
        !           570:   port_overlap_size = port_size_writer;
        !           571:   port_overlap_lane_least = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
        !           572:   lane = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
        !           573:   if (port_overlap_lane_least < lane) {
        !           574:     port_overlap_size -= (lane - port_overlap_lane_least);
        !           575:     port_overlap_lane_least = lane;
        !           576:   }
        !           577:   lane += port_size_reader;
        !           578:   if ((port_overlap_lane_least + port_overlap_size) > lane) {
        !           579:     port_overlap_size -= (lane - (port_overlap_lane_least + port_overlap_size));
        !           580:   }
        !           581:   assert(port_overlap_size > 0);
        !           582:   for (port_overlap_size_lg2 = 0;
        !           583:        (port_overlap_size >>= 1) != 0;
        !           584:        port_overlap_size_lg2++);
        !           585: 
        !           586:   /* select the reader's lane routing: */
        !           587:   lane_routing_offset_reader =
        !           588:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port),
        !           589:                         port_overlap_size_lg2,
        !           590:                         port_overlap_lane_least
        !           591:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port));
        !           592: 
        !           593:   /* select the writer's lane routing: */
        !           594:   lane_routing_offset_writer =
        !           595:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port),
        !           596:                         port_overlap_size_lg2,
        !           597:                         port_overlap_lane_least
        !           598:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
        !           599: 
        !           600:   /* loop over all byte lanes in one or both ports: */
        !           601:   lane = TME_MIN(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port),
        !           602:                 TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
        !           603:   lane_end = TME_MAX(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port) + port_size_reader,
        !           604:                     TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port) + port_size_writer);
        !           605:   cycle_size_reader = cycle_size_writer = 0;
        !           606:   for (; lane < lane_end; lane++) {
        !           607: 
        !           608:     /* assume that we won't have to warn on this lane: */
        !           609:     warn_on_lane = FALSE;
        !           610: 
        !           611:     /* see if this lane falls in the reader or writer's port: */
        !           612:     lane_reader = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
        !           613:     lane_writer = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
        !           614:     lane_in_reader = (lane_reader >= 0 && lane_reader < port_size_reader);
        !           615:     lane_in_writer = (lane_writer >= 0 && lane_writer < port_size_writer);
        !           616: 
        !           617:     /* get the value being written to this byte lane.  assume a
        !           618:        garbage value: */
        !           619:     lane_value = 0xd2;
        !           620: 
        !           621:     /* if this lane is in the writer's port, it may supply a real
        !           622:        lane value: */
        !           623:     if (lane_in_writer) {
        !           624: 
        !           625:       /* get the routing for the writer: */
        !           626:       lane_routing_writer = 
        !           627:        cycle_writer->tme_bus_cycle_lane_routing[lane_routing_offset_writer + lane_writer];
        !           628: 
        !           629:       /* if the writer doesn't expect this lane to be connected to the
        !           630:         reader, we will issue a warning on this lane: */
        !           631:       if ((lane_routing_writer & TME_BUS_LANE_WARN)
        !           632:          && lane_in_reader) {
        !           633:        warn_on_lane = TRUE;
        !           634:       }
        !           635:       lane_routing_writer &= ~TME_BUS_LANE_WARN;
        !           636: 
        !           637:       /* dispatch on the routing to get the lane value: */
        !           638:       if (lane_routing_writer == TME_BUS_LANE_ABORT) {
        !           639:        abort();
        !           640:       }
        !           641:       else if (lane_routing_writer != TME_BUS_LANE_UNDEF) {
        !           642:        if (!(lane_routing_writer & TME_BUS_LANE_ROUTE_WRITE_IGNORE)
        !           643:            && lane_routing_writer >= cycle_size_writer) {
        !           644:          cycle_size_writer = lane_routing_writer + 1;
        !           645:        }
        !           646:        lane_routing_writer &= ~TME_BUS_LANE_ROUTE_WRITE_IGNORE;
        !           647: 
        !           648:        /* if the writer is the responder, make sure that only bytes
        !           649:           in the given register are ever referenced.  given the
        !           650:           writer's port size, we could warp the reference index as
        !           651:           needed, but hopefully we'll never have to: */
        !           652:        assert(!(cycle_writer == cycle_resp
        !           653:                 && (((cycle_writer->tme_bus_cycle_address + lane_routing_writer)
        !           654:                      ^  cycle_writer->tme_bus_cycle_address)
        !           655:                     & ~(port_size_writer - 1)) != 0));
        !           656: 
        !           657:        lane_value =
        !           658:          *(cycle_writer->tme_bus_cycle_buffer
        !           659:            + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_writer,
        !           660:                                             buffer_increment_mask_writer));
        !           661:       }
        !           662:     }
        !           663: 
        !           664:     /* if this lane is in the reader's port, it may take the lane
        !           665:        value: */
        !           666:     if (lane_in_reader) {
        !           667: 
        !           668:       /* get the routing for the reader: */
        !           669:       lane_routing_reader =
        !           670:        cycle_reader->tme_bus_cycle_lane_routing[lane_routing_offset_reader + lane_reader];
        !           671: 
        !           672:       /* if the reader doesn't expect this lane to be connected to the
        !           673:         writer, we will issue a warning on this lane: */
        !           674:       if ((lane_routing_reader & TME_BUS_LANE_WARN)
        !           675:          && lane_in_writer) {
        !           676:        warn_on_lane = TRUE;
        !           677:       }
        !           678:       lane_routing_reader &= ~TME_BUS_LANE_WARN;
        !           679: 
        !           680:       /* dispatch on the routing to take the lane value: */
        !           681:       if (lane_routing_reader == TME_BUS_LANE_ABORT) {
        !           682:        abort();
        !           683:       }
        !           684:       else if (lane_routing_reader != TME_BUS_LANE_UNDEF
        !           685:               && !(lane_routing_reader & TME_BUS_LANE_ROUTE_WRITE_IGNORE)) {
        !           686:        if (lane_routing_reader >= cycle_size_reader) {
        !           687:          cycle_size_reader = lane_routing_reader + 1;
        !           688:        }
        !           689: 
        !           690:        /* if the reader is the responder, make sure that only bytes
        !           691:           in the given register are ever referenced.  given the
        !           692:           reader's port size, we could warp the reference index as
        !           693:           needed, but hopefully we'll never have to: */
        !           694:        assert(!(cycle_reader == cycle_resp
        !           695:                 && (((cycle_reader->tme_bus_cycle_address + lane_routing_reader)
        !           696:                      ^  cycle_reader->tme_bus_cycle_address)
        !           697:                     & ~(port_size_reader - 1)) != 0));
        !           698: 
        !           699:        *(cycle_reader->tme_bus_cycle_buffer
        !           700:          + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_reader,
        !           701:                                           buffer_increment_mask_reader)) =
        !           702:          lane_value;
        !           703:       }
        !           704:     }
        !           705: 
        !           706:     /* if we need to issue a warning on this lane: */
        !           707:     if (warn_on_lane) {
        !           708:       /* XXX TBD: */
        !           709:       abort();
        !           710:     }
        !           711:   }
        !           712: 
        !           713:   /* give the reader feedback: */
        !           714:   cycle_reader->tme_bus_cycle_size = cycle_size_reader;
        !           715:   cycle_reader->tme_bus_cycle_address += cycle_size_reader;
        !           716:   cycle_reader->tme_bus_cycle_buffer += 
        !           717:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_reader,
        !           718:                                   buffer_increment_mask_reader);
        !           719:   cycle_reader->tme_bus_cycle_lane_routing += lane_routing_offset_reader;
        !           720:   cycle_reader->tme_bus_cycle_port = 
        !           721:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
        !           722:   
        !           723:   /* give the writer feedback: */
        !           724:   cycle_writer->tme_bus_cycle_size = cycle_size_writer;
        !           725:   cycle_writer->tme_bus_cycle_address += cycle_size_writer;
        !           726:   cycle_writer->tme_bus_cycle_buffer += 
        !           727:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_writer,
        !           728:                                   buffer_increment_mask_writer);
        !           729:   cycle_writer->tme_bus_cycle_lane_routing += lane_routing_offset_writer;
        !           730:   cycle_writer->tme_bus_cycle_port = 
        !           731:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
        !           732: }
        !           733: 
        !           734: /* this handles a bus cycle for a memory-like device: */
        !           735: void
        !           736: tme_bus_cycle_xfer_memory(struct tme_bus_cycle *cycle_init, tme_uint8_t *memory, tme_bus_addr_t address_last)
        !           737: {
        !           738:   tme_uint8_t memory_junk[sizeof(tme_bus_addr_t)];
        !           739:   struct tme_bus_cycle cycle_resp;
        !           740: 
        !           741:   /* check the starting address: */
        !           742:   assert(cycle_init->tme_bus_cycle_address <= address_last);
        !           743: 
        !           744:   /* get the start of the buffer for this starting address: */
        !           745:   if (memory != NULL) {
        !           746:     memory += cycle_init->tme_bus_cycle_address;
        !           747:   }
        !           748:   else {
        !           749:     assert(sizeof(memory_junk)
        !           750:           >= (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port)));
        !           751:     memory = memory_junk;
        !           752:   }
        !           753: 
        !           754:   /* create the responder cycle: */
        !           755:   cycle_resp.tme_bus_cycle_buffer = memory;
        !           756:   cycle_resp.tme_bus_cycle_buffer_increment = 1;
        !           757:   cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing;
        !           758:   cycle_resp.tme_bus_cycle_address = cycle_init->tme_bus_cycle_address;
        !           759:   cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type
        !           760:                                   ^ (TME_BUS_CYCLE_WRITE
        !           761:                                      | TME_BUS_CYCLE_READ));
        !           762:   cycle_resp.tme_bus_cycle_port = cycle_init->tme_bus_cycle_port;
        !           763: 
        !           764:   /* run the cycle: */
        !           765:   tme_bus_cycle_xfer(cycle_init, &cycle_resp);
        !           766: 
        !           767:   /* check the finishing address: */
        !           768:   assert((cycle_init->tme_bus_cycle_address - 1) <= address_last);
        !           769: }
        !           770:   

unix.superglobalmegacorp.com

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