2014-01-31

this is not nice. It's a PITA but everyone uses it: The Gnu Compiler Collection; here with a backend to produce m68k object code. I suffered for some hours, but then i had success: The first test program compiled! Let's see how it works. (and leave out most of whatever did not work.)

Compiling the GCC is not a trivial task, you need a GCC and lot's of other tools, they should match each other, find each other and work on my desktop machine.

Mac Ports (the port system i use on my Mac to port 'alien' stuff) was no help though right now i can see they provide a (very outdated) version of the rtems tool chain. Yesterday i installed a toolchain for ARM and the Mac Ports ARM GCC for Linux is so old that it even fails to install (it's from 2005, today is 2014!)

OSdev.org is a great site but still a little bit over-complicated. (Ok, actually it's the GCC which is over-complicated.)

Next was rtems.org, a project for real-time embedded micro systems. The project supports the 68k CPUs but it's not the bare GCC but with their added extra. Maybe i'll cherry-pick some sources from them... :-) In the first place i didn't realize that this project already comes with a whole OS, else i had eventually skipped it. But so i downloaded the whole stuff from rtems.

(Actually i installed into a different directory, but that doesn't make much difference.) After waiting roughly one hour a couple of new GCC instances entered this world.

The rtems people have configured their installation scripts so that the resulting tool names all start with "m68k-rtems4.11-" which is different to "m68k-elf-" which is normally used. Probably there is a good reason for that.

Next i stumbled over the bitsnbikes blogger site. J. Silva started a 68008 project in 2010 and described the sources for his first "project". He had borrowed from others and i borrowed from him:

2014-01-27

The design phase is coming to an end now, if no problems show up during verification phase later, this will be the K1-Bus I/O circuit:

K1-Bus 68008 CPU board with SRAM – K1-Bus I/O Circuit

Short summary of the K1-Bus

The ➧ K1-Bus is a 16 bit peripherals bus designed for simplicity. The basic unique concept of this bus is that the peripheral board accessed is not encoded in the address of each I/O opcode but the board to talk to must be selected. During selection the boards are addressed with a low level on their assigned data line.

Interrupts are signaled on the !K1_IRPT collector line and during interrupt processing the CPU queries the interrupt state of all devices. The CPU can enable and disable interrupts for each device individually by writing a mask work on the data bus. This way all devices may be assigned an individual interrupt priority if the programmer desires.

There are 5 control lines (strobe signals):

!SELECT – The CPU writes a mask word on the bus to select a peripheral board for subsequent data transfer.

!WR_IRPT – The CPU writes a mask word on the bus to enable or disable interrupts on the attached boards.

!RD_IRPT – The CPU reads a mask word with the interrupt state of all attached boards.

!WR_DATA – Send data to the selected device.

!RD_DATA – Read data from the selected device.

The circuits

The 74HCT138 3-to-8 line decoder generates the strobe signals for the bus when A19 is '1' during a bus cycle when !AS is low. A0, A5 and the !WR signal are used to determine which signal to activate. For the reason to chose A0 see below.

IC 74HC367 with the surrounding resistors and diode implement an i2c interface. Every K1-Bus extension board can provide an i2c EEprom with software driver for the board. Also, the i2c EEprom is used to detect the presence of the board. The funny circuit design is directly taken from my ➧ K1-Bus homepage. It was the simplest circuit i could come up with if no port pins are available to be used for the i2c bus.

The i2c bus is always accessed by reading from the K1-Bus and one of the select lines of the 74HCT138 3-to-8 line decoder is used to address the 74HC367. A6 and A7 are forwarded to the i2c data and clock line while the i2c data line is also read and returned in D7. When the i2c bus is selected, the upper 4 drivers of the 74HC367 are enabled. Then A6 and A7 are forwarded into the lower two drivers. When the upper drivers are disabled the resistors R1 and R2 feed back the output of the lower drivers to their inputs thus making them state keepers. So the low or high state of the i2c data and clock outputs are preserved until the next access is made to the 74HC367. The timing and protocol of the i2c bus must implemented in software. The i2c bus is optional but recommended unless you want to build a one-task computer which does not support to be extended later.

The two LEDs D4 and D5 may be attached here during debugging. As the 68008 CPU board does not have any I/O pins whatsoever, i have spent some time searching for a place to attach some status lights for initial testing. The LEDs should be removed when an I/O board is attached, because the LEDs may disturb operation of the i2c bus.

The two 74HCT574 data latches expand the 8-bit 68008 data bus to 16 bit for the K1-Bus. This is optional and only required if 16 bit extensions are actually attached. A serial card will probably be only 8 bit wide, but an IDE interface will most likely use the full bus width.

When 16 bit data is written to the bus this is done in two stages: First the upper byte is written into the 74HCT574 low-to-high data latch. One output of the 74HCT138 3-to-8 line decoder provides the !WR_HI strobe. Next the low byte is written to the !WR_DATA address as usual. While the CPU provides the low byte the latch outputs are enabled simultaneously and put their data on the upper half of the bus.

Note that only A0 discriminates between !WR_HI and !WR_DATA. This way the program can perform a 16 bit write opcode to the even base address: The high byte will be written first to the even address (A0=0) and the low byte thereafter to the odd address (A0=1). That's really sweet! :-)

When 16 bit data is read from the bus this is also done in two stages: First the low byte is read using !RD_DATA as usual. This will also load the high byte from the K1-Bus into the high-to-low data latch. Then the high byte can be read from the latch. For this the 74HCT138 3-to-8 line decoder provides the !RD_HI strobe.

Reading a 16 bit word is not as convenient as writing. Again !RD_DATA and !RD_HI are chosen to differ only in A0 and the word can be read with one 16 bit read opcode, but the result will be byte-swapped. This cannot be avoided except with some more latches and drivers. So the program has to swap them thereafter and as the 68000 does not provide a byte-swap opcode (though it provides one for word swapping) the best is probably to do an 8-fold rotate left or right on the word data which is a 24 clock cycles time consuming operation.

There are some pull-up resistors and networks related to the K1-Bus:

The !K1_IRPT collector line has a pull-up because it must be driven with open drain outputs.!K1_RESET line has a pull-up for the same reason.!K1_WAIT has a pull-up in case no peripheral board is selected. Whenever a board which uses the wait line is selected it must drive the wait line with a tri-state driver which actively pulls high and low. When a board is not selected it must not drive the wait line.

D0..D7 are pulled high with 3.3kΩ resistors. The data bus of the CPU is connected without bus drivers to the K1-Bus. This is possible for very small projects because the K1-Bus is defined to attach CMOS devices which draw only very little current, though switching the level on a line draws some current for the line capacitance which increases with line length and every device attached.

The 68008 CPU outputs TTL levels with very poor high-driving capability: 0.4mA only. The K1-Bus is defined for symmetrical signals as used by 74HC or 74AC types. This is in general no problem, only some timing parameters will shift a little. But as the 68008 can only drive 0.4mA high (and still guaranteeing only 2.4V, so effectively driving even less than 0.4mA) these resistors are there to help the CPU with the '1' bits. 3.3kΩ result in 1.5mA when the outputs are low which is approx. 1/2 of what the CPU can drive low. Peripheral drivers also must provide this additional current for low bits, but 1.5mA should be ok with almost any IC.

A0..A5 (on the K1 Bus) are pulled high for the same reason.

A6 and A7 are pulled high for the same reason because they are attached to the 74HC367 which is not a 74HCT367. I'm too lazy to modify the circuit for a 74HCT367 and i have HCs in stock, HCTs none.

More random notes:

The 74HCT574 high-to-low and low-to-high data latches were chosen to use HCT because when the CPU can operate the bus with TTL levels then the latches can do this as well. No need to read some data lines with HC circuits – keep it consistent.

This CPU board can attach 16 bit K1-Bus extension boards. This means, it can read and write 16 bit data. But it cannot use the upper byte of the data bus for board selection: !SELECT, !RD_IRPT and !WR_IRPT all do not trigger a read or write of the high-to-low / low-to-high data latches. Therefore peripheral cards are limited to D0..D7 for selection.

2014-01-26

The design phase is coming to an end now, if no problems show up during verification phase later, this will be the main circuit:

K1-Bus 68008 CPU board with SRAM – Main Circuit

Connection of the static Ram and Eprom are straight forward. Ram is mapped starting at address 0x00000 and the Eprom is mapped starting at 0x40000 by use of the 2-to-4 line decoder IC2A.

After power-up the Eprom is forced into the address range of the Ram so that the reset vectors can be read from Rom. This is done by diode D2 which pulls the input A0 of IC2A high while the two-NAND-gate flip flop is in the power-up state.

The address decoder ICB2 either activates !DTACK or !VPA to terminate a bus cycle. !VPA is activated for addresses with A19=1 and A14=1 which will perform a slow 6800-style memory cycle, for all other addresses !DTACK is activated. K1-Bus peripherals may add wait states by pulling !K1_WAIT low. By choice of A14 to discriminate between fast and slow I/O all peripherals can be accessed using short addressing with A15 to A31 all '1'.

Multiple bus masters and single-stepping using the !HALT input are not supported. Bus errors are not detected. All bus cycles will terminate, unless someone pulls !K1_WAIT low. The CPU board does not have it's own timer interrupt and no own I/O pins. This must be provided by at least one attached K1-Bus peripheral board.

2014-01-25

As i expect my 68008 computer not to work with an empty Eprom, i will probably have to program it. For this i have bought some years ago a Genius NSP universal programmer from Shenzhen Stagger Electric. No need to remember this name, they are probably folded. For good reason.

I had installed the software on some kind of old Pentium Desktop running Windows 98 which i kept for this purpose only. But it's sitting in the Loft and i'd need to find a free space to work with it. Frankly, i want to get rid of it.

The idea is to install a Windows in Virtual Box on my Mac. I have already a Linux Mint running in Virtual Box (every now and then) and i know there are free pre-built images of this or that operating system available in the net. I thought, i'd pick an XP image, get an XP license key from an unused pre-scrapped computer from my employer, install the image, register Windows and try whether i can attach the programmer through an USB-to-Serial connection.

Good news: Microsoft offers pre-built Windows images on it's web site for testing the IE and maybe non-commercial use (some websites say). They are not registered but they are freshly installed and the registration period has not yet started. Also, i got a Windows XP Home Edition key from my employer.

I downloaded one of the XP images available, figured out how to combine the split .rar archive which consisted of one .rar file and one .sfx file (how-to: make the .sfx file executable and execute it) and imported the resulting .ova Virtual Box Appliance into Virtual Box. Made a snapshot. Started it.

Step One: It was unregistered as expected and i tried to register my key. This did not work. It seems that the XP instance is a Windows XP Professional and probably this is the reason why the key is rejected. Ok, no problem, i have 30 days ahead.

Second step is to install an anti virus software. I downloaded it with OSX, dropped it in a shared folder and installed it in XP. Yeah!

Third step is to install Firefox. :-)

Fourth step is to install this piece of crap, erm, the software for the Genius NSP programmer. I was afraid it could be on floppy disk, but it was on CD, and, yes, important, on a full-sized CD. I have a slot-in CD drive in my Mac and this matters. Installation worked within few seconds. My Mac is SO fast! :-)

