After a long hiatus due to school, I've finally had time to put some more work into the 68000 tablet.
I was able to write a driver for the LCD screen, as well as some commands for writing text and controlling individual pixels. I tested this by drawing images manually over a serial connection. I also attempted to write a function to draw a Mandelbrot fractal on the display, but it kept crashing. I looked through the generated assembler code, but everything looked fine. So, I started to investigate.
After adding the Mandelbrot code, I noticed other functions behaving strangely. For example, attempting to call
sleep() would often - but not always! - cause the board to reboot. At this point, I decided to add actual error handling to the board. Now, an exception would print a message stating the cause to the serial bus, and would halt execution. After adding this, calling the Mandelbrot function would halt the board with an "invalid instruction" exception. This wasn't my first time dealing with invalid instructions - previously, I accidentally set the target CPU to 68030, which caused gcc to generate instructions that didn't exist on the 68000. I went through all of the generated Mandelbrot assembler code and verified every instruction existed in the 68000 manual. Still, everything looked fine.
At this point, I thought the problem was related to the power bus.
mandelbrot(), being a very CPU-intensive function, would probably thrash the address and data busses, causing a current spike. I measured the board, and voltage hovered around 4.0V when the computer was running! Clearly, this was way out of spec for a 5V CPU. I connected a more powerful supply up, and was able to maintain a voltage of a little over 5V.
mandelbrot() still caused the board to halt immediately.
Debugging was starting to get difficult. Repeatedly plugging and unplugging the EEPROM from the programmer I built was causing the socket holes to widen. I'd have to fiddle with the chips until it made a solid connection, and then hit program. At this point, I realized that the same thing could be happening on the 68000 board.
mandelbrot(), I noticed that the resulting binary size had surpassed 8KB. Since the data bus is 16 bits, each EEPROM chip was now holding over 4KB of data. My theory was that a12 wasn't making a solid connection with one of the chips - not making a difference for the first 4KB, but rereading that 4KB for the next 12 bits of address space. This would mean that instructions in
mandelbrot() wouldn't be read - random data would be read instead. Using a multimeter, I checked the pins of the EEPROMs, and verified that a12 wasn't making a proper connection with the board.
I've ordered a proper EEPROM programmer, and I've also ordered some ZIF sockets, which I'm going to install on the 68000 board. Once that's done, hopefully all of the errors will disappear. Until then, I'm back to programming blind - like I did while waiting for parts to come in, many months ago.
Also, I wanted to post a picture of the screen displaying a message. Unfortunately, my current programmer can't make a good connection at all, and I corrupted the EEPROMs while trying to get write to them.0 comments Categories: 68000-sbc
I finally have enough parts to start running programs on my 68000 tablet. The only thing I'm missing is the 68681, which is required to use the serial port.
I did had to make a small modification to the board to get it running though. I decided to switch from EPROMs to EEPROMs, and the new EEPROMs had a slightly different pinout. The only thing I had to change was to assert the ~WE pin HIGH so that I could actually read from the chip. This was done by running a wire from each ~WE pin to the VCC pin of an unused socket. Other than that, the board has no significant bugs!
As a simple test, I thought I'd blink a light. My source code is below:
/* Tests the timer circuit/interrupt. Code enters an infinite loop at 0x1000. This lights up only one of the address LEDs. Once the timer interrupt fires 386 times, we switch to 0x2000. We flip back to 0x1000 after another 386 interrupts. The result of this is that the address LEDs toggle between 0x1000 and 0x2000 every second. */ .global _start /* we have 256KB of RAM connected however a17 is connected to CE2, so we need to assert it and RAM is only enabled from 1MB to 2MB hence the weird number here this stores the interrupt count (how many times the timer interrupt has fired) */ .equ INT_COUNT, 0x140000 /* Are we at 0x1000 or 0x2000? */ .equ WHEREWEAT, 0x140002 .long 0x140500 /* stack pointer */ .long _start .org 0x100 .long timer /* Timer vector */ .org 0x400 _start: MOVE.W #0, (INT_COUNT) /* set int count to 0 */ MOVE.B #0, (WHEREWEAT) /* set whereweat to 0 */ /* Enable interrupts by negating int mask */ ANDI.W #0xF8FF, %sr JMP LOWER_LOOP timer: MOVE.W (INT_COUNT), %d0 /* Increment INT_COUNT */ ADD.L #1, %d0 CMP #386, %d0 BEQ timer_rollover MOVE.W %d0, (INT_COUNT) RTE /* done */ /* Timer interrupt triggered 386 times */ timer_rollover: MOVE.W #0, (INT_COUNT) /* reset counter */ MOVE.B (WHEREWEAT), %d1 EORI.B #1, %d1 /* flip WHEREWEAT */ MOVE.B %d1, (WHEREWEAT) CMP.B #1, %d1 BNE timer_upper /* temp */ /* switch to 0x1000 */ MOVE.L #0x1000, (2, %ssp) /* Overwrite PC in stack */ RTE /* done */ timer_upper: /* switch to 0x2000 */ MOVE.L #0x2000, (2, %ssp) RTE /* done */ .org 0x1000 LOWER_LOOP: JMP LOWER_LOOP /* Infinite loop */ .org 0x2000 UPPER_LOOP: JMP UPPER_LOOP
Basically, we define two infinite loops: one at 0x1000, and one at 0x2000. The timer interrupt fired roughly 386 times per second, so we count the number of times it fires and use that to call the timer_rollover branch roughly once per second. When it fires, we flip between 0x1000 and 0x2000.
Video below. I put a box over the data bus LEDs because they were washing out the imagine significantly. One of these days, I'm going to put higher-value resistors in place.
As you can see, it works as intended! It took me a few hours to get it running properly on the computer. Debugging with LEDs is a huge amount of fun!0 comments Categories: 68000-sbc
I have finally received enough parts to run a basic test of the 68000 tablet computer I designed. The main thing that I was waiting on was female headers, so that I could install the 68000 into the board. Here it is running:
I don't have enough parts for the address decoding circuit, so I'm unable to use ROM or RAM (nor has the ROM arrived). Instead, I used 16 220 ohm resistors to pull the data bus to 0x00. This corresponds to the instruction
OR.b #0, d0, which does nothing. The result of this is that the CPU races up the memory address space, executing the same instruction as it does so. The green LEDs are connected to the address bus, and we can see it counting up in binary, looping back to 0 when the bus overflows.
A few other jumpers can be seen around the board, pulling CPU pins high and low to compensate for chips that aren't installed.
Overall, this was a success! I'm looking forward to the arrival of the rest of the parts so I can get this board finished.0 comments Categories: 68000-sbc
Quick update to my 68000 tablet - The PCB has arrived! Even though I knew the dimensions of it, it's a lot bigger than I was expecting.
Here is the empty board, which arrived earlier today. I have added some parts on, as you can see here:
So far, I have found several problems.
The CPU socket on the PCB is slightly too wide. However, I can easily bend the pins slightly out so that it still fits. Turns out that it is the right size, it just requires a socket to fit properly.
The barrel jack is backwards (facepalm). Also, the holes are slightly too small. This isn't a concern, because I wasn't really planning on using the barrel jack anyway. As a workaround, I could purchase a jack with slightly thinner leads, and mount it on the bottom of the board so that it would face the right way.
The on/off switch was the wrong form-factor, slightly. I expected this, as the original switch was out of stock. I had to bend the leads, but was able to get the new switch to fit.
I expected some problems to occur, and they're minor enough that it doesn't really affect anything. I am waiting for more parts to come from China. My campus just closed due to COVID-19, so I am unable to source parts from there. I was hoping to get some resistors so that I could do a basic test of the busses. At the moment, I don't have any way to drive the LEDs.
I've been testing the board as I add each component. Until I get some resistors, I will not be able to assemble more of the board.0 comments Categories: 68000-sbc
I have ordered some parts for the 68000 Tablet I have designed. The most expensive part was the PCB - it was $90 CAD for 5 tablet boards, as well as 5 programmer boards. About half of that cost was shipping. I also put together a BOM, of which most of the parts come from Ebay, along with some from Digikey. It's crazy how fast the cost of a few dozen logic gates add up! I placed the Ebay order, but not the one with Digikey. The latter will arrive within a day or two from shipment, so it's not as high of a priority.
I made a few part substitutions to save money. I swapped out the 1MB of RAM for 256K. This brings RAM cost from $14 to $8. I'm also using an EEPROM where the ROM goes. Again, I swapped out the 1MB for 256KB. One thing is that the A17 line connects directly up to the WE line, which is active low. This means that when the computer turns on, it will overwrite its ROM immediately. I will probably just not connect WE and leave it floating. I haven't had problems doing that in the past, but if it causes problems I'll run a wire to +5V. The last thing I did was swap a 74 series logic chip out, because it was discontinued. The new one is pin-compatible, but I had to update the schematic with the new part number.
I opted not to order the screen yet. At $40, it is the most expensive part. I can still debug the system fine without it, by using the bus LEDs and serial ports. I also didn't order the mechanical key switches. They're quite expensive and I can get by with shorting the pins out manually. Once the system is up and running, I'll get these ordered too.
I have already identified some changes I would like to make to rev1 of the board(currently on rev0). For one, the LEDs need to be able to be turned off via a hardware switch. Some simple calculations say that the lights will use up to 600mA when all are lit. This is on par with the consumption of the rest of the system. Being able to turn the lights off would increase battery life, and would make it less distracting to use.
I think it's also worth splitting the board up into two parts - one for the system and one for the keyboard. I'll probably end up making several revisions of the system, but I should only need one version of the keyboard. I'm also going to update the schematic to use an EEPROM instead of ROM. It's not the 90s any more!
The next step is to write some assembler code to make sure the computer works, once the parts arrive.0 comments Categories: 68000-sbc
My favourite retro-computing devices are those that are portable. The TRS-80 model 100 is especially interesting to me; it is a tablet computer released in 1983. I few days ago, I decided I should design my own portable computer.
Anyone who knows me in person knows that I am an avid supporter of the Motorola 68000, and other 68000-based CPUs. In my opinion, they are a much better design than the x86 architecture we are stuck with. For this reason, I decided to base my tablet around this CPU. Even though it was released in 1979, it is a very capable computing device. A 23 bit address bus and 16 bit data bus provides access to up to 16MB of address space, without having to use memory banking. Internally, the CPU is fitted with a large array of 32 bit general-purpose registers - 8 of them! That doesn't even include the 7 address registers and stack pointer register. Amazingly, this 40 year old CPU is still in production and used regularly; that's how good it is.
After picking the CPU, I added on pretty much whatever hardware I could think of. It has 1MB of ROM, up to 2MB of RAM, and 64K of EEPROM. On top of this, it features a CF card slot for mass storage, a mechanical keyboard, 2 serial ports, and a 240x64 screen. Physically, this takes up nearly all of the available board space.
The memory map is as follows:
|0xF10000||I/O||1MB - 64kB|
Most of the address space is unused.
I will now walk-through some of the design I came up with. It was created in Kicad, which I have switched over to from Eagle.
This is the general overview of the board. It only contains the CPU, the M68000, as well as the other pages that make up the computer. Other devices are not allowed to become bus masters, so the respective pins on the CPU are either left disconnected, or negated. Similarly, there is no circuitry to detect bus errors, so that pin is also negated.
This is another fairly simple schematic. It contains the ROM, RAM, and EEPROM. Another page generates the chip select, lower read, and lower write signals used here. These are connected to each chip so that they talk to the address and data bus only when required.
This page makes up the address decoder. It consists of two multiplexers, connected together. The first reads the upper 4 bits of the address bus, to determine which MB is selected. This is used to generate the ROM and RAM chip select signals. If the top MB of address space is selected, it enabled the second multiplexer. This multiplexer divides up the address space into 64kB chunks. The bottom chunk is reserved for the EEPROM. Each I/O device gets its own 64kB as well. It's overkill, but since the majority of the address space is unused, we don't give anything up by being inefficient.
This page is also responsible for generating the DTACK (data acknowledge) signal, which is asserted when the bus slave is done servicing its request. Only the serial controller uses this signal. All other devices are fast enough that we don't really need to worry about it. We can also abuse the DTACK line to allow single stepping. By negating the DTACK line by default, the CPU grinds to a halt. We can then apply a short pulse to the DTACK line whenever we want to step forward. The circuitry in the bottom left is responsible for generating a short pulse when the single step button is clicked.
Another simple page. This takes the LDS (lower data select), UDS (upper data select), and R/W (read/write) signals from the CPU, and combines them in a way that makes sense to the memory chips.
As you can see, the data bus is connected directly to the CF card slot. The comment above it is out of date - it has a 16 bit connection to the bus. Enabling/disabling the slot is done by pulling the CS0 and CS1 lines high. However, the CPU still needs to be able to control them. This is done with the two OR gates, which allows a3 and a4 to pass through to CS0/CS1 when the card is enabled.
A 68681 is used as a serial port controller. It is able to support both ports. Two MAX232 ICs are used to boost the voltage to 12V for the RS-232 ports.
There are more pages, but I don't want to explain them all here as there are a lot of them. I have covered the most important ones.
For debugging, I have placed LEDs on the board that display the current address and data bus values. I will be writing a custom BIOS and OS from scratch to run on the device.
The full project is on my git server: https://git.scd31.com/stephen/68000-sbc/
There is also a PDF of the schematics in main/rev0.0 comments Categories: 68000-sbc