tag 标签: hex cross-debugger

相关博文
  • 热度 14
    2011-3-11 14:42
    1766 次阅读|
    0 个评论
    Fortunately for me, I was able to scream loud enough to talk management into buying a decent, disk-based development system. I don't think I made any points with my boss, though. I learned another good lesson from this experience. It's called, "Never let a hardware guy choose your development system for you."   Understand, the term "decent" is a relative one. The new system, supplied by Zilog at an exorbitant fee, was nothing more than a CP/M computer hiding a Z80 chip. Its only bulk storage was a single 5-inch floppy drive. Even so, it was head-and-shoulders better than the silly eval kit.   The Z-8000 cross-assember was serviceable but horribly slow. Instead of reading the source file into RAM and assembling it, this assembler only read the source file one source line at a time. After leisurely pondering that line, it would finally get around to reading the next one. I've never seen or heard of such an approach, before or since.   This project involved interfacing with real hardware: a gyro sampled at the high rate of 1,000Hz. No single-stepping here; whatever you were going to do with the gyro data, you had better do it before the next interrupt came in. Every clock cycle counted, and I absolutely did count them all. To get the data through the system in time, I didn't have the luxury of moving data in and out of RAM. Every byte that could be, needed to be stored in CPU registers. To figure out how best to allocate the registers, I invented my own, pencil and paper version of a graph-coloring algorithm.   For this project, I applied the lesson learned in the previous ones: emulate, simulate, and unit-test every line of code before committing it to the target hardware. Because this target hardware couldn't be breakpointed, my abilities to test were very limited.   Where was the Blue Box when I needed one? A Blue Box would have let me take a snapshot of the data without halting the unit under test (UUT). So we built one. We added a piggyback board with a second Z-8000, run from a common clock. The Z-8000 had a control pin, a chip-enable, if you like, that would pause the CPU. I needed a pause in the UUT like I needed a hole in the head, but a little math showed that I had saved enough clock cycles to let the CPU store a small amount of data—10 words or so—into an area of shared RAM. The Z-8000's block-transfer instruction let us do the move pretty quickly, and the second CPU could move the block of data into a safe place before the next major cycle. Cross-connecting the hold pins kept the CPUs from walking on each other.   Finally, I wrote a hex cross-debugger for the test CPU, and the tiniest bit of debug support in the UUT. This support let me read a single word from the shared RAM and store it somewhere else, including a register.   After all was said and done, the system worked pretty well, and we had the software working in time to meet a revised, delayed, revised-again delivery date.   Stated another way, we achieved every software person's goal, which is to finish before the hardware is finished.   For the record, the hardware was never finished. In operation, this system was supposed to monitor inputs from the gyro and grab only those just before and just after a certain event. The hardware designer thought it would be helpful to shuffle the data in hardware, from time-sequential to something else. Unfortunately, the hardware sometimes dropped a data point if it was too close in time to the triggering event. So the data would come in shuffled. It was something I couldn't correct in software because the needed data wasn't there. And the hardware never got fixed.   From this experience, I was able to add a new entry to my "lessons learned" list: when working in an embedded environment, never let the hardware guy or a systems engineer make all the design decisions.   More Z-8000 I did a couple more embedded projects using the Z-8000. One was on a government contract, so we went with a high-end development system from Tektronix, costing a mere $30,000. This one actually had a hard drive, and it was a full-blown ICE. Still no high-order language, just your everyday cross-assembler with hex debugger. It got the job done, but it couldn't run at the top speed of the Z-8000, and the debugger sucked rocks. I mean, this thing was bad news.   Over time, I've learned how to build hex debuggers for just about any CPU, and I've done it many times—sometimes for hobby systems like Z-80s and 68000s. It's not exactly rocket science, after all. My debuggers are typically minimal systems, less than 1K in size. But on my worst day, I could never write a debugger as bad as this one. Some of the instructions required commas between fields, some a space. Never both together, and never a tab or more than one space. It couldn't even accept lower- and upper-case characters. I'd be embarrassed to have my name associated with something like that.   One other thing was notable on this project: the hardware was being developed along with the software, and its first few iterations didn't work. It also suffered from a persistent design flaw: its two CPUs were connected via FIFOs, but they ran on different clocks. Can we see the flaw in that design? No matter how deep the FIFOs, one is going to fill up to overflowing, and the other is going to run dry.   On this project, I learned to expand my list of "never let" rules. Because the hardware was being developed in parallel with the software, we had to determine, by testing, if a given problem was in the software or the hardware. Whenever we told the hardware guys that we'd found a hardware problem, they wouldn't believe us. Thus began a time-consuming and often acrimonious debate.   So the new rule is and should be: Never develop software for a system that isn't built yet.   For that matter, there's a top-level rule that subsumes all the others: if you're the manager of an embedded system project, never divide your people into "hardware guys" and "software guys." They all have to be "team guys."     Proprietary computer In the 1970s, most of the companies building military hardware used their own proprietary computer designs. Ours was no exception. At first glance, it seemed to be a ruggedized version of our 16-bit minicomputer, but it wasn't. It was a custom system with an instruction set optimized for real-time embedded systems.   My job was to build an 18-state Kalman filter and related software. And this time, we certainly couldn't say the development system wasn't big enough or fast enough. It was a Multics timeshare system, so big that it filled three floors of the computer center.   There were only a couple of catches. First, the software all had to be written in assembly language; the company had never gotten around to building a C (or any other language) compiler for this proprietary chip.   Second, the computer was 1,000 miles away. Our only connection to it was via dial-up landlines, using yet another thermal-printer terminal and a 110-Baud acoustic modem. You dialed the phone and then put the handset into a cradle in the modem.   We certainly couldn't say that the computer was too small, and it had data storage of many, many terabytes. And the cross-assembler and hex debugger, while slow, were capable enough.   Our biggest problem with this system was the fact that our phone connection ran through the telephone switchboard. The switchboard operators had no idea what we were using the line for, but they quite naturally assumed that people were talking to each other.   When an operator looked at her switchboard, she saw one light constantly on, indicating a single call running into hours. Curious, she'd listen in to the "converzation" and here only modem squeaks and squawks. She'd say, "Good Heavens, this connection has gone bad," and pull the plug on us. We learned to save files early and often.   Two aspects of this job stand out. First, when we started the job, I was curious as to how capable an assembler we could expect. I approached one of the other software guys, an expert who had been working with this processor for years, even decades. The converzation went like this:   Jack: "Is this a macro assembler?"   John: "A what?'   Jack: "A macro assembler."   John: "What's that?"   Jack: "You know, it lets you define macros."   John: "What's a macro?"   Jack: "You can define common blocks of code, and give them names."   John, looking at Jack quizzically but sincerely: "Why would you want to do that?"   Jack, to himself: "This may take longer than I thought."   Second, after I had some code that I felt was ready for integration, I brought it to John. I said, "Let's put this into the ROMs, please." He said, "Can't do that now. We just completed a build. You'll have to wait for the next one."   Jack: "When will that be?   John: "We usually make a build every two weeks." (He might well have added, "Whether we need it or not.")   Jack, in his usual discreet and tactful fashion, "two weeks??? I'm used to getting a build every two seconds!" (O.K., a minor exaggeration, but still on the order of seconds.)