summaryrefslogblamecommitdiffstats
path: root/ebs.c
blob: f2d1c9343b7e82f19fe617debda3c7a9086f8b7e (plain) (tree)



















































































































                                                                                                              
                


                                       
      












































































                                                                                                                                                                      
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <inttypes.h>
#include <signal.h>
#include <string.h>
#define RAM_VELIKOST 16
#ifndef NO_HOOKS
#define HOOK e->
#else
#define HOOK
#endif

typedef uint16_t naslov;

/**
 * držalo za enobitni stroj
 */

struct ebs {
	unsigned char ram[RAM_VELIKOST-2+2]; /**< ne vsebuje programskega števca, ampak vsebuje magic bite */
	unsigned char * pm;
	unsigned pm_velikost;
	uint16_t pc;
#ifndef NO_HOOKS
	bool (* peek)(struct ebs *, naslov);
	void (* poke)(struct ebs *, naslov, bool);
	struct inštrukcija (* inštrukcija)(struct ebs *, naslov);
#endif
	void * userdata;
	unsigned char vhod_medp;
	unsigned char vhod_medp_indeks;
	unsigned char izhod_medp;
	unsigned char izhod_medp_indeks;
	void (* vhod_prazen)(struct ebs *);
	void (* izhod_poln)(struct ebs *);
};

enum operacija {
	copy_ram = 0,
	copy_pm = 1,
	nand = 2,
	xor = 3
};

char * operacija_str[] = {"copyRAM", "copyPM", "nand", "xor"};

struct inštrukcija {
	unsigned vir;
	unsigned destinacija;
	enum operacija operacija;
	unsigned char * dobesedno;
};

/**
 * bralec rama
 *
 * @param 	[in]	držalo
 * @param a	[in]	naslov
 * @return vrednost v ramu na tem naslovu
 */

static bool peek (struct ebs * e, naslov a) {
	assert(a < RAM_VELIKOST*8+15);
	if (a < 16)
		return e->pc & (1 << (15-a));
	return e->ram[a/8-2] & (1 << (a % 8));
}

/**
 * pisalec rama
 *
 * @param e	[in]	držalo
 * @param a	[in]	naslov
 * @param v	[in]	vrednost
 */

static void poke (struct ebs * e, naslov a, bool v) {
	assert(a < RAM_VELIKOST*8+15);
	if (a < 16) {
		if (v)
			e->pc |= (1 << (15-a));
		else
			e->pc &= ~(1 << (15-a));
		return;
	}
	if (v)
		e->ram[a/8-2] |= (1 << (a % 8));
	else
		e->ram[a/8-2] &= ~(1 << (a % 8));
}

static struct inštrukcija inštrukcija (struct ebs * e, naslov a) {
	struct inštrukcija r = { 0 };
	if (!(a*2 < e->pm_velikost))
		return r;
	r.vir = (e->pm[a*2] & ~1) >> 1;
	r.destinacija = ((e->pm[a*2] & 1) << 6) | ((e->pm[a*2+1] & 0xfc) >> 2);
	r.operacija = e->pm[a*2+1] & 3;
	r.dobesedno = e->pm+a*2;
	return r;
}

static void vhod_prazen (struct ebs * e __attribute__((unused))) {
	return;
}

static void izhod_poln (struct ebs * e) {
	putchar(e->izhod_medp);
	fflush(stdout);
	e->izhod_medp_indeks = 0;
}

void ebs_init (struct ebs * e) {
	memset(e, '\0', sizeof *e);
#ifndef NO_HOOKS
	e->peek = peek;
	e->poke = poke;
	e->inštrukcija = inštrukcija;
#endif
	e->vhod_medp_indeks = 8;
	e->izhod_medp_indeks = 0;
	e->vhod_prazen = vhod_prazen;
	e->izhod_poln = izhod_poln;
}

/**
 * stanje izvajanja
 */

enum stanje {
	nadaljuj,
	konec,
	čaka_vhod,
	čaka_izhod
};

/**
 * požene eno inštrukcijo
 *
 * @param e	[in]	držalo
 * @return 
 */

enum stanje ebs_delo (struct ebs * e) {
	uint16_t prejšnji_pc = e->pc;
	if (!HOOK peek(e, 16+1) && e->vhod_medp_indeks < 8) {
		HOOK poke(e, 16+1, 1);
		HOOK poke(e, 16+0, e->vhod_medp & (1 << (7-e->vhod_medp_indeks++)));
	}
	if (HOOK peek(e, 16+3) && e->izhod_medp_indeks < 8) {
		HOOK poke(e, 16+3, 0);
		if (HOOK peek(e, 16+2))
			e->izhod_medp |= (1 << (7-e->izhod_medp_indeks++));
		else
			e->izhod_medp &= ~(1 << (7-e->izhod_medp_indeks++));
			
	}
	if (e->izhod_medp_indeks > 7)
		e->izhod_poln(e);
	struct inštrukcija š = HOOK inštrukcija(e, e->pc++);
	switch (š.operacija) {
		case nand:
			HOOK poke(e, š.destinacija, !(HOOK peek(e, š.destinacija) && HOOK peek(e, š.vir)));
			break;
		case xor:
			HOOK poke(e, š.destinacija, HOOK peek(e, š.destinacija) != HOOK peek(e, š.vir));
			break;
		case copy_ram:
			;
			unsigned char buffer[16];
			for (int i = 0; i < 16; i++)
				buffer[i] = HOOK peek(e, š.vir+i);
			for (int i = 0; i < 16; i++)
				HOOK poke(e, š.destinacija+i, buffer[i]);
			break;
		case copy_pm:
			;
			struct inštrukcija vir = HOOK inštrukcija(e, š.vir);
			for (int i = 0; i < 16; i++)
				HOOK poke(e, š.destinacija+i, vir.dobesedno ? vir.dobesedno[i/8] & (1 << (7-i%8)) : 0);
			break;
	}
	/* fprintf(stderr, "0x%04x\t%s\t0x%02x\t0x%02x\t0x%02x%02x ", e->pc-1, operacija_str[š.operacija], š.vir, š.destinacija, š.dobesedno[0], š.dobesedno[1]);
	for (int i = 0; i < 32; i++) {
		if (peek(e, i))
			fprintf(stderr, "1");
		else
			fprintf(stderr, "0");
		if (i == 15)
			fprintf(stderr, " ");
	}
	fprintf(stderr, "\n"); */
	if (e->pc == prejšnji_pc)
		return konec;
	return nadaljuj;
}