#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 {
#ifdef FAST_RAM
int_fast32_t ram[(RAM_VELIKOST+2)*8];
#else
unsigned char ram[RAM_VELIKOST-2+2]; /**< ne vsebuje programskega števca, ampak vsebuje magic bite */
#endif
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));
#ifdef FAST_RAM
return e->ram[a];
#else
return e->ram[a/8-2] & (1 << (a % 8));
#endif
}
/**
* 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;
}
#ifdef FAST_RAM
e->ram[a] = v;
#else
if (v)
e->ram[a/8-2] |= (1 << (a % 8));
else
e->ram[a/8-2] &= ~(1 << (a % 8));
#endif
}
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);
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;
}