I attached the programmer with an USB-to-Serial adapter to my Mac and started the software. As expected the software did not find the programmer. Ok, let's figure out why.

Windows does not see the adapter. I investigate settings for the virtual machine and found a place to enable this specific USB device which instantly bothered me with the next problem: USB 2.0 controller enabled – you need the VirtualBox Extension Pack. Googled for it, downloaded it from Oracle, it automatically installed into Virtual Box – fine!

After starting XP again and waiting for some seconds, it found 'new hardware'. Do i have a driver disk? hmm, no. Shall i search online for a driver? – yes. Wait. wait. I didn't find a driver. Mist. (Did it ever find a driver this way?)

I figured out what is inside the USB adapter – a Prolific Technology Inc. USB-Serial Controller C, product ID 0x2303. So i downloaded the PL2303_Prolific_DriverInstaller_v1_9_0 driver from the Prolific website from OSX, moved it into the shared folder and installed it in XP.

Ok installed. What's next? The Stagger software still doesn't find it. Hmm, given my experience with Windows i restarted it. And yes, now there is a Prolific USB-to-Serial Comm Port in the Device Manager and – ta ta – the NSP software can talk to the programmer! That's not a matter of course, because even if the serial communication works the software may do some weird things with the serial port, like bit-banging, and that is likely to fail with an USB adapter.

