URL
https://opencores.org/ocsvn/bitserial/bitserial/trunk
Subversion Repositories bitserial
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/bitserial/trunk/LICENSE
0,0 → 1,19
Copyright (c) 2019 Richard James Howe |
|
Permission is hereby granted, free of charge, to any person obtaining a |
copy of this software and associated documentation files (the "Software"), |
to deal in the Software without restriction, including without limitation |
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
and/or sell copies of the Software, and to permit persons to whom the |
Software is furnished to do so, subject to the following conditions: |
|
The above copyright notice and this permission notice shall be included |
in all copies or substantial portions of the Software. |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
OTHER DEALINGS IN THE SOFTWARE. |
/bitserial/trunk/bit-sim.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
bitserial/trunk/bit-sim.gif
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: bitserial/trunk/bit-state.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: bitserial/trunk/bit-state.png
===================================================================
--- bitserial/trunk/bit-state.png (nonexistent)
+++ bitserial/trunk/bit-state.png (revision 2)
bitserial/trunk/bit-state.png
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: bitserial/trunk/bit-wave.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: bitserial/trunk/bit-wave.png
===================================================================
--- bitserial/trunk/bit-wave.png (nonexistent)
+++ bitserial/trunk/bit-wave.png (revision 2)
bitserial/trunk/bit-wave.png
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: bitserial/trunk/bit.bin
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: bitserial/trunk/bit.bin
===================================================================
--- bitserial/trunk/bit.bin (nonexistent)
+++ bitserial/trunk/bit.bin (revision 2)
bitserial/trunk/bit.bin
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: bitserial/trunk/bit.c
===================================================================
--- bitserial/trunk/bit.c (nonexistent)
+++ bitserial/trunk/bit.c (revision 2)
@@ -0,0 +1,260 @@
+/* Bit-Serial CPU simulator
+ * LICENSE: MIT
+ * AUTHOR: Richard James Howe
+ * EMAIL: howe.r.j.89@gmail.com
+ * GIT: https://github.com/howerj/bit-serial */
+#ifdef __unix__
+#include
+#include
+#include
+#include
+#define __USE_POSIX199309
+#define _POSIX_C_SOURCE 199309L
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MSIZE (8192u)
+#define ESCAPE (27)
+
+typedef uint16_t mw_t; /* machine word */
+
+typedef struct {
+ mw_t pc, acc, flg, m[MSIZE];
+ FILE *in, *out;
+ mw_t ch, leds, switches;
+ long done, sleep_ms, sleep_every;
+#ifdef __unix__
+ struct termios oldattr; /* ugly, but needed for Unix only */
+#endif
+} bcpu_t;
+
+enum { fCy, fZ, fNg, fR, fHLT, };
+
+#ifdef __unix__ /* unix junk... */
+extern int fileno(FILE *file);
+
+static int os_getch(bcpu_t *b) {
+ assert(b);
+ return fgetc(b->in);
+}
+
+static void sleep_us(const unsigned long microseconds) {
+ struct timespec ts = {
+ .tv_sec = (microseconds / 1000000ul),
+ .tv_nsec = (microseconds % 1000000ul) * 1000ul,
+ };
+ nanosleep(&ts, NULL);
+}
+
+static void os_sleep_ms(bcpu_t *b, unsigned ms) {
+ assert(b);
+ sleep_us(ms * 1000ul);
+}
+
+static int os_kbhit(bcpu_t *b) {
+ assert(b);
+ const int fd = STDIN_FILENO;
+ if (!isatty(fd))
+ return 1;
+ int bytes = 0;
+ ioctl(fd, FIONREAD, &bytes);
+ return !!bytes;
+}
+
+static int os_init(bcpu_t *b) {
+ assert(b);
+ const int fd = fileno(b->in);
+ if (!isatty(fd))
+ return 0;
+ if (tcgetattr(fd, &b->oldattr) < 0)
+ return -1;
+ struct termios newattr = b->oldattr;
+ newattr.c_iflag &= ~(ICRNL);
+ newattr.c_lflag &= ~(ICANON | ECHO);
+ if (tcsetattr(fd, TCSANOW, &newattr) < 0)
+ return -2;
+ return 0;
+}
+
+static int os_deinit(bcpu_t *b) {
+ assert(b);
+ if (!isatty(fileno(b->in)))
+ return 0;
+ return tcsetattr(fileno(b->in), TCSANOW, &b->oldattr) < 0 ? -1 : 0;
+}
+#else
+#ifdef _WIN32
+#include
+extern int getch(void);
+extern int kbhit(void);
+static int os_getch(bcpu_t *b) { assert(b); return b->in == stdin ? getch() : fgetc(b->in); }
+static int os_kbhit(bcpu_t *b) { assert(b); Sleep(1); return kbhit(); }
+static void os_sleep_ms(bcpu_t *b, unsigned ms) { assert(b); Sleep(ms); }
+static int os_init(bcpu_t *b) { assert(b); return 0; }
+static int os_deinit(bcpu_t *b) { assert(b); return 0; }
+#else
+static int os_kbhit(bcpu_t *b) { assert(b); return 1; }
+static int os_getch(bcpu_t *b) { assert(b); return fgetc(b->in); }
+static void os_sleep_ms(bcpu_t *b, unsigned ms) { assert(b); (void)ms; }
+static int os_init(bcpu_t *b) { assert(b); return 0; }
+static int os_deinit(bcpu_t *b) { assert(b); return 0; }
+#endif
+#endif /** __unix__ **/
+
+static int wrap_getch(bcpu_t *b) {
+ assert(b);
+ const int ch = os_getch(b);
+ if ((ch == ESCAPE) || (ch < 0))
+ b->done = 1;
+ return ch;
+}
+
+static int wrap_putch(bcpu_t *b, const int ch) {
+ assert(b);
+ const int r = fputc(ch, b->out);
+ if (fflush(b->out) < 0)
+ return -1;
+ return r;
+}
+
+static inline unsigned bits(unsigned b) {
+ unsigned r = 0;
+ do if (b & 1) r++; while (b >>= 1);
+ return r;
+}
+
+static inline mw_t add(mw_t a, mw_t b, mw_t *carry) {
+ assert(carry);
+ const mw_t r = a + b;
+ *carry &= ~(1u << fCy);
+ if (r < a && r < b)
+ *carry |= (1u << fCy);
+ return r;
+}
+
+static inline mw_t bload(bcpu_t *b, mw_t addr) {
+ assert(b);
+ if (!(0x4000ul & addr))
+ return b->m[addr % MSIZE];
+ switch (addr & 0x7) {
+ case 0: return b->switches;
+ case 1: return (!os_kbhit(b) << 8ul) | (b->ch & 0xFF);
+ }
+ return 0;
+}
+
+static inline void bstore(bcpu_t *b, mw_t addr, mw_t val) {
+ assert(b);
+ if (!(0x4000ul & addr)) {
+ if (addr >= MSIZE)
+ return;
+ b->m[addr % MSIZE] = val;
+ return;
+ }
+ switch (addr & 0x7) {
+ case 0: b->leds = val; break;
+ case 1:
+ if (val & (1u << 13)) {
+ wrap_putch(b, val & 0xFFu);
+ fflush(b->out);
+ }
+ if (val & (1u << 10))
+ b->ch = wrap_getch(b);
+ break;
+ case 2: /* TX control */ break;
+ case 3: /* RX control */ break;
+ case 4: /* UART control */ break;
+ }
+}
+
+static int bcpu(bcpu_t *b) {
+ assert(b);
+ int r = 0;
+ mw_t * const m = b->m, pc = b->pc, acc = b->acc, flg = b->flg;
+
+ for (unsigned count = 0; b->done == 0; count++) {
+ if ((b->sleep_every && (count % b->sleep_every) == 0) && b->sleep_ms > 0)
+ os_sleep_ms(b, b->sleep_ms);
+
+ const mw_t instr = m[pc % MSIZE];
+ const mw_t op1 = instr & 0x0FFF;
+ const mw_t cmd = (instr >> 12u) & 0xFu;
+
+ if (flg & (1u << fHLT))
+ goto halt;
+ if (flg & (1u << fR)) {
+ pc = 0;
+ acc = 0;
+ flg = 0;
+ continue;
+ }
+
+ flg &= ~((1u << fZ) | (1u << fNg));
+ flg |= ((!acc) << fZ); /* set zero flag */
+ flg |= ((!!(acc & 0x8000)) << fNg); /* set negative flag */
+
+ const mw_t lop = (cmd & 0x8) ? op1 : bload(b, op1);
+
+ pc++;
+ switch (cmd) {
+ case 0x0: acc |= lop; break; /* OR */
+ case 0x1: acc &= lop; break; /* AND */
+ case 0x2: acc ^= lop; break; /* XOR */
+ case 0x3: acc = add(acc, lop, &flg); break; /* ADD */
+
+ case 0x4: acc <<= bits(lop); break; /* LSHIFT */
+ case 0x5: acc >>= bits(lop); break; /* RSHIFT */
+ case 0x6: acc = bload(b, lop); break; /* LOAD */
+ case 0x7: bstore(b, lop, acc); break; /* STORE */
+
+ case 0x8: acc = bload(b, op1); break; /* LOAD-C */
+ case 0x9: bstore(b, op1, acc); break; /* STORE-C */
+ case 0xA: acc = op1; break; /* LITERAL */
+ case 0xB: break; /* UNUSED */
+
+ case 0xC: pc = op1; break; /* JUMP */
+ case 0xD: if (!acc) pc = op1; break; /* JUMPZ */
+ case 0xE: if (op1 & 1) flg = acc; else pc = acc; break; /* SET */
+ case 0xF: if (op1 & 1) acc = flg; else acc = pc - 1u; break; /* GET */
+ default: r = -1; goto halt;
+ }
+ }
+halt:
+ b->pc = pc;
+ b->acc = acc;
+ b->flg = flg;
+ return r;
+}
+
+int main(int argc, char **argv) {
+ static bcpu_t b = { .flg = 1u << fZ, .sleep_ms = 5, .sleep_every = 64 * 1024 };
+ if (argc != 2)
+ return 1;
+ b.in = stdin;
+ b.out = stdout;
+ FILE *in = fopen(argv[1], "rb");
+ if (!in)
+ return 2;
+ for (size_t i = 0; i < MSIZE; i++) {
+ unsigned pc = 0;
+ if (fscanf(in, "%x", &pc) != 1)
+ break;
+ b.m[i] = pc;
+ }
+ if (os_init(&b) < 0)
+ return 3;
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ const int r = bcpu(&b) < 0 ? 4 : 0;
+ if (os_deinit(&b) < 0)
+ return 5;
+ return r;
+}
+
Index: bitserial/trunk/bit.fth
===================================================================
--- bitserial/trunk/bit.fth (nonexistent)
+++ bitserial/trunk/bit.fth (revision 2)
@@ -0,0 +1,845 @@
+\
+\ Cross Compiler and eForth interpreter for the bit-serial CPU available at:
+\
+\
+\
+\ This implements a Direct Threaded Code virtual machine on which we can
+\ build a Forth interpreter.
+\
+\ References:
+\
+\ -
+\ -
+\ -
+\ -
+\ -
+\ - 8086 eForth 1.0 by Bill Muench and C. H. Ting, 1990
+\
+\ The cross compiler has been tested and works with gforth versions 0.7.0 and
+\ 0.7.3. An already compiled image (called 'bit.hex') should be available if
+\ you do not have gforth installed.
+\
+
+only forth also definitions hex
+
+wordlist constant meta.1
+wordlist constant target.1
+wordlist constant assembler.1
+wordlist constant target.only.1
+
+: (order) ( u wid*n n -- wid*n u n )
+ dup if
+ 1- swap >r recurse over r@ xor if
+ 1+ r> -rot exit then r> drop then ;
+: -order ( wid -- ) get-order (order) nip set-order ;
+: +order ( wid -- ) dup >r -order get-order r> swap 1+ set-order ;
+
+meta.1 +order also definitions
+
+ 2 constant =cell
+4000 constant size ( 16384 bytes, 8192 cells )
+2000 constant =end ( 8192 bytes, leaving 4096 for Dual Port Block RAM )
+ 40 constant =stksz
+ 60 constant =buf
+0008 constant =bksp
+000A constant =lf
+000D constant =cr
+007F constant =del
+
+create tflash size cells here over erase allot
+
+variable tdp
+variable tep
+variable tlast
+size =cell - tep !
+0 tlast !
+
+: :m meta.1 +order also definitions : ;
+: ;m postpone ; ; immediate
+:m there tdp @ ;m
+:m tc! tflash + c! ;m
+:m tc@ tflash + c@ ;m
+:m t! over ff and over tc! swap 8 rshift swap 1+ tc! ;m
+:m t@ dup tc@ swap 1+ tc@ 8 lshift or ;m
+:m talign there 1 and tdp +! ;m
+:m tc, there tc! 1 tdp +! ;m
+:m t, there t! 2 tdp +! ;m
+:m $literal [char] " word count dup tc, 0 ?do count tc, loop drop talign ;m
+:m tallot tdp +! ;m
+:m thead
+ talign
+ there tlast @ t, tlast !
+ parse-word dup tc, 0 ?do count tc, loop drop talign ;m
+:m hex# ( u -- addr len ) 0 <# base @ >r hex =lf hold # # # # r> base ! #> ;m
+:m save-hex ( -- )
+ parse-word w/o create-file throw
+ there 0 do i t@ over >r hex# r> write-file throw =cell +loop
+ close-file throw ;m
+:m save-target ( -- )
+ parse-word w/o create-file throw >r
+ tflash there r@ write-file throw r> close-file ;m
+:m .h base @ >r hex u. r> base ! ;m
+:m .d base @ >r decimal u. r> base ! ;m
+:m twords
+ cr tlast @
+ begin
+ dup tflash + =cell + count 1f and type space t@
+ ?dup 0= until ;m
+:m .stat
+ 0 if
+ ." target: " target.1 +order words cr cr
+ ." target-only: " target.only.1 +order words cr cr
+ ." assembler: " assembler.1 +order words cr cr
+ ." meta: " meta.1 +order words cr cr
+ then
+ ." used> " there dup ." 0x" .h ." / " .d cr ;m
+:m .end only forth also definitions decimal ;m
+:m atlast tlast @ ;m
+:m tvar get-current >r meta.1 set-current create r> set-current there , t, does> @ ;m
+:m label: get-current >r meta.1 set-current create r> set-current there , does> @ ;m
+:m tdown =cell negate and ;m
+:m tnfa =cell + ;m ( pwd -- nfa : move to name field address)
+:m tcfa tnfa dup c@ $1F and + =cell + tdown ;m ( pwd -- cfa )
+:m compile-only tlast @ tnfa t@ $20 or tlast @ tnfa t! ;m ( -- )
+:m immediate tlast @ tnfa t@ $40 or tlast @ tnfa t! ;m ( -- )
+:m t' ' >body @ ;m
+:m call 2/ C000 or ;m
+:m t2/ 2/ ;m
+
+: iOR 0000 or t, ;
+: iAND 1000 or t, ;
+: iXOR 2000 or t, ;
+: iADD 3000 or t, ;
+: iLSHIFT 4000 or t, ;
+: iRSHIFT 5000 or t, ;
+: iLOAD 2/ 6000 or t, ;
+: iSTORE 2/ 7000 or t, ;
+
+: iLOAD-C 2/ 8000 or t, ;
+: iSTORE-C 2/ 9000 or t, ;
+: iLITERAL A000 or t, ;
+: iUNUSED B000 or t, ;
+: iJUMP C000 or t, ;
+: iJUMPZ D000 or t, ;
+: iSET E000 or t, ;
+: iGET F000 or t, ;
+
+ 1 constant flgCy
+ 2 constant flgZ
+ 4 constant flgNg
+ 8 constant flgR
+10 constant flgHlt
+
+: flags? 1 iGET ;
+: flags! 1 iSET ;
+: halt! flgHlt iLITERAL flags! ;
+: branch 2/ iJUMP ;
+: ?branch 2/ iJUMPZ ;
+: zero? flags? 2 iAND ;
+:m postpone t' branch ;m
+
+assembler.1 +order also definitions
+: begin there ;
+: until ?branch ;
+: again branch ;
+: if there 0 ?branch ;
+: mark there 0 branch ;
+: then begin 2/ over t@ or swap t! ;
+: else mark swap then ;
+: while if swap ;
+: repeat branch then ;
+assembler.1 -order
+meta.1 +order also definitions
+
+\ ---- ---- ---- ---- ---- image generation ---- ---- ---- ---- ---- ----
+
+0 t, \ must be 0 ('0 iOR' works in either indirect or direct mode )
+1 t, \ must be 1 ('1 iADD' works in either indirect or direct mode )
+2 t, \ must be 2 ('2 iADD' works in either indirect or direct mode )
+label: entry
+0 t, \ entry point to virtual machine
+
+FFFF tvar set \ all bits set, -1
+ FF tvar low \ lowest bytes set
+ 0 tvar \ entry point of virtual machine program, set later on
+ 0 tvar pwd \ previous word pointer
+
+ 0 tvar ip \ instruction pointer
+ 0 tvar w \ working pointer
+ 0 tvar t \ temporary register
+ 0 tvar tos \ top of stack
+ 0 tvar h \ dictionary pointer
+ 0 tvar {state} \ compiler state
+ 0 tvar {hld} \ hold space pointer
+ 0 tvar {base} \ input/output radix, default = 16
+ 0 tvar {dpl} \ number of places after fraction
+ 0 tvar {in} \ position in query string
+ 0 tvar {handler} \ throw/catch handler
+ 0 tvar {last} \ last defined word
+ 0 tvar #tib \ terminal input buffer
+
+ =end dup tvar {sp0} tvar {sp} \ grows downwards
+ =end =stksz 2* - dup tvar {rp0} tvar {rp} \ grows upwards
+ =end =stksz 2* - =buf - constant TERMBUF \ pad buffer space
+
+TERMBUF =buf + constant =tbufend
+
+: vcell 1 ( cell '1' should contain '1' ) ;
+: -vcell set 2/ ;
+: --sp {sp} iLOAD-C vcell iADD {sp} iSTORE-C ;
+: ++sp {sp} iLOAD-C -vcell iADD {sp} iSTORE-C ;
+: --rp {rp} iLOAD-C -vcell iADD {rp} iSTORE-C ;
+: ++rp {rp} iLOAD-C vcell iADD {rp} iSTORE-C ;
+
+\ ---- ---- ---- ---- ---- Forth VM ---- ---- ---- ---- ---- ---- ---- ----
+
+label: start
+ start call entry t!
+ {sp0} iLOAD-C {sp} iSTORE-C
+ {rp0} iLOAD-C {rp} iSTORE-C
+ iLOAD-C
+ ip iSTORE-C
+ \ -- fall-through --
+label: vm ( The Forth virtual machine )
+ ip iLOAD-C
+ w iSTORE-C
+ ip iLOAD-C 1 iADD ip iSTORE-C
+ w iLOAD-C
+ 0 iSET \ jump to next token
+
+label: {nest} ( function call: accumulator must contain '0 iGET' prior to call )
+ w iSTORE-C ( store '0 iGET' into working pointer )
+ ++rp
+ ip iLOAD-C
+ {rp} iSTORE
+ w iLOAD-C
+ 2 iADD
+ ip iSTORE-C
+ vm branch
+
+label: {unnest} ( return from function call )
+ {rp} iLOAD
+ t iSTORE-C
+ --rp
+ t iLOAD-C
+ ip iSTORE-C
+ vm branch
+
+:m nest 0 iGET {nest} branch ;m
+:m unnest {unnest} branch ;m
+:m =nest {nest} call ;m
+:m =unnest {unnest} call ;m
+:m =0iGET F000 ;m
+
+:m :ht ( "name" -- : forth only routine )
+ get-current >r target.1 set-current create
+ r> set-current CAFEBABE talign there ,
+ nest
+ does> @ branch ( really a call ) ;m
+
+:m :t ( "name" -- : forth only routine )
+ >in @ thead >in !
+ get-current >r target.1 set-current create
+ r> set-current CAFEBABE talign there ,
+ nest
+ does> @ branch ( really a call ) ;m
+
+:m :to ( "name" -- : forth only, target only routine )
+ >in @ thead >in !
+ get-current >r target.only.1 set-current create r> set-current
+ there ,
+ nest CAFEBABE
+ does> @ branch ;m
+
+:m ;t CAFEBABE <> if abort" unstructured" then talign unnest target.only.1 -order ;
+
+:m a: ( "name" -- : assembly only routine, no header )
+ CAFED00D
+ target.1 +order also definitions
+ create talign there ,
+ assembler.1 +order
+ does> @ branch ;m
+:m (a); CAFED00D <> if abort" unstructured" then assembler.1 -order ;m
+:m a; (a); vm branch ;m
+
+label: IncIp ip iLOAD-C 1 iADD ip iSTORE-C vm branch
+label: decSp tos iSTORE-C --sp vm branch
+
+a: opPush ( pushes the next value in instruction stream on to the stack )
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ ip iLOAD-C
+ t iSTORE-C
+ t iLOAD
+ tos iSTORE-C
+ IncIp branch
+ (a);
+
+a: opJump ( jump to next value in instruction stream )
+label: Jump
+ ip iLOAD
+ ip iSTORE-C
+ a;
+
+a: opJumpZ
+ tos iLOAD-C
+ t iSTORE-C
+ {sp} iLOAD
+ tos iSTORE-C
+ --sp
+ t iLOAD-C
+ if
+ IncIp branch
+ then
+ Jump branch
+ (a);
+
+a: opNext
+ {rp} iLOAD
+ if
+ set 2/ iADD
+ {rp} iSTORE
+ Jump branch
+ then
+ --rp
+ IncIp branch
+ (a);
+
+:m lit opPush t, ;m
+:m [char] char opPush t, ;m
+:m char char opPush t, ;m
+:m =push [ t' opPush ] literal call ;m
+:m =jump [ t' opJump ] literal call ;m
+:m =jumpz [ t' opJumpZ ] literal call ;m
+:m begin talign there ;m
+:m until talign opJumpZ 2/ t, ;m
+:m again talign opJump 2/ t, ;m
+:m if opJumpZ there 0 t, ;m
+:m mark opJump there 0 t, ;m
+:m then there 2/ swap t! ;m
+:m else mark swap then ;m
+:m while if ;m
+:m repeat swap again then ;m
+:m aft drop mark begin swap ;m
+:m next talign opNext 2/ t, ;m
+
+a: bye halt! a; ( -- : bye bye! )
+a: exit unnest a; ( -- : exit from current function )
+
+a: lls ( u shift -- u : shift left by number of bits set )
+ {sp} iLOAD
+ tos 2/ iLSHIFT
+ decSp branch
+ (a);
+
+a: lrs ( u shift -- u : shift right by number of bits set )
+ {sp} iLOAD
+ tos 2/ iRSHIFT
+ decSp branch
+ (a);
+
+a: and ( u u -- u : bit wise AND )
+ {sp} iLOAD
+ tos 2/ iAND
+ decSp branch
+ (a);
+
+a: or ( u u -- u : bit wise OR )
+ {sp} iLOAD
+ tos 2/ iOR
+ decSp branch
+ (a);
+
+a: xor ( u u -- u : bit wise XOR )
+ {sp} iLOAD
+ tos 2/ iXOR
+ decSp branch
+ (a);
+
+a: + ( u u -- u : Plain old addition )
+ {sp} iLOAD
+ tos 2/ iADD
+ decSp branch
+ (a);
+
+a: um+ ( u u -- u f : Add with carry )
+ {sp} iLOAD
+ tos 2/ iADD
+ {sp} iSTORE
+ flags?
+ flgCy iAND
+ tos iSTORE-C
+ a;
+
+a: @ ( a -- u : load a memory address )
+ tos iLOAD-C
+ 1 iRSHIFT
+ tos iSTORE-C
+ tos iLOAD
+ tos iSTORE-C
+ a;
+
+a: ! ( u a -- store a cell at a memory address )
+ tos iLOAD-C
+ 1 iRSHIFT
+ t iSTORE-C
+ {sp} iLOAD
+ t iSTORE
+ --sp
+ {sp} iLOAD
+ decSp branch
+ (a);
+
+a: c@ ( b -- c )
+ tos iLOAD-C
+ 1 iRSHIFT
+ t iSTORE-C
+ t iLOAD
+ t iSTORE-C
+ tos iLOAD-C
+ 1 iAND if
+ t iLOAD-C
+ low 2/ iRSHIFT
+ else
+ t iLOAD-C
+ low 2/ iAND
+ then
+ tos iSTORE-C
+ a;
+
+a: dup ( u -- u u : duplicate item on top of stack )
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ a;
+
+a: drop ( u -- : drop it like it's hot )
+ {sp} iLOAD
+ decSp branch
+ (a);
+
+a: swap ( u1 u2 -- u2 u1 : swap top two stack items )
+ {sp} iLOAD
+ t iSTORE-C
+ tos iLOAD-C
+ {sp} iSTORE
+ t iLOAD-C
+ tos iSTORE-C
+ a;
+
+a: over ( u1 u2 -- u1 u2 u1 : reach over top of stack and copy next on stack )
+ {sp} iLOAD
+ t iSTORE-C
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ t iLOAD-C
+ tos iSTORE-C
+ a;
+
+a: 1- ( u -- u : decrement top of stack by one )
+ tos iLOAD-C
+ set 2/ iADD
+ tos iSTORE-C
+ a;
+
+a: >r ( u -- , R: -- u : move variable from data to return stack )
+ ++rp
+ tos iLOAD-C
+ {rp} iSTORE
+ {sp} iLOAD
+ decSp branch
+ (a);
+
+:m for talign >r begin ;m
+:m =>r [ t' >r ] literal call ;m
+:m =next [ t' opNext ] literal call ;m
+
+a: r> ( -- u , R: u -- : move variable from return to data stack )
+ {rp} iLOAD
+ t iSTORE-C
+ --rp
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ t iLOAD-C
+ tos iSTORE-C
+ a;
+
+a: r@ ( -- u, R: u -- u : copy top of return stack to data stack )
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ {rp} iLOAD
+ tos iSTORE-C
+ a;
+
+a: rdrop ( --, R: u -- : drop top item on return stack )
+ --rp
+ a;
+
+a: execute ( xt -- : execute an execution token! )
+ tos iLOAD-C
+ t iSTORE-C
+ {sp} iLOAD
+ tos iSTORE-C
+ --sp
+ t iLOAD-C
+ 1 iRSHIFT
+ {nest} branch
+ (a);
+
+a: sp! ( ??? u -- ??? : set stack depth )
+ tos iLOAD-C
+ {sp} iSTORE-C
+ {sp} iLOAD
+ tos iSTORE-C
+ a;
+
+a: rp! ( u -- , R: ??? --- ??? : set return stack depth )
+ tos iLOAD-C
+ {rp} iSTORE-C
+ {sp} iLOAD
+ decSp branch
+ (a);
+
+a: sp@ ( -- u : get variable stack depth )
+ {sp} iLOAD-C
+ t iSTORE-C
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ t iLOAD-C
+ tos iSTORE-C
+ a;
+
+a: rp@ ( -- u : get return stack depth )
+ ++sp
+ tos iLOAD-C
+ {sp} iSTORE
+ {rp} iLOAD-C
+ tos iSTORE-C
+ a;
+
+\ ---- ---- ---- ---- ---- no more direct assembly ---- ---- ---- ---- ----
+
+assembler.1 -order
+
+:ht #0 0 lit ;t ( -- 0 : space saving measure, push 0 onto variable stack )
+:ht #1 1 lit ;t ( -- 1 : space saving measure, push 1 onto variable stack )
+:ht #-1 -1 lit ;t ( -- -1 : space saving measure, push -1 onto variable stack )
+
+\ Add words written in assembly into dictionary, you will need an understanding
+\ of wordlists to understand this.
+
+:to bye bye ;t
+:to and and ;t
+:to or or ;t
+:to xor xor ;t
+:to + + ;t
+:to um+ um+ ;t
+:to @ @ ;t
+:to ! ! ;t
+:to c@ c@ ;t
+:to dup dup ;t
+:to drop drop ;t
+:to swap swap ;t
+:to over over ;t
+:to 1- 1- ;t
+:to >r r> swap >r >r ;t compile-only
+:to r> r> r> swap >r ;t compile-only
+:to r@ r> r@ swap >r ;t compile-only
+:to execute execute ;t
+
+:t 0= if #0 exit then #-1 ;t
+:t invert #-1 xor ;t
+:t 1+ #1 + ;t
+:t emit ( ch -- : )
+ begin 8002 lit @ 1000 lit and 0= until
+ FF lit and 2000 lit or 8002 lit ! ;t
+:t key? ( -- ch -1 | 0 )
+ 8002 lit @ 100 lit and if #0 exit then
+ 400 lit 8002 lit ! 8002 lit @ FF lit and #-1 ;t
+:t here h lit @ ;t
+:t base {base} lit ;t ( -- a : base variable controls input/output radix )
+:t dpl {dpl} lit ;t ( -- a : push address of 'dpl' onto the variable stack )
+:t hld {hld} lit ;t ( -- a : push address of 'hld' onto the variable stack )
+:t bl 20 lit ;t ( -- space : push a space onto the stack )
+:t >in {in} lit ;t ( -- b : push pointer to terminal input position )
+:t hex $10 lit base ! ;t ( -- : switch to hexadecimal input/output radix )
+:t source TERMBUF lit #tib lit @ ;t ( -- b u )
+:t last {last} lit @ ;t ( -- : last defined word )
+:t state {state} lit ;t ( -- a : compilation state variable )
+:t ] #-1 state ! ;t ( -- : turn compile mode on )
+:t [ #0 state ! ;t immediate ( -- : turn compile mode off )
+:t nip swap drop ;t ( u1 u2 -- u2 : remove next stack value )
+:t tuck swap over ;t ( u1 u2 -- u2 u1 u2 : save top stack value )
+:t ?dup dup if dup then ;t ( u -- u u | 0 : duplicate if not zero )
+:t rot >r swap r> swap ;t ( u1 u2 u3 -- u2 u3 u1 : rotate three numbers )
+:t 2drop drop drop ;t ( u u -- : drop two numbers )
+:t 2dup over over ;t ( u1 u2 -- u1 u2 u1 u2 : duplicate set of values )
+:t +! tuck @ + swap ! ;t ( n a -- : increment value at address by 'n' )
+:t = xor 0= ;t ( u u -- f : equality )
+:t <> = 0= ;t ( u u -- f : inequality )
+:t 0>= 8000 lit and 0= ;t ( n -- f : greater or equal to zero )
+:t 0< 0>= 0= ;t ( n -- f : less than zero )
+:t negate 1- invert ;t ( n -- n : negate [twos compliment] )
+:t - negate + ;t ( u u -- u : subtract )
+:t < - 0< ;t ( n n -- f : signed less than )
+:t > swap < ;t ( n n -- f : signed greater than )
+:t 0> #0 > ;t ( n -- f : greater than zero )
+:t 2* #1 lls ;t ( u -- u : multiply by two )
+:t 2/ #1 lrs ;t ( u -- u : divide by two )
+:t cell 2 lit ;t ( -- u : size of memory cell )
+:t cell+ cell + ;t ( a -- a : increment address to next cell )
+:t pick sp@ + 2* @ ;t ( ??? u -- ??? u u : )
+:t u< 2dup 0>= swap 0>= xor >r < r> xor ;t ( u u -- f : )
+:t aligned dup #1 and + ;t ( b -- u : align a pointer )
+:t align here aligned h lit ! ;t ( -- : align dictionary pointer )
+:t depth {sp0} lit @ sp@ - 1- ;t ( -- u : variable stack depth )
+:t c! ( c b -- : store character at address )
+ dup dup >r #1 and if
+ @ 00FF lit and swap FF lit lls
+ else
+ @ FF00 lit and swap FF lit and
+ then or r> ! ;t
+:t count dup 1+ swap c@ ;t ( b -- b c : advance string, get next char )
+:t allot aligned h lit +! ;t ( u -- : allocate space in dictionary )
+:t , align here ! cell allot ;t ( u -- : write a value into the dictionary )
+:t abs dup 0< if negate then ;t ( n -- u : absolute value of a number )
+:t mux dup >r and swap r> invert and or ;t ( u1 u2 f -- )
+:t max 2dup < mux ;t ( n n -- n : maximum of two numbers )
+:t min 2dup > mux ;t ( n n -- n : minimum of two numbers )
+:t +string #1 over min rot over + rot rot - ;t ( b u -- b u : increment str )
+:t catch ( xt -- exception# | 0 \ return addr on stack )
+ sp@ >r ( xt ) \ save data stack pointer
+ {handler} lit @ >r ( xt ) \ and previous handler
+ rp@ {handler} lit ! ( xt ) \ set current handler
+ execute ( ) \ execute returns if no throw
+ r> {handler} lit ! ( ) \ restore previous handler
+ rdrop ( ) \ discard saved stack ptr
+ #0 ;t ( 0 ) \ normal completion
+:t throw ( ??? exception# -- ??? exception# )
+ ?dup if ( exc# ) \ 0 throw is no-op
+ {handler} lit @ rp! ( exc# ) \ restore prev return stack
+ r> {handler} lit ! ( exc# ) \ restore prev handler
+ r> swap >r ( saved-sp ) \ exc# on return stack
+ sp! drop r> ( exc# ) \ restore stack
+ then ;t
+:t um* ( u u -- ud : double cell width multiply )
+ #0 swap ( u1 0 u2 ) $F lit
+ for dup um+ >r >r dup um+ r> + r>
+ if >r over um+ r> + then
+ next rot drop ;t
+:t um/mod ( ud u -- ur uq : unsigned double cell width divide/modulo )
+ ?dup 0= if -A lit throw then
+ 2dup u<
+ if negate $F lit
+ for >r dup um+ >r >r dup um+ r> + dup
+ r> r@ swap >r um+ r> or
+ if >r drop 1+ r> else drop then r>
+ next
+ drop swap exit
+ then 2drop drop #-1 dup ;t
+:t key begin key? until ;t ( c -- : get a character from UART )
+:t type begin dup while swap count emit swap 1- repeat 2drop ;t ( b u -- )
+:t cmove for aft >r dup c@ r@ c! 1+ r> 1+ then next 2drop ;t ( b1 b2 u -- )
+:t do$ r> r> 2* dup count + aligned 2/ >r swap >r ;t ( -- a : )
+:t ($) do$ ;t ( -- a : do string NB. )
+:t .$ do$ count type ;t ( -- : print string, next cells contain string )
+:m ." .$ $literal ;m
+:m $" ($) $literal ;m
+:t space bl emit ;t ( -- : print space )
+:t cr .$ 2 tc, =cr tc, =lf tc, ;t ( -- : print new line )
+:t ktap ( bot eot cur c -- bot eot cur )
+ dup dup =cr lit <> >r =lf lit <> r> and if \ Not End of Line?
+ dup =bksp lit <> >r =del lit <> r> and if \ Not Delete Char?
+ bl ( tap -> ) dup emit over c! 1+ ( bot eot cur c -- bot eot cur )
+ exit
+ then
+ >r over r@ < dup if
+ =bksp lit dup emit space emit
+ then
+ r> +
+ exit
+ then drop nip dup ;t
+:t accept ( b u -- b u : read in a line of user input )
+ over + over
+ begin
+ 2dup xor
+ while
+ key dup bl - $5F lit u< if ( tap -> ) dup emit over c! 1+ else ktap then
+ repeat drop over - ;t
+:t query TERMBUF lit =buf lit accept #tib lit ! drop #0 >in ! ;t ( -- : get line)
+:t ?depth depth > if -4 lit throw then ;t ( u -- : check stack depth )
+:t -trailing ( b u -- b u : remove trailing spaces )
+ for
+ aft bl over r@ + c@ <
+ if r> 1+ exit then
+ then
+ next #0 ;t
+:ht look ( b u c xt -- b u : skip until *xt* test succeeds )
+ swap >r rot rot
+ begin
+ dup
+ while
+ over c@ r@ - r@ bl = 4 lit pick execute
+ if rdrop rot drop exit then
+ +string
+ repeat rdrop rot drop ;t
+:ht no-match if 0> exit then 0= 0= ;t ( c1 c2 -- t )
+:ht match no-match invert ;t ( c1 c2 -- t )
+:t parse ( c -- b u ; )
+ >r source drop >in @ + #tib lit @ >in @ - r@
+ >r over r> swap >r >r
+ r@ t' no-match lit look 2dup
+ r> t' match lit look swap r> - >r - r> 1+ ( b u c -- b u delta )
+ >in +!
+ r> bl = if -trailing then #0 max ;t
+:t spaces begin dup 0> while space 1- repeat drop ;t ( +n -- )
+:t hold #-1 hld +! hld @ c! ;t ( c -- : save a character in hold space )
+:t #> 2drop hld @ =tbufend lit over - ;t ( u -- b u )
+:t # ( d -- d : add next character in number to hold space )
+ 2 lit ?depth
+ #0 base @
+ ( extract ->) dup >r um/mod r> swap >r um/mod r> rot ( ud ud -- ud u )
+ ( digit -> ) 9 lit over < 7 lit and + [char] 0 + ( u -- c )
+ hold ;t
+:t #s begin # 2dup ( d0= -> ) or 0= until ;t ( d -- 0 )
+:t <# =tbufend lit hld ! ;t ( -- )
+:t sign 0< if [char] - hold then ;t ( n -- )
+:t u.r >r #0 <# #s #> r> over - spaces type ;t ( u +n -- : print u right justified by +n )
+:t u. #0 <# #s #> space type ;t ( u -- : print unsigned number )
+:t . dup >r abs #0 <# #s r> sign #> space type ;t ( n -- print number )
+:t >number ( ud b u -- ud b u : convert string to number )
+ begin
+ 2dup >r >r drop c@ base @ ( get next character )
+ ( digit? -> ) >r [char] 0 - 9 lit over <
+ if 7 lit - dup $A lit < or then dup r> u< ( c base -- u f )
+ 0= if ( d char )
+ drop ( d char -- d )
+ r> r> ( restore string )
+ exit ( ..exit )
+ then ( d char )
+ swap base @ um* drop rot base @ um* ( d+ -> ) >r swap >r um+ r> + r> + ( accumulate digit )
+ r> r> ( restore string )
+ +string dup 0= ( advance string and test for end )
+ until ;t
+:t number? ( a u -- d -1 | a u 0 : string to a number [easier to use] )
+ #-1 dpl !
+ base @ >r
+ over c@ [char] - = dup >r if +string then
+ over c@ [char] $ = if hex +string then
+ >r >r #0 dup r> r>
+ begin
+ >number dup
+ while over c@ [char] . xor
+ if rot drop rot r> 2drop #0 r> base ! exit then
+ 1- dpl ! 1+ dpl @
+ repeat
+ 2drop r> if
+ ( dnegate -> ) invert >r invert #1 um+ r> +
+ then r> base ! #-1 ;t
+:t compare ( a1 u1 a2 u2 -- n : string equality )
+ rot
+ over - ?dup if >r 2drop r> nip exit then
+ for ( a1 a2 )
+ aft
+ count rot count rot - ?dup
+ if rdrop nip nip exit then
+ then
+ next 2drop #0 ;t
+:to .s depth for aft r@ pick . then next ;t ( -- : print variable stack )
+:t nfa cell+ ;t ( pwd -- nfa : move word pointer to name field )
+:t cfa nfa dup c@ $1F lit and + cell+ cell negate and ;t ( pwd -- cfa )
+:t (find) ( a wid -- PWD PWD 1|PWD PWD -1|0 a 0: find word in WID )
+ swap >r dup
+ begin
+ dup
+ while
+ dup nfa count $9F lit ( $1F:word-length + $80:hidden ) and r@ count compare 0=
+ if ( found! )
+ rdrop
+ dup ( immediate? -> ) nfa $40 lit swap @ and 0= 0=
+ #1 or negate exit
+ then
+ nip dup @
+ repeat
+ 2drop #0 r> #0 ;t
+:t find last (find) rot drop ;t ( "name" -- b )
+:t literal state @ if =push lit , , then ;t immediate ( u -- )
+:t compile, 2/ align C000 lit or , ;t ( xt -- )
+:t ?found if exit then space count type [char] ? emit cr -D lit throw ;t ( u f -- )
+:t interpret ( b -- )
+ find ?dup if
+ state @
+ if
+ 0> if cfa execute exit then \ <- immediate word are executed
+ cfa compile, exit \ <- compiling word are...compiled.
+ then
+ drop
+ dup nfa c@ 20 lit and if -E lit throw then ( <- ?compile )
+ cfa execute exit \ <- if its not, execute it, then exit *interpreter*
+ then
+ \ not a word
+ dup >r count number? if rdrop \ it is a number!
+ dpl @ 0< if \ <- dpl will be -1 if it is a single cell number
+ drop \ drop high cell from 'number?' for single cell output
+ else \ <- dpl is not -1, it is a double cell number
+ state @ if swap then
+ postpone literal \ literal is executed twice if it's a double
+ then
+ postpone literal exit
+ then
+ r> #0 ?found \ Could vector ?found here, to handle arbitrary words
+ ;t
+:t word parse here dup >r 2dup ! 1+ swap cmove r> ;t ( c -- b )
+:to words last begin dup nfa count 1f lit and space type @ ?dup 0= until ;t
+:to see bl word find ?found
+ cr begin dup @ =unnest lit <> while dup @ u. cell+ repeat @ u. ;t
+:to : align here last , {last} lit ! ( "name" -- : define a new word )
+ bl word
+ dup c@ 0= if -A lit throw then
+ count + h lit ! align
+ =0iGET lit , =nest lit , ] BABE lit ;t
+:to ; postpone [ BABE lit <> if -16 lit throw then =unnest lit , ;t immediate compile-only
+:to begin align here ;t immediate compile-only
+:to until =jumpz lit , 2/ , ;t immediate compile-only
+:to again =jump lit , 2/ , ;t immediate compile-only
+:to if =jumpz lit , here #0 , ;t immediate compile-only
+:to then here 2/ swap ! ;t immediate compile-only
+:to for =>r lit , here ;t immediate compile-only
+:to next =next lit , 2/ , ;t immediate compile-only
+:to ' bl word find ?found cfa literal ;t immediate
+:t compile r> dup 2* @ , 1+ >r ;t compile-only ( -- : compile next compiled into dictionary )
+:to exit compile exit ;t immediate compile-only
+:to ." compile .$ [char] " word count + h lit ! align ;t immediate compile-only
+:to $" compile ($) [char] " word count + h lit ! align ;t immediate compile-only \ "
+:to ( [char] ) parse 2drop ;t immediate ( "comment" -- discard until parenthesis )
+:to \ source drop @ >in ! ;t immediate ( "comment" -- discard until end of line )
+:to immediate last nfa @ $40 lit or last nfa ! ;t ( -- : turn previously defined word into an immediate one )
+:to dump begin over c@ u. +string ?dup 0= until drop ;t
+:t eval begin bl word dup c@ while interpret #1 ?depth repeat drop ." ok" cr ;t ( "word" -- )
+:t ini hex postpone [ #0 >in ! #-1 dpl ! ;t ( -- )
+:t quit ( -- : interpreter loop [and more, does more than most QUITs] )
+ there t2/ t! \ program entry point set here
+ ." eForth 3.2" cr
+ ini
+ begin
+ query t' eval lit catch
+ ( ?error -> ) ?dup if
+ space . [char] ? emit cr ini
+ then again ;t
+
+\ ---- ---- ---- ---- ---- implementation finished ---- ---- ---- ---- ----
+
+there h t!
+atlast {last} t!
+save-hex bit.hex
+save-target bit.bin
+.stat
+.end
+.( DONE ) cr
+bye
+
Index: bitserial/trunk/bit.hex
===================================================================
--- bitserial/trunk/bit.hex (nonexistent)
+++ bitserial/trunk/bit.hex (revision 2)
@@ -0,0 +1,2401 @@
+0000
+0001
+0002
+C019
+FFFF
+00FF
+0947
+0000
+0000
+0000
+0000
+0000
+12C2
+0000
+0000
+0000
+0000
+0000
+0000
+1282
+0000
+2000
+2000
+1F80
+1F80
+8015
+9016
+8017
+9018
+8006
+9008
+8008
+9009
+8008
+3001
+9008
+8009
+E000
+9009
+8018
+3001
+9018
+8008
+7018
+8009
+3002
+9008
+C01F
+6018
+900A
+8018
+3004
+9018
+800A
+9008
+C01F
+8008
+3001
+9008
+C01F
+900B
+8016
+3001
+9016
+C01F
+8016
+3004
+9016
+800B
+7016
+8008
+900A
+600A
+900B
+C038
+6008
+9008
+C01F
+800B
+900A
+6016
+900B
+8016
+3001
+9016
+800A
+D058
+C038
+C04B
+6018
+D05E
+3004
+7018
+C04B
+8018
+3004
+9018
+C038
+A010
+E001
+C01F
+C030
+C01F
+6016
+400B
+C03C
+6016
+500B
+C03C
+6016
+100B
+C03C
+6016
+000B
+C03C
+6016
+200B
+C03C
+6016
+300B
+C03C
+6016
+300B
+7016
+F001
+1001
+900B
+C01F
+800B
+5001
+900B
+600B
+900B
+C01F
+800B
+5001
+900A
+6016
+700A
+8016
+3001
+9016
+6016
+C03C
+800B
+5001
+900A
+600A
+900A
+800B
+1001
+D09B
+800A
+5005
+C09D
+800A
+1005
+900B
+C01F
+8016
+3004
+9016
+800B
+7016
+C01F
+6016
+C03C
+6016
+900A
+800B
+7016
+800A
+900B
+C01F
+6016
+900A
+8016
+3004
+9016
+800B
+7016
+800A
+900B
+C01F
+800B
+3004
+900B
+C01F
+8018
+3001
+9018
+800B
+7018
+6016
+C03C
+6018
+900A
+8018
+3004
+9018
+8016
+3004
+9016
+800B
+7016
+800A
+900B
+C01F
+8016
+3004
+9016
+800B
+7016
+6018
+900B
+C01F
+8018
+3004
+9018
+C01F
+800B
+900A
+6016
+900B
+8016
+3001
+9016
+800A
+5001
+C026
+800B
+9016
+6016
+900B
+C01F
+800B
+9018
+6016
+C03C
+8016
+900A
+8016
+3004
+9016
+800B
+7016
+800A
+900B
+C01F
+8016
+3004
+9016
+800B
+7016
+8018
+900B
+C01F
+F000
+C026
+C041
+0000
+C030
+F000
+C026
+C041
+0001
+C030
+F000
+C026
+C041
+FFFF
+C030
+0000
+6203
+6579
+F000
+C026
+C062
+C030
+0220
+6103
+646E
+F000
+C026
+C06D
+C030
+022E
+6F02
+0072
+F000
+C026
+C070
+C030
+023C
+7803
+726F
+F000
+C026
+C073
+C030
+024A
+2B01
+F000
+C026
+C076
+C030
+0258
+7503
+2B6D
+F000
+C026
+C079
+C030
+0264
+4001
+F000
+C026
+C080
+C030
+0272
+2101
+F000
+C026
+C086
+C030
+027E
+6302
+0040
+F000
+C026
+C090
+C030
+028A
+6403
+7075
+F000
+C026
+C09F
+C030
+0298
+6404
+6F72
+0070
+F000
+C026
+C0A5
+C030
+02A6
+7304
+6177
+0070
+F000
+C026
+C0A7
+C030
+02B6
+6F04
+6576
+0072
+F000
+C026
+C0AE
+C030
+02C6
+3102
+002D
+F000
+C026
+C0B8
+C030
+02D6
+3E22
+0072
+F000
+C026
+C0C3
+C0A7
+C0BC
+C0BC
+C030
+02E4
+7222
+003E
+F000
+C026
+C0C3
+C0C3
+C0A7
+C0BC
+C030
+02F8
+7222
+0040
+F000
+C026
+C0C3
+C0D0
+C0A7
+C0BC
+C030
+030C
+6507
+6578
+7563
+6574
+F000
+C026
+C0DC
+C030
+0320
+3002
+003D
+F000
+C026
+C04E
+01A2
+C101
+C065
+C10B
+C030
+0332
+6906
+766E
+7265
+0074
+F000
+C026
+C10B
+C073
+C030
+0348
+3102
+002B
+F000
+C026
+C106
+C076
+C030
+035C
+6504
+696D
+0074
+F000
+C026
+C041
+8002
+C080
+C041
+1000
+C06D
+C19C
+C04E
+01BC
+C041
+00FF
+C06D
+C041
+2000
+C070
+C041
+8002
+C086
+C030
+036C
+6B04
+7965
+003F
+F000
+C026
+C041
+8002
+C080
+C041
+0100
+C06D
+C04E
+01DF
+C101
+C065
+C041
+0400
+C041
+8002
+C086
+C041
+8002
+C080
+C041
+00FF
+C06D
+C10B
+C030
+039E
+6804
+7265
+0065
+F000
+C026
+C041
+0018
+C080
+C030
+03D8
+6204
+7361
+0065
+F000
+C026
+C041
+001E
+C030
+03EC
+6403
+6C70
+F000
+C026
+C041
+0020
+C030
+03FE
+6803
+646C
+F000
+C026
+C041
+001C
+C030
+040E
+6202
+006C
+F000
+C026
+C041
+0020
+C030
+041E
+3E03
+6E69
+F000
+C026
+C041
+0022
+C030
+042E
+6803
+7865
+F000
+C026
+C041
+0010
+C1FA
+C086
+C030
+043E
+7306
+756F
+6372
+0065
+F000
+C026
+C041
+1F20
+C041
+0028
+C080
+C030
+0452
+6C04
+7361
+0074
+F000
+C026
+C041
+0026
+C080
+C030
+046C
+7305
+6174
+6574
+F000
+C026
+C041
+001A
+C030
+0480
+5D01
+F000
+C026
+C10B
+C244
+C086
+C030
+0492
+5B41
+F000
+C026
+C101
+C244
+C086
+C030
+04A2
+6E03
+7069
+F000
+C026
+C0A7
+C0A5
+C030
+04B2
+7404
+6375
+006B
+F000
+C026
+C0A7
+C0AE
+C030
+04C2
+3F04
+7564
+0070
+F000
+C026
+C09F
+C04E
+0274
+C09F
+C030
+04D4
+7203
+746F
+F000
+C026
+C0BC
+C0A7
+C0C3
+C0A7
+C030
+04EA
+3205
+7264
+706F
+F000
+C026
+C0A5
+C0A5
+C030
+04FE
+3204
+7564
+0070
+F000
+C026
+C0AE
+C0AE
+C030
+0510
+2B02
+0021
+F000
+C026
+C265
+C080
+C076
+C0A7
+C086
+C030
+0522
+3D01
+F000
+C026
+C073
+C19C
+C030
+0538
+3C02
+003E
+F000
+C026
+C29E
+C19C
+C030
+0546
+3003
+3D3E
+F000
+C026
+C041
+8000
+C06D
+C19C
+C030
+0556
+3002
+003C
+F000
+C026
+C2AE
+C19C
+C030
+056A
+6E06
+6765
+7461
+0065
+F000
+C026
+C0B8
+C1A9
+C030
+057A
+2D01
+F000
+C026
+C2C2
+C076
+C030
+058E
+3C01
+F000
+C026
+C2C9
+C2B8
+C030
+059C
+3E01
+F000
+C026
+C0A7
+C2D0
+C030
+05AA
+3002
+003E
+F000
+C026
+C101
+C2D7
+C030
+05B8
+3202
+002A
+F000
+C026
+C106
+C067
+C030
+05C8
+3202
+002F
+F000
+C026
+C106
+C06A
+C030
+05D8
+6304
+6C65
+006C
+F000
+C026
+C041
+0002
+C030
+05E8
+6305
+6C65
+2B6C
+F000
+C026
+C2F8
+C076
+C030
+05FA
+7004
+6369
+006B
+F000
+C026
+C0EF
+C076
+C2E7
+C080
+C030
+060C
+7502
+003C
+F000
+C026
+C28C
+C2AE
+C0A7
+C2AE
+C073
+C0BC
+C2D0
+C0C3
+C073
+C030
+0622
+6107
+696C
+6E67
+6465
+F000
+C026
+C09F
+C106
+C06D
+C076
+C030
+0640
+6105
+696C
+6E67
+F000
+C026
+C1F0
+C325
+C041
+0018
+C086
+C030
+0658
+6405
+7065
+6874
+F000
+C026
+C041
+002A
+C080
+C0EF
+C2C9
+C0B8
+C030
+0670
+6302
+0021
+F000
+C026
+C09F
+C09F
+C0BC
+C106
+C06D
+C04E
+035B
+C080
+C041
+00FF
+C06D
+C0A7
+C041
+00FF
+C067
+C04B
+0363
+C080
+C041
+FF00
+C06D
+C0A7
+C041
+00FF
+C06D
+C070
+C0C3
+C086
+C030
+068A
+6305
+756F
+746E
+F000
+C026
+C09F
+C1B1
+C0A7
+C090
+C030
+06CE
+6105
+6C6C
+746F
+F000
+C026
+C325
+C041
+0018
+C294
+C030
+06E4
+2C01
+F000
+C026
+C330
+C1F0
+C086
+C2F8
+C376
+C030
+06FA
+6103
+7362
+F000
+C026
+C09F
+C2B8
+C04E
+0391
+C2C2
+C030
+070E
+6D03
+7875
+F000
+C026
+C09F
+C0BC
+C06D
+C0A7
+C0C3
+C1A9
+C06D
+C070
+C030
+0724
+6D03
+7861
+F000
+C026
+C28C
+C2D0
+C395
+C030
+0740
+6D03
+6E69
+F000
+C026
+C28C
+C2D7
+C395
+C030
+0752
+2B07
+7473
+6972
+676E
+F000
+C026
+C106
+C0AE
+C3AC
+C278
+C0AE
+C076
+C278
+C278
+C2C9
+C030
+0764
+6305
+7461
+6863
+F000
+C026
+C0EF
+C0BC
+C041
+0024
+C080
+C0BC
+C0F9
+C041
+0024
+C086
+C0DC
+C0C3
+C041
+0024
+C086
+C0D8
+C101
+C030
+0786
+7405
+7268
+776F
+F000
+C026
+C26E
+C04E
+03F2
+C041
+0024
+C080
+C0EB
+C0C3
+C041
+0024
+C086
+C0C3
+C0A7
+C0BC
+C0E6
+C0A5
+C0C3
+C030
+07B6
+7503
+2A6D
+F000
+C026
+C101
+C0A7
+C041
+000F
+C0BC
+C09F
+C079
+C0BC
+C0BC
+C09F
+C079
+C0C3
+C076
+C0C3
+C04E
+040D
+C0BC
+C0AE
+C079
+C0C3
+C076
+C059
+03FD
+C278
+C0A5
+C030
+07E6
+7506
+2F6D
+6F6D
+0064
+F000
+C026
+C26E
+C19C
+C04E
+0420
+C041
+FFF6
+C3DF
+C28C
+C314
+C04E
+0448
+C2C2
+C041
+000F
+C0BC
+C0BC
+C09F
+C079
+C0BC
+C0BC
+C09F
+C079
+C0C3
+C076
+C09F
+C0C3
+C0D0
+C0A7
+C0BC
+C079
+C0C3
+C070
+C04E
+0441
+C0BC
+C0A5
+C1B1
+C0C3
+C04B
+0442
+C0A5
+C0C3
+C059
+0428
+C0A5
+C0A7
+C065
+C283
+C0A5
+C10B
+C09F
+C030
+0824
+6B03
+7965
+F000
+C026
+C1D3
+C04E
+0452
+C030
+089A
+7404
+7079
+0065
+F000
+C026
+C09F
+C04E
+0466
+C0A7
+C36B
+C1BA
+C0A7
+C0B8
+C04B
+045C
+C283
+C030
+08AC
+6305
+6F6D
+6576
+F000
+C026
+C0BC
+C04B
+0479
+C0BC
+C09F
+C090
+C0D0
+C348
+C1B1
+C0C3
+C1B1
+C059
+0471
+C283
+C030
+08D0
+6403
+246F
+F000
+C026
+C0C3
+C0C3
+C2E7
+C09F
+C36B
+C076
+C325
+C2EF
+C0BC
+C0A7
+C0BC
+C030
+08FA
+2803
+2924
+F000
+C026
+C480
+C030
+091C
+2E02
+0024
+F000
+C026
+C480
+C36B
+C45A
+C030
+092A
+7305
+6170
+6563
+F000
+C026
+C212
+C1BA
+C030
+093C
+6302
+0072
+F000
+C026
+C498
+0D02
+000A
+C030
+094E
+6B04
+6174
+0070
+F000
+C026
+C09F
+C09F
+C041
+000D
+C2A6
+C0BC
+C041
+000A
+C2A6
+C0C3
+C06D
+C04E
+04E6
+C09F
+C041
+0008
+C2A6
+C0BC
+C041
+007F
+C2A6
+C0C3
+C06D
+C04E
+04D6
+C212
+C09F
+C1BA
+C0AE
+C348
+C1B1
+C065
+C0BC
+C0AE
+C0D0
+C2D0
+C09F
+C04E
+04E3
+C041
+0008
+C09F
+C1BA
+C4A2
+C1BA
+C0C3
+C076
+C065
+C0A5
+C25C
+C09F
+C030
+0960
+6106
+6363
+7065
+0074
+F000
+C026
+C0AE
+C076
+C0AE
+C28C
+C073
+C04E
+050B
+C450
+C09F
+C212
+C2C9
+C041
+005F
+C314
+C04E
+0508
+C09F
+C1BA
+C0AE
+C348
+C1B1
+C04B
+0509
+C4B4
+C04B
+04F4
+C0A5
+C0AE
+C2C9
+C030
+09D4
+7105
+6575
+7972
+F000
+C026
+C041
+1F20
+C041
+0060
+C4EF
+C041
+0028
+C086
+C0A5
+C101
+C21A
+C086
+C030
+0A1E
+3F06
+6564
+7470
+0068
+F000
+C026
+C33C
+C2D7
+C04E
+0530
+C041
+FFFC
+C3DF
+C030
+0A44
+2D09
+7274
+6961
+696C
+676E
+F000
+C026
+C0BC
+C04B
+0547
+C212
+C0AE
+C0D0
+C076
+C090
+C2D0
+C04E
+0547
+C0C3
+C1B1
+C065
+C059
+053C
+C101
+C030
+F000
+C026
+C0A7
+C0BC
+C278
+C278
+C09F
+C04E
+0568
+C0AE
+C090
+C0D0
+C2C9
+C0D0
+C212
+C29E
+C041
+0004
+C30A
+C0DC
+C04E
+0565
+C0D8
+C278
+C0A5
+C065
+C3B7
+C04B
+0551
+C0D8
+C278
+C0A5
+C030
+F000
+C026
+C04E
+0572
+C2DF
+C065
+C19C
+C19C
+C030
+F000
+C026
+C56C
+C1A9
+C030
+0A62
+7005
+7261
+6573
+F000
+C026
+C0BC
+C22E
+C0A5
+C21A
+C080
+C076
+C041
+0028
+C080
+C21A
+C080
+C2C9
+C0D0
+C0BC
+C0AE
+C0C3
+C0A7
+C0BC
+C0BC
+C0D0
+C041
+0AD8
+C54B
+C28C
+C0C3
+C041
+0AEA
+C54B
+C0A7
+C0C3
+C2C9
+C0BC
+C2C9
+C0C3
+C1B1
+C21A
+C294
+C0C3
+C212
+C29E
+C04E
+05AB
+C537
+C101
+C3A3
+C030
+0AF4
+7306
+6170
+6563
+0073
+F000
+C026
+C09F
+C2DF
+C04E
+05BD
+C4A2
+C0B8
+C04B
+05B5
+C0A5
+C030
+0B5C
+6804
+6C6F
+0064
+F000
+C026
+C10B
+C20A
+C294
+C20A
+C080
+C348
+C030
+0B7E
+2302
+003E
+F000
+C026
+C283
+C20A
+C080
+C041
+1F80
+C0AE
+C2C9
+C030
+0B98
+2301
+F000
+C026
+C041
+0002
+C527
+C101
+C1FA
+C080
+C09F
+C0BC
+C417
+C0C3
+C0A7
+C0BC
+C417
+C0C3
+C278
+C041
+0009
+C0AE
+C2D0
+C041
+0007
+C06D
+C076
+C041
+0030
+C076
+C5C3
+C030
+0BB2
+2302
+0073
+F000
+C026
+C5DB
+C28C
+C070
+C19C
+C04E
+05FE
+C030
+0BF2
+3C02
+0023
+F000
+C026
+C041
+1F80
+C20A
+C086
+C030
+0C0A
+7304
+6769
+006E
+F000
+C026
+C2B8
+C04E
+061B
+C041
+002D
+C5C3
+C030
+0C1E
+7503
+722E
+F000
+C026
+C0BC
+C101
+C608
+C5FC
+C5CF
+C0C3
+C0AE
+C2C9
+C5B3
+C45A
+C030
+0C38
+7502
+002E
+F000
+C026
+C101
+C608
+C5FC
+C5CF
+C4A2
+C45A
+C030
+0C58
+2E01
+F000
+C026
+C09F
+C0BC
+C38A
+C101
+C608
+C5FC
+C0C3
+C613
+C5CF
+C4A2
+C45A
+C030
+0C70
+3E07
+756E
+626D
+7265
+F000
+C026
+C28C
+C0BC
+C0BC
+C0A5
+C090
+C1FA
+C080
+C0BC
+C041
+0030
+C2C9
+C041
+0009
+C0AE
+C2D0
+C04E
+0668
+C041
+0007
+C2C9
+C09F
+C041
+000A
+C2D0
+C070
+C09F
+C0C3
+C314
+C19C
+C04E
+0672
+C0A5
+C0C3
+C0C3
+C065
+C0A7
+C1FA
+C080
+C3F6
+C0A5
+C278
+C1FA
+C080
+C3F6
+C0BC
+C0A7
+C0BC
+C079
+C0C3
+C076
+C0C3
+C076
+C0C3
+C0C3
+C3B7
+C09F
+C19C
+C04E
+064F
+C030
+0C90
+6E07
+6D75
+6562
+3F72
+F000
+C026
+C10B
+C202
+C086
+C1FA
+C080
+C0BC
+C0AE
+C090
+C041
+002D
+C29E
+C09F
+C0BC
+C04E
+06A2
+C3B7
+C0AE
+C090
+C041
+0024
+C29E
+C04E
+06AB
+C222
+C3B7
+C0BC
+C0BC
+C101
+C09F
+C0C3
+C0C3
+C64D
+C09F
+C04E
+06CE
+C0AE
+C090
+C041
+002E
+C073
+C04E
+06C6
+C278
+C0A5
+C278
+C0C3
+C283
+C101
+C0C3
+C1FA
+C086
+C065
+C0B8
+C202
+C086
+C1B1
+C202
+C080
+C04B
+06B1
+C283
+C0C3
+C04E
+06D9
+C1A9
+C0BC
+C1A9
+C106
+C079
+C0C3
+C076
+C0C3
+C1FA
+C086
+C10B
+C030
+0D16
+6307
+6D6F
+6170
+6572
+F000
+C026
+C278
+C0AE
+C2C9
+C26E
+C04E
+06F0
+C0BC
+C283
+C0C3
+C25C
+C065
+C0BC
+C04B
+06FF
+C36B
+C278
+C36B
+C278
+C2C9
+C26E
+C04E
+06FF
+C0D8
+C25C
+C25C
+C065
+C059
+06F3
+C283
+C101
+C030
+0DBC
+2E02
+0073
+F000
+C026
+C33C
+C0BC
+C04B
+0710
+C0D0
+C30A
+C63A
+C059
+070D
+C030
+0E08
+6E03
+6166
+F000
+C026
+C301
+C030
+0E26
+6303
+6166
+F000
+C026
+C716
+C09F
+C090
+C041
+001F
+C06D
+C076
+C301
+C2F8
+C2C2
+C06D
+C030
+0E34
+2806
+6966
+646E
+0029
+F000
+C026
+C0A7
+C0BC
+C09F
+C09F
+C04E
+0757
+C09F
+C716
+C36B
+C041
+009F
+C06D
+C0D0
+C36B
+C6E3
+C19C
+C04E
+0752
+C0D8
+C09F
+C716
+C041
+0040
+C0A7
+C080
+C06D
+C19C
+C19C
+C106
+C070
+C2C2
+C065
+C25C
+C09F
+C080
+C04B
+0735
+C283
+C101
+C0C3
+C101
+C030
+0E56
+6604
+6E69
+0064
+F000
+C026
+C23A
+C730
+C278
+C0A5
+C030
+0EB8
+6C47
+7469
+7265
+6C61
+F000
+C026
+C244
+C080
+C04E
+0776
+C041
+C041
+C37F
+C37F
+C030
+0ECE
+6308
+6D6F
+6970
+656C
+002C
+F000
+C026
+C2EF
+C330
+C041
+C000
+C070
+C37F
+C030
+0EEE
+3F06
+6F66
+6E75
+0064
+F000
+C026
+C04E
+0790
+C065
+C4A2
+C36B
+C45A
+C041
+003F
+C1BA
+C4AA
+C041
+FFF3
+C3DF
+C030
+0F0C
+6909
+746E
+7265
+7270
+7465
+F000
+C026
+C760
+C26E
+C04E
+07C3
+C244
+C080
+C04E
+07B4
+C2DF
+C04E
+07B1
+C71D
+C0DC
+C065
+C71D
+C77D
+C065
+C0A5
+C09F
+C716
+C090
+C041
+0020
+C06D
+C04E
+07C0
+C041
+FFF2
+C3DF
+C71D
+C0DC
+C065
+C09F
+C0BC
+C36B
+C690
+C04E
+07DA
+C0D8
+C202
+C080
+C2B8
+C04E
+07D2
+C0A5
+C04B
+07D8
+C244
+C080
+C04E
+07D7
+C0A7
+C76C
+C76C
+C065
+C0C3
+C101
+C78B
+C030
+0F36
+7704
+726F
+0064
+F000
+C026
+C57E
+C1F0
+C09F
+C0BC
+C28C
+C086
+C1B1
+C0A7
+C46C
+C0C3
+C030
+0FBC
+7705
+726F
+7364
+F000
+C026
+C23A
+C09F
+C716
+C36B
+C041
+001F
+C06D
+C4A2
+C45A
+C080
+C26E
+C19C
+C04E
+07F6
+C030
+0FDE
+7303
+6565
+F000
+C026
+C212
+C7E2
+C760
+C78B
+C4AA
+C09F
+C080
+C041
+C030
+C2A6
+C04E
+081B
+C09F
+C080
+C62F
+C301
+C04B
+080E
+C080
+C62F
+C030
+1008
+3A01
+F000
+C026
+C330
+C1F0
+C23A
+C37F
+C041
+0026
+C086
+C212
+C7E2
+C09F
+C090
+C19C
+C04E
+0833
+C041
+FFF6
+C3DF
+C36B
+C076
+C041
+0018
+C086
+C330
+C041
+F000
+C37F
+C041
+C026
+C37F
+C24B
+C041
+BABE
+C030
+103C
+3B61
+F000
+C026
+C253
+C041
+BABE
+C2A6
+C04E
+0850
+C041
+FFEA
+C3DF
+C041
+C030
+C37F
+C030
+1086
+6265
+6765
+6E69
+F000
+C026
+C330
+C1F0
+C030
+10A8
+7565
+746E
+6C69
+F000
+C026
+C041
+C04E
+C37F
+C2EF
+C37F
+C030
+10BA
+6165
+6167
+6E69
+F000
+C026
+C041
+C04B
+C37F
+C2EF
+C37F
+C030
+10D2
+6962
+0066
+F000
+C026
+C041
+C04E
+C37F
+C1F0
+C101
+C37F
+C030
+10EA
+7464
+6568
+006E
+F000
+C026
+C1F0
+C2EF
+C0A7
+C086
+C030
+1102
+6663
+726F
+F000
+C026
+C041
+C0BC
+C37F
+C1F0
+C030
+1118
+6E64
+7865
+0074
+F000
+C026
+C041
+C059
+C37F
+C2EF
+C37F
+C030
+112C
+2741
+F000
+C026
+C212
+C7E2
+C760
+C78B
+C71D
+C76C
+C030
+1144
+6327
+6D6F
+6970
+656C
+F000
+C026
+C0C3
+C09F
+C2E7
+C080
+C37F
+C1B1
+C0BC
+C030
+115A
+6564
+6978
+0074
+F000
+C026
+C8B2
+C065
+C030
+1178
+2E62
+0022
+F000
+C026
+C8B2
+C498
+C041
+0022
+C7E2
+C36B
+C076
+C041
+0018
+C086
+C330
+C030
+118A
+2462
+0022
+F000
+C026
+C8B2
+C491
+C041
+0022
+C7E2
+C36B
+C076
+C041
+0018
+C086
+C330
+C030
+11AC
+2841
+F000
+C026
+C041
+0029
+C57E
+C283
+C030
+11CE
+5C41
+F000
+C026
+C22E
+C0A5
+C080
+C21A
+C086
+C030
+11E0
+6909
+6D6D
+6465
+6169
+6574
+F000
+C026
+C23A
+C716
+C080
+C041
+0040
+C070
+C23A
+C716
+C086
+C030
+11F4
+6404
+6D75
+0070
+F000
+C026
+C0AE
+C090
+C62F
+C3B7
+C26E
+C19C
+C04E
+0912
+C0A5
+C030
+1218
+6504
+6176
+006C
+F000
+C026
+C212
+C7E2
+C09F
+C090
+C04E
+092D
+C7A1
+C106
+C527
+C04B
+0922
+C0A5
+C498
+2003
+6B6F
+C4AA
+C030
+1238
+6903
+696E
+F000
+C026
+C222
+C253
+C101
+C21A
+C086
+C10B
+C202
+C086
+C030
+1266
+7104
+6975
+0074
+F000
+C026
+C498
+650A
+6F46
+7472
+2068
+2E33
+0032
+C4AA
+C936
+C513
+C041
+1240
+C3C7
+C26E
+C04E
+095E
+C4A2
+C63A
+C041
+003F
+C1BA
+C4AA
+C936
+C04B
+0950
+C030
Index: bitserial/trunk/bit.vhd
===================================================================
--- bitserial/trunk/bit.vhd (nonexistent)
+++ bitserial/trunk/bit.vhd (revision 2)
@@ -0,0 +1,516 @@
+-- File: bit.vhd
+-- Author: Richard James Howe
+-- Repository: https://github.com/howerj/bit-serial
+-- License: MIT
+-- Description: An N-bit, simple and small bit serial CPU
+
+library ieee, work, std;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use std.textio.all; -- for debug only, not needed for synthesis
+
+-- The bit-serial CPU itself, the interface is bit-serial as well as the
+-- CPU itself, address and data are N bits wide. The enable lines are held
+-- high for N cycles when data is clocked in or out, and a complete read or
+-- write consists of N cycles (although those cycles may not be contiguous,
+-- it is up to the BCPU). The three enable lines are mutually exclusive,
+-- only one will be active at any time.
+--
+-- There are a few configurable items, but the defaults should work fine.
+entity bcpu is
+ generic (
+ asynchronous_reset: boolean := true; -- use asynchronous reset if true, synchronous if false
+ delay: time := 0 ns; -- simulation only, gate delay
+ N: positive := 16; -- size the CPU, minimum is 8
+ parity: std_ulogic := '0'; -- set parity (even = '0'/odd = '1') of parity flag
+ jumpz: std_ulogic := '1'; -- jump on zero = '1', jump on non-zero = '0'
+ debug: natural := 0); -- debug level, 0 = off
+ port (
+ clk, rst: in std_ulogic;
+ i: in std_ulogic;
+ o, a: out std_ulogic;
+ oe, ie, ae: buffer std_ulogic;
+ stop: out std_ulogic);
+end;
+
+architecture rtl of bcpu is
+ type state_t is (RESET, FETCH, INDIRECT, OPERAND, EXECUTE, STORE, LOAD, ADVANCE, HALT);
+ type cmd_t is (
+ iOR, iAND, iXOR, iADD,
+ iLSHIFT, iRSHIFT, iLOAD, iSTORE,
+ iLOADC, iSTOREC, iLITERAL, iUNUSED,
+ iJUMP, iJUMPZ, iSET, iGET);
+
+ constant Cy: integer := 0; -- Carry; set by addition
+ constant Z: integer := 1; -- Accumulator is zero
+ constant Ng: integer := 2; -- Accumulator is negative
+ constant R: integer := 3; -- Reset CPU
+ constant HLT: integer := 4; -- Halt CPU
+
+ type registers_t is record
+ state: state_t; -- state machine register
+ choice: state_t; -- computed next state
+ first: boolean; -- First flag, for setting up an instruction
+ last4: boolean; -- Are we processing the last 4 bits of the instruction?
+ indir: boolean; -- does the instruction require indirection of the operand?
+ tcarry: std_ulogic; -- temporary carry flag
+ dline: std_ulogic_vector(N - 1 downto 0); -- delay line, 16 cycles, our timer
+ acc: std_ulogic_vector(N - 1 downto 0); -- accumulator
+ pc: std_ulogic_vector(N - 1 downto 0); -- program counter
+ op: std_ulogic_vector(N - 1 downto 0); -- operand to instruction
+ flags: std_ulogic_vector(N - 1 downto 0); -- flags register
+ cmd: std_ulogic_vector(3 downto 0); -- instruction
+ end record;
+
+ constant registers_default: registers_t := (
+ state => RESET,
+ choice => RESET,
+ first => true,
+ last4 => false,
+ indir => false,
+ tcarry => 'X',
+ dline => (others => '0'),
+ acc => (others => 'X'),
+ pc => (others => 'X'),
+ op => (others => 'X'),
+ flags => (others => 'X'),
+ cmd => (others => 'X'));
+
+ signal c, f: registers_t := registers_default; -- BCPU registers, all of them.
+ -- These signals are not used to hold state. The 'c' and 'f' registers
+ -- do that.
+ signal cmd: cmd_t; -- Shows up nicely in traces as an enumerated value
+ signal add1, add2, acin, ares, acout: std_ulogic; -- shared adder signals
+ signal last4, last: std_ulogic; -- state sequence signals
+
+ -- 'adder' implements a full adder, which is all we need to implement
+ -- N-bit addition in a bit serial architecture. It is used in the instruction
+ -- and to increment the program counter.
+ procedure adder (x, y, cin: in std_ulogic; signal sum, cout: out std_ulogic) is
+ begin
+ sum <= x xor y xor cin after delay;
+ cout <= (x and y) or (cin and (x xor y)) after delay;
+ end procedure;
+
+ -- 'bit_count' is used for assertions and nothing else. It counts the
+ -- number of bits in a 'std_ulogic_vector'.
+ function bit_count(bc: in std_ulogic_vector) return natural is
+ variable count: natural := 0;
+ begin
+ for index in bc'range loop
+ if bc(index) = '1' then
+ count := count + 1;
+ end if;
+ end loop;
+ return count;
+ end function;
+
+ -- Obviously this does not synthesis, which is why synthesis is turned
+ -- off for the body of this function, it does make debugging much easier
+ -- though, we will be able to see which instructions are executed and do so
+ -- by name.
+ procedure print_debug_info is
+ variable ll: line;
+
+ function hx(slv: in std_ulogic_vector) return string is -- std_ulogic_vector to hex string
+ constant cv: string := "0123456789ABCDEF";
+ constant qu: integer := slv'length / 4;
+ constant rm: integer := slv'length mod 4;
+ variable rs: string(1 to qu);
+ variable sl: std_ulogic_vector(3 downto 0);
+ begin
+ assert rm = 0 severity failure;
+ for l in 0 to qu - 1 loop
+ sl := slv((l * 4) + 3 downto (l * 4));
+ rs(qu - l) := cv(to_integer(unsigned(sl)) + 1);
+ end loop;
+ return rs;
+ end function;
+
+ function yn(sl: std_ulogic; ch: character) return string is -- print a flag
+ variable rs: string(1 to 2) := "- ";
+ begin
+ if sl = '1' then
+ rs(1) := ch;
+ end if;
+ return rs;
+ end function;
+ begin
+ -- synthesis translate_off
+ if debug > 0 then
+ if c.state = EXECUTE and c.first then
+ write(ll, hx(c.pc) & ": ");
+ write(ll, cmd_t'image(cmd) & HT);
+ write(ll, hx(c.acc) & " ");
+ write(ll, hx(c.op) & " ");
+ write(ll, hx(c.flags) & " ");
+ write(ll, yn(c.flags(Cy), 'C'));
+ write(ll, yn(c.flags(Z), 'Z'));
+ write(ll, yn(c.flags(Ng), 'N'));
+ write(ll, yn(c.flags(R), 'R'));
+ write(ll, yn(c.flags(HLT), 'H'));
+ writeline(OUTPUT, ll);
+ end if;
+ if debug > 1 and last = '1' then
+ write(ll, state_t'image(c.state) & " => ");
+ write(ll, state_t'image(f.state));
+ writeline(OUTPUT, ll);
+ end if;
+ end if;
+ -- synthesis translate_on
+ end procedure;
+begin
+ assert N >= 8 report "CPU Width too small: N >= 8" severity failure;
+ assert not (ie = '1' and oe = '1') report "input/output at the same time" severity failure;
+ assert not (ie = '1' and ae = '1') report "input whilst changing address" severity failure;
+ assert not (oe = '1' and ae = '1') report "output whilst changing address" severity failure;
+
+ adder (add1, add2, acin, ares, acout); -- shared adder
+ cmd <= cmd_t'val(to_integer(unsigned(c.cmd))); -- used for debug purposes
+ last4 <= c.dline(c.dline'high - 4) after delay; -- processing last four bits?
+ last <= c.dline(c.dline'high) after delay; -- processing last bit?
+
+ process (clk, rst) begin
+ if rst = '1' and asynchronous_reset then
+ c.dline <= (others => '0') after delay; -- parallel reset!
+ c.state <= RESET after delay;
+ elsif rising_edge(clk) then
+ c <= f after delay;
+ if rst = '1' and not asynchronous_reset then
+ c.dline <= (others => '0') after delay;
+ c.state <= RESET after delay;
+ else
+ -- These are just assertions/debug logging, they are not required for
+ -- running, but we can make sure there are no unexpected state transitions,
+ -- and report on the internal state.
+ print_debug_info;
+ if c.state = RESET and last = '1' then assert f.state = FETCH; end if;
+ if c.state = LOAD and last = '1' then assert f.state = ADVANCE; end if;
+ if c.state = STORE and last = '1' then assert f.state = ADVANCE; end if;
+ if c.state = ADVANCE and last = '1' then assert f.state = FETCH; end if;
+ if c.state = HALT then assert f.state = HALT; end if;
+ if c.state = EXECUTE and last = '1' then
+ assert f.state = ADVANCE or f.state = LOAD or f.state = STORE or f.state = FETCH;
+ end if;
+ end if;
+ assert not (c.first xor f.dline(0) = '1') report "first/dline";
+ end if;
+ end process;
+
+ process (i, c, cmd, ares, acout, last, last4) begin
+ o <= '0' after delay;
+ a <= '0' after delay;
+ ie <= '0' after delay;
+ ae <= '0' after delay;
+ oe <= '0' after delay;
+ stop <= '0' after delay;
+ add1 <= '0' after delay;
+ add2 <= '0' after delay;
+ acin <= '0' after delay;
+ f <= c after delay;
+ f.dline <= c.dline(c.dline'high - 1 downto 0) & "0" after delay;
+
+ -- Our delay line should only contain zero on one bit at a time
+ if c.first then
+ assert bit_count(c.dline) = 0 report "too many dline bits";
+ else
+ assert bit_count(c.dline) = 1 report "missing dline bit";
+ end if;
+
+ -- The processor works by using a delay line (shift register) to
+ -- sequence actions, the top four bits are used for the
+ -- instruction (and if the highest bit is set indirection
+ -- is _not_ allowed), with the lowest twelve bits as an operand
+ -- to use as a literal value or an address.
+ --
+ -- As such, we will want to trigger actions when processing the first
+ -- bit, the last four bits and the last bit.
+ --
+ -- This delay line is used to save gates as opposed using a counter,
+ -- which would require an adder (but not a comparator - we could check
+ -- whether individual bits are set because all the comparisons are
+ -- against power of two values).
+ --
+ if last = '1' then
+ f.state <= c.choice after delay;
+ f.first <= true after delay;
+ f.last4 <= false after delay;
+ -- This is a bit of a hack, in order to place it in its proper
+ -- place within the 'FETCH' state we would need to move the
+ -- 'indirection allowed on instruction' bit from the highest
+ -- bit to a lower bit so we can perform the state decision before
+ -- the bit is being processed.
+ if i = '0' and c.state = FETCH then
+ f.indir <= true;
+ f.state <= INDIRECT; -- Override FETCH Choice!
+ end if;
+ elsif last4 = '1' then
+ f.last4 <= true after delay;
+ end if;
+
+ -- Each state lasts N (which defaults to 16) + 1 cycles.
+ -- Of note: we could make the FETCH state last only 4 + 1 cycles
+ -- and merge the operand fetching in FETCH (and OPERAND state) into
+ -- the 'EXECUTE' state.
+ case c.state is
+ when RESET =>
+ f.choice <= FETCH;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ ae <= '1' after delay;
+ f.acc <= "0" & c.acc(c.acc'high downto 1) after delay;
+ f.pc <= "0" & c.pc (c.pc'high downto 1) after delay;
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ f.flags <= "0" & c.flags(c.flags'high downto 1) after delay;
+ end if;
+ -- When in the running state all state transitions pass through FETCH.
+ -- FETCH does what you expect from it, it fetches the instruction. It also
+ -- partially decodes it and sets flags that the accumulator depends on.
+ --
+ -- What is meant by partially decoding is this; it is determined if we
+ -- should go to the INDIRECT state next or to the EXECUTE state, also
+ -- it is determined whether an I/O operation should be performed for those
+ -- instructions capable of doing I/O.
+ when FETCH =>
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ f.indir <= false after delay;
+ f.flags(Z) <= '1' after delay;
+ else
+ ie <= '1' after delay;
+
+ if c.acc(0) = '1' then -- determine flag status before EXECUTE
+ f.flags(Z) <= '0' after delay;
+ end if;
+ f.acc <= c.acc(0) & c.acc(c.acc'high downto 1) after delay;
+
+ if not c.last4 then
+ f.op <= i & c.op(c.op'high downto 1) after delay;
+ else
+ f.cmd <= i & c.cmd(c.cmd'high downto 1) after delay;
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ end if;
+ end if;
+
+ f.flags(Ng) <= c.acc(0) after delay; -- contains highest bit when 'last' is true
+
+ -- NB. 'f.choice' may be overwritten for INDIRECT.
+ if c.flags(HLT) = '1' then
+ f.choice <= HALT after delay;
+ elsif c.flags(R) = '1' then
+ f.choice <= RESET after delay;
+ else
+ f.choice <= EXECUTE after delay;
+ end if;
+ -- INDIRECT is only used instruction allows for indirection
+ -- (ie. All those instructions in which the top bit is not set).
+ -- The indirection add 2*(N+1) cycles to the instruction so is quite expensive.
+ --
+ -- We could avoid having this state and CPU functionality if we were to
+ -- make use of self-modifying code, however that would make programming the CPU
+ -- more difficult.
+ --
+ when INDIRECT =>
+ assert c.cmd(c.cmd'high) = '0' severity error;
+ f.choice <= EXECUTE after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ f.choice <= OPERAND after delay;
+ end if;
+ -- OPERAND fetches the operand *again*, this time using the operand
+ -- acquired in EXECUTE, the address being set in the previous INDIRECT state.
+ when OPERAND =>
+ f.choice <= EXECUTE after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ ie <= '1' after delay;
+ f.op <= i & c.op(c.op'high downto 1) after delay;
+ end if;
+ -- The EXECUTE state implements the ALU. It is the most seemingly the
+ -- most complex state, but it is not (FETCH is more difficult to
+ -- understand).
+ when EXECUTE =>
+ assert not (c.flags(Z) = '1' and c.flags(Ng) = '1') report "zero and negative?";
+ f.choice <= ADVANCE after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ if cmd = iADD then f.flags(Cy) <= '0' after delay; end if;
+ -- 'tcarry' is added to the program counter in the ADVANCE
+ -- state, instructions that affect the program counter clear
+ -- it (such as iJUMP, and iJUMPZ/iSET (conditionally).
+ f.tcarry <= '1' after delay;
+ else
+ case cmd is -- ALU
+ when iOR =>
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ f.acc <= (c.op(0) or c.acc(0)) & c.acc(c.acc'high downto 1) after delay;
+ when iAND =>
+ f.acc <= c.acc(0) & c.acc(c.acc'high downto 1) after delay;
+ if (not c.last4) or c.indir then
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ f.acc <= (c.op(0) and c.acc(0)) & c.acc(c.acc'high downto 1) after delay;
+ end if;
+ when iXOR =>
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ f.acc <= (c.op(0) xor c.acc(0)) & c.acc(c.acc'high downto 1) after delay;
+ when iADD =>
+ f.acc <= "0" & c.acc(c.acc'high downto 1) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ add1 <= c.acc(0) after delay;
+ add2 <= c.op(0) after delay;
+ acin <= c.flags(Cy) after delay;
+ f.acc(f.acc'high) <= ares after delay;
+ f.flags(Cy) <= acout after delay;
+ -- A barrel shifter is usually quite an expensive piece of hardware,
+ -- but it ends up being quite cheap for obvious reasons. If we really
+ -- needed to we could dispense with the right shift, we could mask off
+ -- low bits and rotate (either way) to emulate it.
+ when iLSHIFT =>
+ if c.op(0) = '1' then
+ f.acc <= c.acc(c.acc'high - 1 downto 0) & "0" after delay;
+ end if;
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ when iRSHIFT =>
+ if c.op(0) = '1' then
+ f.acc <= "0" & c.acc(c.acc'high downto 1) after delay;
+ end if;
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ -- We have two sets of LOAD/STORE instructions, one set which
+ -- optionally respects the indirect flag, and one set (the latter)
+ -- which never does. This allows us to perform direct LOAD/STORES
+ -- when the indirect flag is on.
+ when iLOAD =>
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= c.op(0) & c.op(c.op'high downto 1) after delay;
+ f.choice <= LOAD after delay;
+ when iSTORE =>
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ f.choice <= STORE after delay;
+ when iLOADC =>
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= c.op(0) & c.op(c.op'high downto 1) after delay;
+ f.choice <= LOAD after delay;
+ when iSTOREC =>
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ f.choice <= STORE after delay;
+ when iLITERAL =>
+ f.acc <= c.op(0) & c.acc(c.acc'high downto 1) after delay;
+ f.op <= "0" & c.op (c.op'high downto 1) after delay;
+ when iUNUSED =>
+ -- We could use this if we need to extend the instruction set
+ -- for any reason. I cannot think of a good one that justifies the
+ -- cost of a new instruction. So this will remain blank for now.
+ --
+ -- Candidates for an instruction include:
+ --
+ -- * Arithmetic Right Shift
+ -- * Subtraction
+ -- * Swap Low/High Byte (may be difficult to implement)
+ --
+ -- However, this instruction may not have its indirection bit set,
+ -- This would not be a problem for the swap instruction. Alternatively
+ -- an 'add-constant' could be added.
+ --
+ when iJUMP =>
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ f.pc <= c.op(0) & c.pc(c.pc'high downto 1) after delay;
+ f.choice <= FETCH after delay;
+ when iJUMPZ =>
+ if c.flags(Z) = jumpz then
+ ae <= '1' after delay;
+ a <= c.op(0) after delay;
+ f.op <= "0" & c.op(c.op'high downto 1) after delay;
+ f.pc <= c.op(0) & c.pc(c.pc'high downto 1) after delay;
+ f.choice <= FETCH after delay;
+ end if;
+ -- NB. We could probably eliminate these instructions by mapping
+ -- the registers into the memory address space, this would free
+ -- up another two instructions, and potentially simplify the CPU.
+ --
+ when iSET =>
+ if c.op(0) = '0' then
+ -- NB. We could set the address directly here and
+ -- go to FETCH but that costs us too much time and gates.
+ f.pc <= c.acc(0) & c.pc(c.pc'high downto 1) after delay;
+ f.tcarry <= '0' after delay;
+ else
+ f.flags <= c.acc(0) & c.flags(c.flags'high downto 1) after delay;
+ end if;
+ f.acc <= c.acc(0) & c.acc(c.acc'high downto 1) after delay;
+ when iGET =>
+ if c.op(0) = '0' then
+ f.acc <= c.pc(0) & c.acc(c.acc'high downto 1) after delay;
+ f.pc <= c.pc(0) & c.pc(c.pc'high downto 1) after delay;
+ else
+ f.acc <= c.flags(0) & c.acc(c.acc'high downto 1) after delay;
+ f.flags <= c.flags(0) & c.flags(c.flags'high downto 1) after delay;
+ end if;
+ end case;
+ end if;
+ -- Unfortunately we cannot perform a load or a store whilst we are
+ -- performing an EXECUTE, so we require STORE and LOAD states to do
+ -- more work after a LOAD or STORE instruction.
+ when STORE =>
+ f.choice <= ADVANCE after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ o <= c.acc(0) after delay;
+ oe <= '1' after delay;
+ f.acc <= c.acc(0) & c.acc(c.acc'high downto 1) after delay;
+ end if;
+ when LOAD =>
+ f.choice <= ADVANCE after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ ie <= '1' after delay;
+ f.acc <= i & c.acc(c.acc'high downto 1) after delay;
+ end if;
+ -- ADVANCE reuses our adder in iADD to add one to the program counter
+ -- this state *is* reached when we do a iJUMP, iJUMPZ or an iSET on the
+ -- program counter, those instructions clear the 'tcarry', which is
+ -- normally '1'.
+ when ADVANCE =>
+ f.choice <= FETCH after delay;
+ if c.first then
+ f.dline(0) <= '1' after delay;
+ f.first <= false after delay;
+ else
+ f.pc <= "0" & c.pc(c.pc'high downto 1) after delay;
+ add1 <= c.pc(0) after delay;
+ -- A 'skip' facility could be made by optionally setting this to '1'
+ -- for the first cycle, incrementing the program counter by 2.
+ add2 <= '0' after delay;
+ acin <= c.tcarry after delay;
+ f.pc(f.pc'high) <= ares after delay;
+ a <= ares after delay;
+ f.tcarry <= acout after delay;
+ ae <= '1' after delay;
+ end if;
+ when HALT => stop <= '1' after delay;
+ end case;
+ end process;
+end architecture;
+
Index: bitserial/trunk/makefile
===================================================================
--- bitserial/trunk/makefile (nonexistent)
+++ bitserial/trunk/makefile (revision 2)
@@ -0,0 +1,156 @@
+CC=gcc
+CFLAGS=-Wall -Wextra -std=c99 -O2
+USB?=/dev/ttyUSB0
+BAUD?=115200
+DIFF?=vimdiff
+#BAUD?=9600
+
+.PHONY: all run diff simulation viewer clean documentation
+
+all: bit simulation
+
+run: bit bit.hex
+ ./bit bit.hex
+
+talk:
+ picocom --omap delbs -e b -b ${BAUD} ${USB}
+
+simulation: tb.ghw
+
+viewer: tb.ghw signals.tcl
+ gtkwave -S signals.tcl -f $< > /dev/null 2>&1 &
+
+documentation: readme.htm
+
+%.htm: %.md
+ pandoc $< -o $@
+
+bit.hex bit.bin: bit.fth bit
+ gforth $<
+
+bit: bit.c
+ ${CC} ${CFLAGS} $< -o $@
+
+%.o: %.vhd
+ ghdl -a -g $<
+
+uart.o: uart.vhd util.o
+
+peripherals.o: peripherals.vhd uart.o util.o
+
+top.o: top.vhd peripherals.o bit.o util.o uart.o
+
+tb.o: tb.vhd bit.o peripherals.o top.o
+
+tb: tb.o bit.o peripherals.o top.o
+ ghdl -e $@
+
+tb.ghw: tb tb.conf bit.hex
+ ghdl -r $< --wave=$<.ghw --max-stack-alloc=16384 --ieee-asserts=disable
+
+SOURCES = \
+ top.vhd \
+ bit.vhd \
+ uart.vhd \
+ util.vhd \
+ peripherals.vhd
+
+OBJECTS = ${SOURCES:.vhd=.o}
+
+bitfile: design.bit
+
+reports:
+ @[ -d reports ] || mkdir reports
+tmp:
+ @[ -d tmp ] || mkdir tmp
+tmp/_xmsgs:
+ @[ -d tmp/_xmsgs ] || mkdir tmp/_xmsgs
+
+tmp/top.prj: tmp
+ @rm -f tmp/top.prj
+ @( \
+ for f in $(SOURCES); do \
+ echo "vhdl work \"$$f\""; \
+ done; \
+ echo "vhdl work \"top.vhd\"" \
+ ) > tmp/top.prj
+
+tmp/top.lso: tmp
+ @echo "work" > tmp/top.lso
+
+tmp/top.xst: tmp tmp/_xmsgs tmp/top.lso tmp/top.lso
+ @( \
+ echo "set -tmpdir \"tmp\""; \
+ echo "set -xsthdpdir \"tmp\""; \
+ echo "run"; \
+ echo "-lso tmp/top.lso"; \
+ echo "-ifn tmp/top.prj"; \
+ echo "-ofn top"; \
+ echo "-p xc6slx16-csg324-3"; \
+ echo "-top top"; \
+ echo "-opt_mode area"; \
+ echo "-opt_level 2" \
+ ) > tmp/top.xst
+
+synthesis: bit.hex reports tmp tmp/_xmsgs tmp/top.prj tmp/top.xst
+ @echo "Synthesis running..."
+ @${TIME} xst -intstyle silent -ifn tmp/top.xst -ofn reports/xst.log
+ @mv _xmsgs/* tmp/_xmsgs
+ @rmdir _xmsgs
+ @mv top_xst.xrpt tmp
+ @grep "ERROR\|WARNING" reports/xst.log | \
+ grep -v "WARNING.*has a constant value.*This FF/Latch will be trimmed during the optimization process." | \
+ cat
+ @grep ns reports/xst.log | grep 'Clock period'
+
+implementation: reports tmp
+ @echo "Implementation running..."
+
+ @[ -d tmp/xlnx_auto_0_xdb ] || mkdir tmp/xlnx_auto_0_xdb
+
+ @${TIME} ngdbuild -intstyle silent -quiet -dd tmp -uc top.ucf -p xc6slx16-csg324-3 top.ngc top.ngd
+ @mv top.bld reports/ngdbuild.log
+ @mv _xmsgs/* tmp/_xmsgs
+ @rmdir _xmsgs
+ @mv xlnx_auto_0_xdb/* tmp
+ @rmdir xlnx_auto_0_xdb
+ @mv top_ngdbuild.xrpt tmp
+
+ @${TIME} map -intstyle silent -detail -p xc6slx16-csg324-3 -convert_bram8 -pr b -c 100 -w -o top_map.ncd top.ngd top.pcf
+ @mv top_map.mrp reports/map.log
+ @mv _xmsgs/* tmp/_xmsgs
+ @rmdir _xmsgs
+ @mv top_usage.xml top_summary.xml top_map.map top_map.xrpt tmp
+
+ @${TIME} par -intstyle silent -w -ol std top_map.ncd top.ncd top.pcf
+ @mv top.par reports/par.log
+ @mv top_pad.txt reports/par_pad.txt
+ @mv _xmsgs/* tmp/_xmsgs
+ @rmdir _xmsgs
+ @mv par_usage_statistics.html top.ptwx top.pad top_pad.csv top.unroutes top.xpi top_par.xrpt tmp
+
+design.bit: reports tmp/_xmsgs
+ @echo "Generate bitfile running..."
+ @touch webtalk.log
+ @${TIME} bitgen -intstyle silent -w top.ncd
+ @mv top.bit design.bit
+ @mv top.bgn reports/bitgen.log
+ @mv _xmsgs/* tmp/_xmsgs
+ @rmdir _xmsgs
+ @sleep 5
+ @mv top.drc top_bitgen.xwbt top_usage.xml top_summary.xml webtalk.log tmp
+ @grep -i '\(warning\|clock period\)' reports/xst.log
+
+upload:
+ djtgcfg prog -d Nexys3 -i 0 -f design.bit
+
+design: clean simulation synthesis implementation bitfile
+
+postsyn:
+ @netgen -w -ofmt vhdl -sim ${NETLIST}.ngc post_synthesis.vhd
+ @netgen -w -ofmt vhdl -sim ${NETLIST}.ngd post_translate.vhd
+ @netgen -pcf ${NETLIST}.pcf -w -ofmt vhdl -sim ${NETLIST}.ncd post_map.vhd
+
+clean:
+ git clean -fdx .
+
Index: bitserial/trunk/peripherals.vhd
===================================================================
--- bitserial/trunk/peripherals.vhd (nonexistent)
+++ bitserial/trunk/peripherals.vhd (revision 2)
@@ -0,0 +1,204 @@
+-- File: peripherals.vhd
+-- Author: Richard James Howe
+-- Repository: https://github.com/howerj/bit-serial
+-- License: MIT
+-- Description: Memory and Memory mapped peripherals
+
+library ieee, work, std;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use std.textio.all;
+use work.util.all;
+use work.uart_pkg.all;
+
+entity peripherals is
+ generic (
+ g: common_generics;
+ file_name: string;
+ baud: positive;
+ W: positive;
+ N: positive;
+ uart_fifo_depth: natural;
+ uart_use_cfg: boolean);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ rx: in std_ulogic;
+ tx: out std_ulogic;
+ ld: out std_ulogic_vector(7 downto 0);
+ sw: in std_ulogic_vector(7 downto 0);
+ i, a: in std_ulogic;
+ o: out std_ulogic;
+ oe, ie, ae: in std_ulogic);
+end;
+
+architecture rtl of peripherals is
+ constant data_length: positive := N;
+ constant addr_length: positive := W;
+
+ type registers_t is record
+ r_a: std_ulogic_vector(N - 1 downto 0);
+ r_i: std_ulogic_vector(N - 1 downto 0);
+ r_o: std_ulogic_vector(N - 1 downto 0);
+ r_ld: std_ulogic_vector(ld'range);
+ r_ie: std_ulogic;
+ end record;
+
+ constant registers_default: registers_t := (
+ r_a => (others => '0'),
+ r_i => (others => '0'),
+ r_o => (others => '0'),
+ r_ld => (others => '0'),
+ r_ie => '0'
+ );
+
+ signal c, f: registers_t := registers_default;
+
+ signal io, write: boolean := false;
+ signal dwe, dre: std_ulogic := '0';
+ signal dout: std_ulogic_vector(N - 1 downto 0) := (others => '0');
+
+ signal tx_fifo_full: std_ulogic;
+ signal tx_fifo_empty: std_ulogic;
+ signal tx_fifo_we: std_ulogic;
+ signal tx_fifo_data: std_ulogic_vector(7 downto 0);
+
+ signal rx_fifo_full: std_ulogic;
+ signal rx_fifo_empty: std_ulogic;
+ signal rx_fifo_re: std_ulogic;
+ signal rx_fifo_data: std_ulogic_vector(7 downto 0);
+
+ signal reg: std_ulogic_vector(15 downto 0);
+ signal clock_reg_tx_we: std_ulogic;
+ signal clock_reg_rx_we: std_ulogic;
+ signal control_reg_we: std_ulogic;
+
+ signal io_addr: std_ulogic_vector(2 downto 0);
+begin
+ io <= c.r_a(c.r_a'high - 1) = '1' and ae = '0' after g.delay;
+ io_addr <= c.r_a(io_addr'range) after g.delay;
+ write <= true when (c.r_ie and (c.r_ie xor f.r_ie)) = '1' else false after g.delay;
+ ld <= c.r_ld after g.delay;
+ o <= c.r_o(0) after g.delay;
+ tx_fifo_data <= c.r_i(tx_fifo_data'range) after g.delay;
+ reg <= c.r_i(reg'range) after g.delay;
+
+ uart: entity work.uart_top
+ generic map (
+ clock_frequency => g.clock_frequency,
+ delay => g.delay,
+ asynchronous_reset => g.asynchronous_reset,
+ baud => baud,
+ fifo_depth => uart_fifo_depth,
+ use_cfg => uart_use_cfg)
+ port map(
+ clk => clk, rst => rst,
+
+ tx => tx,
+ tx_fifo_full => tx_fifo_full,
+ tx_fifo_empty => tx_fifo_empty,
+ tx_fifo_we => tx_fifo_we,
+ tx_fifo_data => tx_fifo_data,
+
+ rx => rx,
+ rx_fifo_full => rx_fifo_full,
+ rx_fifo_empty => rx_fifo_empty,
+ rx_fifo_re => rx_fifo_re,
+ rx_fifo_data => rx_fifo_data,
+
+ reg => reg,
+ clock_reg_tx_we => clock_reg_tx_we,
+ clock_reg_rx_we => clock_reg_rx_we,
+ control_reg_we => control_reg_we);
+
+ bram: entity work.single_port_block_ram
+ generic map(
+ g => g,
+ file_name => file_name,
+ file_type => FILE_HEX,
+ addr_length => addr_length,
+ data_length => data_length)
+ port map (
+ clk => clk,
+ dwe => dwe,
+ addr => f.r_a(addr_length - 1 downto 0),
+ dre => dre,
+ din => f.r_i,
+ dout => dout);
+
+ process (clk, rst)
+ begin
+ if rst = '1' and g.asynchronous_reset then
+ c <= registers_default after g.delay;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ c <= registers_default after g.delay;
+ else
+ c <= f after g.delay;
+ end if;
+ end if;
+ end process;
+
+ process (c, i, a, oe, ie, ae, dout, io, write, sw, rx, io_addr,
+ rx_fifo_data, rx_fifo_empty, rx_fifo_full, tx_fifo_empty, tx_fifo_full)
+ begin
+ f <= c after g.delay;
+ f.r_o <= dout after g.delay;
+ f.r_ie <= ie after g.delay;
+ dre <= '1' after g.delay;
+ dwe <= '0' after g.delay;
+ tx_fifo_we <= '0' after g.delay;
+ rx_fifo_re <= '0' after g.delay;
+ clock_reg_tx_we <= '0' after g.delay;
+ clock_reg_rx_we <= '0' after g.delay;
+ control_reg_we <= '0' after g.delay;
+
+ if ae = '1' then f.r_a <= a & c.r_a(c.r_a'high downto 1) after g.delay; end if;
+ if oe = '1' then f.r_o <= c.r_o(0) & c.r_o(c.r_o'high downto 1) after g.delay; end if;
+ if ie = '1' then f.r_i <= i & c.r_i(c.r_i'high downto 1) after g.delay; end if;
+
+ if oe = '0' and ae = '0' then
+ if io = false then
+ dre <= '1' after g.delay;
+ else
+ f.r_o <= (others => '0') after g.delay;
+ case io_addr is
+ when "000" => f.r_o(sw'range) <= sw after g.delay;
+ when "001" =>
+ f.r_o(7 downto 0) <= rx_fifo_data after g.delay;
+ f.r_o(8) <= rx_fifo_empty after g.delay;
+ f.r_o(9) <= rx_fifo_full after g.delay;
+ f.r_o(11) <= tx_fifo_empty after g.delay;
+ f.r_o(12) <= tx_fifo_full after g.delay;
+ when "010" =>
+ when "011" =>
+ when "100" =>
+ when "101" =>
+ when "110" =>
+ when "111" =>
+ when others =>
+ end case;
+ end if;
+ end if;
+
+ if write and ae = '0' then
+ if io = false then
+ dwe <= '1' after g.delay;
+ else
+ case io_addr is
+ when "000" => f.r_ld <= c.r_i(c.r_ld'range) after g.delay;
+ when "001" => tx_fifo_we <= c.r_i(13) after g.delay;
+ rx_fifo_re <= c.r_i(10) after g.delay;
+ when "010" => if uart_use_cfg then clock_reg_tx_we <= '1' after g.delay; end if;
+ when "011" => if uart_use_cfg then clock_reg_rx_we <= '1' after g.delay; end if;
+ when "100" => if uart_use_cfg then control_reg_we <= '1' after g.delay; end if;
+ when "101" =>
+ when "110" =>
+ when "111" =>
+ when others =>
+ end case;
+ end if;
+ end if;
+ end process;
+end architecture;
+
Index: bitserial/trunk/readme.md
===================================================================
--- bitserial/trunk/readme.md (nonexistent)
+++ bitserial/trunk/readme.md (revision 2)
@@ -0,0 +1,574 @@
+# BIT SERIAL CPU and TOOL-CHAIN
+
+* Project: Bit-Serial CPU in VHDL
+* Author: Richard James Howe
+* Copyright: 2019,2020 Richard James Howe
+* License: MIT
+* Email: howe.r.j.89@gmail.com
+* Website:
+
+*Processing data one bit at a time, since 2019*.
+
+# Introduction
+
+This is a project for a [bit-serial CPU][], which is a CPU that has an architecture
+which processes a single bit at a time instead of in parallel like a normal
+CPU. This allows the CPU itself to be a lot smaller, the penalty is that it is
+*a lot* slower. The CPU itself is called *bcpu*.
+
+The CPU is incredibly basic, lacking features required to support
+higher level programming (such as function calls). Instead such features can
+be emulated if they are needed. If such features are needed, or faster
+throughput (whilst still remaining quite small) other [Soft-Core][] CPUs are
+available, such as the [H2][].
+
+To build and run the C based simulator for the project, you will need a C
+compiler and 'make'. To build and run the [VHDL][] simulator, you will need [GHDL][]
+installed.
+
+The cross compiler requires [gforth][], although a pre-compiled image is
+provided in case you do not have access to it, called '[bit.hex][]', this hex file
+contains a working [Forth][] image. To run this:
+
+ make bit
+ ./bit bit.hex
+
+An example session of the simulator running is:
+
+![C Simulator Running eForth](bit-sim.gif)
+
+You should be greeted by a [Forth][] prompt, type 'words' and hit a carriage
+return to get a list of defined functions.
+
+The target [FPGA][] that the system is built for is a [Spartan-6][], for a
+[Nexys 3][] development board. [Xilinx ISE 14.7][] was used to build the
+project.
+
+The following 'make' targets are available:
+
+ make
+
+By default the [VHDL][] test bench is built and simulated in [GHDL][]. This
+requires [gforth][] to assemble the test program [bit.fth][] into a file
+readable by the simulator.
+
+ make run
+
+This target builds the C based simulator, assembles the test program
+and runs the simulator on the assembled program.
+
+ make synthesis implementation bitfile
+
+This builds the project for the [FPGA][].
+
+ make upload
+
+This uploads the project to the [Nexys 3][] board. This requires that
+'djtgcfg' is installed, which is a tool provided by [Digilent][].
+
+ make documentation
+
+This turns this 'readme.md' file into a HTML file.
+
+ make clean
+
+Cleans up the project.
+
+# eForth
+
+The tool-chain for the device is used to build an image for a Forth
+interpreter, more specifically a Forth interpreter similar to a dialect of
+Forth known as 'eForth', it differs between eForth in order to save on space
+which is at a premium. You should be greeted with an eForth prompt when running
+the 'make run' target that looks something like this:
+
+ $ make run
+ ./bit bit.hex
+ eForth 3.1
+
+You can see all of the defined words (or functions) by typing in 'words' and
+hitting return.
+
+ $ make run
+ ./bit bit.hex
+ eForth 3.1
+ words
+
+Arithmetic in Forth in done using Reverse Polish Notation:
+
+ 2 2 + . cr
+
+Will print out '4'. This is not the place for a Forth tutorial, the Forth
+interpreter is mainly here to demonstrate that the bit-serial CPU is working
+correctly and can be used for useful purposes. No demonstration would be
+complete without a 'Hello, World' program, however:
+
+ : hello cr ." Hello, World!" ;
+ hello
+
+Go use your favorite search engine to find a Forth tutorial.
+
+# Use Case
+
+Often in an [FPGA][] design there is spare Dual Port Block RAM (BRAM) available,
+either because only part of the BRAM module is being used or because it is not
+needed entirely. Adding a new CPU however is a bigger decision than using spare
+BRAM capacity, it can take up quite a lot of floor space, and perhaps other
+precious resources. If this is the case then adding this CPU costs practically
+nothing in terms of floor space, the main cost will be in development time.
+
+In short, the project may be useful if:
+
+* FPGA Floor space is at a premium in your design.
+* You have spare memory for the program and storage.
+* You need a programmable CPU that supports a reasonable instruction set.
+* *Execution speed is not a concern*.
+
+There were two use cases that the author had in mind when setting out to build
+this system:
+
+* As a CPU driving a low-baud UART
+* As a controller for a VT100 terminal emulator that would control cursor
+ position and parse escape codes, setting colors and attributes in a hardware
+ based text-terminal (this was to replace an existing VHDL only system that
+ had spare capacity in the FPGAs dual-port block RAMs used to store the Font
+ and text).
+
+# Tool-chain
+
+The tool-chain consists of a cross compiler written in Forth, it itself
+implements a virtual machine on top of which a Forth interpreter is written.
+The accumulator machine lacks call/returns, and a stack, so these have to be
+implemented. The meta-compiler (a Forth specific term for what is a
+more widely known as a cross-compiler) is available in [bit.fth][].
+
+As the instruction set is anemic and CPU features lacking it is best to target
+the virtual machine and program in Forth than it is to program in assembly.
+
+Despite the inherently slow speed of the design and the further slow down
+executing code on top of a virtual machine the interpreter is plenty fast
+enough for interactive use, slowing down noticeably when division has to be
+performed.
+
+# CPU Specification
+
+The CPU is a 16-bit design, in principle a normal bit parallel CPU design could
+be implemented of the same CPU, but in practice you not end up with a CPU like
+this one if you remove the bit-serial restriction.
+
+The CPU has 16 operation, each instruction consists of a 4-bit operation field
+and a 12-bit operand. Depending on the CPU mode that operand and instruction
+that operand can either be a literal or an address to load a 16-bit word from
+(addresses are word and not byte oriented, so the lowest bit of an address
+specifies the next word not byte). Only the first 8 operations can have their
+operand indirected, which is deliberate.
+
+The CPU is an accumulator machine, all instructions either modify or use the
+accumulator to store operation results in them. The CPU has three registers
+including the accumulator, the other two are the program counter which is
+automatically incremented after each instruction excluding the jump
+instructions (the SET instruction is also excluded when setting the program
+counter only) and a flags register.
+
+The instructions are:
+
+ | ----------- | -------------------------------------- | --------------------------------- | ---------------- |
+ | Instruction | C Operation | Description | Cycles |
+ | ----------- | -------------------------------------- | --------------------------------- | ---------------- |
+ | OR | acc |= lop | Bitwise Or | [3 or 5]*(N+1) |
+ | AND | acc &= lop | Bitwise And | [3 or 5]*(N+1) |
+ | XOR | acc ^= lop | Bitwise Exclusive Or | [3 or 5]*(N+1) |
+ | ADD | acc += lop | Add with carry, sets carry | [3 or 5]*(N+1) |
+ | LSHIFT | acc = acc << lop (or rotate left) | Shift left or Rotate left | [3 or 5]*(N+1) |
+ | RSHIFT | acc = acc >> lop (or rotate right) | Shift right or Rotate right | [3 or 5]*(N+1) |
+ | LOAD | acc = memory(lop) | Load | [4 or 6]*(N+1) |
+ | STORE | memory(lop) = acc | Store | [4 or 6]*(N+1) |
+ | LOADC | acc = memory(op) | Load from memory constant addr | 4*(N+1) |
+ | STOREC | memory(op) = acc | Store to memory constant addr | 4*(N+1) |
+ | LITERAL | acc = op | Load literal into accumulator | 3*(N+1) |
+ | UNUSED | N/A | Unused instruction | 3*(N+1) |
+ | JUMP | pc = op | Unconditional Jump | 2*(N+1) |
+ | JUMPZ | if(!acc){pc = op } | Jump If Zero | [2 or 3]*(N+1) |
+ | SET | if(op&1){flg=acc}else{pc=acc} | Set Register | 3*(N+1) |
+ | GET | if(op&1){acc=flg}else{acc=pc} | Get Register | 3*(N+1) |
+ | ----------- | -------------------------------------- | --------------------------------- | ---------------- |
+
+* pc = program counter
+* acc = accumulator
+* indir = indirect flag
+* lop = instruction operand if indirect flag not set, otherwise it equals to the memory
+ location pointed to by the operand
+* op = instruction operand
+* flg = flags register
+* N = bit width, which is 16.
+
+The number of cycles an instruction takes to complete depends on whether it
+performs an indirection, or in the case of GET/SET it depends if it it setting
+the program counter (2 cycles only) or the flags register (3 cycles), or performing
+an I/O operation (4 cycles), getting the flags or program counter always costs
+3 cycles.
+
+The flags in the 'flg' register are:
+
+ | ---- | --- | --------------------------------------- |
+ | Flag | Bit | Description |
+ | ---- | --- | --------------------------------------- |
+ | Cy | 0 | Carry flag, set by addition instruction |
+ | Z | 1 | Zero flag |
+ | Ng | 2 | Negative flag |
+ | R | 3 | Reset Flag - Resets the CPU |
+ | HLT | 4 | Halt Flag - Stops the CPU |
+ | ---- | --- | --------------------------------------- |
+
+* The carry flag (Cy) is set by the ADD instruction, it can also be set and cleared
+with the GET/SET instructions.
+* 'Z' is set whenever the accumulator is zero.
+* 'Ng' is set whenever the accumulator has its highest bit set, indicating that
+ the accumulator is negative.
+* 'R', Reset flag, this resets the CPU immediately, only the HLT flag takes
+precedence.
+* 'HLT', The halt flag takes priority over everything else, sending the CPU
+into a halt state.
+
+There is really not much else to this CPU from the point of view of a user of
+this core, integrating this core into another system is more complicated
+however, you will need to be far more aware of timing of signals and their
+enable lines. Much like the processor, a single bit bus in conjunction with an
+enable is used to communicate with the outside world.
+
+The internal state of the CPU is minimal, to make a working system the memory
+and I/O controller will need (shift) registers to store the address and
+input/output.
+
+The CPU state-machine is:
+
+![CPU State Machine](bit-state.png)
+
+And the CPU bus timing diagram:
+
+![CPU Bus timing](bit-wave.png)
+
+
+# Peripherals
+
+The system has a minimal set of peripherals; a bank of switches with LEDs next
+to each switch and a UART capable of transmission and reception, other
+peripherals could be added as needed.
+
+## Register Map
+
+The I/O register map for the device is very small as there are very few
+peripherals.
+
+ | ------- | -------------- |
+ | Address | Name |
+ | ------- | -------------- |
+ | 0x4000 | LED/Switches |
+ | 0x4001 | UART TX/RX |
+ | 0x4002 | UART Clock TX* |
+ | 0x4003 | UART Clock RX* |
+ | 0x4004 | UART Control* |
+ | ------- | -------------- |
+ These registers are turned off by default
+ and will need to be enabled during synthesis.
+
+* LED/Switches
+
+A bank of switches, non-debounced, with LED lights next to them.
+
+ +---------------------------------------------------------------+
+ | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +---------------------------------------------------------------+
+ | | Switches 1 = on, 0 = off | READ
+ +---------------------------------------------------------------+
+ | | LED 1 = on, 0 = off | WRITE
+ +---------------------------------------------------------------+
+
+* UART TX/RX
+
+The UART TX/RX register is used to read and write data bytes to the UART and
+check on the UART status. The UART has a FIFO that is used to capture the
+results of the UART. The usage of which is non-optional.
+
+ +---------------------------------------------------------------+
+ | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +---------------------------------------------------------------+
+ | |TFF|TFE| |RFF|RFE| RX DATA BYTE | READ
+ +---------------------------------------------------------------+
+ | |TFW| |RFR| | TX DATA BYTE | WRITE
+ +---------------------------------------------------------------+
+ RFE = RX FIFO EMPTY
+ RFF = RX FIFO FULL
+ RFR = RX FIFO READ ENABLE
+ TFE = TX FIFO EMPTY
+ TFF = TX FIFO FULL
+ TFW = TX FIFO WRITE ENABLE
+
+* UART Clock TX
+
+The UART Transmission clock, independent from the Reception Clock, is
+controllable via this register.
+
+Defaults are: 115200 Baud
+
+ +---------------------------------------------------------------+
+ | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +---------------------------------------------------------------+
+ | | READ
+ +---------------------------------------------------------------+
+ | UART TX CLOCK DIVISOR | WRITE
+ +---------------------------------------------------------------+
+
+* UART Clock RX
+
+The UART Reception clock, independent from the Transmission Clock, is
+controllable via this register.
+
+Defaults are: 115200 Baud
+
+ +---------------------------------------------------------------+
+ | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +---------------------------------------------------------------+
+ | | READ
+ +---------------------------------------------------------------+
+ | UART RX CLOCK DIVISOR | WRITE
+ +---------------------------------------------------------------+
+
+* UART Clock Control
+
+This clock is used to control UART options such as the number of bits,
+
+Defaults are: 8N1, no parity
+
+ +---------------------------------------------------------------+
+ | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ +---------------------------------------------------------------+
+ | | READ
+ +---------------------------------------------------------------+
+ | | DATA BITS |STPBITS|EPA|UPA| WRITE
+ +---------------------------------------------------------------+
+ UPA = USE PARITY BITS
+ EPA = EVEN PARITY
+ STPBITS = Number of stop bits
+ DATA BITS = Number of data bits
+
+
+# Other Soft Microprocessors
+
+This is a *very* specialized core, that cannot be emphasized enough. It
+executes slowly, but is small. Other, larger core (but still relatively small)
+may be useful for your needs. In terms of engineering trade offs this design
+takes things to the extreme in one direction only.
+
+The core should be written to be portable to different [FPGA][]s, however the
+author only tests what they have available (Xilinx, Spartan-6).
+
+* The H2
+
+Another small core, based on the J1. This core executes quite quickly (1
+instruction per CPU cycle) and uses
+few resources, although much more than this core. The instruction set is quite
+dense and allows for higher level programming than just using straight
+assembler. See .
+
+This CPU core has deeper stacks, more instructions, and interrupts, which the
+original J1 core lacks. It is also written in VHDL instead of Verilog.
+
+* Tiny CPU in a CPLD
+
+This is a 8-bit CPU designed to fit in the limited resources of a CPLD:
+
+See and
+.
+
+It is written in Verilog, it is based on the 6502, implementing a subset of its
+instructions. It is probably easier to directly program than this bit-serial
+CPU, and roughly the same size (although a direct comparison is difficult).
+It can address less memory (1K) without bank-switching. There is also a
+different version made with 7400 series logic gates
+ .
+
+* Leros and Lipsi
+
+See ,
+also ,
+
+# References / Appendix
+
+The state-machine diagram was made using [Graphviz][], and can be viewed and
+edited immediately by copying the following text into [GraphvizOnline][].
+
+
+ digraph bcpu {
+ reset -> fetch [label="start"]
+ fetch -> execute
+ fetch -> indirect [label="flag(IND) = '1'\n and op < 8"]
+ fetch -> reset [label="flag(RST) = '1'"]
+ fetch -> halt [label="flag(HLT) = '1'"]
+ indirect -> operand
+ operand -> execute
+ execute -> advance
+ execute -> store [label="op = 'store'"]
+ execute -> load [label="op = 'load'"]
+ execute -> fetch [label="(op = 'jumpz' and acc = 0)\n or op ='jump'"]
+ store -> advance
+ load -> advance
+ advance -> fetch
+ halt -> halt
+ }
+
+
+For timing diagrams, use [Wavedrom][] with the following text:
+
+
+ {signal: [
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2..................', data: ['HALT']},
+ {name: 'ie', wave: 'x0..................'},
+ {name: 'oe', wave: 'x0..................'},
+ {name: 'ae', wave: 'x0..................'},
+ {name: 'o', wave: 'x0..................'},
+ {name: 'i', wave: 'x...................'},
+ {name: 'halt', wave: 'x1..................'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['ADVANCE']},
+ {name: 'ie', wave: 'x0.................x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x01...............0x'},
+ {name: 'o', wave: 'x0================0x', data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', 'F12', 'F13', 'F14', 'F15']},
+ {name: 'i', wave: 'x.................xx'},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['OPERAND or LOAD']},
+ {name: 'ie', wave: 'x01...............0x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x0.................x'},
+ {name: 'o', wave: 'x0.................x'},
+ {name: 'i', wave: 'x.================xx', data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['STORE']},
+ {name: 'ie', wave: 'x0.................x'},
+ {name: 'oe', wave: 'x01...............0x'},
+ {name: 'ae', wave: 'x0.................x'},
+ {name: 'o', wave: 'x0================0x', data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']},
+ {name: 'i', wave: 'x.................xx'},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['INDIRECT or EXECUTE: LOAD, STORE, JUMP, JUMPZ']},
+ {name: 'ie', wave: 'x0.................x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x01...............0x'},
+ {name: 'o', wave: 'x0================0x', data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', 'F12', 'F13', 'F14', 'F15']},
+ {name: 'i', wave: 'x.................xx'},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['EXECUTE: NORMAL INSTRUCTION']},
+ {name: 'ie', wave: 'x0.................x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x0.................x'},
+ {name: 'o', wave: 'x0.................x'},
+ {name: 'i', wave: 'x.................xx'},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['FETCH']},
+ {name: 'ie', wave: 'x01...............0x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x0.................x'},
+ {name: 'o', wave: 'x0.................x'},
+ {name: 'i', wave: 'x.================xx', data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ {name: 'clk', wave: 'pp...p...p...p...p..'},
+ {name: 'cycle', wave: '22222222222222222222', data: ['prev', 'init','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', 'next', 'rest']},
+ {name: 'cmd', wave: 'x2................xx', data: ['RESET']},
+ {name: 'ie', wave: 'x0.................x'},
+ {name: 'oe', wave: 'x0.................x'},
+ {name: 'ae', wave: 'x01...............0x'},
+ {name: 'o', wave: 'x0.................x'},
+ {name: 'i', wave: 'x.................xx'},
+ {name: 'halt', wave: 'x0.................x'},
+ {},
+
+ ]}
+
+
+That's all folks!
+
+[C]: https://en.wikipedia.org/wiki/C_%28programming_language%29
+[Digilent]: https://store.digilentinc.com/
+[FPGA]: https://en.wikipedia.org/wiki/Field-programmable_gate_array
+[Forth]: https://www.forth.com/forth/
+[GHDL]: http://ghdl.free.fr/
+[GraphvizOnline]: https://dreampuf.github.io/GraphvizOnline
+[Graphviz]: https://graphviz.org/
+[H2]: https://github.com/howerj/forth-cpu
+[Nexys 3]: https://store.digilentinc.com/nexys-3-spartan-6-fpga-trainer-board-limited-time-see-nexys4-ddr/
+[Soft-Core]: https://en.wikipedia.org/wiki/Soft_microprocessor#Core_comparison
+[Spartan-6]: https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html
+[VHDL]: https://en.wikipedia.org/wiki/VHDL
+[Wavedrom]: https://wavedrom.com/editor.html
+[Xilinx ISE 14.7]: https://www.xilinx.com/products/design-tools/ise-design-suite/ise-webpack.html
+[bit-serial CPU]: https://en.wikipedia.org/wiki/Bit-serial_architecture
+[bit.c]: bit.c
+[bit.fth]: bit.fth
+[bit.fth]: bit.fth
+[bit.hex]: bit.hex
+[bit.vhd]: bit.vhd
+[gforth]: https://gforth.org/
+
+
+
Index: bitserial/trunk/signals.tcl
===================================================================
--- bitserial/trunk/signals.tcl (nonexistent)
+++ bitserial/trunk/signals.tcl (revision 2)
@@ -0,0 +1,36 @@
+# Richard James Howe
+# TCL Script for GTKWave on tb.ghw
+#
+
+set bits 15
+
+gtkwave::/Edit/Set_Trace_Max_Hier 0
+gtkwave::/Time/Zoom/Zoom_Amount -27.0
+gtkwave::/View/Show_Filled_High_Values 1
+gtkwave::setFromEntry 170ns
+
+# top.tb.uut.cpu.c.first
+set names {
+ top.tb.rst
+ top.tb.clk
+ top.tb.uut.cpu.last
+ top.tb.uut.cpu.c.state
+ top.tb.uut.cpu.c.pc[15:0]
+ top.tb.uut.cpu.cmd
+ top.tb.uut.cpu.c.op[15:0]
+ top.tb.uut.cpu.c.acc[15:0]
+ top.tb.uut.cpu.ae
+ top.tb.uut.cpu.ie
+ top.tb.uut.cpu.oe
+}
+
+gtkwave::addSignalsFromList $names
+
+foreach v $names {
+ set a [split $v .]
+ set a [lindex $a end]
+ gtkwave::highlightSignalsFromList $v
+ gtkwave::/Edit/Alias_Highlighted_Trace $a
+ gtkwave::/Edit/UnHighlight_All $a
+}
+
Index: bitserial/trunk/tb.conf
===================================================================
--- bitserial/trunk/tb.conf (nonexistent)
+++ bitserial/trunk/tb.conf (revision 2)
@@ -0,0 +1,3 @@
+12288
+0
+0
Index: bitserial/trunk/tb.vhd
===================================================================
--- bitserial/trunk/tb.vhd (nonexistent)
+++ bitserial/trunk/tb.vhd (revision 2)
@@ -0,0 +1,104 @@
+-- File: tb.vhd
+-- Author: Richard James Howe
+-- Repository: https://github.com/howerj/bit-serial
+-- License: MIT
+-- Description: Test bench for top level entity
+
+library ieee, work, std;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.util.all;
+use std.textio.all;
+
+entity tb is
+end tb;
+
+architecture testing of tb is
+ constant g: common_generics := default_settings;
+ constant clock_period: time := 1000 ms / g.clock_frequency;
+ constant baud: positive := 115200 * 10; -- speed up TX/RX for simulation
+ shared variable clocks: integer := 10000;
+ shared variable forever: integer := 0;
+ shared variable debug: integer := 1;
+ constant N: positive := 16;
+
+ signal ld: std_ulogic_vector(7 downto 0) := (others => '0');
+ signal sw: std_ulogic_vector(7 downto 0) := x"AA";
+ signal stop: boolean := false;
+ signal clk: std_ulogic := '0';
+ signal halt: std_ulogic := '0';
+ signal rst: std_ulogic := '1';
+ signal tx, rx: std_ulogic := '0';
+
+ impure function configure(the_file_name: in string) return boolean is
+ file in_file: text is in the_file_name;
+ variable in_line: line;
+ variable i: integer;
+ begin
+ if endfile(in_file) then return false; end if;
+ readline(in_file, in_line); read(in_line, i);
+ clocks := i;
+ readline(in_file, in_line); read(in_line, i);
+ forever := i;
+ readline(in_file, in_line); read(in_line, i);
+ debug := i;
+ return true;
+ end function;
+
+ signal configured: boolean := configure("tb.conf");
+begin
+ uut: entity work.top
+ generic map(
+ g => g,
+ file_name => "bit.hex",
+ N => N,
+ baud => baud,
+ debug => debug)
+ port map (
+ clk => clk,
+-- rst => rst,
+ halt => halt,
+ ld => ld,
+ sw => sw,
+ tx => tx,
+ rx => rx);
+
+ clock_process: process
+ variable count: integer := 0;
+ variable ll: line;
+
+ begin
+ rst <= '1';
+ stop <= false;
+ wait for clock_period;
+ rst <= '0';
+ while (count < clocks or forever /= 0) and halt = '0' loop
+ clk <= '1';
+ wait for clock_period / 2;
+ clk <= '0';
+ wait for clock_period / 2;
+ count := count + 1;
+ end loop;
+ if halt = '1' then
+ write(ll, string'("{HALT}"));
+ else
+ write(ll, string'("{CYCLES}"));
+ end if;
+
+ if debug > 0 then
+ writeline(OUTPUT, ll);
+ end if;
+
+ stop <= true;
+ wait;
+ end process;
+
+ stimulus_process: process
+ begin
+ while stop = false loop
+ wait for clock_period;
+ end loop;
+ wait;
+ end process;
+end architecture;
+
Index: bitserial/trunk/top.ucf
===================================================================
--- bitserial/trunk/top.ucf (nonexistent)
+++ bitserial/trunk/top.ucf (revision 2)
@@ -0,0 +1,281 @@
+# Nexys3 board UCF file: Cut down version
+# On Board 100 MHz Clock
+#
+
+#Clock signal
+Net "clk" LOC=V10 | IOSTANDARD=LVCMOS33;
+Net "clk" TNM_NET = sys_clk_pin;
+TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100000 kHz;
+
+# # Input: Buttons
+# Net "btnu" LOC = A8 | IOSTANDARD = LVCMOS33; button up
+# Net "btnd" LOC = C9 | IOSTANDARD = LVCMOS33; button down
+# Net "btnc" LOC = B8 | IOSTANDARD = LVCMOS33; button centre
+# Net "btnl" LOC = C4 | IOSTANDARD = LVCMOS33; button left
+# Net "btnr" LOC = D9 | IOSTANDARD = LVCMOS33; button right
+#
+# Input: Switches
+Net "sw<0>" LOC = T10 | IOSTANDARD = LVCMOS33; # switch 0
+Net "sw<1>" LOC = T9 | IOSTANDARD = LVCMOS33; # switch 1
+Net "sw<2>" LOC = V9 | IOSTANDARD = LVCMOS33; # switch 2
+Net "sw<3>" LOC = M8 | IOSTANDARD = LVCMOS33; # switch 3
+Net "sw<4>" LOC = N8 | IOSTANDARD = LVCMOS33; # switch 4
+Net "sw<5>" LOC = U8 | IOSTANDARD = LVCMOS33; # switch 5
+Net "sw<6>" LOC = V8 | IOSTANDARD = LVCMOS33; # switch 6
+Net "sw<7>" LOC = T5 | IOSTANDARD = LVCMOS33; # switch 7
+#
+# # Output: Individual LEDs
+Net "ld<0>" LOC = U16 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 0
+Net "ld<1>" LOC = V16 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 1
+Net "ld<2>" LOC = U15 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 2
+Net "ld<3>" LOC = V15 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 3
+Net "ld<4>" LOC = M11 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 4
+Net "ld<5>" LOC = N11 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 5
+Net "ld<6>" LOC = R11 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 6
+Net "ld<7>" LOC = T11 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # led 7
+#
+# # Output: 7/8 Segment LEDs
+# Net "an<0>" LOC = P17 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # anode 0
+# Net "an<1>" LOC = P18 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # anode 1
+# Net "an<2>" LOC = N15 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # anode 2
+# Net "an<3>" LOC = N16 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # anode 3
+#
+# Net "ka<0>" LOC = T17 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 0 - CA
+# Net "ka<1>" LOC = T18 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 1 - CB
+# Net "ka<2>" LOC = U17 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 2 - CC
+# Net "ka<3>" LOC = U18 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 3 - CD
+# Net "ka<4>" LOC = M14 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 4 - CE
+# Net "ka<5>" LOC = N14 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 5 - CF
+# Net "ka<6>" LOC = L14 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 6 - CG
+# Net "ka<7>" LOC = M13 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # cathode 7 - DP
+
+# UART serial interface
+Net "rx" LOC = N17 | IOSTANDARD = LVCMOS33; # uart rx
+Net "tx" LOC = N18 | IOSTANDARD = LVCMOS33 | SLEW = FAST; # uart tx
+
+# VGA
+# Net "o_vga_red<0>" LOC = U7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L43P, Sch name = RED0
+# Net "o_vga_red<1>" LOC = V7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L43N, Sch name = RED1
+# Net "o_vga_red<2>" LOC = N7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L44P, Sch name = RED2
+# Net "o_vga_green<0>" LOC = P8 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L44N, Sch name = GRN0
+# Net "o_vga_green<1>" LOC = T6 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L45P, Sch name = GRN1
+# Net "o_vga_green<2>" LOC = V6 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L45N, Sch name = GRN2
+# Net "o_vga_blue<0>" LOC = R7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L46P, Sch name = BLU1
+# Net "o_vga_blue<1>" LOC = T7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L46N, Sch name = BLU2
+# Net "o_vga_hsync" LOC = N6 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L47P, Sch name = HSYNC
+# Net "o_vga_vsync" LOC = P7 | IOSTANDARD = LVCMOS33; # Bank = 2, pin name = IO_L47N, Sch name = VSYNC
+#
+# Time output
+##JA
+#Net "gpt0_q" LOC = T12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19P, Sch name = JA1
+#Net "gpt0_nq" LOC = V12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19N, Sch name = JA2
+
+## Pic USB-HID interface
+# NET "ps2_keyboard_data" LOC = "J13" | IOSTANDARD = "LVCMOS33" | PULLUP; #Bank = 1, Pin name = IO_L39P_M1A3, Sch name = PIC-SDI1
+# NET "ps2_keyboard_clk" LOC = "L12" | IOSTANDARD = "LVCMOS33" | PULLUP; #Bank = 1, Pin name = IO_L40P_GCLK11_M1A5, Sch name = PIC-SCK1
+#
+#NET "ps2_mouse_data" LOC = "K14" | IOSTANDARD = "LVCMOS33"; #Bank = 1, Pin name = IO_L39N_M1ODT, Sch name = PIC-SDO1
+#NET "ps2_mouse_clk" LOC = "L13" | IOSTANDARD = "LVCMOS33"; #Bank = 1, Pin name = IO_L40N_GCLK10_M1A6, Sch name = PIC-SS1
+
+#NET "pic_gpio<0>" LOC = "L16" | IOSTANDARD = "LVCMOS33"; #Bank = 1, Pin name = IO_L42N_GCLK6_TRDY1_M1LDM, Sch name = PIC-GPIO0
+#NET "pic_gpio<1>" LOC = "H17" | IOSTANDARD = "LVCMOS33"; #Bank = 1, Pin name = IO_L43P_GCLK5_M1DQ4, Sch name = PIC-GPIO1
+
+## 12 pin connectors
+
+##JA
+#Net "JA<0>" LOC = T12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19P, Sch name = JA1
+#Net "JA<1>" LOC = V12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19N, Sch name = JA2
+#Net "JA<2>" LOC = N10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20P, Sch name = JA3
+#Net "JA<3>" LOC = P11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20N, Sch name = JA4
+#Net "JA<4>" LOC = M10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L22P, Sch name = JA7
+#Net "JA<5>" LOC = N9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L22N, Sch name = JA8
+#Net "JA<6>" LOC = U11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L23P, Sch name = JA9
+#Net "JA<7>" LOC = V11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L23N, Sch name = JA10
+
+##JB
+#Net "JB<0>" LOC = K2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L38P_M3DQ2, Sch name = JB1
+#Net "JB<1>" LOC = K1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L38N_M3DQ3, Sch name = JB2
+#Net "JB<2>" LOC = L4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L39P_M3LDQS, Sch name = JB3
+#Net "JB<3>" LOC = L3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L39N_M3LDQSN, Sch name = JB4
+#Net "JB<4>" LOC = J3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40P_M3DQ6, Sch name = JB7
+#Net "JB<5>" LOC = J1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40N_M3DQ7, Sch name = JB8
+#Net "JB<6>" LOC = K3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L42N_GCLK24_M3LDM, Sch name = JB9
+#Net "JB<7>" LOC = K5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L43N_GCLK22_IRDY2_M3CASN, Sch name = JB10
+
+##JC
+#Net "JC<0>" LOC = H3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L44N_GCLK20_M3A6, Sch name = JC1
+#Net "JC<1>" LOC = L7 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L45P_M3A3, Sch name = JC2
+#Net "JC<2>" LOC = K6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L45N_M3ODT, Sch name = JC3
+#Net "JC<3>" LOC = G3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L46P_M3CLK, Sch name = JC4
+#Net "JC<4>" LOC = G1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L46N_M3CLKN, Sch name = JC7
+#Net "JC<5>" LOC = J7 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L47P_M3A0, Sch name = JC8
+#Net "JC<6>" LOC = J6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L47N_M3A1, Sch name = JC9
+#Net "JC<7>" LOC = F2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L48P_M3BA0, Sch name = JC10
+
+##JD, LX16 Die only
+#Net "JD<0>" LOC = G11 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40P, Sch name = JD1
+#Net "JD<1>" LOC = F10 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40N, Sch name = JD2
+#Net "JD<2>" LOC = F11 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L42P, Sch name = JD3
+#Net "JD<3>" LOC = E11 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L42N, Sch name = JD4
+#Net "JD<4>" LOC = D12 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L47P, Sch name = JD7
+#Net "JD<5>" LOC = C12 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L47N, Sch name = JD8
+#Net "JD<6>" LOC = F12 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L51P, Sch name = JD9
+#Net "JD<7>" LOC = E12 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L51N, Sch name = JD10
+
+## onBoard USB controller
+#Net "EppAstb" LOC = H1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L41N_GCLK26_M3DQ5, Sch name = U-FLAGA
+#Net "EppDstb" LOC = K4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L42P_GCLK25_TRDY2_M3UDM, Sch name = U-FLAGB
+#Net "EppWait" LOC = C2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L83P, Sch name = U-SLRD
+#Net "EppDB<0>" LOC = E1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L50N_M3BA2, Sch name = U-FD0
+#Net "EppDB<1>" LOC = F4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L51P_M3A10, Sch name = U-FD1
+#Net "EppDB<2>" LOC = F3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L51N_M3A4, Sch name = U-FD2
+#Net "EppDB<3>" LOC = D2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L52P_M3A8, Sch name = U-FD3
+#Net "EppDB<4>" LOC = D1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L52N_M3A9, Sch name = U-FD4
+#Net "EppDB<5>" LOC = H7 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L53P_M3CKE, Sch name = U-FD5
+#Net "EppDB<6>" LOC = G6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L53N_M3A12, Sch name = U-FD6
+#Net "EppDB<7>" LOC = E4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L54P_M3RESET, Sch name = U-FD7
+
+#Net "UsbClk" LOC = H2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L41P_GCLK27_M3DQ4, Sch name = U-IFCLK
+#Net "UsbDir" LOC = F6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L55P_M3A13, Sch name = U-SLCS
+
+#Net "UsbWR" LOC = C1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L83N_VREF, Sch name = U-SLWR
+#Net "UsbOE" LOC = H6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L49P_M3A7, Sch name = U-SLOE
+
+#Net "UsbAdr<1>" LOC = E3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L50P_M3WE, Sch name = U-FIFOAD1
+#Net "UsbAdr<0>" LOC = H5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L49N_M3A2, Sch name = U-FIFOAD0
+
+#Net "UsbPktend" LOC = D3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L54N_M3A11, Sch name = U-PKTEND
+
+#Net "UsbFlag" LOC = F5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L55N_M3A14, Sch name = U-FLAGC
+#Net "UsbMode" LOC = F1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L48N_M3BA1, Sch name = U-INT0#
+
+# ## onBoard Cellular RAM, Numonyx StrataFlash and Numonyx Quad Flash
+# Net "mem_oe" LOC = L18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L46N_FOE_B_M1DQ3, Sch name = P30-OE
+# Net "mem_wr" LOC = M16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L47P_FWE_B_M1DQ0, Sch name = P30-WE
+# Net "mem_adv" LOC = H18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L43N_GCLK4_M1DQ5, Sch name = P30-ADV
+# Net "mem_wait" LOC = V4 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L63N, Sch name = P30-WAIT
+# #Net "MemClk" LOC = R10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L29P_GCLK3, Sch name = P30-CLK
+#
+# Net "ram_cs" LOC = L15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L42P_GCLK7_M1UDM, Sch name = MT-CE
+# #Net "RamCRE" LOC = M18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L47N_LDC_M1DQ1, Sch name = MT-CRE
+# #Net "RamUB" LOC = K15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L41P_GCLK9_IRDY1_M1RASN, Sch name = MT-UB
+# #Net "RamLB" LOC = K16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L41N_GCLK8_M1CASN, Sch name = MT-LB
+#
+# Net "flash_cs" LOC = L17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L46P_FCS_B_M1DQ2, Sch name = P30-CE
+# Net "flash_rp" LOC = T4 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L63P, Sch name = P30-RST
+#
+# #Net "QuadSpiFlashCS" LOC = V3 | IOSTANDARD = LVCMOS33; #Bank = MISC, pin name = IO_L65N_CSO_B_2, Sch name = CS
+# #Net "QuadSpiFlashSck" LOC = R15 | IOSTANDARD = LVCMOS33; #Bank = MISC, pin name = IO_L1P_CCLK_2, Sch name = SCK
+#
+# Net "mem_addr<1>" LOC = K18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L45N_A0_M1LDQSN, Sch name = P30-A0
+# Net "mem_addr<2>" LOC = K17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L45P_A1_M1LDQS, Sch name = P30-A1
+# Net "mem_addr<3>" LOC = J18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L44N_A2_M1DQ7, Sch name = P30-A2
+# Net "mem_addr<4>" LOC = J16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L44P_A3_M1DQ6, Sch name = P30-A3
+# Net "mem_addr<5>" LOC = G18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L38N_A4_M1CLKN, Sch name = P30-A4
+# Net "mem_addr<6>" LOC = G16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L38P_A5_M1CLK, Sch name = P30-A5
+# Net "mem_addr<7>" LOC = H16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L37N_A6_M1A1, Sch name = P30-A6
+# Net "mem_addr<8>" LOC = H15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L37P_A7_M1A0, Sch name = P30-A7
+# Net "mem_addr<9>" LOC = H14 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L36N_A8_M1BA1, Sch name = P30-A8
+# Net "mem_addr<10>" LOC = H13 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L36P_A9_M1BA0, Sch name = P30-A9
+# Net "mem_addr<11>" LOC = F18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L35N_A10_M1A2, Sch name = P30-A10
+# Net "mem_addr<12>" LOC = F17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L35P_A11_M1A7, Sch name = P30-A11
+# Net "mem_addr<13>" LOC = K13 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L34N_A12_M1BA2, Sch name = P30-A12
+# Net "mem_addr<14>" LOC = K12 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L34P_A13_M1WE, Sch name = P30-A13
+# Net "mem_addr<15>" LOC = E18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L33N_A14_M1A4, Sch name = P30-A14
+# Net "mem_addr<16>" LOC = E16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L33P_A15_M1A10, Sch name = P30-A15
+# Net "mem_addr<17>" LOC = G13 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L32N_A16_M1A9, Sch name = P30-A16
+# Net "mem_addr<18>" LOC = H12 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L32P_A17_M1A8, Sch name = P30-A17
+# Net "mem_addr<19>" LOC = D18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L31N_A18_M1A12, Sch name = P30-A18
+# Net "mem_addr<20>" LOC = D17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L31P_A19_M1CKE, Sch name = P30-A19
+# Net "mem_addr<21>" LOC = G14 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L30N_A20_M1A11, Sch name = P30-A20
+# Net "mem_addr<22>" LOC = F14 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L30P_A21_M1RESET Sch name = P30-A21
+# Net "mem_addr<23>" LOC = C18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L29N_A22_M1A14, Sch name = P30-A22
+# Net "mem_addr<24>" LOC = C17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L29P_A23_M1A13, Sch name = P30-A23
+# Net "mem_addr<25>" LOC = F16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L1N_A24_VREF, Sch name = P30-A24
+# Net "mem_addr<26>" LOC = F15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L1P_A25, Sch name = P30-A25
+#
+# #Net "QuadSpiFlashDB<0>" LOC = T13 | IOSTANDARD = LVCMOS33; #Dual/Quad SPI Flash DB<0>, Bank = MISC, pin name = IO_L3N_MOSI_CSI_B_MISO0_2, Sch name = SDI
+# Net "mem_data<0>" LOC = R13 | IOSTANDARD = LVCMOS33; #Ram or Numonyx Paralell Flash DB<0>, or Dual/Quad SPI Flash DB<1>, Bank = MISC, pin name = IO_L3P_D0_DIN_MISO_MISO1_2, Sch name = P30-DQ0
+# Net "mem_data<1>" LOC = T14 | IOSTANDARD = LVCMOS33; #Ram or Numonyx Paralell Flash DB<1>, or Quad SPI Flash DB<2>, Bank = MISC, pin name = IO_L12P_D1_MISO2_2, Sch name = P30-DQ1
+# Net "mem_data<2>" LOC = V14 | IOSTANDARD = LVCMOS33; #Ram or Numonyx Paralell Flash DB<2>, or Quad SPI Flash DB<3>, Bank = MISC, pin name = IO_L12N_D2_MISO3_2, Sch name = P30-DQ2
+# Net "mem_data<3>" LOC = U5 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_49P_D3, Sch name = P30-DQ3
+# Net "mem_data<4>" LOC = V5 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_49N_D4, Sch name = P30-DQ4
+# Net "mem_data<5>" LOC = R3 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L62P_D5, Sch name = P30-DQ5
+# Net "mem_data<6>" LOC = T3 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L62N_D6, Sch name = P30-DQ6
+# Net "mem_data<7>" LOC = R5 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L48P_D7, Sch name = P30-DQ7
+# Net "mem_data<8>" LOC = N5 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L64P_D8, Sch name = P30-DQ8
+# Net "mem_data<9>" LOC = P6 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L64N_D9, Sch name = P30-DQ9
+# Net "mem_data<10>" LOC = P12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L13N_D10, Sch name = P30-DQ10
+# Net "mem_data<11>" LOC = U13 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L14P_D11, Sch name = P30-DQ11
+# Net "mem_data<12>" LOC = V13 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L14N_D12, Sch name = P30-DQ12
+# Net "mem_data<13>" LOC = U10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L30P_GCLK1_D13, Sch name = P30-DQ13
+# Net "mem_data<14>" LOC = R8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L31P_GCLK31_D14, Sch name = P30-DQ14
+# Net "mem_data<15>" LOC = T8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L31N_GCLK30_D15, Sch name = P30-DQ15
+#
+## SMSC ethernet PHY
+#Net "PhyRstn" LOC = P3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L2N, Sch name = ETH-RST
+#Net "PhyCrs" LOC = N3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L1N_VREF, Sch name = ETH-CRS
+#Net "PhyCol" LOC = P4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L2P, Sch name = ETH-COL
+#Net "PhyClk25Mhz" LOC = N4 | IOSTANDARD = LVCMOS33; #Unconnected if R172 is not loaded, Bank = 3, pin name = IO_L1P, Sch name = ETH-CLK25MHZ
+
+#Net "PhyTxd<3>" LOC = T1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L33N_M3DQ13, Sch name = ETH-TXD3
+#Net "PhyTxd<2>" LOC = T2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L33P_M3DQ12, Sch name = ETH-TXD2
+#Net "PhyTxd<1>" LOC = U1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L32N_M3DQ15, Sch name = ETH-TXD1
+#Net "PhyTxd<0>" LOC = U2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L32P_M3DQ14, Sch name = ETH-TXD0
+#Net "PhyTxEn" LOC = L2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L37P_M3DQ0, Sch name = ETH-TX_EN
+#Net "PhyTxClk" LOC = L5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L43P_GCLK23_M3RASN, Sch name = ETH-TX_CLK
+#Net "PhyTxEr" LOC = P2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L34P_M3UDQS, Sch name = ETH-TXD4
+
+#Net "PhyRxd<3>" LOC = M3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L36P_M3DQ8, Sch name = ETH-RXD3
+#Net "PhyRxd<2>" LOC = N1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L35N_M3DQ11, Sch name = ETH-RXD2
+#Net "PhyRxd<1>" LOC = N2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L35P_M3DQ10, Sch name = ETH-RXD1
+#Net "PhyRxd<0>" LOC = P1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L34N_M3UDQSN, Sch name = ETH-RXD0
+#Net "PhyRxDv" LOC = L1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L37N_M3DQ1, Sch name = ETH-RX_DV
+#Net "PhyRxEr" LOC = M1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L36N_M3DQ9, Sch name = ETH-RXD4
+#Net "PhyRxClk" LOC = H4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L44P_GCLK21_M3A5, Sch name = ETH-RX_CLK
+
+#Net "PhyMdc" LOC = M5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L31N_VREF, Sch name = ETH-MDC
+#Net "PhyMdio" LOC = L6 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L31P, Sch name = ETH-MDIO
+
+## VHDCI Connector
+#Net "EXP-IO_P<0>" LOC = B2 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L2P, Sch name = EXP_IO1_P
+#Net "EXP-IO_N<0>" LOC = A2 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L2N, Sch name = EXP_IO1_N
+#Net "EXP-IO_P<1>" LOC = D6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L3P, Sch name = EXP_IO2_P
+#Net "EXP-IO_N<1>" LOC = C6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L3N, Sch name = EXP_IO2_N
+#Net "EXP-IO_P<2>" LOC = B3 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L4P, Sch name = EXP_IO3_P
+#Net "EXP-IO_N<2>" LOC = A3 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L4N, Sch name = EXP_IO3_N
+#Net "EXP-IO_P<3>" LOC = B4 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L5P, Sch name = EXP_IO4_P
+#Net "EXP-IO_N<3>" LOC = A4 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L5N, Sch name = EXP_IO4_N
+#Net "EXP-IO_P<4>" LOC = C5 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L6P, Sch name = EXP_IO5_P
+#Net "EXP-IO_N<4>" LOC = A5 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L6N, Sch name = EXP_IO5_N
+#Net "EXP-IO_P<5>" LOC = B6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L8P, Sch name = EXP_IO6_P
+#Net "EXP-IO_N<5>" LOC = A6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L8N_VREF, Sch name = EXP_IO6_N
+#Net "EXP-IO_P<6>" LOC = C7 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L10P, Sch name = EXP_IO7_P
+#Net "EXP-IO_N<6>" LOC = A7 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L10N, Sch name = EXP_IO7_N
+#Net "EXP-IO_P<7>" LOC = D8 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L11P, Sch name = EXP_IO8_P
+#Net "EXP-IO_N<7>" LOC = C8 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L11N, Sch name = EXP_IO8_N
+#Net "EXP-IO_P<8>" LOC = B9 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L35P_GCLK17, Sch name = EXP_IO9_P
+#Net "EXP-IO_N<8>" LOC = A9 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L35N_GCLK16, Sch name = EXP_IO9_N
+#Net "EXP-IO_P<9>" LOC = D11 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L36P_GCLK15, Sch name = EXP_IO10_P
+#Net "EXP-IO_N<9>" LOC = C11 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L36N_GCLK14, Sch name = EXP_IO10_N
+#Net "EXP-IO_P<10>" LOC = C10 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L37P_GCLK13, Sch name = EXP_IO11_P
+#Net "EXP-IO_N<10>" LOC = A10 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L37N_GCLK12, Sch name = EXP_IO11_N
+#Net "EXP-IO_P<11>" LOC = G9 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L38P, Sch name = EXP_IO12_P
+#Net "EXP-IO_N<11>" LOC = F9 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L38N_VREF, Sch name = EXP_IO12_N
+#Net "EXP-IO_P<12>" LOC = B11 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L39P, Sch name = EXP_IO13_P
+#Net "EXP-IO_N<12>" LOC = A11 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L39N, Sch name = EXP_IO13_N
+#Net "EXP-IO_P<13>" LOC = B12 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L41P, Sch name = EXP_IO14_P
+#Net "EXP-IO_N<13>" LOC = A12 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L41N, Sch name = EXP_IO14_N
+#Net "EXP-IO_P<14>" LOC = C13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L50P, Sch name = EXP_IO15_P
+#Net "EXP-IO_N<14>" LOC = A13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L50N, Sch name = EXP_IO15_N
+#Net "EXP-IO_P<15>" LOC = B14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L62P, Sch name = EXP_IO16_P
+#Net "EXP-IO_N<15>" LOC = A14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L62N_VREF, Sch name = EXP_IO16_N
+#Net "EXP-IO_P<16>" LOC = F13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L63P_SCP7, Sch name = EXP_IO17_P
+#Net "EXP-IO_N<16>" LOC = E13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L63N_SCP6, Sch name = EXP_IO17_N
+#Net "EXP-IO_P<17>" LOC = C15 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L64P_SCP5, Sch name = EXP_IO18_P
+#Net "EXP-IO_N<17>" LOC = A15 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L64N_SCP4, Sch name = EXP_IO18_N
+#Net "EXP-IO_P<18>" LOC = D14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L65P_SCP3, Sch name = EXP_IO19_P
+#Net "EXP-IO_N<18>" LOC = C14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L65N_SCP2, Sch name = EXP_IO19_N
+#Net "EXP-IO_P<19>" LOC = B16 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L66P_SCP1, Sch name = EXP_IO20_P
+#Net "EXP-IO_N<19>" LOC = A16 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L66N_SCP0, Sch name = EXP_IO20_N
+
Index: bitserial/trunk/top.vhd
===================================================================
--- bitserial/trunk/top.vhd (nonexistent)
+++ bitserial/trunk/top.vhd (revision 2)
@@ -0,0 +1,69 @@
+-- File: top.vhd
+-- Author: Richard James Howe
+-- Repository: https://github.com/howerj/bit-serial
+-- License: MIT
+-- Description: Top level entity; Bit Serial CPU
+
+library ieee, work, std;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.util.all;
+
+entity top is
+ generic (
+ g: common_generics := default_settings;
+ file_name: string := "bit.hex";
+ N: positive := 16;
+ baud: positive := 115200;
+ debug: natural := 0; -- will not synthesize if greater than zero (debug off)
+ uart_use_cfg: boolean := false;
+ uart_fifo_depth: natural := 0
+ );
+ port (
+ clk: in std_ulogic;
+ -- synthesis translate_off
+-- rst: in std_ulogic;
+ halt: out std_ulogic;
+ -- synthesis translate_on
+ tx: out std_ulogic;
+ rx: in std_ulogic;
+ sw: in std_ulogic_vector(7 downto 0);
+ ld: out std_ulogic_vector(7 downto 0));
+end entity;
+
+architecture rtl of top is
+ constant W: positive := N - 3;
+ signal rst: std_ulogic := '0';
+ signal i: std_ulogic := 'X';
+ signal o, a, oe, ie, ae: std_ulogic := 'X';
+begin
+ peripheral: entity work.peripherals
+ generic map(
+ g => g,
+ file_name => file_name,
+ W => W,
+ N => N,
+ baud => baud,
+ uart_fifo_depth => uart_fifo_depth,
+ uart_use_cfg => uart_use_cfg)
+ port map (
+ clk => clk, rst => rst,
+ tx => tx, rx => rx, ld => ld, sw => sw,
+ i => o,
+ o => i,
+ a => a, oe => ie, ie => oe, ae => ae);
+
+ cpu: entity work.bcpu
+ generic map (
+ asynchronous_reset => g.asynchronous_reset,
+ delay => g.delay,
+ N => N,
+ debug => debug)
+ port map (
+ clk => clk, rst => rst,
+ -- synthesis translate_off
+ stop => halt,
+ -- synthesis translate_on
+ i => i,
+ o => o, a => a, oe => oe, ie => ie, ae => ae);
+end architecture;
Index: bitserial/trunk/uart.vhd
===================================================================
--- bitserial/trunk/uart.vhd (nonexistent)
+++ bitserial/trunk/uart.vhd (revision 2)
@@ -0,0 +1,1050 @@
+-- FILE: uart.vhd
+-- BRIEF: UART TX/RX module
+-- LICENSE: MIT
+-- COPYRIGHT: Richard James Howe (2019, 2020)
+--
+-- The UART (Universal Asynchronous Receiver/Transmitter) is one of the simplest
+-- serial communication methods available. It is often used for debugging, for
+-- issuing commands to embedded devices and sometimes even for uploading firmware
+-- to devices. The data format and speed are configurable but there is no method
+-- for automatically configuring a UART, both sides must have agreed on the
+-- settings before hand. Configurable options include; baud, use of an
+-- even of odd parity bit, number of data bits and number of stop bits.
+--
+-- The clock is not transmitted as part of the signal (which is why baud
+-- must be agreed upon before hand), a single packet starts with a 'start bit',
+-- where the line goes low. The receiver must synchronize to this start bit (it
+-- resets the clock that generates pulse at the sample rate and baud when it
+-- encounters a start bit).
+--
+-- A transmission with 8 data bits, 1 parity bit and 1 stop bit looks like
+-- this:
+-- ____ ______________________________ ________________
+-- \_/|0|1|2|3|4|5|6|7|P|S| \_/
+-- Start Data Parity Stop |--- More data --->
+--
+-- Start bits are always low, stop bits high. The most common format is
+-- 8 data bits, no parity bit, and 1 stop bit at either 9600 or 115200 baud.
+--
+-- For the receiver a clock that is a multiple of the baud is used so the
+-- bits can be sampled with a higher frequency than the bit rate.
+--
+-- Some notes:
+-- * We can transmit from an 8-bit UART to a less than 8-bit UART fine, so
+-- long as parity is not used, as
+-- * Certain UARTs have the ability to transmit a BREAK signal by holding
+-- the line low for a period greater than the packet length. We can transmit
+-- that by lowering the baud rate and transmitting all zeroes. Receiving a
+-- break (correctly) would require changing the receiver.
+--
+--
+-- See:
+-- *
+--
+-- NOTE: We could replace this entire package with an entirely software driven
+-- solution. The only hardware we would need two timers driven at the sample
+-- rate (one for RX, one for TX) and a deglitched RX signal. An interrupt
+-- would be generated on the timers expiry.
+--
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package uart_pkg is
+ constant uart_8N1: std_ulogic_vector(7 downto 0) := "10000100";
+
+ type uart_generics is record
+ clock_frequency: positive; -- clock frequency of module clock
+ delay: time; -- gate delay for simulation purposes
+ asynchronous_reset: boolean; -- use asynchronous reset if true
+ end record;
+
+ component uart_tx is
+ generic (
+ g: uart_generics;
+ N: positive;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ use_cfg: boolean);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ cr: out std_ulogic;
+ baud: in std_ulogic; -- Pulse at baud
+ tx: out std_ulogic;
+ ok: out std_ulogic;
+ ctr: in std_ulogic_vector(format'range);
+ ctr_we: in std_ulogic;
+ we: in std_ulogic; -- di write enable
+ di: in std_ulogic_vector(N - 1 downto 0));
+ end component;
+
+ component uart_rx is
+ generic (
+ g: uart_generics;
+ N: positive;
+ D: positive;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ use_cfg: boolean);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ cr: out std_ulogic;
+ baud: in std_ulogic;
+ sample: in std_ulogic;
+ failed: out std_ulogic_vector(1 downto 0);
+ ctr: in std_ulogic_vector(7 downto 0);
+ ctr_we: in std_ulogic;
+ rx: in std_ulogic;
+ we: out std_ulogic;
+ do: out std_ulogic_vector(N - 1 downto 0));
+ end component;
+
+ component uart_fifo is
+ generic (
+ g: uart_generics;
+ data_width: positive;
+ fifo_depth: positive;
+ read_first: boolean := true);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ di: in std_ulogic_vector(data_width - 1 downto 0);
+ we: in std_ulogic;
+ re: in std_ulogic;
+ do: out std_ulogic_vector(data_width - 1 downto 0);
+
+ -- optional
+ full: out std_ulogic := '0';
+ empty: out std_ulogic := '1');
+ end component;
+
+ component uart_baud is -- Generates a pulse at the sample rate and baud
+ generic (
+ g: uart_generics;
+ init: integer;
+ N: positive := 16;
+ D: positive := 3);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ we: in std_ulogic;
+ cnt: in std_ulogic_vector(N - 1 downto 0);
+ cr: in std_ulogic := '0';
+ sample: out std_ulogic;
+ baud: out std_ulogic);
+ end component;
+
+ component uart_top is
+ generic (
+ clock_frequency: positive; -- clock frequency of module clock
+ delay: time; -- gate delay for simulation purposes
+ asynchronous_reset: boolean; -- use asynchronous reset if true
+ baud: positive := 115200;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ fifo_depth: natural := 0;
+ use_cfg: boolean := false;
+ use_tx: boolean := true;
+ use_rx: boolean := true
+ ); -- Use FIFO to buffer results?
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+
+ tx: out std_ulogic;
+ tx_fifo_full: out std_ulogic;
+ tx_fifo_empty: out std_ulogic;
+ tx_fifo_we: in std_ulogic;
+ tx_fifo_data: in std_ulogic_vector(7 downto 0);
+
+ rx: in std_ulogic;
+ rx_fifo_full: out std_ulogic;
+ rx_fifo_empty: out std_ulogic;
+ rx_fifo_re: in std_ulogic;
+ rx_fifo_data: out std_ulogic_vector(7 downto 0);
+
+ reg: in std_ulogic_vector(15 downto 0);
+ clock_reg_tx_we: in std_ulogic;
+ clock_reg_rx_we: in std_ulogic;
+ control_reg_we: in std_ulogic);
+ end component;
+
+ component uart_tb is
+ generic(g: uart_generics);
+ end component;
+
+ function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
+ function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic;
+ constant ctr_use_parity: integer := 0;
+ constant ctr_even_parity: integer := 1;
+ function ctr_stop_bits(ctr: std_ulogic_vector(7 downto 0)) return integer;
+ function ctr_data_bits(ctr: std_ulogic_vector(7 downto 0)) return integer;
+end package;
+
+package body uart_pkg is
+ function parity(slv: std_ulogic_vector; even: boolean) return std_ulogic is
+ variable z: std_ulogic := '0';
+ begin
+ if not even then
+ z := '1';
+ end if;
+ for i in slv'range loop
+ z := z xor slv(i);
+ end loop;
+ return z;
+ end;
+
+ function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic is
+ variable z: boolean := false;
+ begin
+ if even = '1' then
+ z := true;
+ end if;
+ return parity(slv, z);
+ end;
+
+ function ctr_stop_bits(ctr: std_ulogic_vector(7 downto 0)) return integer is
+ variable ii: std_ulogic_vector(1 downto 0);
+ begin
+ ii := ctr(3 downto 2);
+ return to_integer(unsigned(ii));
+ end function;
+
+ function ctr_data_bits(ctr: std_ulogic_vector(7 downto 0)) return integer is
+ variable ii: std_ulogic_vector(3 downto 0);
+ begin
+ ii := ctr(7 downto 4);
+ return to_integer(unsigned(ii));
+ end function;
+end;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.uart_pkg.all;
+
+entity uart_top is
+ generic (
+ clock_frequency: positive; -- clock frequency of module clock
+ delay: time; -- gate delay for simulation purposes
+ asynchronous_reset: boolean; -- use asynchronous reset if true
+ baud: positive := 115200;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ fifo_depth: natural := 0; -- FIFO depth, 0,1 = no FIFO
+ use_cfg: boolean := false; -- allow run time configuration of baud rate and format?
+ use_tx: boolean := true; -- instantiate TX functionality?
+ use_rx: boolean := true -- instantiate RX functionality?
+ );
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+
+ tx: out std_ulogic;
+ tx_fifo_full: out std_ulogic;
+ tx_fifo_empty: out std_ulogic;
+ tx_fifo_we: in std_ulogic;
+ tx_fifo_data: in std_ulogic_vector(7 downto 0);
+
+ rx: in std_ulogic;
+ rx_fifo_full: out std_ulogic;
+ rx_fifo_empty: out std_ulogic;
+ rx_fifo_re: in std_ulogic;
+ rx_fifo_data: out std_ulogic_vector(7 downto 0);
+
+ reg: in std_ulogic_vector(15 downto 0);
+ clock_reg_tx_we: in std_ulogic;
+ clock_reg_rx_we: in std_ulogic;
+ control_reg_we: in std_ulogic);
+end entity;
+
+architecture structural of uart_top is
+ constant g: uart_generics := (
+ clock_frequency => clock_frequency,
+ delay => delay,
+ asynchronous_reset => asynchronous_reset
+ );
+ constant tx_init: integer := g.clock_frequency / (baud * 16); -- 54 = 115200 @ 100 MHz
+ constant rx_init: positive := tx_init - 1; -- 50 = 115200 @ 100 MHz + Fudge Factor
+ constant N: positive := 8;
+
+ signal rx_ok, rx_nd, rx_push, rx_re: std_ulogic := '0';
+ signal rx_pushed: std_ulogic_vector(rx_fifo_data'range) := (others => '0');
+ signal tx_pop, tx_ok: std_ulogic := '0';
+ signal tx_popped: std_ulogic_vector(tx_fifo_data'range) := (others => '0');
+ signal tx_fifo_empty_b, rx_fifo_full_b: std_ulogic := '0';
+
+ signal tx_sample, tx_baud, tx_cr: std_ulogic := '0';
+ signal rx_sample, rx_baud, rx_cr, rx_we: std_ulogic := '0';
+ signal rx_fail: std_ulogic_vector(1 downto 0) := (others => '0');
+ signal rx_ok_buf: std_ulogic := '0';
+ signal do, do_c, do_n: std_ulogic_vector(rx_fifo_data'range) := (others => '0');
+ signal fail_c, fail_n: std_ulogic_vector(1 downto 0) := (others => '0');
+ signal nd_c, nd_n: std_ulogic := '0'; -- new data
+
+begin
+ rx_ok_buf <= not (fail_c(0) or fail_c(1)) after g.delay;
+ rx_ok <= rx_ok_buf;
+ rx_pushed <= do after g.delay;
+ rx_nd <= nd_c and rx_ok_buf after g.delay; -- no new data if there are errors
+ rx_re <= rx_push;
+
+ process (clk, rst)
+ begin
+ if use_rx then
+ if rst = '1' and g.asynchronous_reset then
+ do_c <= (others => '0') after g.delay;
+ fail_c <= (others => '0') after g.delay;
+ nd_c <= '0' after g.delay;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ do_c <= (others => '0') after g.delay;
+ fail_c <= (others => '0') after g.delay;
+ nd_c <= '0' after g.delay;
+ else
+ do_c <= do_n after g.delay;
+ nd_c <= nd_n after g.delay;
+ fail_c <= fail_n after g.delay;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ process (do_c, do, nd_c, rx_we, rx_re, fail_c, rx_fail)
+ begin
+ if use_tx then
+ do_n <= do_c after g.delay;
+ nd_n <= nd_c after g.delay;
+ fail_n <= fail_c after g.delay;
+ if rx_we = '1' then
+ nd_n <= '1' after g.delay;
+ do_n <= do after g.delay;
+ fail_n <= rx_fail after g.delay;
+ elsif rx_re = '1' then
+ nd_n <= '0' after g.delay;
+ end if;
+ end if;
+ end process;
+
+ ugen0: if fifo_depth <= 1 generate
+ tx_pop <= tx_fifo_we;
+ tx_popped <= tx_fifo_data;
+ tx_fifo_full <= not tx_ok;
+ tx_fifo_empty <= tx_ok;
+
+ rx_push <= rx_fifo_re;
+ rx_fifo_data <= rx_pushed;
+ rx_fifo_full <= rx_nd;
+ rx_fifo_empty <= not rx_nd;
+ end generate;
+
+ ugen1: if fifo_depth > 1 generate
+ tx_fifo_empty <= tx_fifo_empty_b;
+ tx_pop <= tx_ok and not tx_fifo_empty_b;
+
+ ugen1_fifo_tx: if use_tx generate
+ uart_fifo_tx_0: work.uart_pkg.uart_fifo
+ generic map(g => g,
+ data_width => tx_fifo_data'length,
+ fifo_depth => fifo_depth)
+ port map (clk => clk, rst => rst,
+ di => tx_fifo_data,
+ we => tx_fifo_we,
+ re => tx_pop,
+ do => tx_popped,
+ full => tx_fifo_full,
+ empty => tx_fifo_empty_b);
+ end generate;
+
+ rx_fifo_full <= rx_fifo_full_b;
+ rx_push <= rx_nd and rx_ok and not rx_fifo_full_b;
+ ugen1_fifo_rx: if use_rx generate
+ uart_fifo_rx_0: work.uart_pkg.uart_fifo
+ generic map(g => g,
+ data_width => rx_fifo_data'length,
+ fifo_depth => fifo_depth,
+ read_first => false)
+ port map (clk => clk, rst => rst,
+ di => rx_pushed,
+ we => rx_push,
+ re => rx_fifo_re,
+ do => rx_fifo_data,
+ full => rx_fifo_full_b, empty => rx_fifo_empty);
+ end generate;
+ end generate;
+
+ uart_tx_gen: if use_tx generate
+ baud_tx: work.uart_pkg.uart_baud
+ generic map(g => g, init => tx_init, N => reg'length, D => 3)
+ port map(
+ clk => clk,
+ rst => rst,
+ we => clock_reg_tx_we,
+ cnt => reg, -- 0x32/50 is 1152000 @ 100MHz clk
+ cr => tx_cr,
+ sample => tx_sample,
+ baud => tx_baud);
+
+ tx_0: work.uart_pkg.uart_tx
+ generic map(g => g, N => N, format => format, use_cfg => use_cfg)
+ port map(
+ clk => clk,
+ rst => rst,
+
+ cr => tx_cr,
+ baud => tx_baud,
+ ok => tx_ok,
+ we => tx_pop,
+ ctr => reg(reg'high downto reg'high - 7),
+ ctr_we => control_reg_we,
+ di => tx_popped,
+ tx => tx);
+ end generate;
+
+ uart_rx_gen: if use_rx generate
+ baud_rx: work.uart_pkg.uart_baud
+ generic map(g => g, init => rx_init, N => reg'length, D => 3)
+ port map(
+ clk => clk,
+ rst => rst,
+ we => clock_reg_rx_we,
+ cnt => reg,
+ cr => rx_cr,
+ sample => rx_sample,
+ baud => rx_baud);
+
+ rx_0: work.uart_pkg.uart_rx
+ generic map(g => g, N => N, D => 3, format => format, use_cfg => use_cfg)
+ port map(
+ clk => clk,
+ rst => rst,
+
+ baud => rx_baud,
+ sample => rx_sample,
+ cr => rx_cr,
+ failed => rx_fail,
+ ctr => reg(reg'low + 7 downto reg'low),
+ ctr_we => control_reg_we,
+ we => rx_we,
+ do => do,
+ rx => rx);
+ end generate;
+end architecture;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.uart_pkg.all;
+
+entity uart_fifo is
+ generic (g: uart_generics;
+ data_width: positive;
+ fifo_depth: positive;
+ read_first: boolean := true);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ di: in std_ulogic_vector(data_width - 1 downto 0);
+ we: in std_ulogic;
+ re: in std_ulogic;
+ do: out std_ulogic_vector(data_width - 1 downto 0);
+
+ -- optional
+ full: out std_ulogic := '0';
+ empty: out std_ulogic := '1');
+end uart_fifo;
+
+architecture behavior of uart_fifo is
+ type fifo_data_t is array (0 to fifo_depth - 1) of std_ulogic_vector(di'range);
+ signal data: fifo_data_t := (others => (others => '0'));
+ function rindex_init return integer is
+ begin
+ if read_first then
+ return 0;
+ end if;
+ return fifo_depth - 1;
+ end function;
+
+ signal count: integer range 0 to fifo_depth := 0;
+ signal windex: integer range 0 to fifo_depth - 1 := 0;
+ signal rindex: integer range 0 to fifo_depth - 1 := rindex_init;
+
+ signal is_full: std_ulogic := '0';
+ signal is_empty: std_ulogic := '1';
+begin
+ do <= data(rindex) after g.delay;
+ full <= is_full after g.delay; -- buffer these bad boys
+ empty <= is_empty after g.delay;
+ is_full <= '1' when count = fifo_depth else '0' after g.delay;
+ is_empty <= '1' when count = 0 else '0' after g.delay;
+
+ process (rst, clk) is
+ begin
+ if rst = '1' and g.asynchronous_reset then
+ windex <= 0 after g.delay;
+ count <= 0 after g.delay;
+ rindex <= rindex_init after g.delay;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ windex <= 0 after g.delay;
+ count <= 0 after g.delay;
+ rindex <= rindex_init after g.delay;
+ else
+ if we = '1' and re = '0' then
+ if is_full = '0' then
+ count <= count + 1 after g.delay;
+ end if;
+ elsif we = '0' and re = '1' then
+ if is_empty = '0' then
+ count <= count - 1 after g.delay;
+ end if;
+ end if;
+
+ if re = '1' and is_empty = '0' then
+ if rindex = (fifo_depth - 1) then
+ rindex <= 0 after g.delay;
+ else
+ rindex <= rindex + 1 after g.delay;
+ end if;
+ end if;
+
+ if we = '1' and is_full = '0' then
+ if windex = (fifo_depth - 1) then
+ windex <= 0 after g.delay;
+ else
+ windex <= windex + 1 after g.delay;
+ end if;
+ data(windex) <= di after g.delay;
+ end if;
+ end if;
+ end if;
+ end process;
+end behavior;
+
+-- This module generates a sample pulse and a baud pulse. The sample rate
+-- can be controlled by setting 'cnt'. This sample rate is then divided by
+-- 2^(D+1) to get the baud.
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.uart_pkg.all;
+
+entity uart_baud is
+ generic (g: uart_generics; init: integer; N: positive := 16; D: positive := 3);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+
+ we: in std_ulogic;
+ cnt: in std_ulogic_vector(N - 1 downto 0);
+ cr: in std_ulogic := '0';
+
+ sample: out std_ulogic; -- sample pulse
+ baud: out std_ulogic); -- baud (sample rate / 2^(D+1))
+end entity;
+
+architecture behaviour of uart_baud is
+ constant cmp_init: std_ulogic_vector := std_ulogic_vector(to_unsigned(init, cnt'length));
+ signal cmp_c, cmp_n: std_ulogic_vector(cnt'range) := cmp_init;
+ signal cnt_c, cnt_n: std_ulogic_vector(cnt'range) := (others => '0');
+ signal div_c, div_n: std_ulogic_vector(D downto 0) := (others => '0');
+ signal pul_c, pul_n: std_ulogic := '0';
+ signal pulse: std_ulogic := '0';
+begin
+ pulse <= (not cr) and pul_n and (pul_c xor pul_n) after g.delay; -- rising edge detector
+ baud <= (not cr) and div_n(div_n'high) and (div_c(div_c'high) xor div_n(div_n'high)) after g.delay;
+ sample <= pulse;
+
+ process (clk, rst)
+ begin
+ if rst = '1' and g.asynchronous_reset then
+ cmp_c <= cmp_init after g.delay;
+ cnt_c <= (others => '0') after g.delay;
+ div_c <= (others => '0') after g.delay;
+ pul_c <= '0' after g.delay;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ cmp_c <= cmp_init after g.delay;
+ cnt_c <= (others => '0') after g.delay;
+ div_c <= (others => '0') after g.delay;
+ pul_c <= '0' after g.delay;
+ else
+ cmp_c <= cmp_n after g.delay;
+ cnt_c <= cnt_n after g.delay;
+ div_c <= div_n after g.delay;
+ pul_c <= pul_n after g.delay;
+ end if;
+ end if;
+ end process;
+
+ process (pulse, div_c, cr, we)
+ begin
+ div_n <= div_c after g.delay;
+ if cr = '1' or we = '1' then
+ div_n <= (others => '0') after g.delay;
+ div_n(div_n'high) <= '1' after g.delay;
+ elsif pulse = '1' then
+ div_n <= std_ulogic_vector(unsigned(div_c) + 1) after g.delay;
+ end if;
+ end process;
+
+ process (cmp_c, cnt_c, we, cnt, cr)
+ begin
+ cmp_n <= cmp_c after g.delay;
+ cnt_n <= cnt_c after g.delay;
+
+ if we = '1' then
+ cmp_n <= cnt after g.delay;
+ cnt_n <= (others => '0') after g.delay;
+ pul_n <= '0' after g.delay;
+ elsif cr = '1' then
+ cnt_n <= (others => '0') after g.delay;
+ pul_n <= '0' after g.delay;
+ elsif cnt_c = cmp_c then
+ cnt_n <= (others => '0') after g.delay;
+ pul_n <= '1' after g.delay;
+ else
+ cnt_n <= std_ulogic_vector(unsigned(cnt_c) + 1) after g.delay;
+ pul_n <= '0' after g.delay;
+ end if;
+ end process;
+end architecture;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use work.uart_pkg.all;
+
+entity uart_rx is
+ generic (
+ g: uart_generics;
+ N: positive;
+ D: positive;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ use_cfg: boolean);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ cr: out std_ulogic; -- reset sample/baud clock when start bit detected
+ baud: in std_ulogic;
+ sample: in std_ulogic; -- pulses at baud and sample rate
+ failed: out std_ulogic_vector(1 downto 0);
+ ctr: in std_ulogic_vector(7 downto 0);
+ ctr_we: in std_ulogic;
+ rx: in std_ulogic; -- physical RX signal
+ we: out std_ulogic; -- write 'do' to output register
+ do: out std_ulogic_vector(N - 1 downto 0));
+end entity;
+
+architecture behaviour of uart_rx is
+ type state is (reset, idle, start, data, parity, stop, done);
+ signal state_c, state_n: state;
+ signal ctr_c, ctr_n: std_ulogic_vector(ctr'range);
+ signal rx_c, rx_n: std_ulogic_vector(do'range);
+ signal sr_c, sr_n: std_ulogic_vector(D - 1 downto 0);
+ signal rx_sync: std_ulogic;
+ signal count_c, count_n: integer range 0 to N - 1;
+ signal majority: std_ulogic;
+ signal fail_c, fail_n: std_ulogic_vector(1 downto 0);
+begin
+ do <= rx_c after g.delay;
+ failed <= fail_c after g.delay;
+
+ assert D < 4 severity failure;
+
+ majority_1: if D = 1 generate
+ majority <= sr_c(0) after g.delay;
+ end generate;
+
+ majority_2: if D = 2 generate
+ majority <= sr_c(0) and sr_c(1) after g.delay; -- even wins is 'sr_c(0) or sr_c(1)'
+ end generate;
+
+ majority_3: if D = 3 generate
+ majority <= (sr_c(0) and sr_c(1)) or (sr_c(1) and sr_c(2)) or (sr_c(0) and sr_c(2)) after g.delay;
+ end generate;
+
+ process (clk, rst)
+ procedure reset is
+ begin
+ rx_c <= (others => '0') after g.delay;
+ sr_c <= (others => '0') after g.delay;
+ fail_c <= (others => '0') after g.delay;
+ state_c <= reset after g.delay;
+ count_c <= 0 after g.delay;
+ rx_sync <= '0' after g.delay;
+ if use_cfg then ctr_c <= (others => '0') after g.delay; end if;
+ end procedure;
+ begin
+ if rst = '1' and g.asynchronous_reset then
+ reset;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ reset;
+ else
+ rx_c <= rx_n after g.delay;
+ sr_c <= sr_n after g.delay;
+ state_c <= state_n after g.delay;
+ count_c <= count_n after g.delay;
+ fail_c <= fail_n after g.delay;
+ rx_sync <= rx after g.delay;
+ if use_cfg then ctr_c <= ctr_n after g.delay; end if;
+ end if;
+ end if;
+ if not use_cfg then ctr_c <= format after g.delay; end if;
+ end process;
+
+ process (rx_c, sr_c, ctr_c, ctr_we, ctr, state_c, rx_sync, baud, sample, count_c, fail_c, majority)
+ begin
+ fail_n <= fail_c after g.delay;
+ rx_n <= rx_c after g.delay;
+ sr_n <= sr_c after g.delay;
+ state_n <= state_c after g.delay;
+ we <= '0' after g.delay;
+ cr <= '0' after g.delay;
+ count_n <= count_c after g.delay;
+ if use_cfg then ctr_n <= ctr_c after g.delay; end if;
+
+ if sample = '1' then
+ sr_n <= sr_c(sr_c'high - 1 downto sr_c'low) & rx_sync after g.delay;
+ end if;
+
+ case state_c is
+ when reset =>
+ rx_n <= (others => '0') after g.delay;
+ sr_n <= (others => '0') after g.delay;
+ fail_n <= (others => '0') after g.delay;
+ if use_cfg then
+ ctr_n <= format after g.delay; -- 8 bits, 1 stop bit, parity off
+ end if;
+ state_n <= idle after g.delay;
+ when idle =>
+ count_n <= 0 after g.delay;
+ if rx_sync = '0' then -- and majority = '1' then
+ state_n <= start after g.delay;
+ cr <= '1' after g.delay;
+ sr_n <= (others => '0') after g.delay;
+ fail_n <= (others => '0') after g.delay;
+ end if;
+ when start =>
+ if baud = '1' then
+ if majority /= '0' then
+ state_n <= done after g.delay; -- frame error
+ fail_n(0) <= '1' after g.delay;
+ else
+ state_n <= data after g.delay;
+ end if;
+ sr_n <= (others => '0') after g.delay;
+ end if;
+ when data =>
+ rx_n(count_c) <= majority after g.delay;
+ if baud = '1' then
+ if count_c = (ctr_data_bits(ctr_c) - 1) then
+ count_n <= 0 after g.delay;
+ if ctr_c(ctr_use_parity) = '1' then
+ state_n <= parity after g.delay;
+ else
+ state_n <= stop after g.delay;
+ end if;
+ else
+ count_n <= count_c + 1 after g.delay;
+ end if;
+ sr_n <= (others => '0') after g.delay;
+ end if;
+ when parity =>
+ if baud = '1' then
+ if (ctr_c(ctr_use_parity) = '1') and (majority /= parity(rx_c, ctr_c(ctr_even_parity))) then
+ fail_n(1) <= '1' after g.delay; -- parity error, still process stop bits
+ end if;
+ state_n <= stop after g.delay;
+ sr_n <= (others => '0') after g.delay;
+ end if;
+ when stop =>
+ if baud = '1' then
+ if majority /= '1' then
+ state_n <= done after g.delay; -- frame error
+ fail_n(0) <= '1' after g.delay;
+ elsif count_c = ctr_stop_bits(ctr_c) then
+ state_n <= done after g.delay;
+ else
+ count_n <= count_c + 1 after g.delay;
+ end if;
+ end if;
+ when done => -- The consuming module needs to store rx_c/fail_c immediately
+ we <= '1' after g.delay;
+ state_n <= idle after g.delay;
+ end case;
+
+ if ctr_we = '1' then
+ if not (state_c = idle or state_c = done or state_c = reset) then
+ rx_n <= (others => '0') after g.delay;
+ state_n <= idle after g.delay;
+ we <= '1' after g.delay;
+ fail_n(0) <= '1' after g.delay; -- frame error!
+ end if;
+ ctr_n <= ctr after g.delay;
+ end if;
+ end process;
+end architecture;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use work.uart_pkg.all;
+
+entity uart_tx is
+ generic (
+ g: uart_generics;
+ N: positive;
+ format: std_ulogic_vector(7 downto 0) := uart_8N1;
+ use_cfg: boolean);
+ port (
+ clk: in std_ulogic;
+ rst: in std_ulogic;
+ cr: out std_ulogic;
+ baud: in std_ulogic; -- Pulse at baud
+ tx: out std_ulogic;
+ ok: out std_ulogic;
+ ctr: in std_ulogic_vector(format'range);
+ ctr_we: in std_ulogic;
+ we: in std_ulogic; -- di write enable
+ di: in std_ulogic_vector(N - 1 downto 0));
+end entity;
+
+architecture behaviour of uart_tx is
+ type state is (reset, idle, start, data, parity, stop);
+ signal state_c, state_n: state;
+ signal di_c, di_n: std_ulogic_vector(di'range);
+ signal ctr_c, ctr_n: std_ulogic_vector(ctr'range);
+ signal busy: std_ulogic;
+ signal parity_c, parity_n: std_ulogic;
+ signal count_c, count_n: integer range 0 to 15;
+begin
+ busy <= '0' when state_c = idle else '1' after g.delay;
+ ok <= not busy after g.delay;
+
+ process (clk, rst)
+ procedure reset is
+ begin
+ di_c <= (others => '0') after g.delay;
+ state_c <= reset after g.delay;
+ parity_c <= '0' after g.delay;
+ count_c <= 0 after g.delay;
+ if use_cfg then ctr_c <= (others => '0') after g.delay; end if;
+ end procedure;
+ begin
+ if rst = '1' and g.asynchronous_reset then
+ reset;
+ elsif rising_edge(clk) then
+ if rst = '1' and not g.asynchronous_reset then
+ reset;
+ else
+ di_c <= di_n after g.delay;
+ state_c <= state_n after g.delay;
+ parity_c <= parity_n after g.delay;
+ count_c <= count_n after g.delay;
+ if use_cfg then ctr_c <= ctr_n after g.delay; end if;
+ end if;
+ end if;
+ if not use_cfg then ctr_c <= format after g.delay; end if;
+ end process;
+
+ process (di_c, di, ctr_c, ctr_we, ctr, state_c, we, baud, parity_c, count_c)
+ begin
+ count_n <= count_c after g.delay;
+ state_n <= state_c after g.delay;
+ di_n <= di_c after g.delay;
+ if use_cfg then ctr_n <= ctr_c after g.delay; end if;
+ tx <= '1' after g.delay;
+ cr <= '0';
+
+ if ctr_c(ctr_use_parity) = '1' then
+ parity_n <= parity(di_c, ctr_c(ctr_even_parity)) after g.delay;
+ else
+ parity_n <= '0' after g.delay;
+ end if;
+
+ case state_c is
+ when reset =>
+ state_n <= idle after g.delay;
+ ctr_n <= format after g.delay; -- 8 bits, 1 stop bit, parity off
+ count_n <= 0 after g.delay;
+ parity_n <= '0' after g.delay;
+ di_n <= (others => '0') after g.delay;
+ when idle =>
+ count_n <= 0 after g.delay;
+ if use_cfg and ctr_we = '1' then -- NB. We can either lose data, or control writes
+ ctr_n <= ctr after g.delay;
+ elsif we = '1' then
+ di_n <= di after g.delay;
+ cr <= '1';
+ state_n <= start after g.delay;
+ end if;
+ when start =>
+ tx <= '0' after g.delay;
+ if baud = '1' then
+ state_n <= data after g.delay;
+ end if;
+ when data =>
+ tx <= di_c(count_c) after g.delay;
+ if baud = '1' then
+ if count_c = (ctr_data_bits(ctr_c) - 1) then
+ count_n <= 0 after g.delay;
+ if ctr_c(ctr_use_parity) = '1' then
+ state_n <= parity after g.delay;
+ else
+ state_n <= stop after g.delay;
+ end if;
+ else
+ count_n <= count_c + 1 after g.delay;
+ end if;
+ end if;
+ when parity =>
+ tx <= parity_c after g.delay;
+ if baud = '1' then
+ state_n <= stop after g.delay;
+ end if;
+ when stop =>
+ tx <= '1' after g.delay;
+ if baud = '1' then
+ if count_c = ctr_stop_bits(ctr_c) then
+ count_n <= 0 after g.delay;
+ state_n <= idle after g.delay;
+ else
+ count_n <= count_c + 1 after g.delay;
+ end if;
+ end if;
+ end case;
+ end process;
+end architecture;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.uart_pkg.all;
+
+entity uart_tb is
+ generic(g: uart_generics);
+end entity;
+
+architecture testing of uart_tb is
+ constant clock_period: time := 1000 ms / g.clock_frequency;
+ constant fifo_depth: natural := 8;
+ signal rst, clk: std_ulogic := '1';
+ signal stop: boolean := false;
+ signal loopback: boolean := true;
+ signal tx, rx: std_ulogic;
+ signal di, do: std_ulogic_vector(7 downto 0);
+ signal reg: std_ulogic_vector(15 downto 0);
+ signal clock_reg_tx_we: std_ulogic;
+ signal clock_reg_rx_we: std_ulogic;
+ signal control_reg_we: std_ulogic;
+
+ signal tx_fifo_full: std_ulogic;
+ signal tx_fifo_empty: std_ulogic;
+ signal tx_fifo_we: std_ulogic := '0';
+ signal rx_fifo_full: std_ulogic;
+ signal rx_fifo_empty: std_ulogic;
+ signal rx_fifo_re: std_ulogic := '0';
+begin
+ -- duration: process begin wait for 20000 us; stop <= true; wait; end process;
+ clk_process: process
+ begin
+ rst <= '1';
+ wait for clock_period * 5;
+ rst <= '0';
+ while not stop loop
+ clk <= '1';
+ wait for clock_period / 2;
+ clk <= '0';
+ wait for clock_period / 2;
+ end loop;
+ wait;
+ end process;
+
+ stimulus: process
+ procedure write(data: std_ulogic_vector(di'range)) is
+ begin
+ wait for clock_period * 1;
+ while tx_fifo_full = '1' loop
+ wait for clock_period;
+ end loop;
+ di <= data;
+ tx_fifo_we <= '1';
+ wait for clock_period;
+ tx_fifo_we <= '0';
+ end procedure;
+ begin
+ di <= x"00";
+ wait until rst = '0';
+ wait for clock_period;
+ reg <= x"8080";
+ control_reg_we <= '1';
+ wait for clock_period;
+ control_reg_we <= '0';
+ reg <= x"0036";
+ clock_reg_tx_we <= '1';
+ wait for clock_period;
+ clock_reg_tx_we <= '0';
+ clock_reg_rx_we <= '1';
+ reg <= x"0035";
+ wait for clock_period;
+ clock_reg_rx_we <= '0';
+ wait for clock_period;
+
+ write(x"AA");
+ write(x"BB");
+ write(x"CC");
+ write(x"DD");
+ write(x"EE");
+ write(x"FF");
+ wait for clock_period;
+ while tx_fifo_empty = '0' loop
+ wait for clock_period;
+ end loop;
+ loopback <= false;
+ wait for clock_period * 50000;
+ stop <= true;
+ wait;
+ end process;
+
+ ack: process
+ begin
+ while not stop loop
+ if rx_fifo_empty = '0' then
+ rx_fifo_re <= '1';
+ else
+ rx_fifo_re <= '0';
+ end if;
+ wait for clock_period;
+ end loop;
+ wait;
+ end process;
+ rx <= tx when loopback else '0'; -- loop back test
+ uut: work.uart_pkg.uart_top
+ generic map (
+ clock_frequency => g.clock_frequency,
+ delay => g.delay,
+ asynchronous_reset => g.asynchronous_reset,
+ baud => 115200,
+ format => uart_8N1,
+ fifo_depth => fifo_depth)
+ port map (
+ clk => clk,
+ rst => rst,
+
+ tx => tx,
+ tx_fifo_full => tx_fifo_full,
+ tx_fifo_empty => tx_fifo_empty,
+ tx_fifo_we => tx_fifo_we,
+ tx_fifo_data => di,
+
+ rx => rx,
+ rx_fifo_full => rx_fifo_full,
+ rx_fifo_empty => rx_fifo_empty,
+ rx_fifo_re => rx_fifo_re,
+ rx_fifo_data => do,
+
+ reg => reg,
+ clock_reg_tx_we => clock_reg_tx_we,
+ clock_reg_rx_we => clock_reg_rx_we,
+ control_reg_we => control_reg_we);
+
+end architecture;
+
Index: bitserial/trunk/util.vhd
===================================================================
--- bitserial/trunk/util.vhd (nonexistent)
+++ bitserial/trunk/util.vhd (revision 2)
@@ -0,0 +1,161 @@
+-- File: util.vhd
+-- Author: Richard James Howe
+-- Repository: https://github.com/howerj/bit-serial
+-- License: MIT
+-- Description: Utility module, mostly taken from another project
+-- of mine, .
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use std.textio.all;
+
+package util is
+ -- Not all modules will need every generic specified here, even so it
+ -- is easier to group the common generics in one structure.
+ type common_generics is record
+ clock_frequency: positive; -- clock frequency of module clock
+ delay: time; -- gate delay for simulation purposes
+ asynchronous_reset: boolean; -- use asynchronous reset if true
+ end record;
+
+ constant default_settings: common_generics := (
+ clock_frequency => 100_000_000,
+ delay => 0 ns,
+ asynchronous_reset => true
+ );
+
+ type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
+
+ component single_port_block_ram is
+ generic (g: common_generics;
+ addr_length: positive := 12;
+ data_length: positive := 16;
+ file_name: string := "memory.bin";
+ file_type: file_format := FILE_BINARY);
+ port (
+ clk: in std_ulogic;
+ dwe: in std_ulogic;
+ dre: in std_ulogic;
+ addr: in std_ulogic_vector(addr_length - 1 downto 0);
+ din: in std_ulogic_vector(data_length - 1 downto 0);
+ dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
+ end component;
+
+ function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector;
+end;
+
+package body util is
+ function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector is
+ variable slv: std_ulogic_vector(3 downto 0);
+ begin
+ case hc is
+ when '0' => slv := "0000";
+ when '1' => slv := "0001";
+ when '2' => slv := "0010";
+ when '3' => slv := "0011";
+ when '4' => slv := "0100";
+ when '5' => slv := "0101";
+ when '6' => slv := "0110";
+ when '7' => slv := "0111";
+ when '8' => slv := "1000";
+ when '9' => slv := "1001";
+ when 'A' => slv := "1010";
+ when 'a' => slv := "1010";
+ when 'B' => slv := "1011";
+ when 'b' => slv := "1011";
+ when 'C' => slv := "1100";
+ when 'c' => slv := "1100";
+ when 'D' => slv := "1101";
+ when 'd' => slv := "1101";
+ when 'E' => slv := "1110";
+ when 'e' => slv := "1110";
+ when 'F' => slv := "1111";
+ when 'f' => slv := "1111";
+ when others => slv := "XXXX";
+ end case;
+ assert (slv /= "XXXX") report " not a valid hex character: " & hc severity failure;
+ return slv;
+ end;
+end;
+
+library ieee, work;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use std.textio.all;
+use work.util.all;
+
+entity single_port_block_ram is
+ generic (g: common_generics;
+ addr_length: positive := 12;
+ data_length: positive := 16;
+ file_name: string := "memory.bin";
+ file_type: file_format := FILE_BINARY);
+ port (
+ clk: in std_ulogic;
+ dwe: in std_ulogic;
+ dre: in std_ulogic;
+ addr: in std_ulogic_vector(addr_length - 1 downto 0);
+ din: in std_ulogic_vector(data_length - 1 downto 0);
+ dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
+end entity;
+
+architecture behav of single_port_block_ram is
+ constant ram_size: positive := 2 ** addr_length;
+
+ type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
+
+ impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
+ variable ram_data: ram_type;
+ file in_file: text is in the_file_name;
+ variable input_line: line;
+ variable tmp: bit_vector(data_length - 1 downto 0);
+ variable c: character;
+ variable slv: std_ulogic_vector(data_length - 1 downto 0);
+ begin
+ for i in 0 to ram_size - 1 loop
+ if the_file_type = FILE_NONE then
+ ram_data(i):=(others => '0');
+ elsif not endfile(in_file) then
+ readline(in_file,input_line);
+ if the_file_type = FILE_BINARY then
+ read(input_line, tmp);
+ ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
+ elsif the_file_type = FILE_HEX then -- hexadecimal
+ assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
+ for j in 1 to (data_length/4) loop
+ c:= input_line((data_length/4) - j + 1);
+ slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
+ end loop;
+ ram_data(i) := slv;
+ else
+ report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
+ end if;
+ else
+ ram_data(i) := (others => '0');
+ end if;
+ end loop;
+ file_close(in_file);
+ return ram_data;
+ end function;
+
+ shared variable ram: ram_type := initialize_ram(file_name, file_type);
+
+begin
+ block_ram: process(clk)
+ begin
+ if rising_edge(clk) then
+ if dwe = '1' then
+ ram(to_integer(unsigned(addr))) := din;
+ end if;
+
+ if dre = '1' then
+ dout <= ram(to_integer(unsigned(addr))) after g.delay;
+ else
+ dout <= (others => '0') after g.delay;
+ end if;
+ end if;
+ end process;
+end architecture;
+
+