2012-06-27

Start on blogger.com

Hello,
I'm building a CPU for 4 years now (more or less) and accompanied this on my home page k1.spdns.de. This worked quite well but i wanted to separate the blog from the project documentation itself and i wanted to enable some feed back. So i started this blog on blogger.com. I will move some stuff in here which previously was on my website; i'll see whether i can fix the dates.

     ... Kio !

2012-06-12

2nd Display

Going into mass production. ;-) I built a second, very similar LCD display which uses the same controller board. This one has a backlight, but it was CCFL. I had no inverter and building one and adapting it to the CCFL wold have taken too long and so i replaced it with an array of LEDs. Not good but working. See the photos on the LM64K101 - LCD Display 640x480 project page. Next is to debug the terminal software a little bit more and use it as output for the computer.

2012-05-26

Debugging the LCD Display Driver and Hardware


This week i worked on the 640x480 pixel b&w LCD terminal.  Soldering was easy, but fixing all the bugs took some time. I also had  to do some changes to the terminal code because i realized that i was using the LCD upside down.

I connected the LCD and powered the board through the programming  header. Off course nothing worked, except for the display refresh routine, which brought up a picture of the erased DRAM cells. Step by  step i brought up more functions: Erase screen, print characters, read  and write whole pixel lines and scrolling. I had to add some nops to the DRAM read and write timing, because the data goes through series resistors which create some delay. For the next board i'll reduce them slightly. Then printing of standard-size characters with 4 attributes in all combinations works.

 Finally one last important step: Attach it via serial line to USB to my Mac. Nothing worked. I adjusted the Baudrate on both sides. I printed text from the LCD terminal on the serial line in an endless loop. There was no signal on the TxD line. Why? But there seemed to be a signal on the RxD handshake line. ... ???

I had connected data lines to handshake and handshake to data lines on the board. :-(. Fixed it with a cutter, solder and wire. Tested. Worked. :-)

2012-05-19

Debugging i2c


And on it goes. The last days i spent finding out, why the i2c interface did not work. Hardware is ok, it's a problem with the software. First i thought, all i2c eeproms have a block size of 64 bytes. But that's not that easy. Block size varies with eeprom size. And manufacturer… :-| But most 8k eeproms have blocks of 32 bytes and most 16k and 32k eeproms have blocks of 64 bytes.

Then busy polling after a block write did not work properly. I started a read cycle to detect the busy state (the eeprom does not respond if busy) but this behaviour is only defined if you start a write cycle. So i rewrote my source to do this.

Then somehow my start and stop sequences on the i2c bus sometimes failed. Now i test-read the data line to see if it is high and not pulled low by the target, for whatever reason.

Now access to the K1 bus eeproms works properly and hopefully reliably. I successfully downloaded the SIO driver code into the SIO driver eeprom and booted the CPU with driver initialization from eeproms, and not with data from the microcode. And it works! :-)

And, last not least, selecting the i2c eeprom on a K1 bus card works as planned: All eeproms are addressed with address 0b000, but only the eeprom on the currently selected extension card actually has this address. The i/o cards disable their eeprom while they are not selected, and the easiest way to do this is to set any address pin of the eeprom to '1', so that the address does not match.

2012-05-14

Debugging the SIO board


Instead of writing some 'useful' commands i spend the last days tracking down a weird error. When i activated the timer interrupt of the 88C192 UART to give me a system timer interrupt of 100 Hz, the whole system got stuck. The simulator worked, the real hardware stalled. Bad!

It took me some time with the minimalistic debugging facilities to come to the conclusion, that the interrupt does not go away. When i rewrote the RETI (return-from-interrupt) opcode to execute the next  opcode regardless of interrupt state the system made it to the shell prompt, though eating all the cpu power. This only happened when i enabled the timer interrupt, else everything seemed to be ok. I double checked my code three times. Have i a broken UART? Is the documentation wrong?
Finally, when i programmed the UART to the longest possible duration, this left ~90% cpu time in the 'Halt' state (at 8MHz). Some observations later i discovered, that interrupts came in bursts. I measured the burst rate: ~3.5Hz. I did a calculation of the interrupt frequency: 7.372MHz/32/0xFFFF = 3.515Hz. This proved, that the timer interrupt generated the bursts.