2014-01-23

yesterday i searched for some of the parts and put the 68008 on the bread board. According to other projects it is possible to do a "free run" by pulling all data lines to low. Though some people say it's the opcode of NOP it actually is some kind of ORI.

I wanted to check some prerequisites of the project:

Does the CPU work?

Can !DTACK (data acknowledge) be held permanently low?

Can !VPA (valid peripheral address) be used for instruction fetch cycle?

ad 1: Yes the CPU works. It cycles through it's address space and toggles A19 with 2 Hz.
ad 2: Yes, as i could tell the CPU works. :-)
ad 3: For curiosity: Yes. I believe that bus cycles and internal logic are completely separated and !VPA can be used for any bus cycle.

Next interesting question: Can i put videos in my blog? It seems i can, but for a final verification i probably have to publish this page.

Update: They are just converted into poor animated GIFs. I'll have to find something better... ok, uploaded them to youtube and embedded. back to the roots...

Free Run using !DTACK-terminated bus cycles

To the left is the 68008 on my bread board and wired up to us !DTACK to terminate bus cycles. !DTACK is permanently low (active) and the CPU runs as fast as it can: At 8 MHz it does 2 opcode fetches per µsec or 2,000,000 opcode fetches per second. As the whole address space of the 68008 is 1 MB only, it cycles through it's address space 2 times a second. The most significant address bit A19 should blink with 2 Hz. A19 is the leftmost LED in the video and i hope you can verify that it blinks with 2 Hz. Thanks.

An important result is that the 68008 actually works without deactivating !DTACK after each bus cycle. Though in all timing diagrams bus cycles start with !DTACK high it is actually possible to keep it low the whole time.

Free Run using !VPA-terminated bus cycles

In the second video i used !VPA to terminate the bus cycles instead. This mode is intended to access old (really old!) 6800 peripherals but it seems true that you can terminate any bus cycle with !VPA, even an opcode fetch cycle. It's just slower. I was curious how slow actually, if every bus cycle uses !VPA, because the 68008 data sheet say it can be from 11 to 18 clock cycles long.

The latter puzzled me, because of course i started with the 68008 documentation, because that's the CPU i'm using, and i was wondering how fast the 68008 could uninterruptedly access the bus using the !VPA mode as 11 cycles is slower than the period of the free running E signal to which !VPA bus cycles are synchronized. But 10 to 19 makes sense (while 11 to 18 makes not) and i found an unnamed cycle in the 68008 manual's 'best case' chart (between the last 'w' cycle and 'S5') and i believe that someone reviewed the charts, found that the 'worst case' chart was only 18 cycles instead of 19 cycles long, demanded a correction and the missing cycle was added ... to the wrong chart. That's how real world works.

In the second video one bus cycle takes 10 clock cycles instead of 4 and therefore A19 should blink with 2 Hz *4 / 10 = 0.8 Hz instead. I think this approximately true.

In my project the !VPA bus cycle is used to access slow peripherals on the K1 bus. But it is also used during interrupt acknowledge, in order to use an auto vectored interrupt. Now the interesting question is: Does the CPU actually perform a !VPA controlled bus cycle here or a dummy cycle, as it ignores the byte read?

