# Máquina ideal ''' RAM de 256 celdas de 8 bits con direcciones 00 a FF CPU con 16 registros numerados 0 a F Celda FE puerto de entrada Celda FF puerto de salida Instrucciones: 1RXY Carga contenido de celda (transferencia de ram, incluído el puerto de entrada FE, a registro de cpu) 2RXY Carga patrón (carga inmediata de patrón en registro de cpu) 3RXY Amacenamiento en celda (transferencia desde registro de cpu a ram, incluído el puerto de salida FF) 40RS Copia contenido de R en S (transferencia interna en cpu) 5RST Suma en complemento a 2 en R 6RST Suma en punto en flotante en R 7RST OR en R 8RST AND en R 9RST XOR en R AR0X Rotación a derecha X posiciones BRXY Salto a ir si contenido de registro R es igual a contenido de registro 0 C000 Fin Programas en archivos de texto con dos patrones hexadecimales en cada línea: dirección de instrucción en 2 dígitos hexadecimales, y código de instrucción de 4 dígitos hexa ''' # Autor: Prof. Arturo Servetto # Versión: 1.0 # Retorna la instrucción en memoria a partir de la dirección dir1 (dirección de primera celda que ocupa la instrucción) y la incrementa en 2 para posicionarse en la siguiente def fetch(memoria, dir1): instruc=memoria[dir1]*256+memoria[dir1+1] dir1+=2 return instruc, dir1 # Realiza operación aritmética o lógica según cód def alu(cód, ixr, ixop1, ixop2, r): ''' ixr es el número de registro del resultado ixop1 es el número de registro con el primer operando ixop2 es el número de registro con el segundo operando r es la lista de registros internos de la CPU, y la función deja el resultado en r[ixr] ''' operando1=r[ixop1] operando2=r[ixop2] if cód==0x5: ''' Suma en complemento a 2 Si el bit más significativo es 1, es decir, el patrón binario es mayor que 127 (2**7-1), el signo es negativo y se complementa restándoselo a 256 ''' if operando1>127: operando1=-(256-operando1) if operando2>127: operando2=-(256-operando2) suma=operando1+operando2 if suma<0: r[ixr]=256+suma else: r[ixr]=suma elif cód==0x6: ''' Suma en punto flotante normalizado s|eee|mmmm --> (-1)**s * 0.mmmm * 10**(eee-100) exponente=(f//16)%8-4 (en exceso de 4) mantisa=(f%16)/16 signo=(-1)**(f//128) ''' m1=(operando1%16)/16 e1=(operando1//16)%8-4 if operando1//128==1: m1=-m1 m2=(operando2%16)/16 e2=(operando2//16)%8-4 if operando2//128==1: m2=-m2 # Alineamiento de mantisas if e1>e2: m2/=pow(2, e1-e2) # equivale a m2=m2/2**(e1-e2) er=e1 elif e1=1.0: mr/=2 er+=1 # Mantisa resultado en 4 bits, y máscara para signo mr=int(mr*16) if mr<0: sr=0b10000000 mr=-mr else: sr=0b00000000 # Exponente resultado en exceso de 4 y en posición correspondiente er+=4 er*=16 suma=sr|er|mr # or de bytes r[ixr]=suma elif cód==0x7: # OR de registros r[ixr]=r[ixop1]|r[ixop2] elif cód==0x8: # AND de registros r[ixr]=r[ixop1]&r[ixop2] elif cód==0x9: # XOR de registros r[ixr]=r[ixop1]^r[ixop2] # Transferencia entre memoria y cpu (registros), E/S con celdas puerto (FE entrada y FF salida) y carga de un patrón en un registro def transf(cód, ixr, ref, r, mem): ''' ixr es el número de registro destino o origen de la transferencia ref es una dirección de memoria o un patrón a cargar en el registro ixr r es la lista de registros internos de la CPU y mem la memoria central ''' if cód==0x1: # Se valida si es de transferencia desde el puerto de entrada if ref==0xfe: print('Elija una de las siguientes opciones:') print(' 1. Ingresar dos dígitos hexadecimales') print(' 2. Ingresar ocho dígitos binarios') forma=int(input('Opción: ')) if forma==1: r[ixr]=int(input('Ingrese el patrón según la opción escogida: '), 16) elif forma==2: r[ixr]=int(input('Ingrese el patrón según la opción escogida: '), 2) print() else: r[ixr]=mem[ref] # transferencia de memoria a registro elif cód==0x2: r[ixr]=ref # carga inmediata de patrón en registro else: # Se valida si es de transferencia al puerto de salida if ref==0xff: print(f'Salida en hexadecimal: {r[ixr]:02X}') print(f'Salida en binario: {r[ixr]:08b}') else: mem[ref]=r[ixr] # transferencia de registro a memoria # Rotación a derecha de registro ixr cant posiciones def rotar(ixr, cant, r): for i in range(cant): últimoBit=r[ixr] & 0b00000001 r[ixr]>>=1 if últimoBit==1: r[ixr]|=0b10000000 # PRÓLOGO ram=[0x00]*256 # inicialización de la ram reg=[0x00]*16 # inicialización de registros de la CPU pc=0x00 # inicialización del contador de programa de la CU de la CPU # Carga del programa en la ram: nomProg=input('Ingrese el nombre del archivo con el programa: ') print() prog=open(nomProg, 'r') # apertura del archivo con el programa para lectura for línea in prog: parte=línea.split() # descomposición de la línea del archivo en partes separadas por un espacio dirCelda=int(parte[0], 16) # se convierten la direcciones a números enteros, para usarlos como índices de ram instrucción=int(parte[1], 16) # se convierten las instrucciones a números enteros, para descomponerlas con operaciones aritméticas ram[dirCelda]=instrucción//256 # la primer celda de cada instrucción ocupa los 4 bits más significativos ram[dirCelda+1]=instrucción%256 # la segunda celda de cada instrucción ocupa los 4 bits menos significativos prog.close() # cierre del archivo con el preograma # Muestra del programa en pantalla for i in range(0,dirCelda+2, 2): print(f'{i:02X} {(ram[i]*256+ram[i+1]):X}') print() # DESARROLLO # Ciclo de máquina: ir, pc = fetch(ram, pc) # carga de la primera instrucción en el registro de la CU e incrementa en 2 al pc (contador de programa) código=ir//4096 while código != 0xc: # Decodificación de la instrucción: if código!=4: r=(ir//256)%16 else: r=(ir%256)//16 s=ir%16 if código>=0x5 and código<=0x9: s=(ir%256)//16 t=ir%16 elif código in {0x1, 0x2, 0x3, 0xb}: xy=ir%256 elif código==0xa: x=ir%16 # Ejecución de la instrucción if código>=0x5 and código<=0x9: alu(código, r, s, t, reg) # la instrucción es aritmética o lógica elif código in {0x1, 0x2, 0x3}: transf(código, r, xy, reg, ram) # la instrucción es de transferencia entre la cpu (registros) y la ram o de E/S elif código==0x4: reg[s]=reg[r] elif código==0xa: rotar(r, x, reg) else: # código=0xb, la instrucción es de control (salto) if reg[r]==reg[0]: pc=xy ir, pc = fetch(ram, pc) código=ir//4096 # EPÍLOGO print() input('Oprima Enter para terminar el programa...')