Samstag, 8. Februar 2014

KGS K7070 Reparatur

Heute geht es in der Geschichte wieder etwas zurück... Mein A7150 (ein Robotron PC, mit 8086 CPU) meldete zuletzt eine Störung in seinem Grafik Subsystem, genauer dessen Steuerung, der KGS K7070.

Laut Fehlermeldung handelt es sich um einen EPROM Prüfsummenfehler. Ich bin mit normalen Messmethoden dem Fehler bisher nicht auf die Schliche gekommen. Grund genug, etwas größere Geschütze und Zusatzaufwand aufzufahren - die Hardware ist es wert :-)

Grundproblem bei der Fehlerdiagnose alter Hardware sind die Zahlreichen Bausteine. Ohne geeignete, systhematische Vorgehensweise, ist man ziemlich aufgeschmissen. Die KGS K 7070 ist in diesem Sinne ein eigener Rechner (der A7150 ist damit ein Multi CPU System), bestehend aus einer Z80 CPU, einer SIO, CTC, RAM und EPROM. Dazu gesellen sich ein paar Register und Steuerhardware für den Local-Bus zur Grafikkarte.

In diesem Fall liegt es nahe, eine Testfirmware für die Karte zu entwickeln. Diese Firmware muss in einen EPROM und das Verhalten getestet werden. Nun gab es in den 80er Jahren noch kein JTAG, Bootloader und andere komfortable Errungenschaften der Neuzeit. Damals benutzte man sog. EPROM Emulatoren, welche mittels SRAM und zusätzlicher Schnittstellen zum Füllen, einen ROM emulierten.

Ich habe mir einen gebrauchten PEPS Emulator angeschafft und die dafür notwendige Software geschrieben.


Die Befüllung des EPROM Emulators nimmt zeitgenössisch ein 386SX40 mit MS-DOS vor. Die Programme sind ebenfalls zeitgenössisch in Turbo C++ geschrieben :-) Die Schnittstelle zum EPROM Emulator ist ein klassisches BitBang mittels Parallelport.

Ein weiteres Problem war die Einrichtung einer Entwicklungsumgebung für U880 CPUs (Z80). Unter Ubuntu gibt es zum Glück das SDCC Compiler Paket in den Repositories. Zu dem SDCC ist es noch Sinnvoll den z88dk Compiler + Assembler zu installieren (einfach: apt-get install sdcc* z88dk*). Im Netz ist es schwierig, geeignete Informationen für ein funktionierendes Setup zu finden. Mit etwas Hilfe aus dem Robotron-Dunstkreis (thx Holm!), habe ich dann einfache Assemblerprogramme zum Laufen bekommen. Von diesem Schritt zum C - Programm ist es dann nicht mehr weit.

Mein Testprogramm besteht aus folgenden Dateien:
  • crt0.s (Bootscript in Z80 Assembler für Sprung auf _main aus dem folgenden C Code)
  • initi_ctc_sio.s (Init Script für CTC+SIO von Holm Tiffe, gehört mit in die crt0.s nach init)
  • main.c (das eigentliche Testprogramm)
  • ioport.s + ioport.h (Assembler Zugriffsroutinen auf I/O Ports vom C Programm aus)
Folgendes Makefile dient dem Built des Programmes:


all: release.bin release.hex release.dasm

Release: release.bin release.hex release.dasm

#Binary and HEX Output:
release.bin: release.hex release.ihx
srec_cat release.hex -intel -o release.bin -binary

release.hex: release.ihx
packihx < release.ihx > release.hex

#Compile Files:
main.o: main.c
sdcc -I ./ -mz80 -c main.c

mycrt.o: crt0.s
as-z80 -lo mycrt.o crt0.s

ioport.o: ioport.s
as-z80 -lo ioport.o ioport.s

#Links
release.ihx: main.o mycrt.o ioport.o
sdcc -I ./ -mz80 mycrt.o ioport.o main.o --no-std-crt0 --code-loc 0x0200 --data-loc 0x8000
mv mycrt.ihx release.ihx

#Disassembler:
release.dasm: release.bin
z80dasm -t -g 0x0 -l release.bin -o release.dasm

#Clean:
clean:
rm -f *\.o *\.ihx *\.sym *\.lst *\.map *\.noi *\.bin *\.dasm *\.lnk *\.rel *\.def *\.hex


Das ganze Schlamassel bindet man am Besten in eine IDE ein. Ich mag Code::Blocks sehr.

Das Programmgrundgerüst mit Ausgabe auf der seriellen Schnittstelle ist einfach gestrickt:
#include <stdio.h>
#include "ioport.h"

#define ctc    0x00     //RW
#define sioad  0x08     //RW
#define sioac  0x09     //RW
#define siobd  0x0a     //RW
#define siobc  0x0b     //RW
#define ereg   0x010    //R
#define areg   0x011    //W
#define sreg   0x012    //R
#define intrf  0x013    //RW
#define errf   0x014    //RW
#define memsel 0x015    //W
#define dsel0  0x016    //R
#define dsel1  0x017    //R

void out_string(char *str)
{
    unsigned char status;

    while (*str != 0)
    {
        do
        {
            status = in(sioac);
        }
        while( (status & 0x04) == 0x00 );

        out(sioad, *str++);
    }
}

void main()
{
    
    while(1)
    {

    }
}

Ein Speichertest lässt sich wie folgt implementieren, dazu muss "free" als erste ungenutzte Variable im DATA Speicherbereich deklariert sein. Von da an wird alles, inkl. dem Stack, überschrieben.
    addr = &free;

    while(addr < (unsigned char *)0xFFFF)
    {
        *(addr) = 0x55;
        *(addr) = 0xAA;

        if(*(addr) != 0xAA)
        {
            sprintf(buffer, "Error at 0x%X \n\r", addr);
            out_string(buffer);
            n_ok++;
        }
        else
        {
            ok++;
        }
        addr++;
    }

    sprintf(buffer, "ready size: 0x%X, def: 0x%X \n\r", ok, n_ok);
    out_string(buffer);

Über eine serielle Console lassen sich die Ausgaben auswerten. Die Speichergröße ist nicht wie erwartet 0x7FFF, da "free" nach notwendigen Zählvariablen und dem Ausgabebuffer definiert ist. Man sieht also, dass auch der RAM funktioniert.

Ein Registertest z.B. so:
    while(1)
    {
        out(areg, k);
        k++;
    }

Für den Registertest hilft ein billiger Logic Analyzer ungemein. Von 8 möglichen Datenleitungen hängen D0...D6 an den Eingängen 0...7 des DS8282 Registers. D7 nutze ich als Trigger am Strobe Eingang. Die hübschen IC Klammern habe ich beim Umzug der Firma aus dem Müll gefischt :-)

In der Software des Logic Analyzers sieht man schön, wie der Registerwert hochgezählt wird:

Weitere Tests werden folgen. Ich wünsche einen schönen Samstag Nachmittag :-)



Keine Kommentare:

Kommentar veröffentlichen