!VPA used in interrupt vector read cycle

My guess was, that it actually does a !VPA controlled slow bus cycle if you activate !VPA, making interrupts approximately 10 clock cycles slower. And finally i found this chart on the last (!) page of the M68000 8-/16-/32-Bit Microprocessors User’s Manual Ninth Edition. The last pages are appendix B which is about interfacing 6800 devices and which are pasted into the document as bitmaps only. :-)

The bus interface performs a slow memory cycle in the (dummy) interrupt vector read cycle if !VPA is activated to request an auto vector interrupt.

i was reminded to the fact, that the 68000 has something called short addressing: Instead of supplying a 4-byte long address you only supply a 2-byte short address which is sign-extended to 4 bytes. This saves space in program code and – more important – up to 8 CPU clock cycles. So i took a look at my current address layout:

v0.2 address decoder

This allows the first 32k of RAM to be accessed with short addressing as well as the slow I/O address range, but not the fast I/O range:

%xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx selects RAM and%00000000,00000000,0xxxxxxx,xxxxxxxx is a possible subset of this which fit's in a signed word.

%xxxxxxxx,xxxx01xx,xxxxxxxx,xxxxxxxx selects ROM and can never be accessed with short addressing.

%xxxxxxxx,xxxx11xx,xxxxxxxx,xxxxxxxx selects slow I/O and%11111111,11111111,1xxxxxxx,xxxxxxxx is a possible subset of this which fit's in a signed word as a negative value.

%xxxxxxxx,xxxx10xx,xxxxxxxx,xxxxxxxx selects fast I/O and can never be accessed with short addressing.

In order to make all I/O short addressable, all I/O must have A31 .. A15 high. A18 cannot be used to select between slow and fast I/O. The first Address line which can be used for that is A14:

v0.3 address decoder

Now the memory map is as follows:

%xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx selects RAM and%00000000,00000000,0xxxxxxx,xxxxxxxx is a short addressable subset.

%xxxxxxxx,xxxx1xxx,x1xxxxxx,xxxxxxxx selects slow I/O and%11111111,11111111,11xxxxxx,xxxxxxxx is a short addressable subset.

%xxxxxxxx,xxxx1xxx,x0xxxxxx,xxxxxxxx selects fast I/O and%11111111,11111111,10xxxxxx,xxxxxxxx is a short addressable subset.

There is no need to apply the post-reset INIT line pull-up to A14 for the I/O address decoder and there is no need to strobe the outputs with !AS because the I/O control lines are strobed by !AS directly at the 74HC138 which generates them (see other sheet – next to come :-)). It's even better this way because now !SLOW_IO which is directly connected to the CPU's !VPA input to request slow I/O or an auto vector toggles before !AS is valid and not shortly thereafter.

Funny Note

Actually this second 2-to-4 line decoder could be replaced entirely by one NAND gate: !FAST_IO is not used anywhere (actually it is currently used to reset the INIT line, but this could have been !SLOW_IO as well) and !SLOW_IO becomes low when A14 and A19 are both high, so, yes, that's a NAND function. The NAND gate would even be faster (the 74HCT139 is pretty slow) but – i don't have a spare NAND gate, but i had a spare 2-to-4 line decoder. :-)

2014-01-18

Now to something very simple which i always have problems with: The reset circuit. It's only made from few parts but it's ANALOGOUS. (shiver!)

Let's start with the requirements:

For unknown reasons the 68008 CPU needs an excessively long reset pulse after power-up: 0.1 seconds! Because there are other circuits which may pull !RESET low, most namely the CPU itself, !RESET must be driven with an open collector or open drain output.

To the right is an image of the current circuit:

Let's discuss it. This is very important because it's analogous and most times my analogous stuff doesn't work.:-/

Start with R9 + R4 and ignore the rest: These two resistors form a voltage divider for Vcc and the voltage in the middle is 2.5V. (5V/2)

Now add the capacitor: Initially it is discharged and behaves like a piece of wire. But as time goes by and current flows through it (and through the voltage divider) it charges and voltage across it increases which subtracts from the voltage present at the voltage divider. So the middle voltage of the voltage divider starts at 2.5V and drops over time to zero.

Next add transistor T1: The first effect is that the middle voltage is shorted by the base-emitter diode of T1 to ground, so the middle voltage is initially 0.7V, which is the break-through voltage of the diode, stays at that voltage for a while until it drops below 0.7V and resumes dropping as with no transistor present.

While there is current sinked through the base-emitter diode, the transistor switches on, sinking the !RESET line to ground. As soon as the base-emitter voltage drops below 0.7V the transistor will switch off and !RESET rises to Vcc. We only have to choose the capacitance and the resistors appropriately, so that this will happen after approximately 0.1 second.

But that's only half of the story: The transistor is not switched on or off depending on the voltage at it's base pin, instead the amount of current it can sink is a function of the current through the base-emitter diode. While this diode keeps the voltage at the base pin at 0.7V, the current through the diode needed to do this decreases as the voltage at the voltage divider decreases. So at some point in time the transistor is no longer fully able to sink all current from the !RESET line but only a part of it and the voltage on the !RESET line will not switch instantaneous to Vcc but will rise slowly.