But why did the interrupt stay active for ~1/35 sec (given the 10% cpu usage) and then go away? I examined my circuit design very carefully ... VERY carefully ... this whole thing looke like a ... and there i got it: The /INT output of the UART is open collector and i had no pull-up resistor fitted there! Now all observations made sense. I soldered a 5kΩ resistor between 2 suiting pins, restored the SIO eeprom driver, compiled the microcode rom, uploaded it to the front panel, resetted the cpu from the front panel eeproms and yepp, it worked! :-) The timer interrupt now eats approx. 1% (at 8MHz).

2012-05-02

Debugging the CPU

2012-05-02

I'm now moving back from emulation to the real hardware. I expected problems, and there they are.
Somehow upload of microcode files to the front panel did not work. First it hangs with XOFF, so i disable XON/XOFF and lower the baud rate. Then it transfers up to address 0x4A00 and aborts with an error. Each time i try to do 'something' to find out the cause the error changes. Finally i find out that at that position is the first unused gap in the microcode and obviously refresehing the LCD is so time consuming that even the longest delay after one line of code (100ms) is not enough. Strange, when i re-enabled XON/XOFF it worked. So microcode upload to the CPU is working again.
Fundamental Timing of the K1-16/16 CPU
Now the code does not make it beyond the initial register test. Loading the SR (shift-right) register failed to load the CY input to data bit D15. I remember that there was a problem with exactly this when i tested it more than one year ago. I had settled my mind it was a contact issue and tried to prove this now again. But it isn't. Actually the little chart with the fundamental timing of the CPU contains the secret:
The blue clk is the load signal for the registers – SR is a register – and the rising edge is where it latches new data from the data bus and, in case of data bit D15, from the CY line. The CY line is a 'option control' line, it controls options in the various registers, if they have. As can be seen in the image the option control line toggles exactly at the same moment (if it toggles) when the clk line raises. So we have a race condition here.
The only thing i can do is to delay the CY option control line for the shift registers. I examined whether this problem will show up at other places too, but it seems not. Whereever CY (or any other option control line) is used, there are some gate delays between the option control line and the data latching register. So it's enough to delay this signal for SR and SL only. Luckily there is an unused OR gate on the data registers board which i will use for this.

2012-05-03

All test code performed without error. :-) Except for i2c test, because i have not yet attached any io device.

2012-05-04

Weekend … phantastic weather … what to do? ok, i manufactured the K1-system-bus. ;-)

2012-05-05

Tata! The SIO board works. Today i got the console prompt on the terminal. There are still some issues to examine: Speaking to the i2c eeprom did not work. The hardware seems to work properly, but the eeprom does not respond. This is to be investigated. Whether interrupts work as expected is still to be tested. Though they seem to work.

2012-05-06

Yep. Interrupts obviously work. SIO works: i/o to serial to my Mac works and i/o to the front panel works. Now i'll have to add some extras to the terminal in the frontpanel, e.g. handle some control codes. ;-) And then add some stuff to the boot shell of the computer, like cd, ls and so on. And investigate the i2c problem.

2012-03-26

SIO, IDE and Terminal

2012-03:

SIO board
I have used the wrong SO-8 package in the drawings for the SIO and IDE board and had to place the I2C EEprom very carefully on the PCB to solder it. The pins extended beyond the solder pads, but it seemed to work.

2012-03-17: Heart attack: i took a look at the 88C192 SIO's PDF and saw that pins were numbered starting at a corner. X-( .... but this was for the TQFP-44 package only. Pin numbers of the PLCC package start in the middle of one side. HTF were these brain dead idiots... ?


IDE board
Soldering the 50 CF card adapter pins went quite well: Some flux applied in advance, soldering the pins with as little tin as possible, ignoring all junctions and blobs of tin and then removing most of the solder tin with desoldering wick. perfect. Stacking of the CF card and an IDE Flash drive works as desired.
LCD driver board
I hope everything will work. Testing starts ... soon. :-]
 2012-03-26: The PCB for the above mentioned LCD display project arrived. Yet another board to test and to write software for. But this one is easier.

2012-02-22

SIO and IDE Cards


