/*
 * 	@DESC: 	Lee dos bytes desde el pc del tcb, efectua operacion con ambos y los guarda en registro 'a'.
 * 			Cada byte es una letra de un registro.
 * 			Busca el valor del registro.
 */
resultado_t _funcion_operacion(tcb_t* tcb, int32_t operacion(int32_t, int32_t),
	int32_t condicion(int32_t), char* nombre)
{
	char registro1, registro2;

	if (leer_registro(tcb, &registro1) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_registro(tcb, &registro2) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	ansisop_ejecucion_instruccion6(nombre, registro1, registro2);

	int32_t valor_del_registro_1, valor_del_registro_2;

	if (obtener_valor_del_registro(tcb, registro1, &valor_del_registro_1)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	if (obtener_valor_del_registro(tcb, registro2, &valor_del_registro_2)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	if (condicion(valor_del_registro_2))
		return ERROR_EN_EJECUCION;

	actualizar_registro_a(tcb,
		operacion(valor_del_registro_1, valor_del_registro_2));

	return OK;
}
/*
 * 	SETM [Numero], [Registro], [Registro]
 *
 * 	Pone tantos bytes desde el segundo registro hacia la memoria
 * 		apuntada por el primer registro
 */
resultado_t setm(tcb_t* tcb)
{
	char registro1, registro2;
	int32_t valor_del_registro_1, valor_del_registro_2;
	int32_t cantidad_de_bytes_a_copiar;

	if (leer_numero(tcb, &cantidad_de_bytes_a_copiar)
		== FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_registro(tcb, &registro1) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_registro(tcb, &registro2) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	ansisop_ejecucion_instruccion4("SETM", cantidad_de_bytes_a_copiar,
		registro1, registro2);

	if (obtener_valor_del_registro(tcb, registro1, &valor_del_registro_1)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	if (obtener_valor_del_registro(tcb, registro2, &valor_del_registro_2)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	_copiar_bytes_a_memoria(tcb, valor_del_registro_1, valor_del_registro_2,
		cantidad_de_bytes_a_copiar);

	return OK;
}
/* 
 * LLAMADA AL SISTEMA: sis_buscar
 */
int sis_buscar()
{
	int descFichero;
	int offset;
	int ret;

	printk("-> Llamada buscar. id= %d\n", procesoActual->id);
	descFichero=(int)leer_registro(1);
	offset=(int)leer_registro(2);

	ret = buscarEnFichero(descFichero,offset);
	return (ret);
}
/* 
 * LLAMADA AL SISTEMA: sis_abrir
 */
int sis_abrir()
{
	char *nombre;
	int flags;
	int descFichero;

	printk("-> Llamada abrir. id= %d\n", procesoActual->id);
	nombre=(char *)leer_registro(1);
	flags=(int)leer_registro(2);

	descFichero = abrirFichero(nombre,flags);
	return (descFichero);
}
/* 
 * LLAMADA AL SISTEMA: sis_montar
 */
int sis_montar()	
{
	char *nombreDispositivo;
	char *nombreMontaje;
	char *nombreFS;
	int ret;

	printk("-> Llamada montar. id= %d\n", procesoActual->id);
	nombreDispositivo=(char *)leer_registro(1);
	nombreMontaje=(char *)leer_registro(2);
	nombreFS=(char *)leer_registro(3);

	ret = montarVolumen(nombreDispositivo, nombreMontaje,nombreFS);
	return (ret);
}
/* 
 * LLAMADA AL SISTEMA: sis_escribir
 */
int sis_escribir()
{
	int descFichero;
	char *buffer;
	int tamanyo;
	int ret;

	printk("-> Llamada escribir. id= %d\n", procesoActual->id);
	descFichero=(int)leer_registro(1);
	buffer=(char *)leer_registro(2);
	tamanyo=(int)leer_registro(3);

	ret = escribirFichero(descFichero,buffer,tamanyo);
	return (ret);
}
/* 
 * LLAMADA AL SISTEMA: sis_dormir
 */
int sis_dormir()
{
	TipoBCP * procesoAnterior;
	unsigned int segundos;	
	
	segundos = (unsigned int) leer_registro(1);
	
	/*Asignamos el valor de despertarEnTicks*/
	procesoActual->despertarEnTicks = ticks + (segundos*TICK);
	
	/*Insertamos el proceso en la lista de dormidos y cambiamos su estado*/	
	insertarOrdenadoListaBCP(&listaDormidos,procesoActual);
	procesoActual->estado = BLOQUEADO;
	
	/*Cambiamos al siguiente proceso que nos devuelve el planificador*/	
	procesoAnterior = procesoActual;
	procesoActual = planificador();
	
	/*En caso de que el proceso recuperado sea NULL, esperamos a que se encuentre el siguiente no 		NULL*/
	while (procesoActual == NULL) {
		esperaInterrupcion();
		procesoActual=planificador();
	}
	
	/*Cambiamos el estado del proceso y realizamos el cambio de contexto entre los dos procesos*/	
	procesoActual->estado = EJECUCION;
	cambio_contexto(&(procesoAnterior->contextoRegs), &(procesoActual->contextoRegs));

	return 0;
}
/* 
 * LLAMADA AL SISTEMA: sis_crearProceso
 */
int sis_crearProcesoAltaPrioridad()
{
	char *programa;
	int ret;

	printk("-> PROC %d: CREAR PROCESO\n", procesoActual->id);
	programa=(char *)leer_registro(1);
	/* ret=crearTarea(programa); */
	ret=crearTarea(programa, PRIORIDAD_ALTA); /* cambio */
	return ret;
}
/* 
 * LLAMADA AL SISTEMA: sis_desmontar
 */
int sis_desmontar()
{
	char *nombreMontaje;
	int ret;

	printk("-> Llamada desmontar. id= %d\n", procesoActual->id);
	nombreMontaje=(char *)leer_registro(1);

	ret = desmontarVolumen(nombreMontaje);
	return (ret);
}
/* 
 * LLAMADA AL SISTEMA: sis_cerrar
 */
int sis_cerrar()
{
	int descFichero;
	int ret;

	printk("-> Llamada cerrar. id= %d\n", procesoActual->id);
	descFichero=(int)leer_registro(1);

	ret = cerrarFichero(descFichero);
	return (ret);
}
/*
 * Funcion principal a la que se llama para 
 * el tratamiento de cualquier llamada al sistema
 */
void tratarLlamadaSistema()
{
	int numServicio, ret;

	numServicio=leer_registro(0);
	if (numServicio < NUMERO_SERVICIOS)
		ret=(tablaServicios[numServicio].funServicio)();
	else
		ret=-1;		/* servicio no existente */
	escribir_registro(0,ret);
	return;
}
/*
 * 	GETM [Registro], [Registro]
 *
 * 	Carga en el primer registro el valor de memoria apuntado por el segundo registro
 */
resultado_t getm(tcb_t* tcb)
{
	char buffer;
	char registro1, registro2;
	int32_t valor_del_registro_2;
	int32_t pid;

	if (leer_registro(tcb, &registro1) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_registro(tcb, &registro2) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	ansisop_ejecucion_instruccion6("GETM", registro1, registro2);

	if (obtener_valor_del_registro(tcb, registro2, &valor_del_registro_2)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	pid = tcb->pid;

	if (tcb->km)
		pid = 1;

	if (leer_de_memoria(pid, valor_del_registro_2, sizeof(char), &buffer)
		== FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	int32_t valor_de_memoria = buffer;

	if (actualizar_valor_del_registro(tcb, registro1, valor_de_memoria)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	return OK;
}
/*
 * 	MOVR [Registro], [Registro]
 *
 *	Copia el valor del segundo registro hacia el primero
 */
resultado_t movr(tcb_t* tcb)
{
	char registro1, registro2;

	if (leer_registro(tcb, &registro1) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_registro(tcb, &registro2) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	ansisop_ejecucion_instruccion6("MOVR", registro1, registro2);

	int32_t valor_del_registro_2;

	if (obtener_valor_del_registro(tcb, registro2, &valor_del_registro_2)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	if (actualizar_valor_del_registro(tcb, registro1, valor_del_registro_2)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	return OK;
}
/*
 * 	LOAD [Registro], [Numero]
 *
 * 	Carga en el registro el número dado
 */
resultado_t load(tcb_t* tcb)
{
	char registro;
	int32_t numero;

	if (leer_registro(tcb, &registro) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	if (leer_numero(tcb, &numero) == FALLO_LECTURA_DE_MEMORIA)
		return ERROR_EN_EJECUCION;

	ansisop_ejecucion_instruccion3("LOAD", numero, registro);

	if (actualizar_valor_del_registro(tcb, registro, numero)
		== EXCEPCION_NO_ENCONTRO_EL_REGISTRO)
		return ERROR_EN_EJECUCION;

	return OK;
}