This is totally unreliable. !RESET must go away very fast, ideally within one CPU clock cycle. This is where T2 and it's two associated resistors enter the game: While !RESET is low T2 is switched off and the circuit behaves as if T2 wasn't there. But when !RESET slowly rises above 0.7V T2 will start to sink current. This will subtract from the base current of T1 which will in return sink less current from the !RESET line and the voltage on the !RESET line rises even more which will open T2 more which will ... Yes, a positive feedback and !RESET will rise very fast once it has reached 0.7V.Now let's examine power-up and power-down behavior.

At power-up C1 is empty. But the state of the !RESET line is unknown. If it rises with Vcc then T2 will be open right from the start and may finish the reset pulse before it has been activated at all. It's very likely that it will do this because of the pull-up resistor on the !RESET line. To prevent this the voltage at the base of T1 must be asserted to be clearly above 0.7V when C1 is empty: This is true with the given values for R4, R9 and R12 (all 50kΩ) because when C1 is empty the voltage at the voltage divider will be 1/3 Vcc which is approximately 1.65V and which will be sinked through the base-emitter diode of T1, opening T1 which will pull !RESET low. Check.✓

After a while capacitor C1 is loaded (nearly) to Vcc and the input of the voltage divider is Vcc minus Vcap which is (nearly) 0V. When power is switched off, Vcc drops to 0V but the capacitor is still loaded, so the voltage at the voltage divider drops to -Vcc. We'll have to check the circuit that this does no harm. Check.✓

Now the capacitor must be discharged, so that it is discharged when power is switched on again. This happens through the voltage divider R4+R9 in approximately the same time as was required to load the capacitor after power-on. Check.✓Last step: calculate the values.!RESET is pulled up by a 5kΩ resistor which sources 1mA at Vcc=5V and there is some more circuitry attached, so let's say T1 must sink 5mA.

T1 may have a current amplification of 100 (this is a value which widely varies even for transistors of the same type) so the base-emitter current of T1 must be ~ 0.05mA.

This current must be sinked through the base-emitter diode of T1 even after C1 has charged to – let's say – 1/2 and the remaining voltage at the voltage divider is 2.5V. This leaves a voltage drop of ~2V across R9. Using the formula U=R*I <=> U/I=R we calculate the value for R9 = 2/0.05e-3 = 40kΩ.

Next the capacitor voltage must rise 2.5V (see above) during 0.1s while being loaded with 0.05mA. The formula for the capacitance is: C = I*t/U. So C1 = 0.05e-3*0.1/2.5 = 2µF. Because the calculation is very rough (actually we ignore R4 which sinks some current as well and we should integrate the current over time because it's not const) so we double the capacitance. Fine adjustments will be made when it is built on the bread board. :-)

Note: You didn't remember the formula for the capacitance? Using ISO units (not inch, miles and gallons) you don't need to look up the formula, you can construct it by pure logics:

Using ISO units there will be no constant factor in the formula. Yeah!

therefore: C = I * t / U.

Alternatives We could use a timer IC for the reset circuit, most likely a 555. But this would have a larger footprint than the discrete solution. Else we could use a mono-flop from the 74 series. But basically this increases the footprint even more (14 pin DIP instead of 8 pin DIP).

Or use a counter. But even if fed from the E output of the CPU (which is CLK/10) we'd need to count up to 100,000 for 0.1 seconds which is impractical.

I have also seen using a PIC for reset (basically because the project used a PIC for various control purposes) but using a CPU to generate the reset pulse for a CPU is a little bit ... over designed.

Update: Reset Circuit Test on the Bread Board

Today i tested the circuit and as expected it did not work as expected. Let's see why. For your convenience to the right is another image of the circuit.

As discussed above resistor R12 must be high enough so that T1 actually switches on at power-up.

Full flip requirement:

But there's another requirement for R12: It must be able to sink the whole current which flew through the base-emitter diode of T1 when T2 switches on. Else there will be some base current left at T1 and it will not fully close and therefore the voltage at the reset line will not fully rise to +5V.

To estimate this current is a little bit tricky: It depends on the pull-up current on the reset line and the transistor's current amplification. Worst case is high pull-up current and low current amplification:

Immediately after power-on we require that T1 opens, even if T2 is also open due to the pull-up resistor on the reset line. For practical reason we assume C1 not completely empty but discharged to 1V, which leaves 4V at R9. So the current across R9 is:

So R12 must be at least 112.5kΩ to ensure that T1 is initially open at power-up even if T2 is open.

Gotcha! We're trapped!

Can we solve this?

First, we were calculating with worst-case values. We could require better worst cases. Second, we can adjust R4.

Power-up requirement with new R4 value:

R4 is used to make the circuit a bit independent of the current amplification of T1 and of the pull-up current on the reset line and it is needed to discharge C1 when power is off. We can't remove it entirely but we could double it's value which will half the current through it and redo the above calculations:

IR4 = 0.65 / 100kΩ = 6.5µA

IBE ≥ 50µA

IR12 ≤ (67µA-6.5µA-50µA) = 10.5µA

R12 ≥ (0.65V-0.2V) / 10.5µA = 43kΩ

Now R12 must be at least 43kΩ to ensure that T1 is initially open at power-up even if T2 is open. Much better. :-)