After a long time where i played around with the C-style compiler for the microcode, which i expanded to a virtual instruction code compiler for use on my Mac, i resumed work on the half-sized IDE interface and the half-sized serial adapter. The IDE interface will connect two devices, a 96 MB DiskOnModule with a 40 pin IDE connector and a CF adapter for removable drives. The serial adapter will only be used temporarily for the K1-CPU itself. It will be replaced by a 4 channel (or evtl. more) serial card later which will also incorporate a LAN adapter module, which i own. The serial ports can be used for asynchronous communication with SW or HW handshake or with clock signals of any polarity. XOR gates are useful programmable inverters. ;-) The 88C192 chips have idiotic restrictions for the selectable bit rates. :-|
The two boards have been ordered on 2012-02-04 from Leiton, like the others.
Related to the CPU project is another project which i was working upon the last two weeks: A controller board for an old black&white reflective LCDisplay i own. It is based on an ATMega8 and uses old 41464 DRAM chips for it's frame buffer.
20212-02-22: The IDE and SIO boards arrived. I got two of each, due to overproduction, for fair additional costs. But the boards don't look good this time. Like processed in over-aged chemicals or the like. I don't know.

2011-07-15

Serial and IDE Cards

Currently i'm working on the microcode again. I reworked the existing c-code to match the new compiler and started work on device drivers and file system. Some peculiarities were introduced due to the pure 16 bit design of the CPU.
Also, i started the design of a half-sized serial card for the K1 bus and a half sized IDE card. When these are built i can restart working with the real CPU. But i'll probably test them in the emulator first. For the IDE card i have the choice to use a 96MB 40-pin IDE flash rom module or a compact flash adapter. Combining them may be a little bit tricky because IDE uses TTL levels and compact flash CMOS levels.
For the serial card i'm using an 88C192 which can also provide a regular system timer interrupt.

2011-04-15

Vicci 's got a name


The last months i was busy rewriting the compiler in C++. Meanwhile it evolved into a fully fledged compiler/linker/virtual code interpreter for i386/i386x64/ppc. Now most things work and i'm starting work on the K1-CPU [microcode] assembler backend.


2010-07-15

Reworking the assembler


I'm in rehabilitation after the operation. I use the spare time to rework the microcode assembler. It was a 2-pass assembler with a not-so-good approach for code placement (fitting). Now it is a single-pass assembler which is faster in most cases and much faster in all others and which tiles the microcode 'threads' much better than before.

2010-06-27

In Hospital

2010-06-22 – 2010-06-08

In hospital for operation of my herniated disk. After back pains suddenly disapeared one month ago i developped paralysis of some muscles in the left leg.

2010-06-27

A good friend of mine died unexpectedly.
Rest in Peace, Gômmel.

2010-06-15

New: a c-style compiler


The zoo of programs became an additional member: a c-style compiler. Internally it generates an 'intermediate' instruction format which is converted by an 'assembler' step into assembler opcodes which the microcode assembler understands. Later the assembler step will be replaced by an opcode assembler to create ram-loadable programs. The compiler will take some while to debug...

2010-05-31

Short Survey on Programs

The microcode software is under development. I'm juggling with 5 or 6 types oft software:
- microcode
- millicode (yes, that's new!)
- bytecode (new too)
- assembler opcodes in ram
- the microcode assembler
- the microcode emulator (new)
- vipsi script interpreter (found the second bug in it after 5 years) B-)
So, slowly, what are they all about?

Vipsi Script Interpreter

The thing of software which also delivers this web site. The microcode assembler and the microcode emulator are written in this script language too.

Microcode

That's obvious, hopefully. The codes actually executed by the control unit. All living starts here. After reset it also is obligued to setup the machine and load drivers and program. There are no other roms in the CPU: the microcode also contains the BIOS.

Assembler Opcodes

That's what the microcode is going to implement: Opcodes for a program running in ram. All opcodes are actually addresses of tiny programs in the microcode rom which load the next opcode when they are done:
:ADD ( a b -- c )
    add (hp--)
    jp  (ip++)

Microcode Assembler

The piece of software which reads the microcode sources and creates the hex files for downloading into the microcode roms. It eases my live with flow control instructions, compound instructions, checking, postponing and fitting the code into the roms. That's all not trivial and all very error prone. See what it creates from the above code example:
:ADD ( a b -- c )
    tst_add (hp)            // 1
    add     (hp--)          // 2
    ld      cmd,(ip++)      // 3
    nop     :bit15          // 4
