Das Schneider CPC Systembuch

Die Abteilungen des Betriebssystems

Der Kernel - Software-Interrupts

Semaphoren - nur für Interessierte

Der Der Kernel - Software-Interrupts: DruckerspoolerDruckerspooler hat in dieser 'Bauart' allerdings ein Problem, das man vielleicht nicht sofort erkennt: Weil sich die Event-Routine selbst abschaltet, muss man 'teuflisch' aufpassen, dass man sie immer wieder kickt, wenn der Timer 'abgelaufen' ist, dass man sie andererseits aber nicht zuviel kickt, weil die Event-Routine nicht testet, ob der Puffer leer ist.

Das führte dann auch zu dem kurzzeitigen Verbieten des Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupts beim Label JOB1: Es könnte (rein theoretisch) passieren, dass genau zwischen LD_(ENDE),BC und LD_HL,(ANF) das Der Kernel - Software-Interrupts: EventsEvent ausgelöst wird, wenn man den Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupt nicht verboten hätte. Dann könnte die Interrupt-Routine gerade alle Zeichen bis auf das neue, letzte Zeichen ausdrucken, bevor der Drucker wieder zu lange Busy bleibt. Im Puffer wäre noch ein Zeichen enthalten, ANF stände einen Platz vor dem neuen ENDE, mithin also genau auf der Position vom alten ENDE!

Der darauf folgende Vergleich ergäbe, dass ANF = ENDEalt und damit, dass der Puffer vorher leer gewesen sein muss und dass der BCE9: KL ADD TICKER: TickerblockTickerblock eingehängt werden muss. Obwohl ein noch aktiver BCE9: KL ADD TICKER: TickerblockTickerblock eingehängt würde, wäre das nicht weiter schlimm (der MAIN FIRMWARE JUMPBLOCK: KERNEL
Die Firmware des Schneider CPC: KERNEL
Kernel
erkennt das), wenn nicht in der Zwischenzeit das Der Kernel - Software-Interrupts: EventsEvent erneut gekickt wird und erfolgreich das (nun tatsächlich) letzte Zeichen absetzen kann. Dann würde der BCE9: KL ADD TICKER: TickerblockTickerblock von JOB erneut eingehängt, wenn der Puffer bereits leer ist. Da die Routine EVROUT nicht auf einen leeren Puffer testet, würde ANF den ENDE-Zeiger überholen und der leere Puffer einmal zusätzlich ausgedruckt.

Dieser Fall ist Datentypen: Realreal zwar höchst unwahrscheinlich, gleichwohl 'möglich', und muss ausgeschlossen werden. Das wird durch das kurze Verbieten eines Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupts erreicht. Wird jetzt vor JOB1 das (alte) ENDE erreicht, so hängt sich die Eventroutine aus und muss für das neue letzte Zeichen wieder angestoßen werden.

Wird das alte ENDE erst nach EI erreicht, so geht es in den Erklärung der Anschlussbelegung: TestTest nicht mehr ein. Jetzt kann man sich überlegen, was passiert, wenn zufällig ANF bis ENDEalt gestellt würde: Der BCE9: KL ADD TICKER: TickerblockTickerblock wird nicht eingehängt, bleibt aber aktiv (weil das von EVROUT erkannte ENDE jetzt schon ENDEneu ist). Wird ANF aber schon bis ENDEneu weitergestellt, so wird der BCE9: KL ADD TICKER: TickerblockTickerblock wieder ausgehängt. Das ist auch o.k., weil der Puffer dann ja auch tatsächlich leer ist.

Ganz allgemein ist die Programmierung von parallel laufenden Prozessen außerordentlich viel schwieriger, als ein einziger, linear ablaufender Strang. Dieses Beispiel wird zwar, zugegebenermaßen, dadurch verkompliziert, dass sich die Interrupt-Routine selbst wieder aushängen kann. Aber diese Art von Problemen tritt bei paralleler Verarbeitung immer wieder auf und hat in der Fachliteratur auch einen eigenen Namen:

Das Semaphoren-Problem.