Full flip requirement with reduced maximum pull-up current on the reset line:

The other two screws are the current amplification of T1 and the pull-up current on the reset line.

The allowed pull-up current was defined as 5mA which means a pull-up resistor as low as 1kΩ. Let's reduce this to 2.5mA which is still much more than we expect, because the actually used value is 5kΩ, but there may be some current added from the attached devices, though this should be negligible. Let's redo the calculations:

IBE ≥ 2.5mA/100 = 25µA

R12 ≤ UR12 / IR12 = (0.65V-0.2V) / 25µA = 18kΩ

So R12 must be at most 18kΩ to ensure a full flip when T2 opens.

Power-up requirement with reduced maximum pull-up current on the reset line:

IR4 = 0.65 / 100kΩ = 6.5µA

IR12 ≤ (67µA-6.5µA-25µA) = 35.5µA

R12 ≥ (0.65V-0.2V) / 35.5µA = 12.75kΩ

So R12 must be at least 12.75kΩ to ensure that T1 is initially open at power-up even if T2 is open.

Both requirements are met if we use 15kΩ for R12. Fine. :-)

Reset circuit with validated resistor values

To the left is the updated reset circuit as tested on the bread board. Actually i had still problems with the power-up reset if C1 was not completely empty, but that was due to a LED which i connected to the reset line to show it's state. It had clearly more than 5mA.:-)

2014-01-17

i worked on the main circuit and removed 2 (two!) of the four glue logic ICs. Wow! This is near-Sinclair. I could remove one more IC and become equal-Sinclair. Or remove both remaining glue ICs and become super-Sinclair.

What does this nonsense mean?

You know i come from the Sinclair ZX Spectrum side of the universe (as opposed to the C64) and i have certain ideas about how Sir Sinclair worked. What he did was like this:

Use the cheapest components,

reduce the design to the absolute minimum

and then take away one more part.

That is equal-Sinclair. It seems that Sinclair is a measure for uselessness. Currently my design is only near-Sinclair, because i still could take away some parts. Let's take a look at the current circuit (version 0.2) and discuss it:

Hint: right-click on the image and open it in another window if you want to keep it visible while you read on!

As you can see there are only two glue ICs: one Quad NAND 74HCT00 and a Dual 2-to-4 line decoder 74HCT139 with only one decoder actually used.

The 2nd NANDIC7C is used as an inverter and constructs a !RD signal from the CPU's !WR signal, required by the RAM and the ROM.

The next two NANDs construct a flip flop, which is set by !RESET to indicate the initialization phase after system reset. The INIT signal from this flip flop is used to pull A18 high at the input of the 2-to-4 decoder IC2A. (The resistor R5 and the diode D2 actually construct an OR gate without wasting 3 unused gates in a 74HCT32.)

This is used to circumvent a design flaw in the 68000 microprocessor series: After reset the supervisor stack pointer and the program counter are read from addresses 0x00000.l and 0x00004.l respectively so there must be ROM mapped in. But then the whole vector table of the cpu is located here; actually roughly the first 1 kByte of memory is used for vectors. It is very desirable to have these in RAM because otherwise you cannot change them without a secondary vector table in RAM which is jumped to by the vectors in ROM. So you need ROM after reset but you prefer RAM here at any other time. The normal memory layout is RAM at address 0x00000 as you can see from the 2-to-4 decoder outputs, but during initialization A18 is pulled high so that the processor, when trying to read from address 0x00000 and 0x00004 reads from the ROM instead. After that the first memory access to the slow I/O address range will also reset the NAND flip flop and A18 is no longer forced high and the RAM can be accessed.

After we know where the !SLOW_IO signal comes from we can understand what the first NAND gate IC7D does: If !WAIT is high and !SLOW_IO is high then the !DTACK signal to the CPU is low (asserted). The !DTACK signal is used to terminate a normal bus cycle of the CPU, either memory or other bus access. !DTACK will not be asserted when !WAIT from the K1 bus is active, thus implementing the wait processing for the K1 bus, or when !SLOW_IO is low which means a memory access to an address with A18=1 and A19=1. This memory range is used for slow I/O (sic!) and shall use the 6800 peripherals slow addressing mode, which is signaled to the CPU by pulling it's !VPA entry low instead of activating !DTACK. You can see that !SLOW_IO is directly connected to !VPA of the CPU. So either !DTACK is asserted (for the first 3 memory ranges, eventually suppressed by !WAIT) or !VPA.

Trick: Connecting !SLOW_IO to !VPA has a second effect: This also requests the CPU to use an auto-vector from it's vector table for interrupts. When an interrupt is acknowledged and the CPU reads the vector number for this interrupt, most address lines are pulled high, most notably A18 and A19, which will activate !SLOW_IO which activates !VPA which requests an auto-vector if it is pulled low during an interrupt acknowledge cycle. We only have to take precautions that this not also performs spurious I/O on the K1 bus; but that's on the other sheet. :-)

That's all about the glue logics. Not supported are:

Bus arbitration for multiple bus masters

Bus error or any other exception signaling

How to become Equal-Sinclair

Let's remove the Quad NAND IC. Will it still work?

