Archive for 2008
Hello World, Take 2
In my continuing quest to procrastinate actual construction of the machine, I took some time this week to tinker around with my LCD module. It has a somewhat complicated command interface for configuring the display properties and uploading data, and a lengthy data sheet that I found pretty mind-numbing. I decided to jury-rig something to display a test message, by storing a sequence of LCD commands in a ROM, and using a counter to cycle continuously through the ROM contents. Figuring out the right sequence of commands and control signals took some fiddling, but after a night’s experimentation… voila!
Oh wow, what’s that there on the LCD display… it’s “Hello World”! Or actually no, it’s “dHello World”, but that’s close enough. The actual command sequence causes the display to continuously overwrite itself with copies of “Hello World”, and my photo just happened to catch it there.
In actual BMOW-related news, this weekend I ordered what I hope is the last batch of parts I need to construct the machine: a few assorted sockets, resistors, and capacitors. I’ve already assembled what I hope is the final list of parts for my wire-wrap board, so my next step is to engage in the Tetris-like task of optimally fitting all the components onto the limited space of the board, while also accounting for the maximum possible length of various external connectors. Hopefully everything will fit, otherwise I’m going to look pretty stupid.
Be the first to comment!BMOW Simulator
I spent a few days last week, and wrote a functional simulator for BMOW. This replaces the hardware-level Verilog simulation with a custom program written to match the behavior of the BMOW microcode interpreter. The simulator loads the microcode ROM images as well as the program boot ROM, so the simulation will keep working fine regardless of later ROM changes.
I’m really happy with the way the whole thing turned out. It’s probably one of the most interesting pieces of software I’ve ever written. Here’s a screenshot of the simulator in action:
The top-left panel shows the current state of the registers and condition codes, as well as the current opcode, instruction, and phase (the index of the current micro-instruction). Eventually this area will also show the current state of the LCD.
The top-right is a standard memory view. Just type in the base address of the region of memory to examine.
At the bottom-left is the source view. This shows a disassembly of the program boot ROM, in the area near the PC. Yes, I wrote a BMOW-6502 disassembler to generate the source for this view. The current instruction is shown with a yellow arrow, and you can set breakpoints by clicking in the margin to the left of an instruction, just like in Visual Studio.
The bottom-right is the microcode source view. It shows a micro-disassembly (yes, I wrote a second disassembler) of the instruction currently being executed in the source view. The microinstructions in each phase are shaded the same color, to make it easier to visualize the groupings. Only one microinstruction from each phase will get executed, depending on the state of the condition codes at the time of execution.
Breakpoints can be set in the microcode too. Here you can see I set a breakpoint within BCS (branch if carry set) for the case where the branch is taken but the address arithmetic doesn’t generate an address carry when adding the branch offset to the PC. This is really cool, in my not-so-disinterested opinion.
Be the first to comment!Schematics!
The first draft of the BMOW schematics are finished, along with complete equation lists for the 11 unique GALs (18 GALs total). This is everything needed to actually build the machine. You can view it all on the technical info page, along with an updated block diagram.
Whew, what a job that was! The datasheets, the timing diagrams, the insomnia… I’m really beginning to question my own sanity. If some of the schematics seem a little confusing and convoluted, it’s probably because I was asleep while I drew them. Ditto for the spaghetti wire paths.
I’m going to step back now and review the whole system, looking for any blunders I’ve made, or any opportunities for improvement. I hope that the people who’ve been following my progress can find some time to review the plans as well. Your design feedback is welcome and appreciated!
Initial Schematics Complete
The first draft of the schematics are complete. It was a good exercise, as working out every connection for every chip forced me to consider a few points I’d glossed over before. I ended up having to introduce a few more components than I originally planned on, to help generate needed control signals, or work around timing problems.
The memory and device schematics were the most difficult. As I wrote about previously, the timing requirements for the memory and USB module required careful design in order to avoid constraining the clock speed too severely.
The LCD module proved even more troublesome. It has some truly horrible timing constraints, including an 80ns setup time for data, and a minimum 230ns pulse width for the write enable signal. I couldn’t find a way to connect it directly to the memory data bus without slowing the clock down to below 2MHz. Instead, data for the LCD is actually written to a special register, and then on the next clock cycle, dedicated control logic writes the register value to the LCD. During cycles where the LCD isn’t being written, I’ve configured things so that it will always read the LCD busy flag. That means it’s impossible to read any other data from the LCD, like what character is currently at each location on the screen, but I can’t imagine why you’d want to do that anyway.
Now I need to go back through all the schematics, clean them up a bit, and check for places where I’ve exceeded TTL fanout limits (generally each output can feed no more than 10 inputs). Then I need to write the equations for all the GALs called for in the schematics: 18 in all. Once everything’s ready, I’ll post it up here for feedback.
Be the first to comment!More Timing Analysis
The schematics are nearly done. I’ve finished all of them except the memory/device subsystem, which is proving to be difficult. Unlike the registers and all the other machine components, the RAM and the USB interface don’t use a clock. Instead, they have a write-enable signal that causes data to be written the instant the signal is asserted. That means I need to take extra care to prevent the write-enable signal from being momentarily asserted while the state of the machine is changing from one instruction to the next– something that’s not necessary for clocked components.
The common strategy I’ve seen is to combine these kinds of write-enable signals with another signal that’s guaranteed to be asserted only when the write-enable signal is sure to be valid. Typically, this is the clock signal itself, or something derived from the clock signal. For example, if the write-enable signal is active low, it can be OR-ed with the clock signal, and the result will only be low if write-enable is asserted and it’s the second (low) half of the clock cycle. This allows the write-enable signal to temporarily take on invalid values during the first half of the clock cycle without harm.
I did a static timing analysis, based on my schematics and the chip datasheets, and in the worst case it will be 233ns from the start of a clock cycle until the write-enable signal and memory address are guaranteed valid. If I use the clock signal to combine with the write-enable signal, then the clock period must be at least twice 233ns, so 466ns, or 2.14MHz. I’d like to go faster than that.
My clock module also generates a signal called Q1, that lags the main clock (Q0) by a quarter cycle. By OR-ing together Q0, Q1, and write-enable, the result will only be low if write-enable is asserted and it’s last quarter of the clock cycle. That implies a limit of 233ns for three-quarters of the clock cycle, so 310ns for the whole cycle, or 3.22MHz. That’s a little better.
Unfortunately, using Q1 and Q0 to mask write-enable until the last quarter-cycle causes problems with the USB inteface. The USBMOD4 needs to have its read-enable input gated as well, because reading actually changes the state of the device by advancing its internal FIFO. Once read-enable is asserted, it can take up to 50ns for the USBMOD4 to put valid data on the output pins. Data must then pass through the 74LS245 bus driver (40ns), and arrive at the destination register 20ns before the end of the clock cycle to observe the setup time requirements. Therefore the quarter cycle must be at least 50 + 40 + 20 = 110ns, so 440ns for the whole cycle, or 2.27MHz. That’s hardly any better than the 2.14MHz achieved by using Q0 alone and ignoring Q1.
So for two different reasons, it appears that the machine will be limited to a top speed of 2MHz. With some redesigning, I could probably speed that up, but I’m more interested in just getting it working right now than in getting the fastest possible performance. It’s entirely likely that in practice I’ll be able to run faster than 2MHz, since all of my numbers are the worst-case figures from the datasheets. The listed “typical” numbers are generally about 1.5x faster than worst-case, so it might be possible to run as fast as 3MHz with the current design.
For the curious, the time-limiting path from beginning of a clock cycle to valid read/write-enable and memory address is:
Cumulative Time | Delta Time | Path |
---|---|---|
0 | 0 | clock cycle begins |
35 | 35 | 74LS194 condition code register’s new values are valid, and used as micro-ROM inputs |
105 | 70 | 29F010 micro-ROM output |
143 | 38 | 74LS139 decodes address register enable from micro-ROM output |
168 | 25 | 22V10-based address register’s output is ready |
193 | 25 | 22V10 address decoder determines if address is in program ROM, RAM, or memory-mapped hardware |
233 | 40 | 74LS138 decodes read/write-enable signals for specific hardware devices |
Follow up: After a more careful reading of the datasheets, things aren’t quite as bad as I’d first thought when combining Q1 and Q0 to mask the enable signals to the last quarter clock cycle. First, the worst-case data propagation delay for the 74LS245 is only 12ns, not 40. The 40ns figure is for the output-enable signal on the ‘245, which should already be set by the time the data is coming through. Second, the setup time at the data registers is actually 15ns, not 20. Add up the 50ns delay from the USBMOD4, 12ns at the ‘245 bus driver, and 15ns setup time, and you get 77ns. Coincidentally, that’s precisely the amount of time allowed by a 233ns time for three-quarters of the clock. So the limitation imposed to guarantee valid read-write/enable signals exactly matches the limitation imposed to guarantee valid data read from the USBMOD4, at a clock period of 310ns for the whole cycle, or 3.22MHz.
Be the first to comment!Logic Analyzer/Oscilloscope
My Hewlett-Packard 1631D logic analyzer / digital oscilloscope arrived today: the finest 1985 technology that $35 can buy. I bought it dirt cheap from eBay in “as is” condition, but it seems to be working great! With this acquisition, I can proudly say that I’ve crossed the line from ordinary run-of-the-mill nerd to super-nerd.
Holy cow, there are a lot of buttons and wires on this thing. What’s a trigger? Where’s the manual? My head hurts just thinking about it.
After some time spent jabbing hesitantly at buttons, I finally managed to get a scope trace working. Here it is, showing the output of a 1 MHz clock oscillator. Mmmm, square wavy goodness!
Read 10 comments and join the conversation