#!/usr/bin/python """ The Imlac main CPU. """ import sys from Globals import * import DisplayCPU import Memory import Ptr import Ptp import TtyIn import TtyOut import Kbd import Trace ###### # The main CPU registers ###### PC = None # main CPU program counter L = 0 # main CPU link register AC = 0 # main CPU accumulator Sync40Hz = 1 # main CPU 40Hz flag register DS = 0 # dataswitches value # address of base of local code block BlockBase = 0 # decode dictionaries (initialized in init()) main_decode = None page_00_decode = None page02_decode = None micro_opcodes = None micro_singles = None # module-level state variables running = False def init(): global running, main_decode, page_00_decode, page02_decode, micro_opcodes global micro_singles # main dispatch dictionary for decoding opcodes in bits 1-4 main_decode = {000: page_00, # secondary decode 001: i_LAW_LWC, 002: i_JMP, # 003: illegal, 004: i_DAC, 005: i_XAM, 006: i_ISZ, 007: i_JMS, # 010: illegal 011: i_AND, 012: i_IOR, 013: i_XOR, 014: i_LAC, 015: i_ADD, 016: i_SUB, 017: i_SAM} # page_00 dispatch dictionary for decoding opcodes # HLT may be handled specially page_00_decode = {001003: i_DLA, 001011: i_CTB, 001012: i_DOF, 001021: i_KRB, 001022: i_KCF, 001023: i_KRC, 001031: i_RRB, 001032: i_RCF, 001033: i_RRC, 001041: i_TPR, 001042: i_TCF, 001043: i_TPC, 001051: i_HRB, 001052: i_HOF, 001061: i_HON, 001062: i_STB, 001071: i_SCF, 001072: i_IOS, 001101: i_IOT101, 001111: i_IOT111, 001131: i_IOT131, 001132: i_IOT132, 001134: i_IOT134, 001141: i_IOT141, 001161: i_IOF, 001162: i_ION, 001271: i_PUN, 001274: i_PSF, # 003000: illegal RAL0 003001: i_RAL1, 003002: i_RAL2, 003003: i_RAL3, # 003020: illegal RAR0, 003021: i_RAR1, 003022: i_RAR2, 003023: i_RAR3, # 003040: illegal SAL0, 003041: i_SAL1, 003042: i_SAL2, 003043: i_SAL3, # 003060: illegal SAR0, 003061: i_SAR1, 003062: i_SAR2, 003063: i_SAR3, 003100: i_DON} page02_decode = {0002001: i_ASZ, 0102001: i_ASN, 0002002: i_ASP, 0102002: i_ASM, 0002004: i_LSZ, 0102004: i_LSN, 0002010: i_DSF, 0102010: i_DSN, 0002020: i_KSF, 0102020: i_KSN, 0002040: i_RSF, 0102040: i_RSN, 0002100: i_TSF, 0102100: i_TSN, 0002200: i_SSF, 0102200: i_SSN, 0002400: i_HSF, 0102400: i_HSN} micro_opcodes = {0100000: 'NOP', 0100001: 'CLA', 0100002: 'CMA', 0100003: 'STA', 0100004: 'IAC', 0100005: 'COA', 0100006: 'CIA', 0100010: 'CLL', 0100011: 'CAL', 0100020: 'CML', 0100030: 'STL', 0100040: 'ODA', 0100041: 'LDA'} micro_singles = {0100001: 'CLA', 0100002: 'CMA', 0100004: 'IAC', 0100010: 'CLL', 0100020: 'CML', 0100040: 'ODA'} running = False def BLOCKADDR(address): return BlockBase | address def execute_one_instruction(): """Execute one MAIN instruction, return # cycles used""" global main_decode global PC, BlockBase if not running: return 0 # get instruction word to execute, advance PC instruction = Memory.fetch(PC, False) BlockBase = PC & ADDRHIGHMASK PC = MASK_MEM(PC + 1) # get instruction opcode, indirect bit and address opcode = (instruction >> 11) & 017 indirect = bool(instruction & 0100000) address = (instruction & 03777) return main_decode.get(opcode, illegal)(indirect, address, instruction) def illegal(indirect, address, instruction): if instruction: msg = ('Illegal instruction (%6.6o) at address %6.6o' % (instruction, PC-1)) else: msg = 'Illegal instruction at address %6.6o' % (PC-1) raise RuntimeError(msg) def page_00(indirect, address, instruction): if (instruction & 0077700) == 000000: return microcode(instruction) elif (instruction & 0077000) == 002000: return page02_decode.get(instruction, illegal)() return page_00_decode.get(instruction, illegal)(indirect, address, instruction) def i_LAW_LWC(indirect, address, instruction): global AC if indirect: AC = ~address & WORDMASK Trace.itrace('LWC', False, address) else: AC = address Trace.itrace('LAW', False, address) return 1 def i_JMP(indirect, address, instruction): global PC address = Memory.eff_address(address, indirect) PC = address & PCMASK Trace.itrace('JMP', indirect, address) return 3 if indirect else 2 def i_DAC(indirect, address, instruction): address = Memory.eff_address(address, indirect) Memory.put(AC, address, False) Trace.itrace('DAC', indirect, address) return 3 if indirect else 2 def i_XAM(indirect, address, instruction): global AC address = Memory.eff_address(address, indirect) tmp = Memory.fetch(address, False) Memory.put(AC, address, False) AC = tmp Trace.itrace('XAM', indirect, address) return 3 if indirect else 2 def i_ISZ(indirect, address, instruction): global PC address = Memory.eff_address(address, indirect) value = (Memory.fetch(address, False) + 1) & WORDMASK Memory.put(value, address, False) if value == 0: PC = (PC + 1) & WORDMASK Trace.itrace('ISZ', indirect, address) return 3 if indirect else 2 def i_JMS(indirect, address, instruction): global PC address = Memory.eff_address(address, indirect) Memory.put(PC, address, False) PC = (address + 1) & PCMASK Trace.itrace('JMS', indirect, address) return 3 if indirect else 2 def i_AND(indirect, address, instruction): global AC AC &= Memory.fetch(address, indirect) Trace.itrace('AND', indirect, address) return 3 if indirect else 2 def i_IOR(indirect, address, instruction): global AC AC |= Memory.fetch(address, indirect) Trace.itrace('IOR', indirect, address) return 3 if indirect else 2 def i_XOR(indirect, address, instruction): global AC AC ^= Memory.fetch(address, indirect) Trace.itrace('XOR', indirect, address) return 3 if indirect else 2 def i_LAC(indirect, address, instruction): global AC AC = Memory.fetch(address, indirect) Trace.itrace('LAC', indirect, address) return 3 if indirect else 2 def i_ADD(indirect, address, instruction): global AC, L AC += Memory.fetch(BLOCKADDR(address), indirect) if AC & OVERFLOWMASK: L = (~L) & 01 AC &= WORDMASK Trace.itrace('ADD', indirect, address) return 3 if indirect else 2 def i_SUB(indirect, address, instruction): global AC, L addit = Memory.fetch(BLOCKADDR(address), indirect) addit = (~addit + 1) & WORDMASK AC += addit if AC & OVERFLOWMASK: L = not L AC &= WORDMASK Trace.itrace('SUB', indirect, address) return 3 if indirect else 2 def i_SAM(indirect, address, instruction): global PC samaddr = BLOCKADDR(address) if AC == Memory.fetch(samaddr, indirect): PC = (PC + 1) & PCMASK Trace.itrace('SAM', indirect, address) return 3 if indirect else 2 def microcode(instruction): global AC, L, PC, DS, running # T1 if instruction & 001: AC = 0 if instruction & 010: L = 0 # T2 if instruction & 002: AC = (~AC) & WORDMASK if instruction & 020: L = (~L) & 01 # T3 if instruction & 004: AC += 1 if AC & OVERFLOWMASK: L = (~L) & 1 AC &= WORDMASK if instruction & 040: AC |= DS # do some sort of trace combine = [] opcode = micro_opcodes.get(instruction, None) if opcode: combine.append(opcode) if not combine: # nothing so far, we have HLT or unknown microcode if not instruction & 0100000: # bit 0 is clear, it's HLT running = False combine.append('HLT') else: for (k, op) in micro_singles.items(): if instruction & k: combine.append(op) Trace.itrace('+'.join(combine), False) return 1 def i_DLA(indirect, address, instruction): DisplayCPU.DPC = AC Trace.itrace('DLA') return 1 def i_CTB(indirect, address, instruction): Trace.itrace('CTB') return 1 def i_DOF(indirect, address, instruction): DisplayCPU.stop() Trace.itrace('DOF') return 1 def i_KRB(indirect, address, instruction): global AC AC |= Kbd.read() Trace.itrace('KRB') return 1 def i_KCF(indirect, address, instruction): Kbd.clear() Trace.itrace('KCF') return 1 def i_KRC(indirect, address, instruction): global AC AC |= Kbd.read() Kbd.clear() Trace.itrace('KRC') return 1 def i_RRB(indirect, address, instruction): global AC AC |= TtyIn.read() Trace.itrace('RRB') return 1 def i_RCF(indirect, address, instruction): TtyIn.clear() Trace.itrace('RCF') return 1 def i_RRC(indirect, address, instruction): global AC AC |= TtyIn.read() TtyIn.clear() Trace.itrace('RRC') return 1 def i_TPR(indirect, address, instruction): TtyOut.write(AC & 0xff) Trace.itrace('TPR') return 1 def i_TCF(indirect, address, instruction): TtyOut.clear() Trace.itrace('TCF') return 1 def i_TPC(indirect, address, instruction): TtyOut.write(AC & 0xff) TtyOut.clear() Trace.itrace('TPC') return 1 def i_HRB(indirect, address, instruction): global AC AC |= Ptr.read() Trace.itrace('HRB') return 1 def i_HOF(indirect, address, instruction): Ptr.stop() Trace.itrace('HOF') return 1 def i_HON(indirect, address, instruction): Ptr.start() Trace.itrace('HON') return 1 def i_STB(indirect, address, instruction): Trace.itrace('STB') return 1 def i_SCF(indirect, address, instruction): global Sync40Hz Sync40Hz = 0 Trace.itrace('SCF') return 1 def i_IOS(indirect, address, instruction): Trace.itrace('IOS') return 1 def i_IOT101(indirect, address, instruction): Trace.itrace('IOT101') return 1 def i_IOT111(indirect, address, instruction): Trace.itrace('IOT111') return 1 def i_IOT131(indirect, address, instruction): Trace.itrace('IOT131') return 1 def i_IOT132(indirect, address, instruction): Trace.itrace('IOT132') return 1 def i_IOT134(indirect, address, instruction): Trace.itrace('IOT134') return 1 def i_IOT141(indirect, address, instruction): Trace.itrace('IOT141') return 1 def i_IOF(indirect, address, instruction): Trace.itrace('IOF') return 1 def i_ION(indirect, address, instruction): Trace.itrace('ION') return 1 def i_PUN(indirect, address, instruction): Ptp.write(PC & 0xff) Trace.itrace('PUN') return 1 def i_PSF(indirect, address, instruction): global PC if Ptp.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('PSF') return 1 def i_RAL1(indirect, address, instruction): global AC, L newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK Trace.itrace('RAL', False, 1) return 1 def i_RAL2(indirect, address, instruction): global AC, L newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK Trace.itrace('RAL', False, 2) return 1 def i_RAL3(indirect, address, instruction): global AC, L newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK newl = AC >> 15 newac = (AC << 1) | L L = newl AC = newac & WORDMASK Trace.itrace('RAL', False, 3) return 1 def i_RAR1(indirect, address, instruction): global AC, L newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK Trace.itrace('RAR', False, 1) return 1 def i_RAR2(indirect, address, instruction): global AC, L newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK Trace.itrace('RAR', False, 2) return 1 def i_RAR3(indirect, address, instruction): global AC, L newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK newl = AC & 1 newac = (AC >> 1) | (L << 15) L = newl AC = newac & WORDMASK Trace.itrace('RAR', False, 3) return 1 def i_SAL1(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK value = AC & 037777 AC = (value << 1) | high_bit Trace.itrace('SAL', False, 1) return 1 def i_SAL2(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK value = AC & 017777 AC = (value << 2) | high_bit Trace.itrace('SAL', False, 2) return 1 def i_SAL3(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK value = AC & 007777 AC = (value << 3) | high_bit Trace.itrace('SAL', False, 3) return 1 def i_SAR1(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK AC = (AC >> 1) | high_bit Trace.itrace('SAR', False, 1) return 1 def i_SAR2(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK AC = (AC >> 1) | high_bit AC = (AC >> 1) | high_bit Trace.itrace('SAR', False, 2) return 1 def i_SAR3(indirect, address, instruction): global AC high_bit = AC & HIGHBITMASK AC = (AC >> 1) | high_bit AC = (AC >> 1) | high_bit AC = (AC >> 1) | high_bit Trace.itrace('SAR', False, 3) return 1 def i_DON(indirect, address, instruction): DisplayCPU.DRSindex = 0 DisplayCPU.start() Trace.itrace('DON') return 1 def i_ASZ(): global PC if AC == 0: PC = (PC + 1) & WORDMASK Trace.itrace('ASZ') return 1 def i_ASN(): global PC if AC != 0: PC = (PC + 1) & WORDMASK Trace.itrace('ASN') return 1 def i_ASP(): global PC if not (AC & HIGHBITMASK): PC = (PC + 1) & WORDMASK Trace.itrace('ASP') return 1 def i_ASM(): global PC if (AC & HIGHBITMASK): PC = (PC + 1) & WORDMASK Trace.itrace('ASM') return 1 def i_LSZ(): global PC if L == 0: PC = (PC + 1) & WORDMASK Trace.itrace('LSZ') return 1 def i_LSN(): global PC if L != 0: PC = (PC + 1) & WORDMASK Trace.itrace('LSN') return 1 def i_DSF(): global PC if DisplayCPU.ison(): PC = (PC + 1) & WORDMASK Trace.itrace('DSF') return 1 def i_DSN(): global PC if not DisplayCPU.ison(): PC = (PC + 1) & WORDMASK Trace.itrace('DSN') return 1 def i_KSF(): global PC if Kbd.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('KSF') return 1 def i_KSN(): global PC if not Kbd.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('KSN') return 1 def i_RSF(): global PC if TtyIn.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('RSF') return 1 def i_RSN(): global PC if not TtyIn.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('RSN') return 1 def i_TSF(): global PC if TtyOut.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('TSF') return 1 def i_TSN(): global PC if not TtyOut.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('TSN') return 1 def i_SSF(): global PC if Display.ready(): # skip if 40Hz sync on PC = (PC + 1) & WORDMASK Trace.itrace('SSF') return 1 def i_SSN(): global PC if not Display.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('SSN') return 1 def i_HSF(): global PC if Ptr.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('HSF') return 1 def i_HSN(): global PC if not Ptr.ready(): PC = (PC + 1) & WORDMASK Trace.itrace('HSN') return 1