If we remove the first NANDIC7D then we'll lose wait handling for the K1 bus. Ok, well, that may be acceptable. But we'll still need an inverter here to invert !SLOW_IO to !DTACK.

To solve this, we could connect A19 directly to !DTACK, so whenever the CPU accesses RAM or ROM !DTACK will be asserted. But then we'll lose !FAST_IO because whenever !DTACK is not asserted !VPA must be asserted instead to finish the bus cycle. So !VPA must be connected to !A19. How can we invert A19? We can use the unused gate from the Dual 2-to-4 decoder. If we have no fast I/O we also need no wait cycle handling. :-)Check.✓

If we remove the second NANDIC7C then we'll lose the !RD signal. This is acceptable: !OE of the ROM can be tied high so whenever the ROM is enabled it puts it's data on the bus. Disadvantage: If the CPU writes to the ROM then there'll be a collision on the data bus. We'll have to be cautious.

!OE of the RAM can also tied high. When !WR is enabled this will supersede the !OE signal. (eventually this is not true for all RAMs, but RAMs exist which can be operated in this way). Check.✓

If we remove the NAND flip flop, we'll no longer have the INIT signal. Ok, let's remove the resistor-diode OR gate as well and let's swap !ROM_CE and !RAM_CE. ROM has to be at address 0x00000 and we can't modify the vector table in ROM. Check.✓

Summary: Yes, we can become Equal-Sinclair! We just have no fast I/O and we'll have to live with the vector table in ROM. That's easy.✓✓✓

How to become Super-Sinclair

Obviously we must remove the Quad 2-to-4 line decoder as well. Will it still work? Ok, that's real hard, but Super-Sinclair IS real hard. You get a "Sir" for Equal-Sinclair, right?

First let's remove the gate used to construct the inverter for address line A19 which we just have added to become Equal-Sinclair. Now we have the choice: We could build an inverter from two resistors and one transistor or we could ... leave it out. Yes, that's what Sir Sinclair had done. :-)

We either need !VPA to be asserted during interrupt acknowledge or we must to supply a vector address. Both is possible:

Supply !VPA: Tie !VPA fixed low and !DTACK fixed high and the CPU will do all bus cycles in 6800 mode. Will be a little slow though. We'll have slow memory access and only slow I/O.

Supply !DTACK: Tie !VPA fixed high and !DTACK fixed low and the CPU will do all bus cycles in standard mode. We'll have fast I/O (with no wait cycles) but no slow I/O. During an interrupt acknowledge cycle we'll have to provide a vector number on the data bus. We can use a resistor network to pull up all data lines if no one else drives the bus, then the vector number will be 0xFF (255). Check.✓

Yes, we can! We can use 3 address lines directly to do that:
• Use A17 for !RAM_CE,
• A18 for !ROM_CE and
• A19 for !FAST_IO.

Drawbacks:
Each range is limited to 128 kByte. (A0..A16) Accepted.
There will be be bus collisions if the program accesses addresses with more than one of A17 .. A19 low. Accepted.
There may be short bus collisions when the address lines toggle between bus cycles. Accepted.
After reset the CPU will read from address 0x00000.l and 0x00004.l Uh uh... This will read from RAM, ROM and IO simultaneously. And any other vector will be read from this page with triple-collision as well. That's bad.

I'm a programmer and i'm here to find solutions: We have to disable RAM and IO when the ROM is selected. This will also reduce the forbidden address ranges with bus collisions.

We can get the RAM out of the way by its positive CE input. Yeah, it has one. Look at the circuit diagram. Just connect RAM.CE to A18 (!ROM_CE). When the CPU reads any vector from the first kByte of memory then A18 will be low and the RAM is not enabled. Check.✓

Next we can suppress the K1 bus control signals in a similar way: As you not yet know they are generated with a 3-to-8 line decoder 74HC138 which has two negative and one positive enable input. We can connect A19 (!FAST_IO) and !AS to the negative enables, and A18 (!ROM_CE) to the positive enable. Check.✓

Summary: Yes, we can become Super-Sinclair! We just have only fast I/O with no wait cycles, we'll have the vector table in ROM and we are limited to 128k ROM and 128k RAM and there is a risk of bus collisions if the program accesses forbidden address ranges and there may be regular very short bus collisions between each bus cycle.Accepted. Design finished, let's ship it. ;-) Check✓ Check✓ Check.✓

Update: For completeness here is the main circuit of the Super-Sinclair design. Of course i won't build it this way, because, as said above, Super-Sinclair means reduced beyond usability.

2014-01-14

one of my weird ideas is to build a microcomputer with every CPU i own. Ok, maybe not really *every*, but some of them i memorize with nostalgia. These are:

Z80 with SRAM

Z80 with DRAM and paged memory

68008, one with SRAM and one with ~ 2MB DRAM SIMMs

68000, let's see

68020, eventually with FPU

68040, with ~ 64MB DRAM PS2-SIMMs probably

All of them will connect to the K1 Peripheral Bus, so that half of the work is already done. ;-) Beyond that, no I/O will be implemented on these boards.

You see, in essence these are two processors. I started with a ZX Spectrum and proceeded with an Atari ST before i entered the world of Apple, Linux and not Windows.

68008 SRAM Microcomputer