Semaphoren sind Signale, mit dem beispielsweise ein Programm einem parallel laufenden Prozess einen Zugriff auf eine bestimmte Abteilung des Betriebssystems, Daten o. AE. signalisieren kann. Dabei ist es ausgesprochen wichtig, dass das Lesen und Neu-Setzen des Signals nicht von einem Parallel-Prozess unterbrochen werden kann. Dieser Zugriff muss unteilbar sein. Sonst wäre der Fall denkbar, dass Prozess 1 auf ein Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag zugreift, sieht, er darf und wird, bevor er das Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag auf 'besetzt' stellen kann, von einem weiteren Prozess unterbrochen, der das Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag ebenfalls testet. Dann erkennen beide, dass sie einen, wie auch immer gearteteten Zugriff machen dürfen. Der Zweck der Semaphore wäre nicht erreicht.

Entsprechend ist es bei JOB1: Der Erklärung der Anschlussbelegung: TestTest, ob der Puffer im Augenblick leer ist und das endgültige Anfügen des neuen Zeichens müssen 'unteilbar' durchgeführt werden.

 ; Interrupt-Programmierung in Maschinensprache:
 ; ---------------------------------------------
 ;
 ; ein Der Kernel - Software-Interrupts: DruckerspoolerDruckerspooler   Erklärung zu den Anschlüssen: Vcc und Vss