1: add is too slow, because the carry can ripple through 16 bits until the result has settled. Therefore 'add' and similar opcodes must add a wait cycle, where the inputs are applied but the result is not yet latched.
3: This is, basically, what 'jp' in microcode does: it loads a new address into the microcode address counter, instead of incrementing it.
4: But this is what is required too:
- The next opcode is already fetched by the control unit and will be executed before the jump takes effect
- The feedback line (aka 'flag') 'bit15' is selected to determine in which code plane the jump will actually jump to. In a simple case this would be flag '0' (unconditional plane 0) or flag '1' (unconditional plane 1). But here i use flag 'bit15', which forwards bit 15 from the data bus, so that the jump destination will be in plane 0 (1) if bit 15 of the jump address is cleared (set).

Microcode Emulator

This is the newest piece of software. I'm currently no longer downloading the microcode to the real CPU but to an emulator written in vipsi. The emulator code has ~ 100 lines netto. Debugging stuff and comments increase it to ~ 400 lines currently. The simulator mcsim.vs is located in Software/Microcode/ aside the microcode source.

Millicode

One of the best things which are possible in the K1 CPU's microcode is to jump to microcode addresses via table. Huh great! Great?
At first it seems impossible to do this. You cannot read microcode cells at arbitrary locations. There is no other source for addressing than the microcode address counter. It is hard to put a string of text into microcode. But, pretty soon, i felt it would be simpler to write something like
    pushstr "abc"
    printstr
instead of:
    push 'a'
    printchar
    push 'b'
    printchar
    push 'c'
    printchar
This could be solved similar to this:
    jsr pushstr
    dw  'a','b','c',0
    jp  p3
    ...
pushstr:
    jsr allocstr
    pop a0              // get return address
p1: ld  cmd,a0++        // jump
    ld  d0,ival :bit15  // already loaded microcode
 // --- 
p3: tst d0
    jp  !z,p2
    jsr storechar
    jp  p1
p2: ...
I tried to keep the example as short as possible. Microcode execution starts with a subroutine call to pushstr. pushstr pops the return address from the return stack which points to the 'a'. Now it loads the microcode address counter with this address (line p1:) but the next microcode is already loaded and is executed next: This loads register D0 with an immediate value which follows in the next microcode. This next microcode is the 'a' where A0 pointed to. Then the microcode runs through the other data bytes which just consume time but do nothing. Finally it reaches the 'jp p3' which jumps back to the string reading loop. Next time the jump hits the next char, because a0 is incremented each time.
Though this example has lots of room for improvement it shows how 'the impossible' thing works. With a little tweaking microcode can read constant data from the microcode rom.
The next step was to realize, that this works even better if the constant data is not 'data' but code:
    ld  alu,jptab1
    add alu,d0
    add alu,d0
    jp  alu
jptab1:
    jp  proc1
    jp  proc2
    jp  ...
Step 3 was to realize, that not the whole 'jp' instruction must be in the table, but only the address:
    ld  alu,jptab1
    add alu,d0
    ld  cmd,alu
    ld  cmd,ival  :bit15
jptab1:
    dw  proc1     :bit15
    dw  proc2     :bit15
    dw  ...
The trick are the two 'ld cmd' instructions in succession. It's a combination of the ideas in 'step 1' and 'step 2'.
Ok, and if, now, we use the address register 'ip' (instruction pointer, sic!) to point to the 'table' of addresses and if the addresses only point to routines which, after having done their job, jump to the next address in this list, we have in microcode exactly what assembler opcodes in ram do, and i called this millicode. It is much easier to write programs in millicode than in microcode assembler. :-) Though a little bit slower, due to the linking jumps and because i use a forth-style approach of argument passing on a data stack, like i do for assembler opcodes in ram.
After adding some glue to the microcode assembler, millicode programs look like this:
:DictShrinkToFit ( dict -- )
    Millicoded          // switch from microcode to millicode
    mc  Dup,DictWordsGet
    mc  Addq dict_word0 
    mc  Resize,Drop
    mc  Next            // kind of return
Yes, not only do i have a Forth CPU, but it's microcode is also programmed in Forth! :-)

Bytecode

Last thing to explain in this list is the 'bytecode'. This is a subset or at least very similar to assembler opcodes, only that instead of the opcodes it uses enumerated codes for instructions. Bytecode is the code loaded from driver eeproms on the K1-bus extension cards and is translated to assembler opcodes by the microcoded boot loader after reset.

2010-04-30

First Time Power On

