#!/bin/vipsi // // Test1 // 2009-02-22 // // 2. Testprogramm für das Schrittschaltwerk // // Für zweite Version ohne NAND in MA12 und MA13 // // Errata: In Sprungadressen muss Bit D14=1 gesetzt werden, damit beim Laden nicht Bits 0..7 genullt werden. // /* Jeder Microcode besteht aus 24 Bits: MD0..3: D0.OE ... D15.OE 16 Output Enables für den Datenbus MD4..7: D0.CLK ... D15.CLK 16 Lade-Clocks für den Datenbus MD8..10: A0.OE ... A7.OE 8 Output Enables für den Adressbus MD11..13: A0.CLK ... A7.CLK 8 Lade-Clocks für den Adressbus MD14..19: OPT0 ... OPT5 6 Options-Flags wählen Funktionsvarianten in versch. Funktionen aus OPT2 ist auch das Datenbit für das '259er DIV.FF OPT3..5 ist die Adresse dazu MD20: CMD.EN Command-Enable, unterdrückt ggf. die Ausführung des Codes, wenn er einen Direktwert für den vorangegangenen Opcode oder für das '259er DIV.FF enthält. Wird auch durch INIT unterdrückt. MD21..23: COND Auswahl aus 8 Bedingungen für den nächsten Code. Führt zum Lesen des nächsten Codes aus Codeebene 0 (MA14=0) oder 1 (MA14=1) 6 Bedingungen testen Flags, zwei (COND.0 und COND.1) dienen dazu, die Verarbeitung in der jeweiligen Codeebene zu halten. */ // Datenbus: // andere noch nicht definiert var cmd = { oe=0, clk=0<<4 } var mem = { oe=1, clk=1<<4 } var io = { oe=2, clk=2<<4 } // Adressbus: // andere noch nicht definiert var pc = { oe=0<<8, clk=0<<11 } // Options-Steuerleitungen: var opt0 = 1<<14; var opt1 = 1<<15; var opt2 = 1<<16; var opt3 = 1<<17; var opt4 = 1<<18; var opt5 = 1<<19; // Befehlsausführungsunterdrückung für Direktwerte: var cmd.en = 0<<20; var cmd.dis = 1<<20; // '259 Addressable Latch DIV.FF: // wird geladen, wenn die Ausführung des Opcodes mit cmd.dis unterdrückt wird. // value: opt2 // address: opt3,4,5 var div = { off = 0<<16, on = 1<<16 } div ##= { clk_pre_0 = 0<<17, // clock prescaler, low bit clk_pre_1 = 1<<17, // clock prescaler, high bit: %00=16, %01=8, %10=4, %11=2 halt = 2<<17 + div.on, // wait while no interrupt run = 2<<17 + div.off, // disable halt ei = 3<<17 + div.on, // enable loading of interrupt vector during opcode fetch di = 3<<17 + div.off, // disable loading of interrupt vector led_grn_on = 4<<17 + div.on, led_grn_off = 4<<17 + div.off, led_yel_on = 5<<17 + div.on, led_yel_off = 5<<17 + div.off, led_red_on = 6<<17 + div.on, led_red_off = 6<<17 + div.off, reset = 7<<17 + div.on, nop = 7<<17 + div.off } // Conditions // wirken immer auf den nächsten Code. var cond = { null=0<<21, // wählt Microcode-Ebene MA14=0 aus eins=1<<21, // wählt Microcode-Ebene MA14=1 aus cy=2<<21, // ALU: Unsigned Carry z=3<<21, // ALU: Zero scy=4<<21, // ALU: Signed Carry z88=5<<21, // ALU: unteres oder oberes Byte ist Null d0=6<<21, // Datenbus Bit D0 d15=7<<21 // Datenbus Bit D15 } // ========================================================= // Microcode Array: // cave-at: Indexes start at 1. // bis $4000 ist Code-Ebene 0 (MA14=0) // bis $8000 ist Code-Ebene 1 (MA14=1) var mc[$8000] var mcaddr=0 // Speichere Microcode in den Array: // proc store( code ) { mc[++mcaddr] = code; mc[mcaddr+$4000] = code } proc store2( code0,code1 ) { mc[++mcaddr] = code0; mc[mcaddr+$4000] = code1 } /* ====================================================== Microcode-Source: die CPU startet mit: • Ausführung von Opcode $7FFF (MA14=1) • mit cmd.dis wg. !INIT im letzten Zyklus Wegen cmd.dis wird opt2..5 des Opcodes in das '259er DIV.FF geladen. Am besten $7FFF = div.nop • während $7FFF ausgeführt wird, wird $0000 (MA14=0) geladen. */ /* Testprogramm: schalte speed auf max A: setze grün in codeebene 0 setze rot gem. CY-Flag ((pull_up=>on)) setze gelb gem. Z-Flag ((pull_up=>on)) warte lösche grün in codeebene 1 warte loop to A wenn D15=1 ((pull_up=>loop)) else halt reset */ store( cmd.dis + div.clk_pre_0 + div.on + cond.null ) store( cmd.dis + div.clk_pre_1 + div.on + cond.null ) store2( cmd.dis + div.led_grn_on + cond.cy, cmd.dis + div.nop + cond.cy ) store2( cmd.dis + div.led_red_off + cond.z, cmd.dis + div.led_red_on + cond.z ) store2( cmd.dis + div.led_yel_off + cond.null, cmd.dis + div.led_yel_on + cond.null ) do while mcaddr < $2000 store( cmd.en + cmd.oe + mem.clk + cond.null ) store( cmd.dis + div.nop + $5555 + cond.null ) store( cmd.en + cmd.oe + io.clk + cond.null ) store( cmd.dis + div.nop + $AAAA + cond.null ) loop store( cmd.dis + div.nop + cond.eins ) store2( cmd.dis + div.nop + cond.null, cmd.dis + div.led_grn_off + cond.null ) do while mcaddr < $3FF0 store( cmd.en + cmd.oe + mem.clk + cond.null ) store( cmd.dis + div.nop + $5555 + cond.null ) store( cmd.en + cmd.oe + io.clk + cond.null ) store( cmd.dis + div.nop + $AAAA + cond.null ) loop store( cmd.dis + div.nop + cond.d15 ) store2( cmd.dis + div.halt + cond.null, cmd.en + cmd.oe + cmd.clk + cond.eins ) store2( cmd.dis + div.reset + cond.null, cmd.dis + div.nop + $0002 + cond.null ) // never reached: store2( cmd.en + cmd.oe + cmd.clk + cond.null, cmd.en + cmd.oe + cmd.clk + cond.eins ) store2( cmd.dis + div.nop + (mcaddr-1) + cond.null, cmd.dis + div.nop + (mcaddr-1) + cond.eins ) // really never reached: store( cmd.dis + div.reset + cond.null ) // $7FFF: do while mcaddr < $4000 store( cmd.dis + div.nop + cond.null ) loop // ================================================================ // Schreibe Hex-Files für die Eproms: // schreibe 16 bytes: // proc w16(eprom,addr) // eprom = bitshift: 0, 8, 16 { put#4, ":10", hexstr(addr,4), "00" var checksum = $10 + (addr>>8) + addr + $00 var byte do addr += 1 // note: array indexes start at 1 byte = int(mc[addr]>>eprom) put #4, hexstr( byte, 2 ) checksum += byte while addr & $000F loop put#4, hexstr(checksum^$00ff,2), nl } // schreibe 1 Eprom: // proc write_rom(eprom) // eprom = bitshift: 0, 8, 16 { var addr=0; do while addr < $8000 w16(eprom,addr) addr += 16 loop } openout #4, "microcode_l.hex"; write_rom(0); close#4 openout #4, "microcode_m.hex"; write_rom(8); close#4 openout #4, "microcode_h.hex"; write_rom(16); close#4 put nl,"done.",nl