|
||||||||||||||||||||||||||||||||||||||||
May 22, 1997 Shattering the programmable-logic speed barrier BRIAN DIPERT, TECHNICAL EDITORUpfront planning and careful design, plus an awareness of architecture and development-tool strengths and shortcomings, ensure that you squeeze maximum performance out of your programmable-logic device. Read almost any magazine article written on programmable logic in the last several years, and you immediately sense the battle cry of the industry: "We're going after gate-array ASICs!" Today, this once-quixotic prediction is increasingly becoming reality. Ever-smaller process lithographies improve programmable-logic cost-effectiveness, resulting in die sizes comparable to gate-array counterparts, even at gate densities of several tens of thousands. Ironically, these same lithography trends also enable gate arrays to squeeze more logic onto a die and more die onto a wafer. However, lithography shrinks are pushing ASIC cost-effective gate counts, minimum-order quantities, and leadtimes beyond the needs of a growing number of designs, creating opportunities for programmable-logic alternatives in the process. Finally, more and more companies are growing to depend on programmable logic's flexibility, which provides them with the fastest possible time to market for their products. However, programmable logic currently doesn't come close to matching gate arrays and other ASIC technologies in one area: performance. Thanks to aggressive lithographies, direct metal-to-metal interconnections, and abundant signal-routing resources, ASICs' logic gate delays are measured in tens of picoseconds, with input-to-output delays for even complex multilevel logic paths only a few nanoseconds. Delays for comparably sized programmable-logic counterparts are easily an order of magnitude longer. In the past, you could make an effective argument that most designs didn't use the performance potential that ASICs provided. However, times have changed dramatically, especially in applications such as networking and telecommunications. The migration from 10-Mbit Ethernet to 100 Mbits (and, soon, 1Gbit), 155-Mbps asynchronous transfer mode (ATM), high-bandwidth digital-cellular protocols, the embedded-PCI push beyond 33 MHz, fast DSP functions, 50-MHz DMA, 100-MHz graphics controllers, and other examples highlight the growing "need for speed." Given that you're sold on programmable logic for your next design (either for prototyping, initial production runs, or even through full production), how do you hit the required system-performance targets? Unfortunately, easy answers to this problem rarely exist. As is the case with most problems of this nature, you must first do a fair amount of research into silicon and tools, coupled with some creative "out- of-box" brainstorming, and finish by weighing various combinations of system-level trade-offs to determine the right answer for your situation. With programmable-logic devices increasingly resembling systems on a chip, many of the performance optimizations for logic modules within a device have much in common with techniques for optimizing device performance on a board. Don't rely on your tools The first time you hear a presentation from a PLD- or FPGA-device or -tool vendor, you might get the impression that you can implement your design as sloppily as you want, using any synthesis method you prefer, and the tools will take care of cleaning up the design for you (somehow reading your mind in the process to figure out exactly what you want). After subsequent evaluation, odds are you'll probably modify that opinion. Leaving the optimization up to the compiler and fitter is an admirable goal, and in relatively simple designs it may in fact be a reality. (For brevity's sake, the PLD term "fitter" also refers to an FPGA's mapper and automated place-and-route tools.) However, in most cases, remember the phrase, "garbage in, garbage out, " and realize that you'll have to take a more active role in the optimization. Until recently, this scenario was especially applicable when using third-party tools (that is, tools not developed by or proprietary to a specific silicon vendor), which tended to generate relatively generic netlists because of the tools' ASIC foundations. You're asking a bit much if you expect a silicon vendor's mapper to look at a collection of random gates and correctly infer that some of the gates represent a fast counter, others are a narrow-but-deep FIFO buffer, and the rest are slow decoding logic. Even if the tools have selections for high performance or low gate count, this option list is often too coarse to produce meaningful results. A more effective alternative is to follow some relatively straightforward steps in the upfront design to guide the downstream compilation and fitting. As Rocky Awalt, senior member of the technical staff at Memec Design Services, states, "Fixing [the design] does not necessarily mean placing and routing by hand; it means designing in a way that fits the architecture of the part and that suits the tools you are using." (See Reference 1.) At a high level, programmable-logic-device performance is a function of several main variables:
Note that logic and interconnects that function in parallel may decrease available resources, but they do not slow performance.
Because FPGAs are
register-rich but fan-in-poor, you might want to consider
an interesting alternative, the One-Hot state machine, to
the standard binary counter. This technique was developed
for FPGAs as a variant of the state-per-bit approach in
use since the days of paper-tape readers and front-panel
computer-input switches. One-Hot uses a register for each
device state (state-per-bit), with only one register
active (or "hot") at a time. In other At first glance, One-Hot state machines might seem resource-inefficient. Remember, though, that FPGAs are register-rich but have logical units with limited fan-in and that the design might therefore consume incremental FPGA-logic resources, both to generate wide fan-in functions and to route signals. By minimizing next-state decoding logic and interconnect delays, a One-Hot state machine often runs significantly faster in an FPGA than its binary-counter-based alternative does. However, note that the One-Hot technique does not apply to SPLDs and CPLDs; these devices, in contrast, are fan-in-rich but register-poor and thus are best suited for traditional counter-based state machines. Another caution: Because of the number of register elements involved, you must carefully define and control One-Hot state machines. They contain a large number of invalid states, defined as any combination of more than one active register. Alpha-particle effects, ground bounce, metastability, and asynchronous inputs all potentially cause unintended state transitions. Many tool sets, both silicon-vendor-supplied and third-party-developed, support not only Mealy and Moore but also One-Hot state-machine generation. Some tools automatically select an optimum state machine in response to your circuit implementation, guidance, or both (for example, prioritizing performance to the compiler), whereas other tools always default to one method unless you override them. Consult your development-tool documentation for more information.
Two examples illustrate possible LFSR applications (Reference 1). Often, when dividing something down, you need to know the number of division steps and the terminal count, but not the various counter values along the way. Also, if you are designing a RAM address generator and only your hardware will access the memory, the addressing pattern must be only consistent, not sequential. Even if you have to use a binary counter with an FPGA, minimize the counter's feature set to reduce logic and routing complexity and thereby boost performance. For example, if the counter can wait after loading before actually beginning to count (allowing time for sequential-logic initialization), you can significantly simplify its design.
Another technique you can use to overcome long propagation delays involves inserting one or several synchronous pipelines within a logic-level chain. This approach increases the clock latency from first input to first valid-circuit output. However, this approach usually also allows the circuit to operate at a faster frequency by reducing the number of combinatorial-logic levels that a signal must traverse between successive clock edges. In many applications that use counters and data-flow circuits, you often find that sustainable performance or bandwidth is more critical than initial latency. Remember that when you determine the placement of the pipe-line or pipelines, include the delays not only of the logic gates but also of the interconnects. (See box, "Andraka's top-10 list," rules 4 and 7.) Reducing logic complexity to boost speed is an important aspect of programmable-logic design. Ironically, you can also increase performance by increasing logic complexity, but only in specific situations. These situations in-volve configurations that execute in parallel functions that would otherwise happen in a slower serial fashion. One device example compares a multibit ripple-carry adder or subtracter with the adder or subtracter's carry-look-ahead counterpart. Al-though this circuit requires more gates to implement, it calculates the sum/difference and carry values for all bits in a parallel fashion, significantly reducing the delay path needed to calculate a valid result (Reference 3). Another example involves minimizing logic-output fan-out by splitting a signal and routing it through multiple buffers to its destinations or, in a more extreme case, also duplicating the logic that generates the signal. Notice that, although you've in-creased both logic and interconnect complexity, you've also reduced the loading that any of the parallel signals see, thereby speeding propagation. Be careful, though, that the greater interconnect complexity doesn't result in significantly longer routing paths, whose negative results would outweigh any loading improvements. Probably the most challenging technique of adding and removing gates is that of breaking a large, complex state machine into several smaller, faster alternatives. Although several smaller, tighter state machines can independently outperform their unified, bigger, and more cumbersome counterpart, the degree of interaction between the smaller machines is often a roadblock to high performance. At best, several small state machines may take longer to conceptualize and implement, which would toss your development schedule out the window. At worst, the interaction between the state machines, the added logic complexity, and the routing delays that the added logic complexity causes negate any potential performance advantage. One suggested approach that often works well is to think of your design as an operating system with one main process that occasionally starts subprocesses in response to input stimuli. By compartmentalizing any single state machine's functions in this way, you can often minimize interaction and maximize performance (References 4 and 5). Software developers are increasingly turning to high-level languages (HLLs) with object-oriented structures, such as C++, Visual Basic, and Java. HLLs offer some simple yet compelling benefits: They enable straightforward code-module integration and reuse, they are relatively isolated from, and therefore portable to, a variety of hardware platforms, and they relatively quickly generate a large amount of software. For engineers evaluating HDLs, such as VHDL and Verilog, the same selling points apply as compared with schematic entry and other more traditional approaches. You can easily reuse circuits implemented in HDLs later in other designs. HDL-based designs can compile to any programmable-logic architecture that provides sufficient resources. And, in this era of 100,000-gate CPLDs and FPGAs and shrinking development schedules, anything that can more rapidly generate a lot of logicthan alternative methods garners lots of interest. However, low-level sche-matic entry for programmable logic (just like low-level assembly language for software) offers one compelling advantage: It produces high-performance results. Al-though HDL tools today are more programmable-logic-optimized than in the past, a Boolean-equation- or sche-matic-generated design is sometimes smaller and runs faster than its HDL-synthesized alternative. So what do you do? If necessary, follow the approach of your software-engineer counterparts and design the performance-critical portions of your logic using schematic-entry tools and still harness HDL's advantages for less speed-critical circuits. Many HDL compilers enable you to insert, or instantiate, an EDIF-compliant netlist generated by schematic entry. In the future, as HDL compilers become more robust and silicon becomes more flexible, you'll un-doubtedly implement a greater percentage of your designs in HDLs (just as more programmers now choose HLL-only software development than in the past). In your HDL code, you can make many simple optimizations to boost speed. Often, they involve explicitly defining all possible values of variables and functions so that the compiler doesn't generate additional gates to cover the situations you've inadvertently omitted. Also, compilers are doing a better, though not perfect, job of compressing combinatorial-logic levels, and you can help compilers here. The examples that follow use VHDL (although the concepts apply equally to other HDLs) and represent some of the more common optimizations. When coding VHDL, be careful with IF...THEN or CASE statements. Listing 1a shows a process that generates a latch, whereas Listing 1b's process does not. The difference between the two listings is the ELSE clause. In VHDL, when you do not assign a value to a signal under a condition (such as to q when a1='0'), the signal retains its previous value, thereby generating a latch. Listing 1b clearly defines what happens when a1 does not equal '1,' so no latch is generated. If d in this example happened to be a 16-bit bus, Listing 1a would use almost twice the number of logic cells as Listing 1b.
CASE statements operate under the same rules. Listing 2a generates a latch, whereas Listing 2b does not. When you don't define '01' and '10' states for sel, the synthesis tool generates latches to retain previous values.
Careful use of parentheses can direct the compiler to implement a circuit that maximizes its performance (perhaps, however, at the expense of additional gate count). As an example, Listing 3a often generates a design that uses three cascaded adders. Listing 3b, by simple inclusion of two sets of parentheses, synthesizes to two parallel adders whose outputs the circuit then adds. The first design uses three combinatorial-logic levels, and the second design uses two.
Also, CASE statements infer an equal-priority parallel comparison, whereas IF...THEN... statements imply a prioritized serial design. A CASE statement often significantly compresses synthesized logic levels and boosts speed, especially if it can fit within a single FPGA look-up table or multiplexer, for example. A balancing act Given enough time, knowledge, and effort, you can almost always compile and fit a design that is smaller and faster and that consumes less power than one an automated tool generates. Having said that, the 100% manual-fitting approach is almost never the option you should choose because of fundamental time-to-market reasons. Subdue the ever-present engineering temptation to "do it yourself" or "tweak it just a little bit more," and let your timing-driven automated tools help you complete your project on schedule and under budget. Just as with the HDL-compilation examples discussed earlier, you can influence your tools to produce the kinds of results you need. Also, the tools themselves are moving from their ASIC-centric foundations toward more programmable-logic-aware approaches. The tools now tend to compile directly to a vendor's specific architecture instead of to ASIClike, two-input NAND gates, which would then rely on the vendor's mapper to reconstruct the coarse-grained programmable-logic cell.
Modifying the design in this way can produce significant positive results to a point. Beyond this threshold, additional investment often produces diminishing returns. Your silicon and tool vendors can advise you on which options you should focus your time and effort. The experience of multiple design projects if you standardize on common tools and devices is also an effective teacher. Sometimes, more drastic surgery is necessary. Considering the less-than-perfect abilities of today's tools to accurately infer your design intent, you might consider a partially manual-fitted approach. This option is especially attractive when your design contains performance-critical and structured datapath elements that minimally interact with other circuitry (or not at all). Floorplanning your design involves conceptualizing where you'd like the fitter to locate various logic blocks within the device--such as close to inputs to quickly respond to a stimulus or close to outputs to guarantee fastest possible clock to output (important in PCI designs, for example) (References 8 and 9). Sometimes, you can even bypass an FPGA's input registers and directly drive a signal through the buffer and into the core to save a few nanoseconds. In this case, make sure that the corresponding logic block is physically close to the input pin, or your hard work will be for naught. Defining pins where necessary or where obvious from a floorplanning exercise and leaving other definitions to the compiler for flexibility often provide significant benefits. SPLD architectures usually force at least some of the input- and output-pin definitions. However, you can configure some pins as either inputs or outputs. With CPLDs and FPGAs, you have even more pin-definition flexibility. At this point, look at the internal device architecture. Some PLD macrocells have more product-term inputs than others, and some macrocell outputs can feed back to the interconnect, whereas others cannot. Some FPGA architectures are symmetrical, whereas others, via the layout of their registers and routing resources, naturally encourage a certain data flow (usually, from one side of the chip to another, with control signals making up the remainder of the device). Use the expertise of others As an engineer, your job is to understand the subsystem or system that you're designing, not necessarily every nuance of every component you use in it. Programmable-logic vendors, on the other hand, understand their silicon in abundant detail. Working with the design-software vendor, you can produce amazing results. That is the point of the industry-standard Library of Parameterizable Modules (LPM). You specify generic elements, such as discrete-logic gates, counters, adders, shift registers, multiplexers, and memory blocks, in your design, and during compilation, the company's fitter replaces these elements with silicon-optimized circuits. Often, a vendor creates multiple versions of the same circuit, with one optimized for performance, another optimized for speed, and a third taking a middle-of-the-road approach, for example. You control which version the fitter uses via the previously described method. Utilities, such as Actel's ActGen macro builder and Lucent's SCUBA (Synthesis Compiler for User-Programmable Arrays), automate the creation of higher complexity logic functions optimized for speed, area, or some prioritized combination of these lower level elements, and you can instantiate the results into either schematics or HDL code. For even more complex functions, such as PCI initiators or targets, USB interfaces, and even entire CPUs, consider cores provided by either your silicon vendor or a third party. Often referred to as "intellectual property" (IP) or a variety of other vendor-specific names, cores are completed and verified designs with interface "hooks" for your logic. Cores can be "soft" (implemented in HDLs or schematics), "hard" (already compiled and laid out and added to your design in floorplanning), or "firm" (an intermediate step implemented in netlist form). Hard cores tend to deliver the highest performance but the least flexibility and ease of integration, soft cores are slower but easier to work with, and firm cores take a middle-ground position. However, to guarantee functionality and performance, core providers prefer that you standardize on one vendor's silicon and require this standardization with hard cores (References 10 and 11). Performance also depends on how symmetrically a vendor routes its logic array and, if asymmetrical, where you place the core. Look beyond the chip If you've followed all the suggestions so far and you're still a few nanoseconds short, it's time to lift your head out of the one-chip details and look for system-related optimizations. As noted earlier, you can partition one state machine into several smaller and faster alternatives. Sometimes, this approach works at the chip level as well. As a general rule, smaller and less complex chips perform faster than their bigger, more complex counterparts. One example when the smaller/faster approach works well is when you have several sections of parallel logic performing identical functions and only minimally interacting with each other, analogous to very-long-instruction-word (VLIW) processors. Note, however, that the timing delays if you go off-chip with signals, such as the carry-in and -out functions of parallel arithmetic units, can be significant. Another scenario in which using more chips is better might be the partitioning of functions into optimized devices, such as putting a small, fast decode unit into an SPLD, a controlling state machine into a CPLD, and a data-flow engine into an FPGA. Balance the performance you might gain from this approach against factors such as power consumption, reliability, total cost, and board space before heading too far down this path. Minimize fan-out to minimize output-transition times. For example, don't run a CPLD's decoded READ output to the inputs of 20-mP peripheral devices. Sometimes, you can minimize each output's fan-out within a programmable-logic device by routing an internal signal to multiple outputs. (Ensure that you duplicate sufficient internal circuitry to avoid excessive signal loading.) Otherwise, look for opportunities to run an output through several external parallel buffers to lower the loading on any one path. Device packages might also have slightly different thermal and bond-wire- or lead-frame impedance characteristics, which affect performance. If necessary, consider alternatives to programmable-logic devices. Chip Express' (Santa Clara, CA) Quick Laser LPGAs (laser-programmable gate arrays) are true gate-array ASICs, with circuits formed via laser trimming of a generic, fully fused silicon array instead of a semiconductor process. You can't program Quick Laser LPGAs at your desktop, and the fastest possible turnaround is 24 hours (not minutes), but they do offer inherently faster performance than any programmable-logic device and are particularly interesting if you're eventually going to move to ASICs anyway. Like any other semiconductor, a programmable-logic device's performance depends on variables such as voltage and temperature. Data sheets specify minimum or maximum values or both for various specifications across ranges; if you can tighten the tolerances, the parts usually run faster. However, some vendors do not guarantee your results at these altered ranges, thereby avoiding additional testing steps for the vendors that would impact device cost for all customers. This technique is a bit like overclocking a processor: It might work sometimes, but you'll probably eventually get caught. You can always characterize the parts yourself or have a company that provides this service do so for you, but there's often a significant yield loss that you still have to pay for. In most cases, the results do not justify the investment. Real engineering, as opposed to pure R&D, naturally involves trading off criteria to achieve a balanced and optimized result. Specifically, focusing exclusively on performance often causes you to overlook other important design objectives. From a synthesis angle, the HDL approach becomes more appealing and often essential as gate counts rise and time-to-market pressures increase. A balance between schematics for performance-critical sections of a design and HDL for the remainder of the design, plus time invested in learning an HDL if you haven't yet got around to it, will pay dividends down the road. As tools grow more capable over time, the balance will increasingly tilt toward HDL-only design. As a general rule, power consumption increases with corresponding increases in gate count and frequency. PLD and FPGA power is a complex and hard-to-predict combination of the number of transistors switching at a clock edge and the power burned in driving signals, especially clocks, down routing paths. Programmable-logic manufacturers, like their mP and memory counterparts, encourage and in some cases require their customers to transition to lower voltages to keep power consumption manageable. You can often configure advanced programmable-logic architectures to consume little power when in standby, but the usefulness of this feature depends on your application and sometimes involves a speed trade-off. What happens when your design changes in response to simulation or prototype testing results or as a result of the invariable last-minute requests from marketing? If you've packed your programmable-logic device almost full, a recompilation might not change things at all. More realistically, though, rerouting the design causes negative results in performance or pinout change or both, which mean head-aches. Do you want to take the chance? To prepare for the inevitable, don't allow a design to consume a large percentage of a device's resources, and make sure that the design has enough performance headroom to tolerate some degradation. Saving pennies by selecting a smaller or slower part now might force more substantial redesigns, which cost more in time, effort, and money down the road. The amount of resource and performance headroom you require depends on a device's routing capability and efficiency, so let practice and the experience of those who have gone before you be your guide. If possible, you should also select devices that have larger gate-count family members available in identical packages and pinouts, just in case you need the additional resources in the future. You need to walk the tightrope between using the sole-sourced capabilities of a vendor's architecture and choosing a more generic, conservative, multisourced design approach. In reality, you'll more often choose the route. (If you don't, your competition probably will.) This situation is especially true with CPLDs and FPGAs, but blind reliance on each and every feature of one product in one vendor's portfolio may be unwise. HDL techniques help make your design portable to multiple silicon platforms, but your results might vary widely, depending on the degree to which each company's fitter uses unique product options. Also, every time you instantiate a vendor's module or core into your design, you're making your design less portable to others' devices. Architecture optimizations Identifying greater performance as an increasing need of their customers, programmable-logic suppliers have developed some interesting options. The stringent requirements of PCI were notable in driving improvements in performance, which came about thanks to silicon-design changes and process-lithography shrinks. For PLDs, the fundamental specification areas that define performance include input-to-output propagation delay (tPD), input setup to clock (tS), input hold after clock (tH), and clock to output (tCO). With FPGAs, performance is harder to decipher and predict from a data sheet; usually, you need to compile and simulate a design to see where you are and then tweak the device and design as required. Sometimes an FPGA's speed bin refers to the maximum toggle frequency, sometimes it refers to the propagation delay through a look-up table, and sometimes it doesn't directly correlate to any one device characteristic. When interpreting device specifications, a little research into the assumptions involved can be instructive. Operating-frequency specifications are especially confusing, because the vendor often quotes toggle frequency using a circuit that is little more than a tightly coupled shift register or an internal flip-flop output feeding back into its input, an uncommon implementation in the real world. Even when the specifications include clock-to-output and input-setup times, the vendor often assumes a 0-nsec external trace-propagation delay. Specified input-to-output delays sometimes bypass the internal logic array. (This approach is valid in devices that include logic as part of the input or output buffer or both.) With PLDs, vendors often assume a best possible design with no product-term sharing or output feedback. Finally, look at the assumed operating-temperature and voltage ranges and the specified output capacitive loading. Timing specified with a 5-pF load is usually not applicable if your device's output is driving four inputs! With appropriate test conditions understood, speed also varies with voltage, gate count, and complexity. Lattice Semiconductor's GAL 16V8D-3 offers a 3.5-nsec tPD, 3-nsec tCO, and 2.5-nsec tS, whereas other SPLDs commonly offer 5-nsec or slower tPD. Altera is shipping 6-nsec-tPD versions of its MAX7000 devices with as many as 1250 usable gates, and the entire family is no slower than 7.5 nsec throughout the maximum 5000-gate range. Altera's upcoming "A" versions of the MAX9000 family are targeting similar performance levels. Xilinx reports that its XC4000E-1 FPGA family is 25% faster than its preceding -2 family speed bin in many designs, with a maximum operating frequency specified at greater than 80 MHz.
From a technological perspective, Actel's and QuickLogic's antifuse FPGAs tend to deliver a performance boost on a comparable lithography as compared with SRAM and flash-based alternatives. Antifuse interconnects have lower impedance than pass transistors do, and the interconnects are smaller, allowing comparatively more routing resources at a gate count. Because clock routing is so crucial to performance, programmable-logic vendors focus a great deal of effort here. In its upcoming ORCA 3C FPGA family, for example, Lucent Technologies will provide not only horizontal and vertical traces, but also diagonal interconnect to route clock signals throughout the device as fast as possible. Other specialized routing resources on some programmable-logic devices include dedicated carry and set-reset networks.
A variety of options exists to optimize programmable-logic performance. Admittedly, discussing the breadth of options is different from depth of discussion in any one area. Each design is somewhat different, and each silicon architecture and tool is unique. To tailor the general concepts to your situation, first ignore the temptation to "dive in," and spend a little time upfront researching what re-sources are available. When evaluating prospective silicon and tool vendors, look for implementation flexibility that you can easily and quickly use for your benefit. Many times, if you supply a vendor with a portion of your design, the vendor will compile the design in its architecture and let you know the performance and other results. Vendors also often provide high-level tools for rough speed, gate count, and power estimation before detailed implementation. Don't overlook the potential of evaluation boards, if necessary, to give you more in-depth information. After selecting your vendors, look for design suggestions and sometimes even full-blown reference designs that can apply to your situation. Find out what design-tool settings produce the most significant improvement for the types of circuits you develop. Companies are substantially beefing up their Web-site contents for 24-hour access to documentation, technical-support-database contents, and other useful information. Use the work of others when you can to complete your design more quickly and to avoid making mistakes. Sometimes, a broader perspective is also useful. The Programmable Logic Jump Station (pw1.netcom.com/~optmagic) has links to a variety of industry resources, including user-developed documentation and consultation services. Internet newsgroup comp.arch.fpga provides effective data-sharing and feedback from those who have already solved the problems you're facing.
Acknowledgment Stephen Wasson from HighGate Design Inc, a programmable-logic-design consultation company, was an invaluable source of both detailed information and extensive feedback during the development of this article. |
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
| EDN Access | Feedback | Table of Contents | |
||||||||||||||||||||||||||||||||||||||||
| Copyright © 1997 EDN Magazine, EDN Access. EDN is a registered trademark of Reed Properties Inc, used under license. EDN is published by Cahners Publishing Company, a unit of Reed Elsevier Inc. | ||||||||||||||||||||||||||||||||||||||||