Let's start with the 68008. I have both, the DIL and the PLCC variant. I'll use the DIL version for the SRAM board and the PLCC version for the DRAM board, because it can address more memory: 4MB instead of 1 MB only.

The 68008-SRAM board will the half sized – 79x100mm – pretty tight, but it will fit. The 68k CPUs are a little bit nasty to integrate into a system, because they have quite a lot of requirements, especially the 68008 which implements an asynchronous bus model. But i'll use any trick, cheat and simplification i can find to make it fit. :-)

Basic Requirements

68008 PDIP CPU

Eprom 32 .. 256 kByte

SRAM 128 or 256 kByte

K1-Bus half-sized card

Project Page

The Board

Layout v0.1 2014-01-14

To the left is a first layout of the board with all components required for the current circuit.

The top row ICs are glue logics.
To the left is the K1-bus connector.
The circuits to the left of the CPU connect the CPU to the bus.
The two 74HC573 registers expand the 8 bit bus of the 68008 to the 8 or 16 bit K1-bus.
The 74HC367 hex driver plus some resistors implements the i2c interface.
The 74HC138 decodes the strobe signals for the K1-bus.
In the center of the board is the CPU
and right of it the SRAM and the Eprom.

Requirements and Simplifications

• Memory Map. Memory is divided into 4 sections: RAM, ROM, fast I/O and slow I/O each of which is 256 kByte in size. This limits the size of the RAM and Eprom.

• CPU Clock. This is generated by a 10 MHz clock module. I avoid the hassle of generating the clock signal "by hand" with a quartz and inverters.

• CPU Reset. The 68000 family needs 0.1s low on Reset and on Halt for power-up initialization. This is currently done with some R and C and a Schmitt Trigger inverter.

• CPU DTACK. The 68008 needs an acknowledge for every memory read or write access. By delaying this signal you can add wait cycles. By never asserting this signal you can make the CPU hang for ever. This signal will be handled in the most simple way possible: It is tied to ground and this way always asserted. According to some other 68008 projects, where they do this for the test run on a bread board, this should work. Drawback: No wait cycles possible. I'll need a reasonably fast Eprom and SRAM. This also applies to the fast I/O.

• Bus Error. DTACK is always asserted and BERR is tied to Vcc. There will never be a bus error.

• Bus arbitration. The K1-bus does not support multiple bus masters and so does this board: bus request BR and bus grant BG are not used.

• Interrupt control. The 68008 PDIP has two interrupt input lines which can encode 4 states: no interrupt, 2 normal, prioritized interrupts and a non maskable interrupt. The only source for interrupts on this board is the K1-bus and so i need only one normal interrupt. The K1-bus supports prioritized interrupts by enabling/disabling interrupts directly on the attached extension cards.
Now the nasty thing: Devices must provide an interrupt vector during the interrupt acknowledge cycle. An automatic vector can be requested by asserting VPA and so we need to know when a bus cycle is an interrupt acknowledge cycle. For this we must decode the Function Code outputs FC0, 1 and 2 which are all '1' during an interrupt acknowledge bus cycle.

• K1-bus access. As said above there are two address ranges for the K1-bus: fast and slow.
The idea is to use a standard memory cycle for fast I/O where wait cycles are not supported because DTACK is permanently asserted. This is suitable for very fast peripheral cards and for switching interrupts and i2c on the K1-bus.
For slow devices i want to use 6800 peripheral I/O cycles by asserting VPA (valid peripheral address) in this address range. This will do a bus cycle synchronized with the free-running E output of the CPU (which has a fixed period of 10 CPU clock cycles) with at least 11 and at most 18 CPU clock cycles due to synchronizing; and no wait states because of the fixed alignment to the E signal. Eventually i'll come up with something better here.

• CPU VPA. This input was already discussed in two requirements above: Interrupt control and K1-bus slow access. During an interrupt acknowledge cycle it is pulled low to request an automatic vector (interrupt routine start address) and in slow I/O it is pulled low to request a slow 6800 peripheral bus cycle.

• K1-bus 16-bit I/O. Peripherals on the K1-bus may use 16 bit I/O. The 68008 has only an 8 bit data bus. There are two possibilities: I use it 'as is' and attach only 8-bit extension cards. Or i add 2 latches to store and receive the upper byte during a 16 bit I/O. I have some K1-bus cards which use the 16 bit bus, most namely the IDE board because IDE is 16 bit wide, and so i'll invest in two '573 data latches.

• K1-bus i2c. Peripheral cards on the K1-bus can have i2c EEproms to signal presence of and identify the card and to provide a universal byte-coded drivers. This costs one '367 hex driver IC plus some resistors. This makes it possible to add arbitrary cards to the microcomputer.

• ROM and RAM. The EPROM and the SRAM may be up to 256 kByte in size each. Due to space constraints only one SRAM IC is possible. Memory access cycles of the CPU are without wait states (see DTACK above) and therefore the memory ICs must be fast enough: Scrutinizing the bus cycle timing charts i expect that 150 ns access time will do it; eventually up to 200 ns will work.

• System Timer. There is no system timer on the board. Instead it is expected that one of the K1-bus cards supplies one. This is fairly easy, because my serial cards with one (or more) 88C192 dual UARTs can supply this.

• Serial and Parallel Ports. Any connection to the outer world requires a K1-bus extension card.