diff --git a/emu/chargen.inc b/emu/chargen.inc index 430d0fe..5f664b3 100644 --- a/emu/chargen.inc +++ b/emu/chargen.inc @@ -364,7 +364,7 @@ static int char_q[] = { static int char_r[] = { I, U|I, U|I, U|I, U|I, D|R|I, U|R|I, R|I, D|R|I, - D|R, D|R, D|R, + D|R, D|R, D, 0 }; diff --git a/emu/util.c b/emu/util.c index dca4bed..fcaed91 100644 --- a/emu/util.c +++ b/emu/util.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include diff --git a/fe6/6/emu6.c b/fe6/6/emu6.c index 0f977f8..f0282ee 100644 --- a/fe6/6/emu6.c +++ b/fe6/6/emu6.c @@ -477,6 +477,8 @@ cpu_printflags(void) void fe_svc(void) {} +void initcrt(const char *host) {} + void init6(void) { diff --git a/fe6/6/real6.c b/fe6/6/real6.c index d239931..b8c72c5 100755 --- a/fe6/6/real6.c +++ b/fe6/6/real6.c @@ -81,12 +81,17 @@ enum REG6_PTR = 035, REG6_PTR_LT = 036, REG6_PTR_RT = 037, + + REG6_DIS1 = 040, + REG6_DIS2 = 041, + REG6_DIS3 = 042, }; enum { FEREG_REQ = 0, FEREG_PTR, - FEREG_PTP + FEREG_PTP, + FEREG_DIS }; @@ -106,6 +111,7 @@ static volatile u32 *h2f_cmemif, *h2f_cmemif2; static volatile u32 *h2f_fmemif, *h2f_fmemif2; static volatile u32 *h2f_apr; static volatile u32 *h2f_fe; +static volatile u32 *h2f_csl; static volatile u32 *h2f_lw_led_addr; static volatile u32 *h2f_lw_sw_addr; @@ -137,13 +143,16 @@ deposit(hword a, word w) h2f_fmemif[1] = w & RT; h2f_fmemif[2] = (w >> 18) & RT; }else if(a < 01000020){ +void dep64(u32, u64); +if(0 && a < 01000){ +printf("dep %o %llo\r\n", a, w); +fflush(stdout); +} +// dep64(a, w); + h2f_cmemif[0] = a & RT; h2f_cmemif[1] = w & RT; h2f_cmemif[2] = (w >> 18) & RT; - }else if(a >= 02000000){ - h2f_cmemif2[0] = a & 01777777; - h2f_cmemif2[1] = w & RT; - h2f_cmemif2[2] = (w >> 18) & RT; }else switch(a){ case APR_DS: h2f_apr[REG6_DSLT] = w>>18 & RT; @@ -179,6 +188,8 @@ deposit(hword a, word w) *h2f_lw_led_addr = w; break; } + +// usleep(5); } word @@ -217,15 +228,13 @@ examine(hword a) w <<= 18; w |= h2f_fmemif[1] & RT; }else if(a < 01000020){ +//u64 ex64(u32); +// w = ex64(a); + h2f_cmemif[0] = a & RT; w = h2f_cmemif[2] & RT; w <<= 18; w |= h2f_cmemif[1] & RT; - }else if(a >= 02000000){ - h2f_cmemif2[0] = a & 01777777; - w = h2f_cmemif2[2] & RT; - w <<= 18; - w |= h2f_cmemif2[1] & RT; }else switch(a){ case APR_DS: w = h2f_apr[REG6_DSLT]; @@ -556,6 +565,33 @@ prflags(const char *fmt, u8 flags) l[!!(flags&02)], l[!!(flags&01)]); } +void +prdis(void) +{ + u32 dis1, dis2, dis3; + dis1 = h2f_apr[REG6_DIS1]; + dis2 = h2f_apr[REG6_DIS2]; + dis3 = h2f_apr[REG6_DIS3]; + printf("\r\nDIS\r\n"); + printf("BR/%06o\r\n", dis1); + printf("X/%04o Y/%04o BRM/%03o S/%02o I/%o SZ/%o MODE/%o\r\n", + dis2&01777, (dis2>>10)&01777, (dis2>>20)&0177, + (dis3>>8)&017, (dis3>>5)&7, (dis3>>3)&3, dis3&7); + printf("DATA REQ/%o STOP/%o EDGE/%o LP/%o LP ON/%o LP FIND/%o\r\n", + !!(dis3 & 04000000), + !!(dis3 & 0400000), + !!(dis3 & 02000000), + !!(dis3 & 040000), + !!(dis3 & 020000), + !!(dis3 & 010000)); + printf("MOVE/%o HALT/%o\r\n", + !!(dis3 & 0200000), + !!(dis3 & 0100000)); + + dis3 = h2f_apr[REG6_DIS3+1]; + printf("%X\r\n", dis3); +} + void cpu_printflags(void) { @@ -589,6 +625,8 @@ cpu_printflags(void) printf("RUN/%o MEM STOP/%o\r\n", !!(ctl1 & MM6_RUN), !!(ctl1 & MM6_MCSTOP)); + prdis(); + fflush(stdout); } @@ -628,6 +666,25 @@ fflush(stdout); write(fd, &c, 1); } +int dis_fd = -1; + +static void +svc_dis(void) +{ + u32 pnt; + pnt = h2f_fe[FEREG_DIS]; + if((pnt & 0x80000000) == 0) + return; + if(dis_fd >= 0) + write(dis_fd, &pnt, 4); +/* + else{ + printf("%X\r\n", pnt); + fflush(stdout); + } +*/ +} + void fe_svc(void) { @@ -637,8 +694,30 @@ fe_svc(void) if(req & 1) svc_ptr(); if(req & 2) svc_ptp(); +// if(req & 4) svc_dis(); + svc_dis(); } +void* +wcsl_thread(void *arg) +{ + u32 ctl; + while(readn(dis_fd, &ctl, 4) == 0){ +// printf("%o\r\n", ctl); +// fflush(stdout); + h2f_csl[ctl>>24] = ctl; + } +} + +void +initcrt(const char *host) +{ + dis_fd = dial(host, 3400); + if(dis_fd >= 0){ + printf("display connected\n"); + threadcreate(wcsl_thread, nil); + } +} void init6(void) @@ -668,11 +747,17 @@ init6(void) h2f_fmemif = getLWH2Faddr(0x10010); h2f_fmemif2 = getLWH2Faddr(0x20010); + // enable sdram bridge (???) + *(u32*)((u8*)virtual_base + 0x5080) = 0xFFFF; h2f_apr = getLWH2Faddr(0x10100); h2f_fe = getLWH2Faddr(0x20000); + h2f_csl = getLWH2Faddr(0x30000); h2f_lw_sw_addr = getLWH2Faddr(0x10020); h2f_lw_led_addr = getLWH2Faddr(0x10040); + + +// testshit(); } void diff --git a/fe6/Makefile b/fe6/Makefile index e84cb1e..b98f937 100644 --- a/fe6/Makefile +++ b/fe6/Makefile @@ -1,21 +1,22 @@ XX=/u/aap/de0-nano-soc/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- CFLAGS=-DTEST +LDFLAGS=-lpthread -SRC=fe.c cmd.c util.c pdp6common.c +SRC=fe.c cmd.c util.c netmem.c pdp6common.c threading.c all: fe6_emu fe6_fake fe6 feka clean: rm fe6_emu fe6_fake fe6 fe6: $(SRC) 6/real6.c - $(XX)gcc -I6 $(CFLAGS) -o $@ $^ + $(XX)gcc -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^ fe6_fake: $(SRC) fake.c - $(CC) -I6 $(CFLAGS) -o $@ $^ + $(CC) -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^ fe6_emu: $(SRC) 6/emu6.c - $(CC) -I6 $(CFLAGS) -o $@ $^ + $(CC) -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^ feka: $(SRC) ka/real.c - $(XX)gcc -Ika $(CFLAGS) -o $@ $^ + $(XX)gcc -Ika $(CFLAGS) $(LDFLAGS) -o $@ $^ diff --git a/fe6/cmd.c b/fe6/cmd.c index 9ea83b9..3d62716 100644 --- a/fe6/cmd.c +++ b/fe6/cmd.c @@ -114,8 +114,9 @@ sblk: chk = (chk<<1 | chk>>35) + w & FW; - if(d) + if(d){ deposit(right(iowd), w); + } iowd += 01000001; } if(readwits(fp) != chk) diff --git a/fe6/fake.c b/fe6/fake.c index af24616..ff9b213 100644 --- a/fe6/fake.c +++ b/fe6/fake.c @@ -188,6 +188,8 @@ cpu_printflags(void) void fe_svc(void) {} +void initcrt(const char *host) {} + void init6(void) { diff --git a/fe6/fe.c b/fe6/fe.c index 76d32c3..ea4a674 100644 --- a/fe6/fe.c +++ b/fe6/fe.c @@ -87,6 +87,7 @@ enum { MODE_ASCII, MODE_SIXBIT, MODE_SQUOZE, + MODE_FLOAT, /* flags */ CF = 1, // one altmode @@ -404,6 +405,7 @@ prword(int mode, word wd) int i; char c; char s[7]; + double f; switch(mode){ case MODE_ASCII: @@ -453,6 +455,12 @@ prword(int mode, word wd) typenum((wd>>18)&0777777); break; + case MODE_FLOAT: + f = pdptod(wd); + printf("%lf", f); + fflush(stdout); + break; + default: typenum(wd); } @@ -553,12 +561,14 @@ quit(void) int started; int -main() +threadmain(int argc, char *argv[]) { char chu; word t; init6(); + initcrt("soma"); +// initnetmem("10.0.0.222", 10006); raw(0); erasec = tiosaved.c_cc[VERASE]; @@ -603,6 +613,7 @@ main() typestr("/ "); t = examine(t); prword(MODE_SYM, t); + q = t; typestr(" "); started = 0; @@ -898,6 +909,9 @@ main() case '=': typeout(MODE_NUM); break; + case ';': + typeout(MODE_FLOAT); + break; case '"': if(flags & CF) modechange(MODE_ASCII); diff --git a/fe6/fe.h b/fe6/fe.h index 9afca6d..e04b267 100644 --- a/fe6/fe.h +++ b/fe6/fe.h @@ -5,6 +5,7 @@ #include #include "util.h" #include "pdp6common.h" +#include "threading.h" #define nil NULL @@ -18,7 +19,8 @@ typedef uint8_t u8; #define FW (LT|RT) #define F0 0400000000000 -#define MAXMEM (16*1024) +//#define MAXMEM (16*1024) +#define MAXMEM (256*1024) #include "regs.h" @@ -83,5 +85,8 @@ void cpu_printflags(void); void fe_svc(void); +void initcrt(const char *host); +void initnetmem(const char *host, int port); + void init6(void); void deinit6(void); diff --git a/fe6/ka/real.c b/fe6/ka/real.c index 569225e..aee984c 100755 --- a/fe6/ka/real.c +++ b/fe6/ka/real.c @@ -96,7 +96,8 @@ enum enum { FEREG_REQ = 0, FEREG_PTR, - FEREG_PTP + FEREG_PTP, + FEREG_DIS }; @@ -116,6 +117,7 @@ static volatile u32 *h2f_cmemif; static volatile u32 *h2f_fmemif; static volatile u32 *h2f_apr; static volatile u32 *h2f_fe; +static volatile u32 *h2f_csl; void deposit(hword a, word w) @@ -661,6 +663,23 @@ fflush(stdout); write(fd, &c, 1); } +int dis_fd; + +static void +svc_dis(void) +{ + u32 pnt; + pnt = h2f_fe[FEREG_DIS]; + if((pnt & 0x80000000) == 0) + return; + if(dis_fd >= 0) + write(dis_fd, &pnt, 4); + else{ + printf("%X\r\n", pnt); + fflush(stdout); + } +} + void fe_svc(void) { @@ -670,8 +689,30 @@ fe_svc(void) if(req & 1) svc_ptr(); if(req & 2) svc_ptp(); +// if(req & 4) svc_dis(); + svc_dis(); } +void* +wcsl_thread(void *arg) +{ + u32 ctl; + while(readn(dis_fd, &ctl, 4) == 0){ +// printf("%o\r\n", ctl); +// fflush(stdout); + h2f_csl[ctl>>24] = ctl; + } +} + +void +initcrt(const char *host) +{ + dis_fd = dial(host, 3400); + if(dis_fd >= 0){ + printf("display connected\n"); + threadcreate(wcsl_thread, nil); + } +} void init6(void) @@ -699,6 +740,7 @@ init6(void) h2f_fmemif = getLWH2Faddr(0x10010); h2f_apr = getLWH2Faddr(0x10100); h2f_fe = getLWH2Faddr(0x20000); + h2f_csl = getLWH2Faddr(0x30000); } void diff --git a/fe6/netmem.c b/fe6/netmem.c new file mode 100644 index 0000000..4326c94 --- /dev/null +++ b/fe6/netmem.c @@ -0,0 +1,81 @@ +#include "fe.h" +#include + +int netmemfd = -1; + +enum +{ + WRRQ = 1, + RDRQ = 2, + ACK = 3, + ERR = 4, +}; + +void* +netmemthread(void *arg) +{ + u16 len; + word a, d; + u8 buf[9]; + + while(readn(netmemfd, buf, 2) == 0){ + len = buf[0]<<8 | buf[1]; + if(len > 9){ + fprintf(stderr, "netmem botch(%d), closing\n", len); + close(netmemfd); + netmemfd = -1; + return nil; + } + memset(buf, 0, sizeof(buf)); + readn(netmemfd, buf, len); + + a = buf[1] | buf[2]<<8 | buf[3]<<16; + d = buf[4] | buf[5]<<8 | buf[6]<<16 | + (word)buf[7]<<24 | (word)buf[8]<<32; + a &= 0777777; + d &= 0777777777777; + + switch(buf[0]){ + case WRRQ: + deposit(a, d); + printf("write %06lo %012lo\r\n", a, d); + fflush(stdout); + buf[0] = 0; + buf[1] = 1; + buf[2] = ACK; + writen(netmemfd, buf, buf[1]+2); + break; + case RDRQ: + d = examine(a); + printf("read %06lo %012lo\r\n", a, d); + fflush(stdout); + buf[0] = 0; + buf[1] = 6; + buf[2] = ACK; + buf[3] = d; + buf[4] = d>>8; + buf[5] = d>>16; + buf[6] = d>>24; + buf[7] = d>>32; + writen(netmemfd, buf, buf[1]+2); + break; + default: + fprintf(stderr, "unknown netmem message %d\n", buf[0]); + break; + } + } + fprintf(stderr, "netmem fd closed\n"); + netmemfd = -1; + return nil; +} + +void +initnetmem(const char *host, int port) +{ + netmemfd = dial(host, port); + if(netmemfd >= 0){ + printf("netmem connected\n"); + threadcreate(netmemthread, nil); + } +} + diff --git a/fe6/threading.c b/fe6/threading.c new file mode 100644 index 0000000..d9b7be2 --- /dev/null +++ b/fe6/threading.c @@ -0,0 +1,361 @@ +#include "threading.h" +#include + +#define USED(x) (void)(x) + +/* + * Locks + */ + +static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; + +static void +lockinit(Lock *lk) +{ + pthread_mutexattr_t attr; + + pthread_mutex_lock(&initmutex); + if(lk->init == 0){ + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&lk->mutex, &attr); + pthread_mutexattr_destroy(&attr); + lk->init = 1; + } + pthread_mutex_unlock(&initmutex); +} + +void +lock(Lock *lk) +{ + if(!lk->init) + lockinit(lk); + if(pthread_mutex_lock(&lk->mutex) != 0) + abort(); +} + +int +canlock(Lock *lk) +{ + int r; + + if(!lk->init) + lockinit(lk); + r = pthread_mutex_trylock(&lk->mutex); + if(r == 0) + return 1; + if(r == EBUSY) + return 0; + abort(); +} + +void +unlock(Lock *lk) +{ + if(pthread_mutex_unlock(&lk->mutex) != 0) + abort(); +} + + + +static void +rendinit(Rendez *r) +{ + pthread_condattr_t attr; + + pthread_mutex_lock(&initmutex); + if(r->init == 0){ + pthread_condattr_init(&attr); + pthread_cond_init(&r->cond, &attr); + pthread_condattr_destroy(&attr); + r->init = 1; + } + pthread_mutex_unlock(&initmutex); +} + +void +rsleep(Rendez *r) +{ + if(!r->init) + rendinit(r); + if(pthread_cond_wait(&r->cond, &r->l->mutex) != 0) + abort(); +} + +void +rwakeup(Rendez *r) +{ + if(!r->init) + return; + if(pthread_cond_signal(&r->cond) != 0) + abort(); +} + +void +rwakeupall(Rendez *r) +{ + if(!r->init) + return; + if(pthread_cond_broadcast(&r->cond) != 0) + abort(); +} + + +/* + * Threads + */ + + +static Lock idlock; +static pthread_t *threads; +static int numthreads; +static int maxthreads; + +static __thread int myid; +static __thread void *mypointer; + +static int +addthreadid(void) +{ + int id; + + if(numthreads >= maxthreads){ + maxthreads += 64; + threads = realloc(threads, maxthreads*sizeof(*threads)); + } + id = numthreads++; + threads[id] = 0; + return id; +} + +static pthread_t +gethandle(int id) +{ + pthread_t th; + lock(&idlock); + th = threads[id]; + unlock(&idlock); + return th; +} + +struct ThreadArg +{ + int id; + void *(*f)(void*); + void *arg; +}; + +static void* +trampoline(void *p) +{ + struct ThreadArg *args; + void *(*f)(void*); + void *arg; + + args = p; + myid = args->id; + f = args->f; + arg = args->arg; + free(args); + return f(arg); +} + +int +threadcreate(void *(*f)(void*), void *arg) +{ + struct ThreadArg *args; + int id; + + lock(&idlock); + id = addthreadid(); + args = malloc(sizeof(*args)); + args->id = id; + args->f = f; + args->arg = arg; + pthread_create(&threads[id], nil, trampoline, args); + unlock(&idlock); + return id; +} + +void +threadexits(void *ret) +{ + pthread_exit(ret); +} + +int +threadid(void) +{ + return myid; +} + +void** +threaddata(void) +{ + return &mypointer; +} + +void +threadkill(int id) +{ + assert(id >= 0 && id < numthreads); + pthread_cancel(gethandle(id)); +} + +void +threadwait(int id) +{ + pthread_join(gethandle(id), nil); +} + +int +main(int argc, char *argv[]) +{ + int id; + + id = addthreadid(); + threads[id] = pthread_self(); + return threadmain(argc, argv); +} + + +/* + * Channels + */ + + +Channel* +chancreate(int elemsize, int bufsize) +{ + Channel *c; + + c = malloc(sizeof(Channel) + bufsize*elemsize); + if(c == nil) + return nil; + memset(c, 0, sizeof(Channel)); + c->elemsize = elemsize; + c->bufsize = bufsize; + c->nbuf = 0; + c->buf = (uchar*)(c+1); + c->full.l = &c->lock; + c->empty.l = &c->lock; + return c; +} + +void +chanclose(Channel *c) +{ + lock(&c->lock); + c->closed = 1; + rwakeupall(&c->full); + rwakeupall(&c->empty); + unlock(&c->lock); +} + +void +chanfree(Channel *c) +{ + // TODO: don't free chans still in use + free(c); +} + +static int cansend(Channel *c) { return c->nbuf < c->bufsize; } +static int canrecv(Channel *c) { return c->nbuf > 0; } + +static void +chansend_(Channel *c, void *p) +{ + uchar *pp; + + assert(cansend(c)); + pp = c->buf + (c->off+c->nbuf)%c->bufsize * c->elemsize; + memmove(pp, p, c->elemsize); + c->nbuf++; +} + +static void +chanrecv_(Channel *c, void *p) +{ + uchar *pp; + + assert(canrecv(c)); + pp = c->buf + c->off*c->elemsize; + memmove(p, pp, c->elemsize); + c->nbuf--; + if(++c->off == c->bufsize) + c->off = 0; +} + +int +chansend(Channel *c, void *p) +{ + lock(&c->lock); + while(!(c->closed || cansend(c))) + rsleep(&c->full); + /* closed or can send */ + if(c->closed){ + /* can never send to closed chan */ + unlock(&c->lock); + return -1; + } + chansend_(c, p); + rwakeup(&c->empty); + unlock(&c->lock); + return 1; +} + +int +chanrecv(Channel *c, void *p) +{ + lock(&c->lock); + while(!(c->closed || canrecv(c))) + rsleep(&c->empty); + /* closed or can receive */ + if(canrecv(c)){ + /* can still receive from closed chan */ + chanrecv_(c, p); + rwakeup(&c->full); + unlock(&c->lock); + return 1; + } + unlock(&c->lock); + return -1; +} + +int +channbsend(Channel *c, void *p) +{ + lock(&c->lock); + if(c->closed){ + /* can never send to closed chan */ + unlock(&c->lock); + return -1; + } + if(cansend(c)){ + chansend_(c, p); + rwakeup(&c->empty); + unlock(&c->lock); + return 1; + } + unlock(&c->lock); + return 0; +} + +int +channbrecv(Channel *c, void *p) +{ + lock(&c->lock); + if(canrecv(c)){ + /* can still receive from closed chan */ + chanrecv_(c, p); + rwakeup(&c->full); + unlock(&c->lock); + return 1; + } + if(c->closed){ + unlock(&c->lock); + return -1; + } + unlock(&c->lock); + return 0; +} diff --git a/fe6/threading.h b/fe6/threading.h new file mode 100644 index 0000000..b753eec --- /dev/null +++ b/fe6/threading.h @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#define nil NULL +typedef unsigned char uchar; +typedef unsigned int uint; + +typedef struct Lock Lock; +struct Lock +{ + int init; + pthread_mutex_t mutex; +}; +void lock(Lock *lk); +int canlock(Lock *lk); +void unlock(Lock *lk); + + +typedef struct Rendez Rendez; +struct Rendez +{ + int init; + Lock *l; + pthread_cond_t cond; +}; +void rsleep(Rendez *r); +void rwakeup(Rendez *r); +void rwakeupall(Rendez *r); + + +typedef struct Channel Channel; +struct Channel +{ + int bufsize; + int elemsize; + uchar *buf; + int nbuf; + int off; + + int closed; + Lock lock; + Rendez full, empty; +}; +Channel *chancreate(int elemsize, int bufsize); +void chanclose(Channel *chan); +void chanfree(Channel *c); +int chansend(Channel *c, void *p); +int chanrecv(Channel *c, void *p); +int channbsend(Channel *c, void *p); +int channbrecv(Channel *c, void *p); + +int threadmain(int argc, char *argv[]); +int threadcreate(void *(*f)(void*), void *arg); +void threadexits(void *ret); +int threadid(void); +void **threaddata(void); +void threadkill(int id); +void threadwait(int id); diff --git a/fe6/util.c b/fe6/util.c index cdd48d5..dc78b36 100644 --- a/fe6/util.c +++ b/fe6/util.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include diff --git a/tools/as6.c b/tools/as6.c index 2167012..7f2d7a4 100644 --- a/tools/as6.c +++ b/tools/as6.c @@ -1195,8 +1195,8 @@ opline(word w, int io) w |= 0000020000000; w = fw(left(w), right(w)+right(y.val)); /* TODO: really warn about this? */ - if(left(y.val)) - err(0, "warning: address too large"); +// if(left(y.val)) +// err(0, "warning: address too large"); w = fw(left(w)+left(x.val), right(w)+right(x.val)); if(x.rel) err(0, "warning: X relocation ignored"); @@ -1732,9 +1732,9 @@ checkundef(int glob) s->type != Operator && s->type != IoOperator && s->type != Pseudo){ unsixbit(s->name, name); if(s->type == Undef){ - if(glob) - s->type |= Extern; - else +// if(glob) +// s->type |= Extern; +// else err(1, "undefined symbol: %s\n", name); } } @@ -1909,6 +1909,7 @@ main(int argc, char *argv[]) pass2 = 1; + radix = 8; // printf("\n PASS2\n\n"); startitem(Name); diff --git a/tools/scon33.c b/tools/scon33.c new file mode 100644 index 0000000..127ad71 --- /dev/null +++ b/tools/scon33.c @@ -0,0 +1,111 @@ +#define _XOPEN_SOURCE 600 /* for ptys */ +#define _DEFAULT_SOURCE /* for cfmakeraw */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct termios tiosaved; + +int +raw(int fd) +{ + struct termios tio; + if(tcgetattr(fd, &tio) < 0) return -1; + tiosaved = tio; + cfsetispeed(&tio, B110); + cfsetospeed(&tio, B110); + cfmakeraw(&tio); + tio.c_cflag |= CSTOPB; + if(tcsetattr(fd, TCSAFLUSH, &tio) < 0) return -1; + return 0; +} + +int +reset(int fd) +{ + if(tcsetattr(0, TCSAFLUSH, &tiosaved) < 0) return -1; + return 0; +} + +/* tty1: unix tty + * tty2: serial port */ +void +readwrite(int tty1in, int tty1out, int tty2in, int tty2out) +{ + int n; + struct pollfd pfd[2]; + char c; + + pfd[0].fd = tty2in; + pfd[0].events = POLLIN; + pfd[1].fd = tty1in; + pfd[1].events = POLLIN; + while(pfd[0].fd != -1){ + n = poll(pfd, 2, -1); + if(n < 0){ + perror("error poll"); + return; + } + if(n == 0) + return; + if(pfd[0].revents & POLLHUP) + return; + /* read from tty2, write to tty1 */ + if(pfd[0].revents & POLLIN){ + if(n = read(tty2in, &c, 1), n <= 0) + return; + else{ + c &= 0177; +//if(c == '\a') c = '.'; + if(c < 0140) + write(tty1out, &c, 1); + } + } + /* read from tty1, write to tty2 */ + if(pfd[1].revents & POLLIN){ + if(n = read(tty1in, &c, 1), n <= 0) + return; + else{ + if(c == 035) + return; + /* map character reasonably */ + if(c == 033) c = 0175; // esc to altmode + if(c >= 'a' && c <= 'z') // to upper + c &= ~040; + c |= 0200; // needed? + write(tty2out, &c, 1); + } + } + } +} + +int +main(int argc, char *argv[]) +{ + int fd; + + if(argc < 2) + return 1; + + fd = open(argv[1], O_RDWR); + if(fd < 0) + return 1; + + raw(fd); + raw(0); + + readwrite(0, 1, fd, fd); + printf("\r\n\r\n"); + close(fd); + + reset(0); + + return 0; +} diff --git a/verilog/apr.v b/verilog/apr.v index 0c646d1..132820c 100644 --- a/verilog/apr.v +++ b/verilog/apr.v @@ -155,10 +155,11 @@ module apr( wire key_dp_OR_dp_nxt = key_dep_sync | key_dep_nxt; wire key_run_AND_NOT_ex_OR_dep = run & ~key_ex_OR_dep_st; wire key_ex_OR_ex_nxt = key_ex_sync | key_ex_nxt; - wire key_manual = key_ex | key_ex_nxt | + wire key_manual = ~key_pwr_clr_enbl & + (key_ex | key_ex_nxt | key_dep | key_dep_nxt | key_start | key_inst_cont | key_mem_cont | - key_io_reset | key_execute | key_read_in; + key_io_reset | key_execute | key_read_in); wire key_ex_OR_dep_st = key_ex_st | key_dep_st; wire key_run_AND_ex_OR_dep = run & key_ex_OR_dep_st; wire key_execute_OR_dp_OR_dp_nxt = key_execute | key_dp_OR_dp_nxt; @@ -185,6 +186,7 @@ module apr( wire kt0a_D, kt1_D, kt2_D, kt3_D; `ifdef simulation + wire key_pwr_clr_enbl = 0; pg key_pg0(.clk(clk), .reset(reset), .in(sw_power), .p(mr_pwr_clr)); `else wire sw_power_pulse; @@ -1207,7 +1209,7 @@ module apr( wire ar_jrst_AND_ir11 = ir_jrst & ir[11]; wire ar_flag_set = et1 & ar_jrst_AND_ir11; wire ar_jfcl_clr = et10 & ir_jfcl; - wire ar_eq_fp_half = ar == 36'o000400000000; + wire ar_eq_fp_half = ar[9:35] == 27'o400000000; wire ar_eq_0 = ar == 0; wire ar0_xor_ar1 = ar[0] ^ ar[1]; wire ar_ov_set = ar_cry0 ^ ar_cry1; diff --git a/verilog/core256k_x.v b/verilog/core256k_x.v new file mode 100644 index 0000000..9b4c2cb --- /dev/null +++ b/verilog/core256k_x.v @@ -0,0 +1,404 @@ +module core256k( + input wire clk, + input wire reset, + input wire power, + input wire sw_single_step, + input wire sw_restart, + + input wire membus_wr_rs_p0, + input wire membus_rq_cyc_p0, + input wire membus_rd_rq_p0, + input wire membus_wr_rq_p0, + input wire [21:35] membus_ma_p0, + input wire [18:21] membus_sel_p0, + input wire membus_fmc_select_p0, + input wire [0:35] membus_mb_in_p0, + output wire membus_addr_ack_p0, + output wire membus_rd_rs_p0, + output wire [0:35] membus_mb_out_p0, + + input wire membus_wr_rs_p1, + input wire membus_rq_cyc_p1, + input wire membus_rd_rq_p1, + input wire membus_wr_rq_p1, + input wire [21:35] membus_ma_p1, + input wire [18:21] membus_sel_p1, + input wire membus_fmc_select_p1, + input wire [0:35] membus_mb_in_p1, + output wire membus_addr_ack_p1, + output wire membus_rd_rs_p1, + output wire [0:35] membus_mb_out_p1, + + input wire membus_wr_rs_p2, + input wire membus_rq_cyc_p2, + input wire membus_rd_rq_p2, + input wire membus_wr_rq_p2, + input wire [21:35] membus_ma_p2, + input wire [18:21] membus_sel_p2, + input wire membus_fmc_select_p2, + input wire [0:35] membus_mb_in_p2, + output wire membus_addr_ack_p2, + output wire membus_rd_rs_p2, + output wire [0:35] membus_mb_out_p2, + + input wire membus_wr_rs_p3, + input wire membus_rq_cyc_p3, + input wire membus_rd_rq_p3, + input wire membus_wr_rq_p3, + input wire [21:35] membus_ma_p3, + input wire [18:21] membus_sel_p3, + input wire membus_fmc_select_p3, + input wire [0:35] membus_mb_in_p3, + output wire membus_addr_ack_p3, + output wire membus_rd_rs_p3, + output wire [0:35] membus_mb_out_p3, + + // 36 bit Avalon Master + output wire [17:0] m_address, + output reg m_write, + output reg m_read, + output wire [35:0] m_writedata, + input wire [35:0] m_readdata, + input wire m_waitrequest +); + // TODO: SP + wire cmc_sp = 0; + + reg [18:35] cma; + reg cma_rd_rq, cma_wr_rq; + reg [0:35] cmb; + + // TODO: interleave + + wire cmpc_p0_rq = + ~membus_fmc_select_p0 & + membus_rq_cyc_p0 & + cmc_await_rq; + wire cmpc_p1_rq = + ~membus_fmc_select_p1 & + membus_rq_cyc_p1 & + cmc_await_rq; + wire cmpc_p2_rq = + ~membus_fmc_select_p2 & + membus_rq_cyc_p2 & + cmc_await_rq; + wire cmpc_p3_rq = + ~membus_fmc_select_p3 & + membus_rq_cyc_p3 & + cmc_await_rq; + + wire [18:35] ma_p0 = { membus_sel_p0[18:21], membus_ma_p0[22:35] }; + wire [18:35] ma_p1 = { membus_sel_p1[18:21], membus_ma_p1[22:35] }; + wire [18:35] ma_p2 = { membus_sel_p2[18:21], membus_ma_p2[22:35] }; + wire [18:35] ma_p3 = { membus_sel_p3[18:21], membus_ma_p3[22:35] }; + + wire [18:35] ma_in = + {18{cmc_p0_sel}}&ma_p0 | + {18{cmc_p1_sel}}&ma_p1 | + {18{cmc_p2_sel}}&ma_p2 | + {18{cmc_p3_sel}}&ma_p3; + wire rd_rq_in = + cmc_p0_sel&membus_rd_rq_p0 | + cmc_p1_sel&membus_rd_rq_p1 | + cmc_p2_sel&membus_rd_rq_p2 | + cmc_p3_sel&membus_rd_rq_p3; + wire wr_rq_in = + cmc_p0_sel&membus_wr_rq_p0 | + cmc_p1_sel&membus_wr_rq_p1 | + cmc_p2_sel&membus_wr_rq_p2 | + cmc_p3_sel&membus_wr_rq_p3; + wire [0:35] mb_in = + {36{cmc_p0_sel}}&membus_mb_in_p0 | + {36{cmc_p1_sel}}&membus_mb_in_p1 | + {36{cmc_p2_sel}}&membus_mb_in_p2 | + {36{cmc_p3_sel}}&membus_mb_in_p3; + pa cmpc_pa0(clk, reset, cmc_t1b&cmc_p0_sel, membus_addr_ack_p0); + pa cmpc_pa1(clk, reset, cmc_t1b&cmc_p1_sel, membus_addr_ack_p1); + pa cmpc_pa2(clk, reset, cmc_t1b&cmc_p2_sel, membus_addr_ack_p2); + pa cmpc_pa3(clk, reset, cmc_t1b&cmc_p3_sel, membus_addr_ack_p3); + assign membus_rd_rs_p0 = cmc_rd_rs&cmc_p0_sel; + assign membus_rd_rs_p1 = cmc_rd_rs&cmc_p1_sel; + assign membus_rd_rs_p2 = cmc_rd_rs&cmc_p2_sel; + assign membus_rd_rs_p3 = cmc_rd_rs&cmc_p3_sel; + assign membus_mb_out_p0 = sa & {36{stb_pulse & cmc_p0_sel}}; + assign membus_mb_out_p1 = sa & {36{stb_pulse & cmc_p1_sel}}; + assign membus_mb_out_p2 = sa & {36{stb_pulse & cmc_p2_sel}}; + assign membus_mb_out_p3 = sa & {36{stb_pulse & cmc_p3_sel}}; + wire cmpc_rs_set = membus_wr_rs_p0 & cmc_p0_sel | + membus_wr_rs_p1 & cmc_p1_sel | + membus_wr_rs_p2 & cmc_p2_sel | + membus_wr_rs_p3 & cmc_p3_sel; + + + // TODO: this is all wrong + wire pwr_t1, pwr_t2, pwr_t3; + wire cmc_await_rq_reset, cmc_pwr_clr, cmc_pwr_start; + pg pg0(clk, reset, power, pwr_t1); + // 200ms + ldly1us dly0(clk, reset, pwr_t1, pwr_t2, cmc_await_rq_reset); + // 100μs + ldly1us dly1(clk, reset, pwr_t2, pwr_t3, cmc_pwr_clr); + pa pa0(clk, reset, pwr_t3, cmc_pwr_start); + + + // core control, we don't really have a use for it + reg cmc_read, cmc_write, cmc_inh; + + reg cmc_rq_sync, cmc_cyc_done; + reg cmc_await_rq, cmc_pse_sync, cmc_proc_rs, cmc_stop; + + reg cmc_p0_act, cmc_p1_act, cmc_p2_act, cmc_p3_act; + reg cmc_last_proc; + + // TODO: SP + wire cmc_p0_sel = cmc_p0_act; + wire cmc_p1_sel = cmc_p1_act; + wire cmc_p2_sel = cmc_p2_act; + wire cmc_p3_sel = cmc_p3_act; + + wire cmc_t0, cmc_t1b, cmc_t1a, cmc_t2, cmc_t3; + wire cmc_t4, cmc_t5, cmc_t6, cmc_t6p; + wire cmc_t0_D, cmc_t2_D1; + wire cmc_t3_D1, cmc_t3_D2; + + wire cmc_restart; + wire cmc_start; + wire cmc_state_clr; + wire cmc_pn_act = cmc_p0_act | cmc_p1_act | cmc_p2_act | cmc_p3_act; + wire cmc_aw_rq_set = cmc_t0_D & ~cmc_pn_act; + wire cmc_rq_sync_set = cmc_t0_D & ~cmc_sp & cmc_pn_act; + wire cmc_jam_cma = cmc_t1b; + wire cmc_cmb_clr; + wire cmc_read_off; + wire cmc_pse_sync_set; + wire strobe_sense; + wire cmc_rd_rs; + wire cmpc_rs_set_D; + wire cmc_proc_rs_pulse; + + pa pa1(clk, reset, + (cmpc_p0_rq | cmpc_p1_rq | cmpc_p2_rq | cmpc_p3_rq), + cmc_t0); + pa pa2(clk, reset, cmc_restart | cmc_pwr_start, cmc_start); + pa pa3(clk, reset, cmc_start | cmc_t3_D1, cmc_t5); + pa pa4(clk, reset, cmc_start | cmc_t3_D2, cmc_t6p); + pa pa5(clk, reset, + cmc_start | cmc_t3 & ~cma_wr_rq | cmc_proc_rs_pulse, + cmc_state_clr); + pa pa6(clk, reset, cmc_rq_sync&cmc_cyc_done, cmc_t1b); + pa pa7(clk, reset, cmc_t1b, cmc_t1a); + pa pa9(clk, reset, + cmc_t1b | cmc_pse_sync_set&cma_rd_rq&cma_wr_rq, + cmc_cmb_clr); + pa pa11(clk, reset, cmc_t2_D1&cma_rd_rq, strobe_sense); + pa pa12(clk, reset, stb_pulse, cmc_rd_rs); + + pa pa13(clk, reset, cmc_pse_sync&(cmc_proc_rs | ~cma_wr_rq), cmc_t3); + pa pa14(clk, reset, cmc_proc_rs, cmc_proc_rs_pulse); + // probably wrong + pa pa15(clk, reset, sw_restart, cmc_restart); + + + dly250ns dly2(clk, reset, cmc_t6p, cmc_t6); + dly100ns dly3(clk, reset, cmc_t0, cmc_t0_D); + dly250ns dly4(clk, reset, cmc_t1a, cmc_t2); + dly200ns dly5(clk, reset, cmc_t2, cmc_read_off); + dly100ns dly6(clk, reset, rd_pulse, cmc_pse_sync_set); + // Variable 35-100ns + dly70ns dly7(clk, reset, cmc_t2, cmc_t2_D1); + dly50ns dly9(clk, reset, cmc_t3, cmc_t4); + dly500ns dly10(clk, reset, cmc_t4, cmc_t3_D1); + dly200ns dly11(clk, reset, cmc_t3_D1, cmc_t3_D2); + dly50ns dly12(clk, reset, cmpc_rs_set, cmpc_rs_set_D); + + + reg [0:35] sa; // "sense amplifiers" + wire [17:0] core_addr = cma[18:35]; + + assign m_address = core_addr; + assign m_writedata = cmb; + + + reg stb_sync, stb_done; + wire stb_pulse; + pa pa100(clk, reset, stb_sync&stb_done, stb_pulse); + + reg rd_sync, rd_done; + wire rd_pulse; + pa pa101(clk, reset, rd_sync&rd_done, rd_pulse); + + reg wr_sync, wr_done; + wire wr_pulse; + pa pa102(clk, reset, wr_sync&wr_done, wr_pulse); + + + always @(posedge clk or posedge reset) begin + if(reset) begin + m_read <= 0; + m_write <= 0; + sa <= 0; + + stb_sync <= 0; + stb_done <= 0; + rd_sync <= 0; + rd_done <= 0; + wr_sync <= 0; + wr_done <= 0; + + // value doesn't matter + cmc_last_proc <= 0; + // these should probably be reset but aren't + cmc_proc_rs <= 0; + cmc_pse_sync <= 0; + end else begin + if(m_write & ~m_waitrequest) begin + m_write <= 0; + wr_done <= 1; + end + if(m_read & ~m_waitrequest) begin + m_read <= 0; + sa <= m_readdata; + stb_done <= 1; + end + + if(cmc_start) + wr_done <= 1; + + if(cmc_state_clr) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end + if(cmpc_p0_rq | cmpc_p1_rq | cmpc_p2_rq | cmpc_p3_rq) begin + if(cmpc_p0_rq) begin + cmc_p0_act <= 1; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end else if(cmpc_p1_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 1; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end else if(cmpc_p2_rq & cmpc_p3_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= cmc_last_proc; + cmc_p3_act <= ~cmc_last_proc; + cmc_last_proc <= ~cmc_last_proc; + end else if(cmpc_p2_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 1; + cmc_p3_act <= 0; + end else if(cmpc_p3_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 1; + end + end + if(cmc_t2) begin + if(cmc_p2_act) + cmc_last_proc <= 0; + if(cmc_p3_act) + cmc_last_proc <= 1; + end + + if(cmc_t0 | cmc_await_rq_reset) + cmc_await_rq <= 0; + if(cmc_t5 | cmc_aw_rq_set) + cmc_await_rq <= 1; + + if(cmc_start | cmc_pwr_clr) + cmc_rq_sync <= 0; + if(cmc_rq_sync_set | cmc_t0 & cmc_sp) + cmc_rq_sync <= 1; + + if(cmc_pwr_clr) + cmc_cyc_done <= 0; + if(wr_pulse & ~cmc_stop) + cmc_cyc_done <= 1; + if(cmc_t6) + wr_sync <= 1; + + if(cmc_t1b) begin + cmc_pse_sync <= 0; + cmc_proc_rs <= 0; + cmc_stop <= 0; + end + + // actually through another PA + if(cmc_pse_sync_set) + cmc_pse_sync <= 1; + + if(cmpc_rs_set_D) + cmc_proc_rs <= 1; + + if(cmc_start) + cmc_stop <= 0; + if(cmc_t2 & sw_single_step) + cmc_stop <= 1; + + if(cmc_t2) begin + cmc_rq_sync <= 0; + cmc_cyc_done <= 0; + end + + + if(cmc_jam_cma) begin + cma <= ma_in; + cma_rd_rq <= rd_rq_in; + cma_wr_rq <= wr_rq_in; + end + + cmb <= cmb | mb_in; + if(cmc_cmb_clr) + cmb <= 0; + if(strobe_sense) + stb_sync <= 1; + if(stb_pulse) begin + stb_sync <= 0; + stb_done <= 0; + rd_done <= 1; + cmb <= cmb | sa; + end + + /* Core */ + if(cmc_pwr_clr | cmc_t5) begin + cmc_read <= 0; + cmc_write <= 0; + cmc_inh <= 0; + end + if(cmc_t1a) begin + cmc_read <= 1; + m_read <= cma_rd_rq; + stb_done <= 0; + rd_done <= ~cma_rd_rq; + cmc_write <= 0; + end + if(cmc_read_off) begin + cmc_read <= 0; + rd_sync <= 1; + end + if(rd_pulse) begin + rd_sync <= 0; + rd_done <= 0; + end + if(cmc_t3) begin + cmc_inh <= 1; + m_write <= cma_wr_rq; + wr_done <= ~cma_wr_rq; + end + if(cmc_t4) begin + cmc_write <= 1; + cmc_read <= 0; + end + if(wr_pulse) begin + wr_sync <= 0; + wr_done <= 0; + end + end + end +endmodule diff --git a/verilog/core32k.v b/verilog/core32k.v old mode 100644 new mode 100755 diff --git a/verilog/core32k_x.v b/verilog/core32k_x.v new file mode 100644 index 0000000..82b6a3a --- /dev/null +++ b/verilog/core32k_x.v @@ -0,0 +1,405 @@ +module core32k( + input wire clk, + input wire reset, + input wire power, + input wire sw_single_step, + input wire sw_restart, + + input wire membus_wr_rs_p0, + input wire membus_rq_cyc_p0, + input wire membus_rd_rq_p0, + input wire membus_wr_rq_p0, + input wire [21:35] membus_ma_p0, + input wire [18:21] membus_sel_p0, + input wire membus_fmc_select_p0, + input wire [0:35] membus_mb_in_p0, + output wire membus_addr_ack_p0, + output wire membus_rd_rs_p0, + output wire [0:35] membus_mb_out_p0, + + input wire membus_wr_rs_p1, + input wire membus_rq_cyc_p1, + input wire membus_rd_rq_p1, + input wire membus_wr_rq_p1, + input wire [21:35] membus_ma_p1, + input wire [18:21] membus_sel_p1, + input wire membus_fmc_select_p1, + input wire [0:35] membus_mb_in_p1, + output wire membus_addr_ack_p1, + output wire membus_rd_rs_p1, + output wire [0:35] membus_mb_out_p1, + + input wire membus_wr_rs_p2, + input wire membus_rq_cyc_p2, + input wire membus_rd_rq_p2, + input wire membus_wr_rq_p2, + input wire [21:35] membus_ma_p2, + input wire [18:21] membus_sel_p2, + input wire membus_fmc_select_p2, + input wire [0:35] membus_mb_in_p2, + output wire membus_addr_ack_p2, + output wire membus_rd_rs_p2, + output wire [0:35] membus_mb_out_p2, + + input wire membus_wr_rs_p3, + input wire membus_rq_cyc_p3, + input wire membus_rd_rq_p3, + input wire membus_wr_rq_p3, + input wire [21:35] membus_ma_p3, + input wire [18:21] membus_sel_p3, + input wire membus_fmc_select_p3, + input wire [0:35] membus_mb_in_p3, + output wire membus_addr_ack_p3, + output wire membus_rd_rs_p3, + output wire [0:35] membus_mb_out_p3, + + // 36 bit Avalon Master + output wire [17:0] m_address, + output reg m_write, + output reg m_read, + output wire [35:0] m_writedata, + input wire [35:0] m_readdata, + input wire m_waitrequest +); + /* Jumpers */ + parameter [3:0] memsel_p0 = 4'b0; + parameter [3:0] memsel_p1 = 4'b0; + parameter [3:0] memsel_p2 = 4'b0; + parameter [3:0] memsel_p3 = 4'b0; + + // TODO: SP + wire cmc_sp = 0; + + reg [21:35] cma; + reg cma_rd_rq, cma_wr_rq; + reg [0:35] cmb; + + // TODO: interleave + + wire cmpc_p0_rq = (membus_sel_p0[18:20] == memsel_p0[3:1]) & + ~membus_fmc_select_p0 & + membus_rq_cyc_p0 & + cmc_await_rq; + wire cmpc_p1_rq = (membus_sel_p1[18:20] == memsel_p1[3:1]) & + ~membus_fmc_select_p1 & + membus_rq_cyc_p1 & + cmc_await_rq; + wire cmpc_p2_rq = (membus_sel_p2[18:20] == memsel_p2[3:1]) & + ~membus_fmc_select_p2 & + membus_rq_cyc_p2 & + cmc_await_rq; + wire cmpc_p3_rq = (membus_sel_p3[18:20] == memsel_p3[3:1]) & + ~membus_fmc_select_p3 & + membus_rq_cyc_p3 & + cmc_await_rq; + + wire [21:35] ma_in = + {15{cmc_p0_sel}}&membus_ma_p0 | + {15{cmc_p1_sel}}&membus_ma_p1 | + {15{cmc_p2_sel}}&membus_ma_p2 | + {15{cmc_p3_sel}}&membus_ma_p3; + wire rd_rq_in = + cmc_p0_sel&membus_rd_rq_p0 | + cmc_p1_sel&membus_rd_rq_p1 | + cmc_p2_sel&membus_rd_rq_p2 | + cmc_p3_sel&membus_rd_rq_p3; + wire wr_rq_in = + cmc_p0_sel&membus_wr_rq_p0 | + cmc_p1_sel&membus_wr_rq_p1 | + cmc_p2_sel&membus_wr_rq_p2 | + cmc_p3_sel&membus_wr_rq_p3; + wire [0:35] mb_in = + {36{cmc_p0_sel}}&membus_mb_in_p0 | + {36{cmc_p1_sel}}&membus_mb_in_p1 | + {36{cmc_p2_sel}}&membus_mb_in_p2 | + {36{cmc_p3_sel}}&membus_mb_in_p3; + pa cmpc_pa0(clk, reset, cmc_t1b&cmc_p0_sel, membus_addr_ack_p0); + pa cmpc_pa1(clk, reset, cmc_t1b&cmc_p1_sel, membus_addr_ack_p1); + pa cmpc_pa2(clk, reset, cmc_t1b&cmc_p2_sel, membus_addr_ack_p2); + pa cmpc_pa3(clk, reset, cmc_t1b&cmc_p3_sel, membus_addr_ack_p3); + assign membus_rd_rs_p0 = cmc_rd_rs&cmc_p0_sel; + assign membus_rd_rs_p1 = cmc_rd_rs&cmc_p1_sel; + assign membus_rd_rs_p2 = cmc_rd_rs&cmc_p2_sel; + assign membus_rd_rs_p3 = cmc_rd_rs&cmc_p3_sel; + assign membus_mb_out_p0 = sa & {36{stb_pulse & cmc_p0_sel}}; + assign membus_mb_out_p1 = sa & {36{stb_pulse & cmc_p1_sel}}; + assign membus_mb_out_p2 = sa & {36{stb_pulse & cmc_p2_sel}}; + assign membus_mb_out_p3 = sa & {36{stb_pulse & cmc_p3_sel}}; + wire cmpc_rs_set = membus_wr_rs_p0 & cmc_p0_sel | + membus_wr_rs_p1 & cmc_p1_sel | + membus_wr_rs_p2 & cmc_p2_sel | + membus_wr_rs_p3 & cmc_p3_sel; + + + // TODO: this is all wrong + wire pwr_t1, pwr_t2, pwr_t3; + wire cmc_await_rq_reset, cmc_pwr_clr, cmc_pwr_start; + pg pg0(clk, reset, power, pwr_t1); + // 200ms + ldly1us dly0(clk, reset, pwr_t1, pwr_t2, cmc_await_rq_reset); + // 100μs + ldly1us dly1(clk, reset, pwr_t2, pwr_t3, cmc_pwr_clr); + pa pa0(clk, reset, pwr_t3, cmc_pwr_start); + + + // core control, we don't really have a use for it + reg cmc_read, cmc_write, cmc_inh; + + reg cmc_rq_sync, cmc_cyc_done; + reg cmc_await_rq, cmc_pse_sync, cmc_proc_rs, cmc_stop; + + reg cmc_p0_act, cmc_p1_act, cmc_p2_act, cmc_p3_act; + reg cmc_last_proc; + + // TODO: SP + wire cmc_p0_sel = cmc_p0_act; + wire cmc_p1_sel = cmc_p1_act; + wire cmc_p2_sel = cmc_p2_act; + wire cmc_p3_sel = cmc_p3_act; + + wire cmc_t0, cmc_t1b, cmc_t1a, cmc_t2, cmc_t3; + wire cmc_t4, cmc_t5, cmc_t6, cmc_t6p; + wire cmc_t0_D, cmc_t2_D1; + wire cmc_t3_D1, cmc_t3_D2; + + wire cmc_restart; + wire cmc_start; + wire cmc_state_clr; + wire cmc_pn_act = cmc_p0_act | cmc_p1_act | cmc_p2_act | cmc_p3_act; + wire cmc_aw_rq_set = cmc_t0_D & ~cmc_pn_act; + wire cmc_rq_sync_set = cmc_t0_D & ~cmc_sp & cmc_pn_act; + wire cmc_jam_cma = cmc_t1b; + wire cmc_cmb_clr; + wire cmc_read_off; + wire cmc_pse_sync_set; + wire strobe_sense; + wire cmc_rd_rs; + wire cmpc_rs_set_D; + wire cmc_proc_rs_pulse; + + pa pa1(clk, reset, + (cmpc_p0_rq | cmpc_p1_rq | cmpc_p2_rq | cmpc_p3_rq), + cmc_t0); + pa pa2(clk, reset, cmc_restart | cmc_pwr_start, cmc_start); + pa pa3(clk, reset, cmc_start | cmc_t3_D1, cmc_t5); + pa pa4(clk, reset, cmc_start | cmc_t3_D2, cmc_t6p); + pa pa5(clk, reset, + cmc_start | cmc_t3 & ~cma_wr_rq | cmc_proc_rs_pulse, + cmc_state_clr); + pa pa6(clk, reset, cmc_rq_sync&cmc_cyc_done, cmc_t1b); + pa pa7(clk, reset, cmc_t1b, cmc_t1a); + pa pa9(clk, reset, + cmc_t1b | cmc_pse_sync_set&cma_rd_rq&cma_wr_rq, + cmc_cmb_clr); + pa pa11(clk, reset, cmc_t2_D1&cma_rd_rq, strobe_sense); + pa pa12(clk, reset, stb_pulse, cmc_rd_rs); + + pa pa13(clk, reset, cmc_pse_sync&(cmc_proc_rs | ~cma_wr_rq), cmc_t3); + pa pa14(clk, reset, cmc_proc_rs, cmc_proc_rs_pulse); + // probably wrong + pa pa15(clk, reset, sw_restart, cmc_restart); + + + dly250ns dly2(clk, reset, cmc_t6p, cmc_t6); + dly100ns dly3(clk, reset, cmc_t0, cmc_t0_D); + dly250ns dly4(clk, reset, cmc_t1a, cmc_t2); + dly200ns dly5(clk, reset, cmc_t2, cmc_read_off); + dly100ns dly6(clk, reset, rd_pulse, cmc_pse_sync_set); + // Variable 35-100ns + dly70ns dly7(clk, reset, cmc_t2, cmc_t2_D1); + dly50ns dly9(clk, reset, cmc_t3, cmc_t4); + dly500ns dly10(clk, reset, cmc_t4, cmc_t3_D1); + dly200ns dly11(clk, reset, cmc_t3_D1, cmc_t3_D2); + dly50ns dly12(clk, reset, cmpc_rs_set, cmpc_rs_set_D); + + + reg [0:35] sa; // "sense amplifiers" + wire [14:0] core_addr = cma[21:35]; + + assign m_address = { 3'b0, core_addr }; + assign m_writedata = cmb; + + + reg stb_sync, stb_done; + wire stb_pulse; + pa pa100(clk, reset, stb_sync&stb_done, stb_pulse); + + reg rd_sync, rd_done; + wire rd_pulse; + pa pa101(clk, reset, rd_sync&rd_done, rd_pulse); + + reg wr_sync, wr_done; + wire wr_pulse; + pa pa102(clk, reset, wr_sync&wr_done, wr_pulse); + + + always @(posedge clk or posedge reset) begin + if(reset) begin + m_read <= 0; + m_write <= 0; + sa <= 0; + + stb_sync <= 0; + stb_done <= 0; + rd_sync <= 0; + rd_done <= 0; + wr_sync <= 0; + wr_done <= 0; + + // value doesn't matter + cmc_last_proc <= 0; + // these should probably be reset but aren't + cmc_proc_rs <= 0; + cmc_pse_sync <= 0; + end else begin + if(m_write & ~m_waitrequest) begin + m_write <= 0; + wr_done <= 1; + end + if(m_read & ~m_waitrequest) begin + m_read <= 0; + sa <= m_readdata; + stb_done <= 1; + end + + if(cmc_start) + wr_done <= 1; + + if(cmc_state_clr) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end + if(cmpc_p0_rq | cmpc_p1_rq | cmpc_p2_rq | cmpc_p3_rq) begin + if(cmpc_p0_rq) begin + cmc_p0_act <= 1; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end else if(cmpc_p1_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 1; + cmc_p2_act <= 0; + cmc_p3_act <= 0; + end else if(cmpc_p2_rq & cmpc_p3_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= cmc_last_proc; + cmc_p3_act <= ~cmc_last_proc; + cmc_last_proc <= ~cmc_last_proc; + end else if(cmpc_p2_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 1; + cmc_p3_act <= 0; + end else if(cmpc_p3_rq) begin + cmc_p0_act <= 0; + cmc_p1_act <= 0; + cmc_p2_act <= 0; + cmc_p3_act <= 1; + end + end + if(cmc_t2) begin + if(cmc_p2_act) + cmc_last_proc <= 0; + if(cmc_p3_act) + cmc_last_proc <= 1; + end + + if(cmc_t0 | cmc_await_rq_reset) + cmc_await_rq <= 0; + if(cmc_t5 | cmc_aw_rq_set) + cmc_await_rq <= 1; + + if(cmc_start | cmc_pwr_clr) + cmc_rq_sync <= 0; + if(cmc_rq_sync_set | cmc_t0 & cmc_sp) + cmc_rq_sync <= 1; + + if(cmc_pwr_clr) + cmc_cyc_done <= 0; + if(wr_pulse & ~cmc_stop) + cmc_cyc_done <= 1; + if(cmc_t6) + wr_sync <= 1; + + if(cmc_t1b) begin + cmc_pse_sync <= 0; + cmc_proc_rs <= 0; + cmc_stop <= 0; + end + + // actually through another PA + if(cmc_pse_sync_set) + cmc_pse_sync <= 1; + + if(cmpc_rs_set_D) + cmc_proc_rs <= 1; + + if(cmc_start) + cmc_stop <= 0; + if(cmc_t2 & sw_single_step) + cmc_stop <= 1; + + if(cmc_t2) begin + cmc_rq_sync <= 0; + cmc_cyc_done <= 0; + end + + + if(cmc_jam_cma) begin + cma <= ma_in; + cma_rd_rq <= rd_rq_in; + cma_wr_rq <= wr_rq_in; + end + + cmb <= cmb | mb_in; + if(cmc_cmb_clr) + cmb <= 0; + if(strobe_sense) + stb_sync <= 1; + if(stb_pulse) begin + stb_sync <= 0; + stb_done <= 0; + rd_done <= 1; + cmb <= cmb | sa; + end + + /* Core */ + if(cmc_pwr_clr | cmc_t5) begin + cmc_read <= 0; + cmc_write <= 0; + cmc_inh <= 0; + end + if(cmc_t1a) begin + cmc_read <= 1; + m_read <= cma_rd_rq; + stb_done <= 0; + rd_done <= ~cma_rd_rq; + cmc_write <= 0; + end + if(cmc_read_off) begin + cmc_read <= 0; + rd_sync <= 1; + end + if(rd_pulse) begin + rd_sync <= 0; + rd_done <= 0; + end + if(cmc_t3) begin + cmc_inh <= 1; + m_write <= cma_wr_rq; + wr_done <= ~cma_wr_rq; + end + if(cmc_t4) begin + cmc_write <= 1; + cmc_read <= 0; + end + if(wr_pulse) begin + wr_sync <= 0; + wr_done <= 0; + end + end + end +endmodule diff --git a/verilog/core64k.v b/verilog/core64k.v index 527e0b0..ebc28ac 100644 --- a/verilog/core64k.v +++ b/verilog/core64k.v @@ -93,10 +93,10 @@ module core64k( membus_rq_cyc_p3 & cmc_await_rq; - wire ma_p0 = { membus_sel_p0[18:21], membus_ma_p0[22:35] }; - wire ma_p1 = { membus_sel_p1[18:21], membus_ma_p1[22:35] }; - wire ma_p2 = { membus_sel_p2[18:21], membus_ma_p2[22:35] }; - wire ma_p3 = { membus_sel_p3[18:21], membus_ma_p3[22:35] }; + wire [18:35] ma_p0 = { membus_sel_p0[18:21], membus_ma_p0[22:35] }; + wire [18:35] ma_p1 = { membus_sel_p1[18:21], membus_ma_p1[22:35] }; + wire [18:35] ma_p2 = { membus_sel_p2[18:21], membus_ma_p2[22:35] }; + wire [18:35] ma_p3 = { membus_sel_p3[18:21], membus_ma_p3[22:35] }; wire [20:35] ma_in = {16{cmc_p0_sel}}&ma_p0 | diff --git a/verilog/dis340.v b/verilog/dis340.v new file mode 100644 index 0000000..38ec0b8 --- /dev/null +++ b/verilog/dis340.v @@ -0,0 +1,581 @@ +module dis340( + input wire clk, + input wire reset, + + /* IO bus - 344 interface */ + input wire iobus_iob_poweron, + input wire iobus_iob_reset, + input wire iobus_datao_clear, + input wire iobus_datao_set, + input wire iobus_cono_clear, + input wire iobus_cono_set, + input wire iobus_iob_fm_datai, + input wire iobus_iob_fm_status, + input wire iobus_rdi_pulse, // unused on 6 + input wire [3:9] iobus_ios, + input wire [0:35] iobus_iob_in, + output wire [1:7] iobus_pi_req, + output wire [0:35] iobus_iob_out, + output wire iobus_dr_split, + output wire iobus_rdi_data, // unused on 6 + + /* Indicators */ + output wire [0:17] br_ind, + output wire [0:6] brm_ind, + output wire [0:9] x_ind, + output wire [0:9] y_ind, + output wire [1:4] s_ind, + output wire [0:2] i_ind, + output wire [0:2] mode_ind, + output wire [0:1] sz_ind, + output wire [0:8] flags_ind, + output wire [0:4] fe_ind, + output wire [31:0] foo_ind, + + /* Avalon slave */ + input wire s_read, + output wire [31:0] s_readdata, + + output wire fe_data_rq +); + assign iobus_dr_split = 0; + assign iobus_rdi_data = 0; + + assign br_ind = br; + assign brm_ind = brm; + assign x_ind = x; + assign y_ind = y; + assign s_ind = s; + assign i_ind = i; + assign mode_ind = mode; + assign sz_ind = sz; + assign flags_ind = { + rfd, cf, 1'b0, // TODO: CONT? + stop, move, halt, + lp_flag, lp_enable, lp_find + }; + + /* 344 - fantasy */ + + wire dis_sel = iobus_ios == 7'b001_011_0; + + wire dis_data_clr; + wire dis_data_set; + wire dis_ic_clr; + wire dis_ic_set; + wire iob_reset; + wire dis_datai = dis_sel & iobus_iob_fm_datai; + wire dis_status = dis_sel & iobus_iob_fm_status; + pa ptr_pa0(clk, reset, dis_sel & iobus_datao_clear, dis_data_clr); + pa ptr_pa1(clk, reset, dis_sel & iobus_datao_set, dis_data_set); + pa ptr_pa2(clk, reset, dis_sel & iobus_cono_clear | iob_reset, dis_ic_clr); + pa ptr_pa3(clk, reset, dis_sel & iobus_cono_set, dis_ic_set); + pa ptr_pa4(clk, reset, iobus_iob_reset, iob_reset); + + assign iobus_iob_out = + dis_datai ? { y, 9'b0, x } : + dis_status ? { edge_flag_vert, lp_flag, edge_flag_horiz, + stop_inter, done_flag, 1'b0, + dis_pia_spec, dis_pia_data } : + 36'b0; + + wire dis_flag_spec = edge_flag_vert | edge_flag_horiz | + lp_flag | stop_inter; + wire dis_flag_data = done_flag; + wire [1:7] dis_req_spec = { dis_flag_spec, 7'b0 } >> dis_pia_spec; + wire [1:7] dis_req_data = { dis_flag_data, 7'b0 } >> dis_pia_data; + assign iobus_pi_req = dis_req_spec | dis_req_data; + + reg [30:32] dis_pia_spec; + reg [33:35] dis_pia_data; + reg [0:35] dis_ib; + reg [0:1] dis_ibc; + + always @(posedge clk) begin + if(dis_ic_clr) begin + dis_pia_spec <= 0; + dis_pia_data <= 0; + + // not quite sure.. + dis_ib <= 0; + dis_ibc <= 0; + end + if(dis_ic_set) begin + dis_pia_spec <= iobus_iob_in[30:32]; + dis_pia_data <= iobus_iob_in[33:35]; + end + + if(dis_data_clr) begin + dis_ib <= 0; + dis_ibc <= 0; + end + if(dis_data_set) begin + dis_ib <= dis_ib | iobus_iob_in; + dis_ibc <= 2'b11; + end + if(shift_ib) begin + dis_ib[0:17] <= dis_ib[18:35]; + dis_ibc <= { dis_ibc[1], 1'b0 }; + end + end + + wire done_flag = rfd & ~dis_ibc[0]; + pa dpy_pa100(clk, reset, rfd & dis_ibc[0], data_sync); + + // from interface (?) + wire dpy_go = dis_ic_set & iobus_iob_in[29]; + wire resume = dis_ic_set & ~iobus_iob_in[29]; + wire data_sync; + wire [0:17] br_input = dis_ib[0:17]; + + // ?? + wire clr_flags = 0; + + + /* light pen */ + wire lp_pulse = 0; + + + /* 340 */ + +`ifdef simulation + initial begin + rfd <= 0; + halt <= 0; + end +`endif + + reg rfd; + reg stop; + reg halt; + reg move; + wire initiate; + wire escape_pulse; + wire rfd_pulse; + wire idp; + wire pm_pulse; + wire x_start_pulse; + wire y_start_pulse; + wire cg_end_pulse; + wire next_char; + + wire stop_inter = stop & br[8]; + + wire [0:3] inc = + {4{s[1]}} & br[2:5] | + {4{s[2]}} & br[6:9] | + {4{s[3]}} & br[10:13] | + {4{s[4]}} & br[14:17]; + + wire l = (vm | vcm) & horiz_vec & br[10] | + im & inc[0] & inc[1] | + cg_l; + wire r = (vm | vcm) & horiz_vec & ~br[10] | + im & inc[0] & ~inc[1] | + cg_r; + wire d = (vm | vcm) & vert_vec & br[2] | + im & inc[2] & inc[3] | + cg_d; + wire u = (vm | vcm) & vert_vec & ~br[2] | + im & inc[2] & ~inc[3] | + cg_u; + + pa dpy_pa0(clk, reset, dpy_go, initiate); + pa dpy_pa1(clk, reset, + initiate | cg_escape | + count_x & br[0] & halt | + dly1_pulse & cf, + escape_pulse); + pa dpy_pa2(clk, reset, + dly6_pulse | initiate | cg_escape | + count_x & halt | + dly1_pulse & cf & vcm | // TODO: ??? + pm_pulse & ~br[7] | + next_char & s[4], + rfd_pulse); + pa dpy_pa3(clk, reset, data_sync, clr_br); + pa dpy_pa4(clk, reset, clr_br, clr_brm); + pa dpy_pa5(clk, reset, read_to_s, load_br); + wire shift_ib = load_br; + // TODO: what's RI? + pa dpy_pa7(clk, reset, idp & pm, pm_pulse); + pa dpy_pa8(clk, reset, idp & xym & ~lp_flag & br[1], y_start_pulse); + pa dpy_pa9(clk, reset, idp & xym & ~lp_flag & ~br[1], x_start_pulse); + pa dpy_pa10(clk, reset, + pm_pulse | x_start_pulse | y_start_pulse, + read_to_mode); + pa dpy_pa11(clk, reset, pm_pulse & br[11], store_scale); + pa dpy_pa12(clk, reset, pm_pulse & br[14], store_int_level); + pa dpy_pa13(clk, reset, y_start_pulse, clr_y); + pa dpy_pa14(clk, reset, x_start_pulse | cg_cr, clr_x); + pa dpy_pa15(clk, reset, idp & (im | vm | vcm), count_brm); + pa dpy_pa16(clk, reset, count_brm | cg_count, count_x); + pa dpy_pa17(clk, reset, count_brm | cg_count, count_y); + pa dpy_pa18(clk, reset, count_brm | next_char, shift_s); + + pa dpy_pa6(clk, reset, cg_end_level, cg_end_pulse); + assign next_char = cg_end_pulse & cm; + + wire int_dly1, int_dly2; + wire int_dly = int_dly1 | int_dly2 | cg_intens; + wire intensify = + int_dly1 & move & br[1] | + int_dly2 & br[7] | + cg_intens & cg_int; + + wire dly1_pulse; // sequence delay + wire dly4_pulse; // 35 deflection delay + wire dly6_pulse; // 0.5 after xy intensify + ldly500ns intdly_1(clk, reset, + load_br | // actually through PA + dly1_pulse & ~cf & ~lp_flag & ~rfd | + next_char & ~s[4], + intdly1_pulse /* idp */, int_dly1); + dly2_8us dpy_dly3(clk, reset, clr_br, read_to_s); + dly200ns dpy_dly5(clk, reset, x_start_pulse, load_x); + dly200ns dpy_dly7(clk, reset, y_start_pulse, load_y); +`ifdef simulation + dly2_8us dpy_dly4(clk, reset, +`else + dly35us dpy_dly4(clk, reset, +`endif + x_start_pulse | y_start_pulse & br[7], + dly4_pulse); + ldly500ns intdly_2(clk, reset, + dly4_pulse | y_start_pulse & ~br[7], + intdly2_pulse /* dly6_pulse */, int_dly2); + dly1us dpy_dly1(clk, reset, + count_brm & ~halt | + resume & ~cm, + dly1_pulse); + + always @(posedge clk) begin + if(clr_brm) begin + halt <= 0; + move <= 0; + end + if(count_x & im & s[4] | + dly1_pulse & vm & brm == 'o177) + halt <= 1; + + if(count_x & (l|r|u|d)) + move <= ~cm; + + if(initiate | clr_flags) + stop <= 0; + if(pm_pulse & br[7]) + stop <= 1; + + if(clr_flags | clr_br) + rfd <= 0; + if(rfd_pulse) + rfd <= 1; + end + + reg [0:17] br; + wire clr_br; + wire load_br; + + reg [0:2] mode; + wire read_to_mode; + wire pm = mode == 3'b000; + wire xym = mode == 3'b001; + wire sm = mode == 3'b010; + wire cm = mode == 3'b011; + wire vm = mode == 3'b100; + wire vcm = mode == 3'b101; + wire im = mode == 3'b110; + + reg [0:1] sz; + wire store_scale; + wire scx8 = sz == 2'b11; + wire scx4 = sz == 2'b10; + wire sc = sz[0] | sz[1]; + + reg [0:2] i; + wire store_int_level; + + reg lp_find; + reg lp_enable; + reg lp_flag; + + always @(posedge clk) begin + if(clr_br) + br <= 0; + if(load_br) + br <= br | br_input; + + if(escape_pulse) begin + mode <= 0; + lp_find <= 0; + end + if(read_to_mode) + mode <= br[2:4]; + + if(store_int_level) + i <= br[15:17]; + + if(store_scale) + sz <= br[12:13]; + + if(initiate | resume) // initiate not in drawings + lp_enable <= 0; + if(read_to_mode & br[5]) + lp_enable <= br[6]; + + if(initiate | clr_flags | resume) + lp_flag <= 0; + if((count_y | read_to_s) & lp_enable & lp_find) + lp_flag <= 1; + + if(initiate | resume) + lp_find <= 0; + if(lp_pulse & lp_enable) + lp_find <= 1; + end + + + reg [0:6] brm; + wire [0:6] brm_comp; + wire clr_brm; + wire count_brm; + + assign brm_comp[6] = 1; + assign brm_comp[5] = brm[6] | ~br[3]&~br[11]; + assign brm_comp[4] = (&brm[5:6]) | (&(~br[3:4]))&(&(~br[11:12])); + assign brm_comp[3] = (&brm[4:6]) | (&(~br[3:5]))&(&(~br[11:13])); + assign brm_comp[2] = (&brm[3:6]) | (&(~br[3:6]))&(&(~br[11:14])); + assign brm_comp[1] = (&brm[2:6]); + assign brm_comp[0] = (&brm[1:6]); + + wire horiz_vec = (|(~brm[0:6] & brm_comp[0:6] & + { br[17], br[16], br[15], br[14], br[13], br[12], br[11] })); + wire vert_vec = (|(~brm[0:6] & brm_comp[0:6] & + { br[9], br[8], br[7], br[6], br[5], br[4], br[3] })); + + always @(posedge clk) begin + if(clr_brm) + brm <= 0; + if(count_brm) + brm <= brm ^ brm_comp; + end + + reg [1:4] s; + wire clr_s = clr_brm; // not on drawings + wire shift_s; + wire read_to_s; + + always @(posedge clk) begin + if(clr_s) + s <= 0; + if(read_to_s & cm) + s[2] <= 1; + if(read_to_s & im) + s[1] <= 1; + if(shift_s) + s <= { 1'b0, s[1:3] }; + end + + reg [0:9] x; + reg [0:9] y; + reg edge_flag_vert; + reg edge_flag_horiz; + wire clr_x, load_x, count_x; + wire clr_y, load_y, count_y; + wire clr_cf = clr_brm; // not on drawings + + wire cf = edge_flag_vert | edge_flag_horiz; + + wire [0:9] xyinc = 1<