Erklärung zu den Anschluss-Bezeichnungen: Vcc und Vss
vs
. 3.6.86 (c) G.Woigk ; ------------------ ---------- ----------- ; ORG 40000 ; ADDTIK: EQU #BCE9 ; KERNEL: BCE9: KL ADD TICKERKL ADD TICKER DELTIK: EQU #BCEC ; KERNEL: BCEC: KL DEL TICKERKL DEL TICKER Der Kernel - Software-Interrupts: EventsEVENT: EQU #BCF2 ; KERNEL: BCF2: KL EVENTKL EVENT BUSY: EQU #BD2E ; MACHINE PACK: BD2E: MC BUSY PRINTERMC BUSY PRINTER SEND: EQU #BD31 ; MACHINE PACK: BD31: MC SEND PRINTMC SEND PRINTER IPRINT: EQU #BDF1 ; Die Indirections der Firmware-Packs: BDF1: IND MC WAIT PRINTERIND MC WAIT PRINTER ; ; Initialisierung ; --------------- ; BANF: EQU $ ; Druckerpuffer-Anfang ist HIER! INIT: LD HL,PATCH ; Sprung zur eig. Routine JOB in die LD DE,IPRINT ; Überblick: Die Indirections der Firmware-Packs
Die Firmware des Schneider CPC: Die Indirections der Firmware-Packs
Indirection
kopieren. LD BC,3 LDIR ; LD HL,(BUSY+1) ; MACHINE PACK: BD2E: MC BUSY PRINTERMC BUSY PRINTER ohne ROM-Konfiguration: RestartsRestart an Aufrufstelle RES 7,H ; kopieren. RES 6,H LD (EVROUT+1),HL ; LD HL,(SEND+1) ; MACHINE PACK: BD31: MC SEND PRINTMC SEND PRINTER ohne ROM-Konfiguration: RestartsRestart an Aufrufstelle RES 7,H ; kopieren. RES 6,H LD (PRINT+1),HL RET ; DEFS 1000 ; *** Puffer *** ; PATCH: JP JOB ; Patch für PRINT ; BENDE: EQU $ ; Druckerpuffer-Ende ist HIER! (last+1) ANF: DEFW BANF ; Zeiger auf 1. Zeichen (next to print) ENDE: DEFW BANF ; Zeiger hinter letztes Zeichen (next free place) ; TICKB: DEFS 6 ; TICKER Die Speicherkonfiguration im Schneider CPC: BlockBLOCK: EVBLOK: DEFS 2 ; und der darin enthaltene BCEF: KL INIT EVENT: EventblockEventblock: COUNT: DEFB 0 ; COUNT: Zähl- und Steuerbyte DEFB %10000001 ; CLASS: asynchron, normal, near address DEFW EVROUT ; Routinenadresse ; ; BC innerhalb des Puffers weiterstellen ; -------------------------------------- ; INCRBC: LD HL,BENDE AND Operationen: BD5B / 349A / 349A: FLO SUBA INC BC SBC HL,BC RET NZ LD BC,BANF RET ; ; Ersatzroutine für Die Indirections der Firmware-Packs: BDF1: IND MC WAIT PRINTERIND MC WAIT PRINTER: Zeichen im Puffer speichern. ; --------------------------------------- ; JOB: PUSH HL ; retten wg. I/O-Bedingungen LD BC,(ENDE) LD (BC),Operationen: BD5B / 349A / 349A: FLO SUBA ; Zeichen im Puffer speichern PUSH BC Maschinencode über HIMEM: CALLCALL INCRBC ; ENDE-Zeiger weiterstellen ; JOB2: LD HL,(ANF) ; Puffer voll ? (ANF = ENDEalt ?) AND Operationen: BD5B / 349A / 349A: FLO SUBA SBC HL,BC JR NZ,JOB1 ; NEIN --> weiter. ; ; Puffer ist voll. Solange direkt kicken, bis wieder Platz ist. ; (evtl. könnte man hier einen Erklärung der Anschlussbelegung: TestTest auf 'time out' einfügen.) ; PUSH BC ; Der Kernel - Software-Interrupts: EventsEvent kicken: PUSH DE LD HL,COUNT ; Der Kernel - Software-Interrupts: EventsEvent scharf machen LD (HL),0 LD HL,EVBLOK Maschinencode über HIMEM: CALLCALL Der Kernel - Software-Interrupts: EventsEVENT ; und anstoßen (wird sofort aufgerufen) POP DE POP BC JR JOB2 ; und Erklärung der Anschlussbelegung: Testtesten, ob was gedruckt wurde. ; JOB1: DI LD (ENDE),BC ; ENDE-Zeiger abspeichern: Erst jetzt ist Operationen: BD5B / 349A / 349A: FLO SUBA drin! ; LD HL,(ANF) ; Erklärung der Anschlussbelegung: TestTest: War Puffer vorher leer? (ANF = ENDEalt ?) EI POP BC ; alter Wert von ENDE ohne dieses Zeichen. AND Operationen: BD5B / 349A / 349A: FLO SUBA SBC HL,BC ; POP HL ; HL restaurieren SCF ; CY := 1 -> o.k. anmerken RET NZ ; zurück, wenn Puffer vorher nicht leer war. ; ; Puffer war vorher leer. Dann BCE9: KL ADD TICKER: TickerblockTickerblock einhängen: ; PUSH HL ; Sonst: BCE9: KL ADD TICKER: TickerblockTickerblock einhängen: PUSH DE LD HL,COUNT LD (HL),0 LD HL,TICKB ; HL -> BCE9: KL ADD TICKER: TickerblockTickerblock LD DE,1 ; Count Down LD BC,1 ; Reload Count Maschinencode über HIMEM: CALLCALL ADDTIK ; BCE9: KL ADD TICKER: TickerblockTickerblock einhängen POP DE POP HL SCF ; CY := 0 -> o.k. anmerken RET ; ; Event-Routine: Drucke Zeichen aus dem Puffer weg: ; ------------------------------------------------- ; EVROUT: Maschinencode über HIMEM: CALLCALL #00 ; MACHINE PACK: BD2E: MC BUSY PRINTERMC BUSY PRINTER: Drucker bereit? RET C ; Nein, dann fertig. ; LD BC,(ANF) LD Operationen: BD5B / 349A / 349A: FLO SUBA,(BC) ; Zeichen aus Puffer holen, PRINT: Maschinencode über HIMEM: CALLCALL #00 ; MAIN FIRMWARE JUMPBLOCK: MACHINE PACK
Die Firmware des Schneider CPC: MACHINE PACK
MC
SEND CHAR: zum Drucker senden, Maschinencode über HIMEM: CALLCALL INCRBC ; ANF-Zeiger weiterstellen LD (ANF),BC ; und wieder abspeichern. ; LD HL,(ENDE) ; ANF- mit ENDE-Zeiger vergleichen: AND Operationen: BD5B / 349A / 349A: FLO SUBA SBC HL,BC ; Z=1 -> Puffer leer? ; LD HL,COUNT ; Vorsorglich 20 weitere Kicks anmerken: LD (HL),20 ; Falls noch was im Puffer ist, wird nach dem RET NZ ; Return EVROUT noch 20 mal aufgerufen. ; LD (HL),#C0 ; Puffer leer -> BCEF: KL INIT EVENT: EventblockEventblock ruhigstellen LD HL,TICKB ; und den BCE9: KL ADD TICKER: TickerblockTickerblock aushängen. JP DELTIK

Valid HTML   Valid CSS