#include #include #include #include #include #include #include #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; }