2010-04-01: The frontpanel software is making progress: Meanwhile i can upload microcode to the i2c eeproms or directly to the microcode upload header of the CPU! This also required a small modification to the microcode assembler, to generate a combined file for the three eproms. I am using CoolTerm on my Mac with an usbserial adapter for uploading the hex files. Also, implementation of the XON/XOFF protocol proofed to be useful. :-)

2010-04-05: During Easter holydays i made a great leap and put it all together!
Off course, there were problems. E.g. when my highly valued power supply unit did only deliver 4.4 instead of 5.1 Volts. And became quite warm. First i had problems to measure the current drawn by the CPU, because the PSU always switched off when i cramped the amperemeter into the fuse socket. Measure leads too high impedance... But i was lucky to revive an old pair of leads and see: 3.2 ampere. Off limit for the PSU. Why? Hu hu hu. Some explorations later: i had connected the ALU data registers in reverse direction in the circuit drawing. Impressive what they can survive! I made a dead-cockroach-type operation to both of them. (100 points for those who know what i'm citing! :-))
The ALU Registers [on the left] after Operation

But still the power drawn is a little bit suspicious. The CPU now draws 350mA when stopped and up to 1.3A when running at full speed. But at some points the power consumption rises from 0.5A to 1.0A and above while slowly idling through some random microcode found in the eproms. No explanation yet, but i decided to finish the frontpanel's debugger and start from there. If there is some cause to draw more than 0.5A unexpectedly there will be some error. Hopefully.
So, as said, i worked on the debugger. I implemented routines to read in the sensor ring, which provides information on all three busses (data, address and control). And a preliminary single stepper. Occasionally i could alredy verify that the address incrementer seems to work. Yeah. Tomorrow more...

2010-04-08: It seems that i have more problems with the assembler than with the CPU now. B-) Slowly but shurely i am writing test routines for registers and functions and so far they all work. Except if the assembler fails to generate correct code. Data registers, ALU functions, shift registers, address registers and address increment/decrement up and running. Ram test ok! And on we go...

2010-04-10: I am excessively testing the CPU. At one point i probably had a non-connect in a socket (the CY input to the SR register) which now seems to be fixed. And i was hunting an error in the z-flag result:
    tst $0008 : z
    jp  1,error
jumped to error sometimes, but when i uploaded hundreds of tests into the microcode rams it always failed at the same microcode address, if it failed, which was different for every special code mix. What was going wrong here?
Nothing. It was ok. I will have to put a wait cycle here (or eventually it works when i replace the condition selector, a 74HC151 by it's AC counterpart.) The 'error' was the impression, that the immediate value came from the 'ival' registers on the control unit. But these are no registers, but drivers. And they put the data from the microcode rams on the bus, thus i had to add the latency from the microcode rams to the total round-trip time and – alas! – that was tight. VERY tight...


For the records: Power drawn by the CPU is ~350mA@5V when halted and ~800mA@5V when running at 16MHz.
2010-04-11 to 2010-04-15: Webside down, because iMac down. PSU failure.
2010-04-16: Resuming testing.

2010-03-22

The New Front Panel

I finished the new frontpanel board: Exposed, etched, drilled, soldered and connected. The software for the ATmega32 is under development.
Front panel showing the K1-16/16 Logo

2010-02-28

I/O Board and Microcode Upload Header

2010-01:

I have ordered the I/O board from LeitOn.
The new front panel is still under development.
The microcode upload header is designed and routed.

2010-02:

The I/O board is finished:
K1-16/16 Expansion Bus Board
 The microcode upload header is finished:
The Microcode Upload Header ontop of the Control Unit

2009-12-24

2009-12

I decided to design a new front panel with more 'gears'.
• Subproject LCDs mostly finished.
• Subproject IR-Keyboard mostly finished.

2009-11-30

Data and Address Register Boards

I have ordered the address and data registers boards from LeitOn. Again the quality is not as good as from PCB-Pool, the boards are slightly bent. Both boards are now finished:
K1-16/16 Data Registers Board
K1-16/16 Address Registers Board
Seemingly some companies expect a great economical success for my groundbreaking CPU design:
Spam


2009-10-05

The ALU

2009-10-05: CadSoft is bought by Premier Farnell plc.
I have ordered the ALU PCB from LeitOn.
It is of lower quality than the board from PCB-Pool.
K1-16/16 Arithmetic/Logic Unit