|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.