commit 657a54ba18af7b3b357bb86a1794c681252ceda8 Author: Thomas Fehmel Date: Tue Oct 18 14:21:45 2016 +0200 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd417de --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +### TEX Temps +*.out +*.toc +*.aux +*.log +*.pdf +*.synctex.gz +*.lof +*.lot +*.lol +*.dvi +*.bbl +*.ps +*.blg +*.loc +*.pyg + +### Other Files +*~ +*.kate-swp +*.patch +*.orig + +### Assembler Eclipse Stuff +assembler/.cproject +assembler/.project +assembler/.settings/org.eclipse.cdt.managedbuilder.core.prefs + +### Assembler Project Compiles +assembler/obj/* +assembler/asm +assembler/test.ram +assembler/test.map + +### test program files +*.ram +*.map diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..56251b6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +As of the time of the year 2015, intellectual property ownership of the processor core LT16x32, +its software assembler, the documentation and as well as the various components comprising +the LT16 system on chip lies with the Electronics Design Automation Group, University of Kaiserlsautern, Germany (henceforth the "Owner"). + +The Owner grants the following rights free of charge: + * duplication + * modification, and + * use +for private, educational and academic purposes. + +To obtain the following rights, the Owner needs to be contacted and explicit permission granted: + * redistribution + * republishing +of the original or modified work for commercial, academic or educational purposes, and + * use +for commercial puposes and applications. + +In all cases mentioned above, the orginal author's notices and license must be kept in place and redistributed with any copies made. + +Contact the original authors first in case of doubt to ensure your intended use does not violate this license or get explicit permission to use it in a way not covered or prohibited by this license. + diff --git a/README b/README new file mode 100644 index 0000000..ab33d07 --- /dev/null +++ b/README @@ -0,0 +1,30 @@ + +Setup + +The following Instruction apply if you are intending to build the toolchain for the LT16x32 and associated SoC, and want to create a synthesized bitfile of said SoC. + +It is assumed that: +* you run linux +* have make installed +* have gcc, flex and bison installed +* have inkscape installed +* have all required latex packages installed (install texlive-latex-extra metapackage for ubuntu/Debian) +** packages for openSUSE: texlive-latex,texlive-multirow,texlive-lineno +* pygmetize for minted source code, (python-pygments package in ubuntu/Debian/openSuse) + +1. Making of... +1.1 the assembler + +Change into the 'assembler' directory and run the Makefile with +$ make all + +The LT16x32 assembler should then be present as 'asm' binary executeable. +To integrate this executeable, create a symbolic link in a user directory which exists in your $PATH or directly link to it. + +1.2 the documentation + +Change into the 'documentation' directory and run the Makefile with +$ make all + +A file named 'soc.pdf' should then pop up and be placed in the documentation directory. +It contains information about the the LT16x32 core and assembler. diff --git a/assembler/Makefile b/assembler/Makefile new file mode 100644 index 0000000..8d0778f --- /dev/null +++ b/assembler/Makefile @@ -0,0 +1,104 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf +CC = gcc -g + +IDIR=inc +ODIR=obj +SDIR=src + +CFLAGS = -Wall + +_DEPS = command.h files.h labels.h +DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) + +_OBJS = output.o msg.o check.o label.o main.o handle_o.o handle_oi.o handle_omi.o handle_omr.o handle_omr2.o handle_or2.o handle_or2i.o handle_or3.o handle_ori.o handle_or.o handle_om.o +OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS)) + +_FLEX_OBJ = asm.tab.o lex.yy.o +FLEX_OBJS = $(patsubst %,$(ODIR)/%,$(_FLEX_OBJ)) +_FLEX_COMPILES = asm.tab.c asm.tab.h lex.yy.c +FLEX_COMPILES = $(patsubst %,$(ODIR)/%,$(_FLEX_COMPILES)) + +# All Target +all: $(ODIR) asm + +$(ODIR): + mkdir -p $(ODIR) + +# Tool invocations +asm: flex bison $(FLEX_OBJS) $(OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + $(CC) -o "asm" -I"inc/" $(OBJS) $(FLEX_OBJS) $(CFLAGS) + @echo 'Finished building target: $@' + @echo ' ' + +bison: $(SDIR)/asm.y + bison -o obj/asm.tab.c -d $(SDIR)/asm.y +flex: $(SDIR)/asm.l + flex -o obj/lex.yy.c $(SDIR)/asm.l + +# Object Files + +#obj/%.o: src/%.c $(DEPS) +# $(CC) -c -o $@ $< $(CFLAGS) + +obj/asm.tab.c: bison +obj/asm.tab.h: bison +obj/lex.yy.c : flex + +$(ODIR)/output.o: $(SDIR)/output.c + $(CC) -c $(CFLAGS) -o $@ $< +$(ODIR)/msg.o: $(SDIR)/msg.c + $(CC) -c $(CFLAGS) -o $@ $< +$(ODIR)/check.o: $(SDIR)/check.c + $(CC) -c $(CFLAGS) -o $@ $< + +$(ODIR)/main.o: $(SDIR)/main.c + $(CC) -c -o $@ $< $(CFLAGS) + +$(ODIR)/label.o: $(SDIR)/label.c + $(CC) -c $(CFLAGS) -o $@ $< + +$(ODIR)/handle_or3.o: $(SDIR)/handle_or3.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_or2i.o: $(SDIR)/handle_or2i.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_ori.o: $(SDIR)/handle_ori.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_omr2.o: $(SDIR)/handle_omr2.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_omi.o: $(SDIR)/handle_omi.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_omr.o: $(SDIR)/handle_omr.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_oi.o: $(SDIR)/handle_oi.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_o.o: $(SDIR)/handle_o.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_or2.o: $(SDIR)/handle_or2.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_or.o: $(SDIR)/handle_or.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/handle_om.o: $(SDIR)/handle_om.c + $(CC) -c -o $@ $< $(CFLAGS) + +$(ODIR)/asm.tab.o: $(ODIR)/asm.tab.c + $(CC) -c -o $@ $< $(CFLAGS) +$(ODIR)/lex.yy.o: $(ODIR)/lex.yy.c + $(CC) -c -o $@ $< $(CFLAGS) + +# Other Targets +clean: + -$(RM) $(OBJS) $(FLEX_OBJS) $(FLEX_COMPILES) asm + -@echo ' ' + +.PHONY: all clean dependents +.SECONDARY: + +-include ../makefile.targets diff --git a/assembler/inc/check.h b/assembler/inc/check.h new file mode 100644 index 0000000..d126fa4 --- /dev/null +++ b/assembler/inc/check.h @@ -0,0 +1,33 @@ +/* + * This file declares functions for + * - checking instruction parameters for their validity + */ + +#ifndef CHECK_H_ +#define CHECK_H_ + +/* + * returns a valid register number or throws error if r out of range + * r: number of register to be checked + */ +int reg(int r); + +/* + * returns a valid 8bit signed value or throws error if imm out of range + * imm: immediate to be checked + */ +int signed8(int imm); + +/* + * returns a valid 4bit unsigned value or throws error if imm out of range + * imm: immediate to be checked + */ +int unsigned4(int imm); + +/* + * returns a valid 32bit signed value or throws error if imm out of range + * imm: immediate to be checked + */ +int word(int imm); + +#endif /* CHECK_H_ */ diff --git a/assembler/inc/global.h b/assembler/inc/global.h new file mode 100644 index 0000000..529ccb1 --- /dev/null +++ b/assembler/inc/global.h @@ -0,0 +1,85 @@ +/* + * This file + * - defines globally used constants + * - defines enum types + * - declares globally used variables + */ + +#ifndef GLOBAL_H_ +#define GLOBAL_H_ + +#include + +// maximal filename length +#define MAX_FILENAME_LENGTH (128); +// nop instruction for 16bit +#define nop16 (0b0000000000000000) +// number of link register +#define lr_num (13) + + +// all supported modes +typedef enum { + mode_eq, mode_neq, mode_ge, mode_gg, mode_le, mode_ll, + + mode_cond_true, mode_cond_unconditional +} opmode_t; + +// all supported (pseudo) instructions and directives +typedef enum { + op_add, op_sub, op_and, op_or, op_xor, op_lsh, op_rsh, op_addi, + + op_cmp, op_ssr, + + op_ldr, op_ld08, op_ld16, op_ld32, op_st08, op_st16, op_st32, + + op_brt, op_br, op_call, op_trap, op_reti, + + op_tst, + + op_mov, op_nop, op_ret, op_clr, + + op_word, // used for direct placement of words (=32 bit) + op_addr, // used for setting of current address (forward movement only) + op_align, // used for aligning next instruction/immediate value +} op_t; + +// input file +extern FILE* f_in; +// output file +extern FILE* f_out; +// map file, 0 if unused +extern FILE* f_map; + +// input filename +char* inputfile; + +// do verbose output, boolean value +int verbose; +// automatically align 32bit instructions, boolean value +int autoalign; +// fill branch delay slot with nop, boolean value +int fillbds; +// continue even after error, boolean value +int continueonerror; + +// error has happened in first run, boolean value +int errorhappened; + +// buffer of the currently parsed line +char linebuf[500]; + +/* in first run, boolean value + * 1 if in first run + * 0 if in second run + */ +int isfirstrun; + +// current address (byte address) +int address; + +// destructor, closes programs and cleans up memory +// exitvalue: value for exit +void destruct(); + +#endif /* GLOBAL_H_ */ diff --git a/assembler/inc/handle.h b/assembler/inc/handle.h new file mode 100644 index 0000000..80e1648 --- /dev/null +++ b/assembler/inc/handle.h @@ -0,0 +1,99 @@ +/* + * This file declares functions for + * - handling of instructions + */ + +#ifndef HANDLE_H_ +#define HANDLE_H_ + +#include "global.h" + +/* + * outputs instruction to output for instructions width or3 instruction type + * opcode: opcode of instruction + * r1: register 1 + * r2: register 2 + * r3: register 3 + */ +void handle_or3(op_t opcode, int r1, int r2, int r3); + +/* + * outputs instruction to output for instructions width ori instruction type + * opcode: opcode of instruction + * r1: register 1 + * imm: immediate + */ +void handle_ori(op_t opcode, int r1, int imm); + +/* + * outputs instruction to output for instructions width omr2 instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + * r2: register 2 + */ +void handle_omr2(op_t opcode, opmode_t mode, int r1, int r2); + +/* + * outputs instruction to output for instructions width omi instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * imm: immediate + */ +void handle_omi(op_t opcode, opmode_t mode, int imm); + +/* + * outputs instruction to output for instructions width omr instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + */ +void handle_omr(op_t opcode, opmode_t mode, int r1); + +/* + * outputs instruction to output for instructions width oi instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * imm: immediate + */ +void handle_oi(op_t opcode, int imm); + +/* + * outputs instruction to output for instructions width o instruction type + * opcode: opcode of instruction + */ +void handle_o(op_t opcode); + +/* + * outputs instruction to output for instructions width or instruction type + * opcode: opcode of instruction + * r1: register 1 + */ +void handle_or(op_t opcode, int r1); + +/* + * outputs instruction to output for instructions width or2 instruction type + * opcode: opcode of instruction + * r1: register 1 + * r2: register 2 + */ +void handle_or2(op_t opcode, int r1, int r2); + +/* + * outputs instruction to output for instructions width or2i instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + * r2: register 2 + * imm: immediate + */ +void handle_or2i(op_t opcode, int r1, int r2, int imm); + +/* + * outputs instruction to output for instructions width om instruction type + * opcode: opcode of instruction + * mode: mode of instruction + */ +void handle_om(op_t opcode, opmode_t mode); + +#endif /* HANDLE_H_ */ diff --git a/assembler/inc/label.h b/assembler/inc/label.h new file mode 100644 index 0000000..d0dfc06 --- /dev/null +++ b/assembler/inc/label.h @@ -0,0 +1,51 @@ +/* + * This file declares functions and declares variables for + * - handling of labels + * and defines constants, types. + */ + +#ifndef LABEL_H_ +#define LABEL_H_ + +// maximum length of label names +#define LABEL_MAX_NAME_LENGTH (64) + +// struct of a label item in list +typedef struct { + // name of the label + char name[LABEL_MAX_NAME_LENGTH]; + // address the label points to + int address; + // next item in list + void* next; +} label_t; +// head of list +label_t* label_listhead; + +/* + * adds a label to the list + * name: name of the label + * address: address the label points to + */ +void label_add(char* name, int address); + +/* + * returns absolute address of a label + * name: name of the label + * return: absolute address of label or -1 if label not found + */ +int label_absolute(char* name); + +/* + * returns relative address of a label + * name: name of the label + * return: relative address of label or -1 if label not found + */ +int label_relative(char* name); + +/* + * frees the allocated space used for the list of labels + */ +void label_free(); + +#endif /* LABEL_H_ */ diff --git a/assembler/inc/msg.h b/assembler/inc/msg.h new file mode 100644 index 0000000..29b4765 --- /dev/null +++ b/assembler/inc/msg.h @@ -0,0 +1,21 @@ +/* + * This file declares functions for + * - checking instruction parameters for range + */ + +#ifndef MSG_H_ +#define MSG_H_ + +/* + * verbose output (if flag is set) + * msg: verbose message + */ +void yyverbose(char* msg); + +/* + * error handler + * msg: error message + */ +void yyerror(char* msg); + +#endif /* MSG_H_ */ diff --git a/assembler/inc/output.h b/assembler/inc/output.h new file mode 100644 index 0000000..c9408a5 --- /dev/null +++ b/assembler/inc/output.h @@ -0,0 +1,36 @@ +/* + * This file declares functions for + * - writing to output file + * - writing to map file + */ + +#ifndef OUTPUT_H_ +#define OUTPUT_H_ + +/* + * outputs a number of length bits, given in instr to the output stream and inserts a linebreak after each 32bit + * instr: number to be printed + * length: number of bits to be printed + */ +void output_instr(int instr, int length); + +/* + * outputs a number of 16bits and updates address + * instr: number to be printed + */ +void output_instr16(int instr); + +/* + * outputs a number of 32bits and updates address + * instr: number to be printed + */ +void output_instr32(int instr); + +/* + * outputs a line to the mapfile (if specified and if in first run) + * s: string to be put to mapfile + */ +void output_line(char* s); + + +#endif /* OUTPUT_H_ */ diff --git a/assembler/src/asm.l b/assembler/src/asm.l new file mode 100644 index 0000000..86e10c5 --- /dev/null +++ b/assembler/src/asm.l @@ -0,0 +1,105 @@ +%option nodefault yylineno + +%{ +#include +#include "../inc/msg.h" +#include "../inc/label.h" +#include "../inc/global.h" +#include "../inc/output.h" +#include "../obj/asm.tab.h" + +void yyerror(char *s); + +union yylval { + op_t op; + int i; +}; + +%} + +LABELNAME [_a-zA-Z][_a-zA-Z0-9]* + +%% + +\n.* { strncpy(linebuf, yytext+1, sizeof(linebuf)); /* save the next line */ + yyless(1); /* give back all but the \n to rescan */ + output_line(linebuf); return EOL; + } +\r\n.* { + strncpy(linebuf, yytext+2, sizeof(linebuf)); /* save the next line */ + yyless(2); /* give back all but the \r\n to rescan */ + output_line(linebuf); return EOL; + } +<> { yyterminate(); return EOL; } + +[ \t] { /* ignore whitespace*/ } +[,] { return ','; } + +"//".*$ { /* comment */ } + +[r][0-9]+ { yylval.i = atoi(yytext+1); return REGISTER; } +(sp) { yylval.i = 12; return REGISTER; } +(lr) { yylval.i = 13; return REGISTER; } +(sr) { yylval.i = 14; return REGISTER; } +(pc) { yylval.i = 15; return REGISTER; } +[+-]?"0x"?[0-9A-F]+ { yylval.i = strtol(yytext, 0, 0); return IMMEDIATE; } + +(add) { yylval.op = op_add; return MNEMONIC; } +(sub) { yylval.op = op_sub; return MNEMONIC; } +(and) { yylval.op = op_and; return MNEMONIC; } +(or) { yylval.op = op_or; return MNEMONIC; } +(xor) { yylval.op = op_xor; return MNEMONIC; } +(lsh) { yylval.op = op_lsh; return MNEMONIC; } +(rsh) { yylval.op = op_rsh; return MNEMONIC; } +(addi) { yylval.op = op_addi; return MNEMONIC; } +(cmp) { yylval.op = op_cmp; return MNEMONIC; } +(ssr) { yylval.op = op_ssr; return MNEMONIC; } + +(ldr) { yylval.op = op_ldr; return MNEMONIC; } +(ld08) { yylval.op = op_ld08; return MNEMONIC; } +(ld16) { yylval.op = op_ld16; return MNEMONIC; } +(ld32) { yylval.op = op_ld32; return MNEMONIC; } +(st08) { yylval.op = op_st08; return MNEMONIC; } +(st16) { yylval.op = op_st16; return MNEMONIC; } +(st32) { yylval.op = op_st32; return MNEMONIC; } + +(brt) { yylval.op = op_brt; return MNEMONIC; } +(br) { yylval.op = op_br; return MNEMONIC; } +(call) { yylval.op = op_call; return MNEMONIC; } +(trap) { yylval.op = op_trap; return MNEMONIC; } +(reti) { yylval.op = op_reti; return MNEMONIC; } + +(tst) { yylval.op = op_tst; return MNEMONIC; } + +(mov) { yylval.op = op_mov; return MNEMONIC; } +(nop) { yylval.op = op_nop; return MNEMONIC; } +(ret) { yylval.op = op_ret; return MNEMONIC; } +(clr) { yylval.op = op_clr; return MNEMONIC; } + +(\.word) { yylval.op = op_word; return MNEMONIC; } +(\.address) { yylval.op = op_addr; return MNEMONIC; } +(\.align) { yylval.m = op_align; return MNEMONIC; } + +(eq) { yylval.m = mode_eq; return MODE; } +(neq) { yylval.m = mode_neq; return MODE; } +(gg) { yylval.m = mode_gg; return MODE; } +(ge) { yylval.m = mode_ge; return MODE; } +(ll) { yylval.m = mode_ll; return MODE; } +(le) { yylval.m = mode_le; return MODE; } + +(true) { yylval.m = mode_cond_true; return MODE; } +(always) { yylval.m = mode_cond_unconditional; return MODE; } + +{LABELNAME} { strcpy(yylval.s, yytext); return LABEL; } +(\>{LABELNAME}) { yylval.i = label_relative(yytext+1); return IMMEDIATE; } +(\={LABELNAME}) { yylval.i = label_absolute(yytext+1); return IMMEDIATE; } + + +: { return ':'; } +. { yyerror("unexpected input"); } + +%% + + +int yywrap() { return 1; } + diff --git a/assembler/src/asm.y b/assembler/src/asm.y new file mode 100644 index 0000000..70e7fde --- /dev/null +++ b/assembler/src/asm.y @@ -0,0 +1,59 @@ +%{ +#include +#include "../inc/msg.h" +#include "../inc/handle.h" +#include "../inc/label.h" +#include "../inc/global.h" +%} + +%union { + int i; + op_t op; + opmode_t m; + char s[32]; +} + +%token EOL + +%token MNEMONIC +%token MODE +%token REGISTER +%token IMMEDIATE +%token LABEL + +%% + +line: + | line lbldef + | line r3-line EOL + | line r2-line EOL + | line ri-line EOL + | line r2i-line EOL + | line mr2-line EOL + | line mi-line EOL + | line mr-line EOL + | line i-line EOL + | line o-line EOL + | line or-line EOL + | line om-line EOL + | line EOL + | line error-line EOL + ; + +r3-line: MNEMONIC REGISTER ',' REGISTER ',' REGISTER { handle_or3($1, $2, $4, $6); } +r2-line: MNEMONIC REGISTER ',' REGISTER { handle_or2($1, $2, $4); } +ri-line: MNEMONIC REGISTER ',' IMMEDIATE { handle_ori($1, $2, $4); } +r2i-line: MNEMONIC REGISTER ',' REGISTER ',' IMMEDIATE { handle_or2i($1, $2, $4, $6); } +mr2-line: MNEMONIC MODE REGISTER ',' REGISTER { handle_omr2($1, $2, $3, $5); } +mi-line: MNEMONIC MODE IMMEDIATE { handle_omi($1, $2, $3); } +mr-line: MNEMONIC MODE REGISTER { handle_omr($1, $2, $3); } +i-line: MNEMONIC IMMEDIATE { handle_oi($1, $2); } +o-line: MNEMONIC { handle_o($1); } +or-line: MNEMONIC REGISTER { handle_or($1, $2); } +om-line: MNEMONIC MODE { handle_om($1, $2); } +lbldef: LABEL ':' { label_add($1, address); } +error-line: error { } + + +%% + diff --git a/assembler/src/check.c b/assembler/src/check.c new file mode 100644 index 0000000..53a4321 --- /dev/null +++ b/assembler/src/check.c @@ -0,0 +1,70 @@ +/* + * This file implements functions for + * - checking instruction parameters for their validity + */ +#include +#include "../inc/msg.h" +#include "../inc/global.h" + +/* + * returns a valid register number or throws error if r out of range + * r: number of register to be checked + */ +int reg(int r) { + if ((r >= 0) && (r <= 15)) { + // in valid range + return r; + } else { + // out of valid range + yyerror("register number out of range"); + return 0; + } +} + +/* + * returns a valid 8bit signed value or throws error if imm out of range + * imm: immediate to be checked + */ +int signed8(int imm) { + if ((imm >= -128) && (imm <= 127)) { + // in valid range + return imm & 0xFF; + } else { + // out of valid range + yyerror( + "immediate value out of bounds. expecting 8bit signed immediate."); + return 0; + } +} + +/* + * returns a valid 4bit unsigned value or throws error if imm out of range + * imm: immediate to be checked + */ +int unsigned4(int imm) { + if ((imm >= 0) && (imm <= 15)) { + // in valid range + return imm & 0x0F; + } else { + // out of valid range + yyerror( + "immediate value out of bounds. expecting 4bit unsigned immediate."); + return 0; + } +} + +/* + * returns a valid 32bit signed value or throws error if imm out of range + * imm: immediate to be checked + */ +int word(int imm) { + if ((imm >= -2147483648) && (imm <= 2147483647)) { + // in valid range + return imm; + } else { + // out of valid range + yyerror( + "immediate value out of bounds. expecting 32bit signed immediate."); + return 0; + } +} diff --git a/assembler/src/handle_o.c b/assembler/src/handle_o.c new file mode 100644 index 0000000..bc866ba --- /dev/null +++ b/assembler/src/handle_o.c @@ -0,0 +1,72 @@ +/* + * This file implements functions for + * - handling of instructions of type o + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width o instruction type + * opcode: opcode of instruction + */ +void handle_o(op_t opcode) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_reti: // reti instruction + // opcode: bct + instr |= (0b1100) << 12; + // mode: reti + instr |= (0b0000) << 8; + // output instruction + output_instr16(instr); + break; + + case op_ret: // return instruction (unconditional) + // model with branch always to lr + // opcode: branch + instr |= (0b1100) << 12; + // mode: to register + instr |= (0b0110) << 8; + // register a: LR + instr |= lr_num << 4; + // output instruction + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + case op_nop: // no operation instruction + // model with or r0, r0, r0 + // opcode: or + instr |= (0b0000) << 12; + // all registers: r0 + // output instruction + output_instr16(instr); + break; + + case op_align: // make address be word-aligned + if ((address % 4) != 0) { + // not word-aligned, insert nop + output_instr16(nop16); + } else { + // already word-aligned, put verbose message + yyverbose("Already aligned, ignoring .align directive."); + } + break; + + default: // invalid opcode for o-instruction + yyerror("opcode not compatible with o syntax"); + break; + } +} diff --git a/assembler/src/handle_oi.c b/assembler/src/handle_oi.c new file mode 100644 index 0000000..de206d1 --- /dev/null +++ b/assembler/src/handle_oi.c @@ -0,0 +1,90 @@ +/* + * This file implements functions for + * - handling of instructions of type i + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width oi instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * imm: immediate + */ +void handle_oi(op_t opcode, int imm) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_word: // add immediate word + + // immediate word + instr = word(imm); + // output instruction + output_instr32(instr); + break; + + case op_addr: // move to new address + if (imm >= address) { + // if new address is larger than current address + while (imm - 2 >= address) { + // add nop until next new address is equal to immediate value + output_instr16(nop16); + } + } else { + // new address smaller than current address + // backward setting of address not possible + yyerror("can't move backwards with .address"); + } + break; + + case op_trap: // trap instruction + // opcode: bct + instr |= (0b1100) << 12; + // mode: trap + instr |= (0b1100) << 8; + // immediate: irq number + instr |= signed8(imm) << 0; + // output + output_instr16(instr); + break; + + case op_br: // branch instruction to immediate (unconditional) + // opcode: bct + instr |= (0b1100) << 12; + // immediate: branch target + instr |= signed8(imm) << 0; + // mode: branch and unconditional to immediate + instr |= (0b0100) << 8; + // output + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + case op_call: // call instruction to immediate (unconditional) + // opcode: bct + instr |= (0b1100) << 12; + // immediate: call target + instr |= signed8(imm) << 0; + // mode: call unconditional to immediate + instr |= (0b1000) << 8; + // output + output_instr16(instr); + break; + + default: + // invalid opcode for oi-instruction + yyerror("opcode not compatible with i syntax"); + break; + } +} diff --git a/assembler/src/handle_om.c b/assembler/src/handle_om.c new file mode 100644 index 0000000..9a34c9a --- /dev/null +++ b/assembler/src/handle_om.c @@ -0,0 +1,55 @@ +/* + * This file implements functions for + * - handling of instructions of type om + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width om instruction type + * opcode: opcode of instruction + * mode: mode of instruction + */ +void handle_om(op_t opcode, opmode_t mode) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + + case op_ret: // return instruction + // model with branch to lr + // opcode: branch + instr |= (0b1100) << 12; + // mode: to register and condition + switch (mode) { + case mode_cond_true: // if true + instr |= (0b0111) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b0110) << 8; + break; + default: // invalid mode for branch instruction + yyerror("mode invalid for ret instruction."); + } + // register a: LR + instr |= lr_num << 4; + // output instruction + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + default: // invalid opcode for o-instruction + yyerror("opcode not compatible with om syntax"); + break; + } +} diff --git a/assembler/src/handle_omi.c b/assembler/src/handle_omi.c new file mode 100644 index 0000000..0603d4e --- /dev/null +++ b/assembler/src/handle_omi.c @@ -0,0 +1,74 @@ +/* + * This file implements functions for + * - handling of instructions of type omi + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width omi instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * imm: immediate + */ +void handle_omi(op_t opcode, opmode_t mode, int imm) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_br: // branch instruction to immediate + // opcode: bct + instr |= (0b1100) << 12; + // immediate: branch target + instr |= signed8(imm) << 0; + // mode: branch and (un)conditional to immediate + switch (mode) { + case mode_cond_true: // if true + instr |= (0b0101) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b0100) << 8; + break; + default: // invalid mode for branch instruction + yyerror("mode invalid for branch instruction."); + } + // output + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + case op_call: // call instruction to immediate + // opcode: bct + instr |= (0b1100) << 12; + // immediate: call target + instr |= signed8(imm) << 0; + // mode: call (un)conditional to immediate + switch (mode) { + case mode_cond_true: // if true + instr |= (0b1001) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b1000) << 8; + break; + default: // invalid mode for branch instruction + yyerror("mode invalid for call instruction."); + } + // output + output_instr16(instr); + break; + + default: // invalid opcode for omi-instruction + yyerror("opcode not compatible with mi syntax"); + break; + } +} diff --git a/assembler/src/handle_omr.c b/assembler/src/handle_omr.c new file mode 100644 index 0000000..54fb3fa --- /dev/null +++ b/assembler/src/handle_omr.c @@ -0,0 +1,100 @@ +/* + * This file implements functions for + * - handling of instructions of type omr + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width omr instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + */ +void handle_omr(op_t opcode, opmode_t mode, int r1) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_brt: // branch to table instruction + // opcode: branch to table + instr |= (0b1100) << 12; + // register a: branch target register + instr |= reg(r1) << 4; + // mode: branch to table (un)conditional to register + switch (mode) { + case mode_cond_true: // if true + instr |= (0b0011) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b0010) << 8; + break; + default: // invalid mode for branch to table instruction + yyerror("mode invalid for branch to table instruction."); + } + // output + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + case op_br: // branch instruction to register + // opcode: bct + instr |= (0b1100) << 12; + // register a: branch target register + instr |= reg(r1) << 4; + // mode: branch to table (un)conditional to register + switch (mode) { + case mode_cond_true: // if true + instr |= (0b0111) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b0110) << 8; + break; + default: // invalid mode for branch instruction + yyerror("mode invalid for branch instruction."); + } + // output + output_instr16(instr); + + // fill branch delay with nop if flag is set + if (fillbds) { + yyverbose("filled branch delay slot with nop."); + output_instr16(nop16); + } + break; + + case op_call: // call instruction to register + // opcode: bct + instr |= (0b1100) << 12; + // register a: call target + instr |= reg(r1) << 4; + // mode: call (un)conditional to register + switch (mode) { + case mode_cond_true: // if true + instr |= (0b1011) << 8; + break; + case mode_cond_unconditional: // always + instr |= (0b1010) << 8; + break; + default: // invalid mode for call instruction + yyerror("mode invalid for call instruction."); + } + // output + output_instr16(instr); + break; + + default: // invalid opcode for omr-instruction + yyerror("opcode not compatible with mr syntax"); + break; + } +} diff --git a/assembler/src/handle_omr2.c b/assembler/src/handle_omr2.c new file mode 100644 index 0000000..245a315 --- /dev/null +++ b/assembler/src/handle_omr2.c @@ -0,0 +1,64 @@ +/* + * This file implements functions for + * - handling of instructions of type omr2 + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width omr2 instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + * r2: register 2 + */ +void handle_omr2(op_t opcode, opmode_t mode, int r1, int r2) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_cmp: // compare instruction + // opcode: compare + instr |= (0b1000) << 12; + // register a: first register + instr |= r1 << 4; + // register b: second register + instr |= r2 << 0; + // mode + switch (mode) { + case mode_eq: // equal + instr |= (0b0000) << 8; + break; + case mode_neq: // not equal + instr |= (0b1000) << 8; + break; + case mode_gg: // greater than + instr |= (0b0010) << 8; + break; + case mode_ge: // greater than or equal + instr |= (0b0001) << 8; + break; + case mode_ll: // less than + instr |= (0b1001) << 8; + break; + case mode_le: // less than or equal + instr |= (0b1010) << 8; + break; + default: // invalid mode for compare instruction + yyerror("mode invalid for call instruction."); + break; + } + // output + output_instr16(instr); + break; + + default: // invalid opcode for omr2-instruction + yyerror("opcode not compatible with omr2 syntax"); + break; + } +} diff --git a/assembler/src/handle_or.c b/assembler/src/handle_or.c new file mode 100644 index 0000000..526b506 --- /dev/null +++ b/assembler/src/handle_or.c @@ -0,0 +1,39 @@ +/* + * This file implements functions for + * - handling of instructions of type or + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width or instruction type + * opcode: opcode of instruction + * r1: register 1 + */ +void handle_or(op_t opcode, int r1) { + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_clr: // clear register, model as xor r1, r1, r1 + // opcode: cor + instr |= (0b0100) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 1 + instr |= reg(r1) << 0; + // output + output_instr16(instr); + break; + + default: // invalid opcode for or-instruction + yyerror("opcode not compatible with or syntax"); + break; + } +} diff --git a/assembler/src/handle_or2.c b/assembler/src/handle_or2.c new file mode 100644 index 0000000..22f6501 --- /dev/null +++ b/assembler/src/handle_or2.c @@ -0,0 +1,130 @@ +/* + * This file implements functions for + * - handling of instructions of type or2 + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width or2 instruction type + * opcode: opcode of instruction + * r1: register 1 + * r2: register 2 + */ +void handle_or2(op_t opcode, int r1, int r2) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_mov: // move instruction, model with or r1, r2, r2 + // opcode: or + instr |= (0b0000) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // register a: register 2 + instr |= reg(r2) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_ld08: // load byte instruction + // opcode: mem + instr |= (0b1011) << 12; + // mode: load byte + instr |= (0b0000) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_ld16: // load halfword + // opcode: mem + instr |= (0b1011) << 12; + // mode: load halfword + instr |= (0b0001) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_ld32: // load word + // opcode: mem + instr |= (0b1011) << 12; + // mode: load word + instr |= (0b0010) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_st08: // store byte + // opcode: mem + instr |= (0b1011) << 12; + // mode: store byte + instr |= (0b1000) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_st16: // store halfword + // opcode: mem + instr |= (0b1011) << 12; + // mode: store halfword + instr |= (0b1001) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_st32: // store word + // opcode: mem + instr |= (0b1011) << 12; + // mode: store word + instr |= (0b1010) << 8; + // register a: register 1 + instr |= reg(r1) << 4; + // register b: register 2 + instr |= reg(r2) << 0; + // output + output_instr16(instr); + break; + + case op_tst: // test and set + // opcode: test and set instruction + instr |= (0b1001) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // register a: register 2 + instr |= reg(r2) << 4; + // output + output_instr16(instr); + break; + + default: // invalid opcode for ri-instruction + yyerror("opcode not compatible with ri syntax"); + break; + } +} diff --git a/assembler/src/handle_or2i.c b/assembler/src/handle_or2i.c new file mode 100644 index 0000000..04170c6 --- /dev/null +++ b/assembler/src/handle_or2i.c @@ -0,0 +1,63 @@ +/* + * This file implements functions for + * - handling of instructions of type or2i + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width or2i instruction type + * opcode: opcode of instruction + * mode: mode of instruction + * r1: register 1 + * r2: register 2 + * imm: immediate + */ +void handle_or2i(op_t opcode, int r1, int r2, int imm) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_lsh: // left shift instruction + // immediate must not be 0 + if (imm == 0) + yyerror("lsh with immediate=0 not allowed"); + + // opcode: left shift instruction + instr |= (0b0101) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // register a: register 2 + instr |= reg(r2) << 4; + // immediate: imm-1 (+1 in processor) + instr |= unsigned4(imm - 1) << 0; + // output + output_instr16(instr); + break; + + case op_rsh: // right shift instruction + // immediate must not be zero + if (imm == 0) + yyerror("rsh with immediate=0 not allowed"); + // opcode: right shift instruction + instr |= (0b0110) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // register a: register 2 + instr |= reg(r2) << 4; + // immediate: imm-1 (+1 in processor) + instr |= unsigned4(imm - 1) << 0; + // output + output_instr16(instr); + break; + + default: // invalid opcode for or2i-instruction + yyerror("opcode not compatible with or2i syntax"); + break; + } +} diff --git a/assembler/src/handle_or3.c b/assembler/src/handle_or3.c new file mode 100644 index 0000000..dced981 --- /dev/null +++ b/assembler/src/handle_or3.c @@ -0,0 +1,74 @@ +/* + * This file implements functions for + * - handling of instructions of type or3 + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width or3 instruction type + * opcode: opcode of instruction + * r1: register 1 + * r2: register 2 + * r3: register 3 + */ +void handle_or3(op_t opcode, int r1, int r2, int r3) { + + // instruction to be build + int instr = 0; + + // here, scheme is simple and always the same + + // register d: register 1 + instr |= r1 << 8; + // register a: register 2 + instr |= r2 << 4; + // register b: register 3 + instr |= r3 << 0; + + // opcode + switch (opcode) { + case op_add: // add instruction + // opcode + instr |= (0b0011) << 12; + // output + output_instr16(instr); + break; + + case op_sub: // subtract instruction + // opcode + instr |= (0b0001) << 12; + // output + output_instr16(instr); + break; + + case op_and: // bitwise and instruction + // opcode + instr |= (0b0010) << 12; + // output + output_instr16(instr); + break; + + case op_or: // bitwise or instruction + // opcode + instr |= (0b0000) << 12; + // output + output_instr16(instr); + break; + + case op_xor: // bitwise xor instruction + // opcode + instr |= (0b0100) << 12; + // output + output_instr16(instr); + break; + + default: // invalid opcode for or3-instruction + yyerror("opcode not compatible with or3 syntax"); + break; + } +} diff --git a/assembler/src/handle_ori.c b/assembler/src/handle_ori.c new file mode 100644 index 0000000..83f025d --- /dev/null +++ b/assembler/src/handle_ori.c @@ -0,0 +1,50 @@ +/* + * This file implements functions for + * - handling of instructions of type oi + */ + +#include +#include "../inc/msg.h" +#include "../inc/output.h" +#include "../inc/check.h" +#include "../inc/global.h" + +/* + * outputs instruction to output for instructions width ori instruction type + * opcode: opcode of instruction + * r1: register 1 + * imm: immediate + */ +void handle_ori(op_t opcode, int r1, int imm) { + + // instruction to be build + int instr = 0; + + switch (opcode) { + case op_addi: // add immediate instruction + // opcode: add immediate instruction + instr |= (0b0111) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // immediate: value to add + instr |= signed8(imm) << 0; + // output + output_instr16(instr); + break; + + case op_ldr: // load pc-relative instruction + // opcode: load pc-relative instruction + instr |= (0b1010) << 12; + // register d: register 1 + instr |= reg(r1) << 8; + // immediate: pc-offset + instr |= signed8(imm) << 0; + // output + output_instr16(instr); + break; + + default: // invalid opcode for ori-instruction + yyerror("opcode not compatible with ori syntax"); + break; + } +} diff --git a/assembler/src/label.c b/assembler/src/label.c new file mode 100644 index 0000000..59762ff --- /dev/null +++ b/assembler/src/label.c @@ -0,0 +1,175 @@ +/* + * This file implements functions for + * - handling of labels + */ + +#include +#include +#include +#include "../inc/msg.h" +#include "../inc/label.h" +#include "../inc/global.h" + +/* + * adds a label to the list + * name: name of the label + * address: address the label points to + */ +void label_add(char* name, int address) { + // new element inserted + label_t* newelement; + // tail of list + label_t* tail; + + // verbose message: added label (in second run) + if (verbose) { + char msg[64 + LABEL_MAX_NAME_LENGTH]; + char tmpname[LABEL_MAX_NAME_LENGTH]; + strncpy(tmpname, name, LABEL_MAX_NAME_LENGTH); + sprintf(msg, "adding label '%s' at address '0x%08x'.", tmpname, + address); + yyverbose(msg); + } + + // don't add labels in second run + if (!isfirstrun) { + return; + } + + // check if label already exists + if (label_absolute(name) != -1) { + yyerror("label already exists."); + return; + } + + // allocate memory for new label + newelement = malloc(sizeof(label_t)); + if (newelement == 0) { + fprintf(stderr, "no free memory."); + return; + } + + // copy data to new label + strncpy(newelement->name, name, LABEL_MAX_NAME_LENGTH); + newelement->address = address; + newelement->next = 0; + + // find tail of list + if (label_listhead == 0) { + // empty list, insert as list head + label_listhead = newelement; + + } else { + + // list not empty find tail + tail = label_listhead; + while (tail->next != 0) { + tail = tail->next; + } + + // set next item pointer + tail->next = newelement; + } + + // output information to map file + if (f_map) { + fprintf(f_map, "0x%x: %s\n", newelement->address, newelement->name); + } + +} + +/* + * returns absolute address of a label + * name: name of the label + * return: absolute address of label or -1 if label not found + */ +int label_absolute(char* name) { + // tail of search + label_t* tail; + + if (label_listhead == 0) { + // if empty list, label is not in list, return -1 + return -1; + + } else { + // list not empty find tail + + // start search at list head + tail = label_listhead; + + while (1) { + + if (strcmp(tail->name, name) == 0) { + // name of search tail matches searched name + + // return address + return tail->address; + } + + if (tail->next != 0) { + // end of list not reached, update tail pointer + tail = tail->next; + + } else { + // end of list, not found + + if (!isfirstrun) { // second run: label must be found. + yyerror("label not found."); + } + + // return -1, as label is not found + return -1; + } + } + } + + // program does not reach this point due to earlier returns +} + +/* + * returns relative address of a label + * name: name of the label + * return: relative address of label or -1 if label not found + */ +int label_relative(char* name) { + // absolute address of label + int absolute; + + // find absolute address + absolute = label_absolute(name); + + if (absolute > 0) { + // label found, calculate relative address + return (absolute - address) / 2 - 1; + } else { + // label not found, error message already prompted in label_absolute + return -1; + } +} + +/* + * frees the allocated space used for the list of labels + */ +void label_free() { + // current element pointer + label_t* ptr; + // next element pointer + label_t* next; + + // start at list head + ptr = label_listhead; + + while (ptr != 0) { + // walk through list until end of list reached + + // store next pointer + next = ptr->next; + // delete current item + free(ptr); + // proceed in list + ptr = next; + } + + // reset list head + label_listhead = 0; +} diff --git a/assembler/src/main.c b/assembler/src/main.c new file mode 100644 index 0000000..b5b5e96 --- /dev/null +++ b/assembler/src/main.c @@ -0,0 +1,232 @@ +/* + * This file implements the main function + */ + +#include +#include +#include +#include + +#include "../inc/msg.h" +#include "../inc/label.h" +#include "../inc/global.h" +#include "../inc/output.h" +#include "../obj/asm.tab.h" + +// reference to linenumber supplied by flex/bison +extern int yylineno; +// reference to yyrestart function supplied by flex/bison +void yyrestart(FILE* inputfile); + +// file variable definitions and initialization +FILE* f_in = 0; +FILE* f_out = 0; +FILE* f_map = 0; + +/* + * main function + * argc: number of arguments + * argv: arguments + */ +int main(int argc, char **argv) { + // output filename + char* output = 0; + // mapfile filename + char* map = 0; + + // index of command line argument + int option_index = 0; + // character of command line argument + int c; + + static struct option long_options[] = { { "verbose", 0, 0, 0 }, { + "autoalign", 0, 0, 0 }, { "fillbds", 0, 0, 0 }, { + "continue-on-error", 0, 0, 0 }, { 0, 0, 0, 0 } }; + + // reset flags + verbose = 0; + autoalign = 0; + continueonerror = 0; + errorhappened = 0; + + while (1) { + // iterate through all command line options + + // reset option_index + option_index = 0; + + // get next option + c = getopt_long(argc, argv, "vm:o:", long_options, &option_index); + if (c == -1) + // no more options available, end loop + break; + + // check which option it was + switch (c) { + case 0: // long option + if (strcmp(long_options[option_index].name, "verbose") == 0) { + // verbose flag + verbose = 1; + + } else if (strcmp(long_options[option_index].name, "autoalign") + == 0) { + // auto-align flag + autoalign = 1; + + } else if (strcmp(long_options[option_index].name, "fillbds") + == 0) { + // fill branch delay slot flag + fillbds = 1; + + } else if (strcmp(long_options[option_index].name, + "continue-on-error") == 0) { + // continue on error flag + continueonerror = 1; + + } else { + // unknown option + fprintf(stderr, "error: unknown command line option \"%s\"\n", + long_options[option_index].name); + destruct(EXIT_FAILURE); + } + break; + + case 'v': + // verbose flag (short version) + verbose = 1; + break; + + case 'm': + // map file + map = (char*) optarg; + break; + + case 'o': + // output file + output = (char*) optarg; + break; + + default: + // unknown option + fprintf(stderr, "error: unknown command line option \"%s\"\n", + long_options[option_index].name); + destruct(EXIT_FAILURE); + } + } + + // Check non-option command line arguments + if (optind < argc) { + // one option still available (input) + inputfile = argv[optind++]; + + if (optind < argc) { + // more than one option still available, only one input file supported + fprintf(stderr, "too many input files specified.\n"); + destruct(EXIT_FAILURE); + } + + } else { + // no option available (no input file) + fprintf(stderr, "no input file specified.\n"); + destruct(EXIT_FAILURE); + } + + // Check if output file is specified + if (output == 0) { + // output file not specified + fprintf(stderr, "no output file specified.\n"); + destruct(EXIT_FAILURE); + } + + // Open all (specified) files + + // open input file (must be specified, is checked before) + f_in = fopen(inputfile, "r"); + if (!f_in) { + // could not open input file + fprintf(stderr, "error: could not open input file %s\n", inputfile); + perror(inputfile); + destruct(EXIT_FAILURE); + } + + // open output file (must be specified, is checked before) + f_out = fopen(output, "w"); + if (!f_out) { + // could not open output file + fprintf(stderr, "error: could not open output file %s\n", output); + perror(output); + destruct(EXIT_FAILURE); + } + + // open map file if specified + if (map != 0) { + // mapfile is specified + f_map = fopen(map, "w"); + if (!f_map) { + // could not open mapfile + fprintf(stderr, "error: could not open map file %s\n", map); + perror(map); + destruct(EXIT_FAILURE); + } + } + + // reset variables + address = 0; + label_listhead = 0; + + // start parsing f_in - first run + isfirstrun = 1; + yyrestart(f_in); + yyparse(); + + // go back to first character in input file + fseek(f_in, 0, SEEK_SET); + yylineno = 1; + + // start parsing f_in - second run + address = 0; + isfirstrun = 0; + yyrestart(f_in); + yyparse(); + + // fill last word + if (address % 4 == 2) { + output_instr16(nop16); + } + + // destruction + + // final message + if (verbose) { + printf("%s: : info: output written to %s.\n", inputfile, output); + } + + // exit main + if (!errorhappened) { + // no error happened + destruct(EXIT_SUCCESS); + } else { + // error happend in between + destruct(EXIT_FAILURE); + } + + return 0; // suppress warning, actual program exit in destruct +} + +// destructor, closes programs and cleans up memory +// exitvalue: value for exit +void destruct(int exitvalue) { + if (f_in) { + fclose(f_in); + } + if (f_out) { + fclose(f_out); + } + if (f_map) { + fclose(f_map); + } + + label_free(); + + exit(exitvalue); +} diff --git a/assembler/src/msg.c b/assembler/src/msg.c new file mode 100644 index 0000000..f99d91f --- /dev/null +++ b/assembler/src/msg.c @@ -0,0 +1,47 @@ +/* + * This file implements functions for + * - checking instruction parameters for range + */ + +#include +#include +#include "../inc/global.h" + +// reference to linenumber supplied by flex +extern int yylineno; + +/* + * verbose output (if flag is set) + * msg: verbose message + */ +void yyverbose(char* msg) { + if (verbose) { + // if verbose flag is set + + if (!isfirstrun) { + // output verbose messages in second run + printf("%s:% 3i: info: %s (\"%s\")\n", inputfile, yylineno, msg, + linebuf); + } + } +} + +/* + * error handler + * msg: error message + */ +void yyerror(char *s) { + + if ((!continueonerror) || (!isfirstrun)) { + // output error messages if either stop at error or in second run + fprintf(stderr, "%s:% 3i: error: %s (\"%s\")\n", inputfile, yylineno, s, + linebuf); + } + + // set error happened flag + errorhappened = 1; + if (!continueonerror) { + // if stop on error, stop + destruct(EXIT_FAILURE); + } +} diff --git a/assembler/src/output.c b/assembler/src/output.c new file mode 100644 index 0000000..38e6cd9 --- /dev/null +++ b/assembler/src/output.c @@ -0,0 +1,105 @@ +/* + * This file implements functions for + * - writing to output file + * - writing to map file + */ + +#include +#include "../inc/msg.h" +#include "../inc/global.h" + +/* + * outputs a number of length bits, given in instr to the output stream and inserts a linebreak after each 32bit + * instr: number to be printed + * length: number of bits to be printed + */ +void output_instr(int instr, int length) { + // index of outputted bit + int i; + + for (i=length-1; i>=0; i--) { + // iterate through length bits + + if(instr & (1< 0$, listing \ref{lst:ovf_add}). +In subtractions an overflow occured, if both operands are from opposing sign and the minuend's sign differ from the result's (i.e. $(-8) - 5 > 0$ or $5 - (-4) < 0$, listing \ref{lst:ovf_sub}). +This follows normal rules for signed calculations, which are as well used in other processor designs. + +\begin{vhdl}[Overflow Generation for Addition]{lst:ovf_add} +c_out <= (in_a(reg_width-1) AND in_b(reg_width-1) + AND not result(reg_width-1)) + + OR (not in_a(reg_width-1) AND not in_b(reg_width-1) + AND result(reg_width-1)); +\end{vhdl} +\begin{vhdl}[Overflow Generation for Subtraction]{lst:ovf_sub} +c_out <= (in_a(reg_width-1) AND not in_b(reg_width-1) + AND not result(reg_width-1)) + + OR (not in_a(reg_width-1) AND in_b(reg_width-1) + AND result(reg_width-1)); +\end{vhdl} + +\subsection{Program Counter} +Register \inlineasm{r15} is reserved for the program counter and is read only from the user interface. Write accesses are ignored. It may be altered with special instructions such as branch and call and in interrupt request situations by the processor itself. diff --git a/documentation/documentation.tex b/documentation/documentation.tex new file mode 100644 index 0000000..245b805 --- /dev/null +++ b/documentation/documentation.tex @@ -0,0 +1,212 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% To make formatting easy tell LaTeX what kind of document you want to write +% by changing the according {} to {#1} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Which language do you want to write in +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%English +\newcommand{\EN}[1]{#1} +%German +\newcommand{\DE}[1]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% For print single or double page? +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\newcommand{\single}[1]{#1} +\newcommand{\double}[1]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Now this is followed by a lot of page and command definitions. For the beginning you +% should be able to continue where you find the next comment section like this one. +% However, you might want to take a look a the definitions sometime to be able to use +% them. Of course you can also add the defintions you needed yourself. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\single{\documentclass[12pt,a4paper,oneside,german,english]{book}} +\double{\documentclass[12pt,a4paper,twoside,german,english]{book}} + +\usepackage[ngerman,english]{babel} +%\usepackage[draft,breaklinks=true,colorlinks=false,dvips,bookmarks,pdffitwindow,pdfcenterwindow=true,pdfstartview=Fit]{hyperref} +%\usepackage[breaklinks=true,colorlinks=false,dvips,bookmarks,pdffitwindow,pdfcenterwindow=true,pdfstartview=Fit]{hyperref} +\usepackage{setspace} +\usepackage{cite} +\usepackage{float,times} +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{amsmath,amsthm,latexsym} +\usepackage[dvips]{epsfig} +\usepackage{subfigure} +\usepackage{rotating} + +\usepackage{minted} +\usepackage{newfloat} +\usepackage{xspace} + +\usepackage{xcolor} +\usepackage{afterpage} +\usepackage{multirow} +\usepackage{array} + +%! put the new-command after the inputenc package use, so 'ü' will not be shown as abomination ASCII -TF + +\input{globalcommands.tex} +\newcommand{\DocuTitle}{Documentation to the LT16x32} %TODO: can not use \procname here, why so ever... +%\newcommand{\DiplTitleGerman}{Dokumentation für den LT16x32} + +% format page layout. + +\setlength{\topmargin}{0cm} +\setlength{\textwidth}{15cm} +\setlength{\textheight}{22cm} +\setlength{\oddsidemargin}{1cm} +\setlength{\evensidemargin}{0cm} + +\setlength{\headheight}{15pt} +% \setlength{\voffset}{-0cm} +% \setlength{\topmargin}{0cm} +% \setlength{\headheight}{0.54cm} +% \setlength{\textheight}{23cm} +% % \setlength{\headsep}{1.5cm} +% %\setlength{\hoffset}{-2.54cm} +% \setlength{\hoffset}{0cm} +% \setlength{\oddsidemargin}{0.46cm} +% \setlength{\evensidemargin}{0.46cm} +% \setlength{\textwidth}{15cm} +% \setlength{\marginparsep}{0cm} +% \setlength{\marginparwidth}{1.54cm} + +\setcounter{secnumdepth}{3} + + +% \setlength{\footskip}{1cm} +% \setlength{\parindent}{0cm} +% \setlength{\parskip}{1em} + +\usepackage{fancyhdr} +\pagestyle{fancy} +\fancyhead{} % clear all header fields +%\fancyhead[LO, RE]{\slshape \nouppercase{\leftmark}} % chapter titles +%\fancyhead[LE, RO]{\slshape \nouppercase{\leftmark}\\\nouppercase{\rightmark}} % section titles +\double{\fancyhead[LE]{\slshape \nouppercase{\leftmark}}} % chapter titles +\fancyhead[RO]{\slshape \nouppercase{\rightmark}} % section titles +\fancyfoot{} % clear all footer fields +\fancyfoot[C]{\thepage} + + +\usepackage[%dvips, + colorlinks=false, + bookmarks, + pdffitwindow, + pdfcenterwindow=true, + pdfstartview=Fitpdftex, + pdfauthor={Lasse Schnepel}, + pdftitle={\DocuTitle}, + pdfsubject={LT16x32 Documentation}, % one sentence summery + pdfkeywords={Processor,Firmware-based Verification,Architecture design}, %comma-seperated keywords + pdfproducer={Latex with hyperref}, + pdfcreator={}]{hyperref} + +\begin{document} + +%\lhead[\fancyplain{}{\thepage}] {\fancyplain{}{\rightmark}} +%\chead[\fancyplain{}{}] {\fancyplain{}{}} +%\rhead[\fancy{}{\rightmark}] {\fancy{}{\thepage}} +%\rhead[\fancyplain{}{\rightmark}] {\fancyplain{}{\thepage}} +%\lfoot[\fancyplain{}{}] {\fancyplain{\tstamp}{\tstamp}} +%\cfoot[\fancy{\thepage}{}] {\fancy{\thepage}{}} +%\cfoot[\fancyplain{\thepage}{}] {\fancyplain{\thepage}{}} +%\rfoot[\fancyplain{\tstamp} {\tstamp}] {\fancyplain{}{}} +% \fancyhf{} %delete the current section for header and footer +% \fancyhead[LE,RO]{\bfseries\thepage} +% \fancyhead[LO]{\bfseries\rightmark} +% \fancyhead[RE]{\bfseries\leftmark} +% \renewcommand{\headrulewidth}{0.5pt} +% % make space for the rule +% \fancypagestyle{plain}{% +% \fancyhead{} %get rid of the headers on plain pages +% %\renewcommand{\headrulewidth}{0} % and the line +% } + +\EN{\selectlanguage{english}} +\DE{\selectlanguage{german}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Here you have to start editing +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\title{\DiplTitle} + \author{Lasse Schnepel} +\pagenumbering{arabic} +\hyphenation{Bit-ebenen Gateprop Bit-ebene Fanin Boole-sche + Partial-produkt-generator + Code-inspektion + Verifika-tions-ablauf + IPC-Verifika-tions-ablauf + Abhangig-keiten +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% title page +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\frontmatter +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% titel page +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\thispagestyle{empty} + +\begin{center} + \mbox{} + \vspace{2cm} + \Large{Documentation of the \procname} + \vspace{1cm} + +\normalsize + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Put the current year here +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Kaiserslautern, 2014 \\ + \vfill +\end{center} + +\tableofcontents + +\mainmatter + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Now this is followed by your chapters +% this usually starts with introduction and Fundamentals and then +% continues with whatever you need or did +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\input{content} + +\backmatter +\listoffigures +\listoftables +\listofcodefloat %triggers Errors for me, for whatever reason, but the pdf is generated nonetheless -TF + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Choose your Bibtex Style File (here alphadin.bst) and references. +% Hint: For references make a local link refs2 to our jabref +% directory "/import/jabref/refs2.bib" +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\bibliographystyle{alphadin} +\bibliography{refs3} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Curriculum Vitae +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%\selectlanguage{german} +%\input{cv.tex} +%\selectlanguage{english} + +\end{document} diff --git a/documentation/figures/Makefile b/documentation/figures/Makefile new file mode 100644 index 0000000..1ab71b9 --- /dev/null +++ b/documentation/figures/Makefile @@ -0,0 +1,11 @@ +SVGS= $(wildcard *.svg) +IMGS= $(SVGS:.svg=.pdf) + + +all: $(IMGS) + +%.pdf: %.svg + inkscape -z -T -A $@ $< + +clean: + rm -f *.pdf diff --git a/documentation/figures/block_core.svg b/documentation/figures/block_core.svg new file mode 100644 index 0000000..694d8b5 --- /dev/null +++ b/documentation/figures/block_core.svg @@ -0,0 +1,714 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + ProgramCounter + + + + + + + + + + + Instruction Memory + Data Memory + Interrup Controller + + + + Decoder + ControlPath + DataPath + + Pipeline Stages + 1 + 2 + 3 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/figures/block_cp.svg b/documentation/figures/block_cp.svg new file mode 100644 index 0000000..80b83cf --- /dev/null +++ b/documentation/figures/block_cp.svg @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T-flag + Stage 1Control Signals + Stage 2Control Signals + Stage 3Control Signals + Decoder Input Signals + pc_comb + + + + + diff --git a/documentation/figures/block_dp.svg b/documentation/figures/block_dp.svg new file mode 100644 index 0000000..9917f79 --- /dev/null +++ b/documentation/figures/block_dp.svg @@ -0,0 +1,1438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + s3.register_write_data_select + + + + + dmem_read_data + alu_result_s3 + immediate_sign_ext + write_data + + + + + reg_write_data_sized_calc + hardfault + + + + registerfile + true_writeenable + true_out + + s3.tflag_write_enable + write_en + write_num + a_num + a_out + b_out + ovf_writeenable + ovf_in + pc_in + b_num + + + + + + + + s3.ovflag_write_enable + alu_ovfflag_s3 + + + + + + forward_register_a + forward_register_b + + alu + + forward_tflag + + + s2.alu_input_data_select + + immediate_signext + + + + + + + + data_out + t_out + ovf_out + mode + in_a + in_b + + s2.alu_mode + s1.register_read_number_a + s1.register_read_number_b + pc_value_s2 + s3.register_write_number + s3.register_write_enable + + + + + pc_value_s2 + immediate_signext_s2 & '0' + ldr_address + + s2.memory_read_addr_select + + + + regfile_reg_a_fwd + regfile_reg_b_fwd + + out_dmem.read_address + + s3.tflag_write_data_select + + + NOT dmem_dataa[7] + alu_tflag_s3 + + true_in + + s2.memory_write_data_select + + + regfile_reg_b_fwd + + out_dmem.write_data + + + + 0x80 + + + in_dmem.read_data + dmemORx80 + + + + + alu_result_s3 + alu_tflag_s3 + alu_ovfflag_s3 + + in_pc.value + + + + out_cp.s2.tflag + + + + + + diff --git a/documentation/figures/block_pc.svg b/documentation/figures/block_pc.svg new file mode 100644 index 0000000..6e657f1 --- /dev/null +++ b/documentation/figures/block_pc.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + cp.summand_select + + dp.register_value + + + + + + + dp.immediate_value + + 0x01 + 0x02 + cp.instruction_width + + + + + + cp.mode + + + + + + + + + pc_value + + diff --git a/documentation/figures/decoder_fsm_states.svg b/documentation/figures/decoder_fsm_states.svg new file mode 100644 index 0000000..a6b3ad7 --- /dev/null +++ b/documentation/figures/decoder_fsm_states.svg @@ -0,0 +1,877 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + normal + + copyPCtoLR + + irq_pushSR + + irq_pushLR + + + irq_setSR + + + irq_setPC + + + reti_incSP1 + + reti_popLR + + + reti_incSP2 + + + reti_popSR + + + + + + + + call + interruptrequest + reti + + + reset + + reset2 + + + + + all otherinstructions + + diff --git a/documentation/figures/decoder_schematic.svg b/documentation/figures/decoder_schematic.svg new file mode 100644 index 0000000..8f83803 --- /dev/null +++ b/documentation/figures/decoder_schematic.svg @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + Pre + FSM + 16bit + 32bit + shadow + MUX + + + instructionmemory + controlpath + + + diff --git a/documentation/figures/fpga_sc_slices.svg b/documentation/figures/fpga_sc_slices.svg new file mode 100644 index 0000000..b36176a --- /dev/null +++ b/documentation/figures/fpga_sc_slices.svg @@ -0,0 +1,527 @@ + +image/svg+xml8 +16 +32 +0 +50 +100 +150 +200 +250 +300 +350 +400 +Speed +Area +Register Width +Occupied Slices + \ No newline at end of file diff --git a/documentation/figures/fpga_sc_speed.svg b/documentation/figures/fpga_sc_speed.svg new file mode 100644 index 0000000..4c28570 --- /dev/null +++ b/documentation/figures/fpga_sc_speed.svg @@ -0,0 +1,527 @@ + +image/svg+xml8 +16 +32 +0 +20 +40 +60 +80 +100 +120 +140 +160 +Speed +Area +Register Width +Maximum Frequency + \ No newline at end of file diff --git a/documentation/figures/fundamentals_generalsystemarch.svg b/documentation/figures/fundamentals_generalsystemarch.svg new file mode 100644 index 0000000..150aae2 --- /dev/null +++ b/documentation/figures/fundamentals_generalsystemarch.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Memory + further I/O + + + + Control + Datapath + Processor + Bus + + diff --git a/documentation/figures/memory_hierarchy.svg b/documentation/figures/memory_hierarchy.svg new file mode 100644 index 0000000..8ee0145 --- /dev/null +++ b/documentation/figures/memory_hierarchy.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + ProcessorCore + + Level 1Cache + + Level 2Cache + + Level 3Cache + + Memory(RAM) + + SecondaryStorage(HDD) + + + + + + + diff --git a/documentation/figures/signal_dmem_read.svg b/documentation/figures/signal_dmem_read.svg new file mode 100644 index 0000000..bd7796e --- /dev/null +++ b/documentation/figures/signal_dmem_read.svg @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + clk + + address + en + data + ready + + + + + + + + + + + + + + + + + + + diff --git a/documentation/figures/signal_dmem_write.svg b/documentation/figures/signal_dmem_write.svg new file mode 100644 index 0000000..5d29500 --- /dev/null +++ b/documentation/figures/signal_dmem_write.svg @@ -0,0 +1,503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + clk + + + + + address + data + en + + + + + + + + + diff --git a/documentation/figures/signal_imem.svg b/documentation/figures/signal_imem.svg new file mode 100644 index 0000000..629b30c --- /dev/null +++ b/documentation/figures/signal_imem.svg @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + clk + + address + en + instruction + ready + + + + + + + + + + + + + + + + + + + diff --git a/documentation/figures/signal_irq_req.svg b/documentation/figures/signal_irq_req.svg new file mode 100644 index 0000000..59b6f10 --- /dev/null +++ b/documentation/figures/signal_irq_req.svg @@ -0,0 +1,511 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + clk + + num, prio, nmi + req + ack + + + + + + + + + ... + ... + ... + ... + + diff --git a/documentation/figures/signal_irq_trap.svg b/documentation/figures/signal_irq_trap.svg new file mode 100644 index 0000000..c44bdc3 --- /dev/null +++ b/documentation/figures/signal_irq_trap.svg @@ -0,0 +1,503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + clk + + instruction + + + trap + number + + + req + + + + + + diff --git a/documentation/figures/signal_mem_interlacing.svg b/documentation/figures/signal_mem_interlacing.svg new file mode 100644 index 0000000..179bbf8 --- /dev/null +++ b/documentation/figures/signal_mem_interlacing.svg @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + clk + address + instruction + imem en + dmem read en + dmem write en + + + + + + + + memory active + + + imem + dmem + imem + dmem + imem + dmem + + + + + + + + + diff --git a/documentation/figures/signal_template.svg b/documentation/figures/signal_template.svg new file mode 100644 index 0000000..6d2e796 --- /dev/null +++ b/documentation/figures/signal_template.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + clk + + + diff --git a/documentation/figures/soc_overview.svg b/documentation/figures/soc_overview.svg new file mode 100644 index 0000000..11dde41 --- /dev/null +++ b/documentation/figures/soc_overview.svg @@ -0,0 +1,557 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + Bus Interconnect + LT16x32core wrapper + InstructionMemory + InterruptController + I/OController + + + + InstructionFetch Line + DataBus + + + + + + + + + + Master IF + Slave IF + No Slave IF yet + Slave IFs + stall + irq + + + + + DataMemory + Toplevel Entity + + + + + + Slave IF + InterruptsSources + I/O lines + + + + diff --git a/documentation/figures/soc_overview2.svg b/documentation/figures/soc_overview2.svg new file mode 100644 index 0000000..631d5b2 --- /dev/null +++ b/documentation/figures/soc_overview2.svg @@ -0,0 +1,516 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + Bus Interconnect + LT16x32core wrapper + Host Bridge + Memory + InterruptController + I/O + + + + InstructionFetch Line + DataBus + + + + + + + + + + + + + + + + Master IF + Master IF + Slave IF + SlaveIF + Slave IF + Slave IFs + stall + irq + HostInterface + + diff --git a/documentation/globalcommands.tex b/documentation/globalcommands.tex new file mode 100644 index 0000000..c78dac4 --- /dev/null +++ b/documentation/globalcommands.tex @@ -0,0 +1,130 @@ +%%%%%%%%%%%% +%%% MINTED +%%%%%%%%%%%% + +\DeclareFloatingEnvironment[ + fileext=loc, + listname=List of Listings, + name=Listing, + placement=htp, +]{codefloat} + +\newenvironment{vhdl}[2][] + {\codefloat[htb] + \if\relax\detokenize{#1}\relax\else\caption{#1}\fi + \if\relax\detokenize{#2}\relax\else\label{#2}\fi + \minted[%linenos, + %numbersep=5pt, + tabsize=3, + frame=lines, + framesep=2mm, + fontsize=\footnotesize] + {vhdl}} + {\endminted + \endcodefloat} +\newenvironment{asm}[2][] + {\codefloat[htb] + \if\relax\detokenize{#1}\relax\else\caption{#1}\fi + \if\relax\detokenize{#2}\relax\else\label{#2}\fi + \minted[%linenos, + %numbersep=5pt, + tabsize=3, + frame=lines, + framesep=2mm, + fontsize=\footnotesize] + {c}} + {\endminted + \endcodefloat} + +%%%%%%%%%%%% +%%% COMMENTS AND TODO-MARKERS +%%%%%%%%%%%% + +% \newcommand{\comment}[3]{\marginpar{\textcolor{#2}{Comment: #1}}\textcolor{#2}{\textit{[#1: #3]}}} +% \newcommand{\TF}[1]{\comment{TF}{orange}{#1}} +% \newcommand{\LS}[1]{\comment{LS}{blue}{#1}} +% +% \newcommand{\qn}{\todo{qn!}} +% \newcommand{\sectodo}{\todo{Still todo.}} +% \newcommand{\seccheck}{\marginpar{\textcolor{orange}{reread}}} +% \newcommand{\secthomas}{\marginpar{\textcolor{green}{thomas}}} +% \newcommand{\secdone}{\marginpar{\textcolor{gray}{done}}} +% %\newcommand{\todo}[1]{\pagecolor{red!10}\afterpage{\nopagecolor}\textcolor{red}{\textit{[#1]}}\marginpar{\textcolor{red}{\textbf{TODO}}}} +% \newcommand{\todo}[1]{\textcolor{red}{\textit{[#1]}}\marginpar{\textcolor{red}{\textbf{TODO}}}} +% +% +% %%% BLANK COMMANDS FOR PUBLISHING +% \newcommand{\publish}[1]{} +% \renewcommand{\publish}[1]{#1} % TODO: uncomment this line before printing! +% +% \publish{\renewcommand{\comment}[3]{}} +% \publish{\renewcommand{\TF}[1]{}} +% \publish{\renewcommand{\LS}[1]{}} +% \publish{\renewcommand{\qn}{}} +% \publish{\renewcommand{\sectodo}{}} +% \publish{\renewcommand{\seccheck}{}} +% \publish{\renewcommand{\secthomas}{}} +% \publish{\renewcommand{\secdone}{}} +% \publish{\renewcommand{\todo}[1]{}} + +\newcommand{\comment}[3]{\marginpar{\textcolor{#2}{Comment: #1}}\textcolor{#2}{\textit{[#1: #3]}}} +\newcommand{\TF}[1]{\comment{TF}{red}{#1}} +\newcommand{\TS}[1]{\comment{TS}{blue}{#1}} +\newcommand{\FP}[1]{\comment{TS}{orange}{#1}} + +%%%%%%%%%%%% +%%% LOGIC OPERATORS +%%%%%%%%%%%% + +\newcommand{\logicxor}{\texttt{XOR}\xspace} +\newcommand{\logicor}{$||$\xspace}%TODO: does not show up as OR +\newcommand{\logicand}{\&\xspace} + +%%%%%%%%%%%% +%%% STUFF +%%%%%%%%%%%% + +\newcommand{\mem}[1]{*#1\xspace} +\newcommand{\x}{--\xspace} + +%%%%%%%%%%%% +%%% NAMES +%%%%%%%%%%%% + +\newcommand{\procname}{\textsl{LT16x32}\xspace} + +%%%%%%%%%%%% +%%% FORMAT SHORTCUTS +%%%%%%%%%%%% + +\newcommand{\floatplace}{[ht]} + +\newcommand{\tc}[1]{\textbf{#1}} + +\newcommand{\hex}[1]{#1} +\newcommand{\bits}[1]{#1} + +\newcommand{\filename}[1]{{\small\texttt{#1}}} +\newcommand{\command}[1]{{\small\texttt{#1}}} +\newcommand{\inlinevhdl}[1]{{\small\texttt{#1}}} %TODO with syntax highlighting and check for $\_$ +\newcommand{\inlinec}[1]{{\small\texttt{#1}}} %TODO with syntax highlighting and check for $\_$ +\newcommand{\inlineasm}[1]{{\small\texttt{#1}}} %TODO with syntax highlighting and check for $\_$ + +\newcommand{\instruction}[7]{ +\subsubsection{#1} +\label{instr_#2} +\begin{description} +\nolistskip +\item[Opcode:] \texttt{#3} +\item[Assembler:] \inlineasm{#4} +\item[Operation:] #5 +\item[C-Equivalent:] \inlinec{#6} +\item[Status Register:] #7 +\end{description} +} + + +%%%%%%%%%%%% +%%% TEX WORKAROUNDS +%%%%%%%%%%%% +\newcommand{\nolistskip}{\itemsep-3pt} diff --git a/documentation/guides.tex b/documentation/guides.tex new file mode 100644 index 0000000..98c2175 --- /dev/null +++ b/documentation/guides.tex @@ -0,0 +1,34 @@ +\chapter{Guides} + +\section{How to implement a lookup or branch table} +Due to the limitation of the \verb=ldr= instruction, +addressing large fields of constants with it is not feasible, +especially if those constants are refered to by more than one part of the program. + +This can be circumvented by using the assemblers directive \verb|=labelname| to store a pointer to a labels location (See Section~\ref{sec:AssemblerDirectives}). +Pointers to data in memory can be stored conviently close to an \verb=ldr= instruction, +making the access to the memory content via a pointer based load or store instruction possible. + +The most common use of this mechanic is the lookup table. +An example is given in Listing~\ref{lst:ldr_useage}. + +\begin{asm}[Example on indirect LDR use]{lst:ldr_useage} +.align +lookup_table: + .word 0x0001 + .word 0x0010 +//... +// large amounts of code and/or data +//... + +.align +lookuptable_ptr: + .word =lookup_table +//... + ldr rX , >lookuptable_ptr +//... + ld32 rY,rX // load from pointer + addi rX, 4 + ld32 rZ,rX // load from pointer with offset +//... +\end{asm} diff --git a/documentation/instructionset.tex b/documentation/instructionset.tex new file mode 100644 index 0000000..ef70646 --- /dev/null +++ b/documentation/instructionset.tex @@ -0,0 +1,359 @@ +\chapter{Assembler and Instructions} + +\section{Processor Instructions} +The \procname features a RISC instruction set with 16bit instructions and is prepared to be extended with 32bit and allows multicycle instructions. +In 16bit instructions, the first nibble (4bits) of the instruction code is the opcode determining the operation. +The opcode \bits{1111} is reserved for 32bit instructions which are always are word aligned. + +\subsection{Instruction Format} +Several different instruction formats are used in the \procname. +As at the moment, no 32bit instruction is implemented, this section describes instruction formats for 16bit instructions only. +Each halfword is split up into four nibbles (each of a size of 4bits), whose meaning can be seen in Table \ref{tbl:instr_formatnibbles}. + +\begin{table} +\caption{16bit Instruction Formats} +\label{tbl:instr_formatnibbles} +\begin{center} +\begin{tabular}{|l||c|c|c|c||p{0.2\textwidth}|} +\hline +Format & 15-12 & 11-8 & 7-4 & 3-0 & Example Uses\\ +\hline\hline +Three Registers & opcode & Rd & Ra & Rb & Calculations\\ +\hline +4bit Immediate & opcode & Rd & Ra & Imm(3-0) & Shift\\ +\hline +8bit Immediate & opcode & Rd & Imm(7-4) & Imm(3-0) & Add Immediate, Load PC-Relative\\ +\hline +Mode with Register & opcode & Mode & Ra & Rb & Compare, Load/Store\\ +\hline +Mode with Immediate & opcode & Mode & Imm(7-4) & Imm(3-0) & Branch/Call to Immediate\\ +\hline +\end{tabular} +\end{center} +\end{table} + +\subsection{List of available Instructions} +\label{sec:instructionlist} +The following instructions are supported: +\paragraph{Arithmetic Operations} +\begin{itemize} +\nolistskip +\item \hyperref[instr_add]{Signed Addition} +\item \hyperref[instr_sub]{Signed Subtraction} +\item \hyperref[instr_addi]{Signed Addition with Immediate} +\end{itemize} +\paragraph{Bitwise/Logic Operations} +\begin{itemize} +\nolistskip +\item \hyperref[instr_and]{Bitwise AND} +\item \hyperref[instr_or]{Bitwise OR} +\item \hyperref[instr_xor]{Bitwise XOR} +\item \hyperref[instr_lsh]{Logic Shift Left} +\item \hyperref[instr_rsh]{Logic Shift Right} +\item \hyperref[instr_cmp]{Compare} +\end{itemize} +\paragraph{Memory Operations} +\begin{itemize} +\nolistskip +\item \hyperref[instr_ldr]{Load PC Relative} +\item \hyperref[instr_ld]{Load Data from Pointer} +\item \hyperref[instr_st]{Store Data to Pointer} +\end{itemize} +\paragraph{Branch/Call/Trap Operations} +\begin{itemize} +\nolistskip +\item \hyperref[instr_bri]{Branch to Offset} +\item \hyperref[instr_brr]{Branch to Register} +\item \hyperref[instr_calli]{Call to Offset} +\item \hyperref[instr_callr]{Call to Register} +\item \hyperref[instr_trap]{Trap} +\item \hyperref[instr_reti]{Return from Interrupt} +\item \hyperref[instr_brt]{Branch to Table} +\end{itemize} +\paragraph{Miscellaneous Operations} +\begin{itemize} +\nolistskip +\item \hyperref[instr_tst]{Test and Set} +\end{itemize} + +\instruction{Signed Addition}{add} + {0011 dddd aaaa bbbb} + {add rd, ra, rb} + {Registers ra and rb are treated as two signed numbers and are added. The result is stored in rd.} + {rd = ra + rb;} + {The overflow flag is updated.} + +\instruction{Signed Subtraction}{sub} + {0001 dddd aaaa bbbb} + {add rd, ra, rb} + {Registers ra and rb are treated as two signed numbers and are subtracted. The result is stored in rd.} + {rd = ra - rb;} + {The overflow flag is updated.} + +\instruction{Bitwise AND}{and} + {0010 dddd aaaa bbbb} + {and rd, ra, rb} + {Registers ra and rb are treated as bit masks and are anded with each other. The result is stored in rd.} + {rd = ra \& rb;} + {No flag is updated.} + +\instruction{Bitwise OR}{or} + {0000 dddd aaaa bbbb} + {or rd, ra, rb} + {Registers ra and rb are treated as bit masks and are ored with each other. The result is stored in rd.} + {rd = ra | rb;} + {No flag is updated.} + +\instruction{Bitwise XOR}{xor} + {0100 dddd aaaa bbbb} + {xor rd, ra, rb} + {Registers ra and rb are treated as bit masks and are xored with each other. The result is stored in rd.} + {rd = ra $\hat\ $ rb;} + {No flag is updated.} + +\instruction{Logic Shift Left}{lsh} + {0101 dddd aaaa bbbb} + {lsh rd, ra, imm} + {Register ra is treated as bit masks and shifted to the left by imm bits, ra is filled with zeroes. imm is treated as unsigned number. The result is stored in rd. Internally, imm is incremented by one, which is compensated for in the assembler.} + {rd = ra $<<$ imm;} + {No flag is updated.} + +\instruction{Logic Shift Right}{rsh} + {0110 dddd aaaa bbbb} + {rsh rd, ra, imm} + {Register ra is treated as bit masks and shifted to the right by imm bits, ra is filled with zeroes. imm is treated as unsigned number. The result is stored in rd. Internally, imm is incremented by one, which is compensated for in the assembler.} + {rd = ra $>>$ imm;} + {No flag is updated.} + +\instruction{Signed Addition with Immediate}{addi} + {0111 dddd iiii iiii} + {addi rd, imm} + {Register rd and imm are treated as signed numbers and are added. The result is stored in rd.} + {rd = rd + imm;} + {The overflow flag is updated.} + +\instruction{Compare}{cmp} + {1000 mmmm aaaa bbbb} + {cmp mode ra, rb} + {Registers ra and rb are treated as signed numbers and are compared. If the condition, given by mode is true, the truth-flag is set, otherwise reset. Allowed modes are\begin{description}\nolistskip + \item[0000, eq]equal + \item[1000, neq]not equal + \item[0010, gg]greater + \item[0001, ge]greater or equal + \item[1001, ll]less + \item[1010, le]less or equal + \end{description}} + {(ra == rb) ? (T=1) : (T=0);\\// where == is interchangable by mode} + {The truth flag is updated.} + +\instruction{Load PC Relative}{ldr} + {1010 dddd iiii iiii} + {ldr rd, imm} + {Register rd is loaded with memory data from address (PC+(imm$<<$1)), where imm is treated as signed number and is left shifted by one bit.} + {rd = *(PC + (imm$<<$1)} + {No flag is updated.} + +\instruction{Load Data from Pointer}{ld} + {1011 0mmm aaaa bbbb} + {ld08 ra, rb\\ld16 ra, rb\\ld32 ra, rb} + {Loads data from pointer. Register rb's content is used as absolute address, the loaded data is written to register ra. Following modes are supported: + \begin{description} + \nolistskip + \item[000] Load byte + \item[001] Load halfword + \item[010] Load word +\end{description} + } + {ra = *rb} + {No flag is updated} + +\instruction{Store Data to Pointer}{st} + {1011 1mmm aaaa bbbb} + {st08 ra, rb\\st16 ra, rb\\st32 ra, rb} + {Stores data to pointer. Register ra's content is used as absolute address to store the content of register rb. Following modes are supported: + \begin{description} + \nolistskip + \item[000] Store byte + \item[001] Store halfword + \item[010] Store word +\end{description} + As the data is valid only after two clock cycles, the user must ensure that the same address is not used in read transactions in the following instruction (such as ld, ldr, tst). + } + {*ra = rb} + {No flag is updated} + +\instruction{Branch to Offset}{bri} + {1100 010c iiii iiii} + {br imm\\br always/true imm} + {Sets the program counter to PC+imm, where imm is treated as signed number. For details about the branch delay slot see section \ref{sec:branchdelayslot}. If c==1, the branch is conditional and performed only, if the truth flag is set.} + {if ((c==0) \logicor (T==1)) goto (PC+imm);} + {No flag is updated} + +\instruction{Branch to Register}{brr} + {1100 011c aaaa xxxx} + {br ra\\br always/true ra} + {Sets the program counter to register a. For details about the branch delay slot see section \ref{sec:branchdelayslot}. If c==1, the branch is conditional and performed only, if the truth flag is set.} + {if ((c==0) \logicor (T==1)) goto (ra$<<$1);} + {No flag is updated} + +\instruction{Call to Offset}{calli} + {1100 100c iiii iiii} + {call imm\\call always/true imm} + {Sets the program counter to PC+imm, where imm is treated as signed number, and stores the current program counter in the link register. If c==1, the call is conditional and performed only, if the truth flag is set. This is a multicycle operation which consumes two clock cycles.} + {if ((c==0) \logicor (T==1)) \{LR=PC; goto (PC+imm);\}} + {No flag is updated} + +\instruction{Call to Register}{callr} + {1100 101c aaaa xxxx} + {call ra\\call always/true ra} + {Sets the program counter to register a and stores the current program counter in the link register. If c==1, the call is conditional and performed only, if the truth flag is set. This is a multicycle operation which consumes two clock cycles.} + {if ((c==0) \logicor (T==1)) \{LR=PC; goto (ra$<<$1);\}} + {No flag is updated} + +\instruction{Trap}{trap} + {1100 11xx iiii iiii} + {trap imm} + {Request an interrupt of number imm. Number of bits for imm can be set in processor configuration, the number must be right aligned.} + {no equivalent} + {No flag is updated} + +\instruction{Return from Interrupt}{reti} + {1100 000x xxxx xxxx} + {reti} + {Returns from Interrupt, by popping the link and status register from the stack and branching to the current link register contents. This is a multicycle operation which consumes five clock cycles.} + {no equivalent} + {No flag is updated.} + +\instruction{Branch to Table}{brt} + {1100 001c aaaa xxxx} + {brt ra} + {Increments the program counter by register a. This allows for easy creation of branch tables. For details about the branch delay slot see section \ref{sec:branchdelayslot}. If c==1, the branch is conditional and only performed if the truth flag is set.} + {PC = PC + (ra$<<$1)} + {No flag is updated.} + +\instruction{Test and Set}{tst} + {1001 dddd aaaa xxxx} + {tst rd, ra} + {Test and set can be used to implement mutexes. The lower seven bits of the byte can be used to implement semaphores.} + {temp=$_\text{byte}$*ra; rd = temp;\\T = (temp \& 0x80==0); temp=temp $|$ 0x80; *ra=$_\text{byte}$temp;} + {The T-flag is set if the mutex is free and reset if the mutex is already reserved.} + +\section{Assembler} + +The supplied assembler is a two-pass assembler (see thesis, Section 2.6) based on \filename{flex} and \filename{bison} which are used to parse the input file. + +\subsection{HowTo: Assemble Input Files} +A prepared assembler file \filename{input.prog} (see examples in \filename{/source/programs/}) can easily assembled into a formatted file \filename{output.ram} supported by the \procname by calling the assembler \filename{asm}: +\begin{verbatim} +asm input.prog -o output.ram +\end{verbatim} + +\subsection{Allowed Input} +The input to the assembler is case sensitive and all mnemonics have to be lower case. A typical line follows Listing \ref{lst:asm_general}, where all parts are optional (a mnemonic is needed if parameters are supplied though). + +\begin{asm}[General Inputline]{lst:asm_general} +label: mnemonic mode par1, par2, par3 // comment +\end{asm} + +Parameters can either be registers names r0 to r15, SP, LR, SR or PC, +or can be immediate values in various number formats (decimal, binary or hexadecimal numbers), +for prefixes see Table \ref{tbl:asm_numberformats}. +Binary and hexadecimal numbers are not sign extended and always treated as unsigned values. +Also, absolute or relative references to labels are allowed as parameters, see Section \ref{sec:labels} for details. + +Number and type of parameters vary for each instruction, allowed combinations are listed in Section \ref{sec:instructionlist}. + +\begin{table} + \begin{center} + \begin{tabular}{|c|c|c|} + \hline + Numberformat & Prefix & Example\\ + \hline\hline + Decimal & None & -45 \\ + Binary & 0b & 0b11011 \\ + Hexadecimal & 0x & 0xFE \\ + \hline + \end{tabular} + \end{center} + \caption{Number Format Prefixes} + \label{tbl:asm_numberformats} +\end{table} + +\subsection{Pseudo Instructions} +Several instructions are supported which are not directly processed by the \procname but which are mapped to other instructions. +For details on the instructions used, see Section \ref{sec:instructionlist}. +\begin{description} +\item[No Operation (nop)] No operation is performed, wait one clock cycle. Mapped to \inlineasm{or r0, r0, r0}. +\item[Move Register (mov rd, ra)] The content of \inlineasm{ra} is copied to \inlineasm{rd}. Mapped to \inlineasm{or rd, ra, ra}. +\item[Return (ret)] Returns to callee after a call instruction. Mapped to \inlineasm{br always lr}. +\item[Clear Register (clr rd)] Resets \inlineasm{rd} to zero. Mapped to \inlineasm{xor rd, rd, rd}. +\end{description} + +\subsection{Directives}% +\label{sec:AssemblerDirectives}% +The assembler supports several directives which can be included in the input code, see Listing \ref{lst:asm_directives}. +\begin{description} +\item[.word]stores the following parameter directly into the memory. +\item[.address]inserts nops until the address given as parameter is reached. +\item[.align]if needed, a 16bit nop is inserted to align the following instruction +\end{description} + +\begin{asm}[Example for the use of directives]{lst:asm_directives} +// load variables from constant pointer + ldr r0, >variableA + ldr r1, >variableB + +// store variableA + .align // fix eventual non-word-alignment +variableA: .word 0x1234 + +// store variableB + .address 0x100 // store variableB at address 0x100 +variableB: .word 0xABCD +\end{asm} + +\subsection{Labels} +\label{sec:labels} +Labels can be set in the code directly, as seen in Listing \ref{lst:asm_general}. +They can be reffered to in absolute or relative manner (see Listing \ref{lst:asm_labels}). +Label names can include upper and lower case letters, numbers and underscores. +While absolute referencing puts the whole address into the output, relative referencing adds only the difference to the address of instruction which is referencing to the label. +\begin{asm}[Label References]{lst:asm_labels} +label: br >label // relative reference + .word =label // absolute reference +\end{asm} + +\subsection{Assembler Options} +Several command line options are available: +\begin{description} +\item[-o filename]Determines the output file. +\item[-m filename]The assembler outputs a map file, containing all labels and their addresses. +\item[-v or -\xspace -verbose]Outputs all intermediate information. +\item[-\xspace -autoalign]Automatically aligns 32bit instruction and immediate values +\item[-\xspace -fillbds]Fills branch delay slots with nop instruction (i.e. inserts nop after all branches) +\item[-\xspace -continue-on-error]Continues parsing even with errors. +\end{description} + +\subsection{Output} +The standard output format is a one-word-per-line bitstring representation of the instruction memory, which can directly be read by the testbench provided and used as input for memory synthesis. + +\section{HowTo: Add more instructions} +\subsection{Processor Side} +\begin{enumerate} +\item Add opcode constant define to \verb=lt16x32_internal= package. +\item Add case to 16bit decoder and set control signals that differ from default settings. +\end{enumerate} +\subsection{Assembler Side} +\begin{enumerate} +\item Add enumerate item to op$\_$t in global.h +\item Add pattern to flex code in asm.l +\item Add handling to handle$\_$xy.c according to wished syntax style. +\item Recompile assembler by running the make script. +\end{enumerate} +\subsection{32bit Extension} +If 32bit instruction should be implemented, follow the structure of the 16bit decoder to implement the 32bit decoder in \filename{decoder\_32bit.vhd}. + +\subsection{Multicycle Instructions} +To implement multicycle operations, changes need to be implemented in \filename{decoder$\_$fsm.vhd}. +Use the implementation of reti as an example. + diff --git a/documentation/interrupts.tex b/documentation/interrupts.tex new file mode 100644 index 0000000..5086cb4 --- /dev/null +++ b/documentation/interrupts.tex @@ -0,0 +1,70 @@ +\chapter{Interrupts} +\section{Interrupt Controller} +\label{sec:irq_ctrl} +The interrupt controller features a configurable number of interrupt lines with a configurable amount of priorities. +The configuration follows that of the \procname (see Section \ref{sec:config}). +These intterupts lines need to be asserted for one clock cycle to trigger an interrupt request to the processor core. +Additionally, trap requests from the core are handled (as described in \ref{sec:trap}). + +\section{Priority, NMI} +\label{sec:nmi} +The processor features multiple levels of runtime priority (configurable, see Section \ref{sec:config_priowidth}) where a greater number means higher priority. +Additionally, non maskable interrupts (NMI) are supported which are always executed regardless the current processor runtime priority. + +The processor starts with the highest possible runtime priority by default to disable interrupts at startup (with the exception of NMI). + +This is needed as the stack pointer needs to be set to a valid address before any interrupt (including NMI) can be executed. + +\section{Interface and Timing Diagram} +Both ports \inlinevhdl{in\_irq} and \inlinevhdl{out\_irq} (for type definitions see Listing \ref{lst:typedef_irq}) should be connected to a fitting interrupt controller (for example the implementation described in Section \ref{sec:irq_ctrl}). + +\begin{vhdl}[Type definitions for Interrupt Controller Ports]{lst:typedef_irq} +-- collection of all signals from the +-- interrupt controller to the core +type irq_core is record + -- interrupt number of requested interrupt + num : unsigned(irq_num_width - 1 downto 0); + -- priority of requested interrupt + -- (higher number means higher priority) + priority : unsigned(irq_prio_width - 1 downto 0); + -- request signal, active high + req : std_logic; + -- non maskable interrupt flag, active high + nmi : std_logic; +end record; + +-- collection of all signals from the core +-- to the interrupt controller +type core_irq is record + -- interrupt acknowledge + -- high if requested interrupt is processed + ack : std_logic; + -- number of interrupt requested by + -- internal trap instruction + trap_num : unsigned(irq_num_width - 1 downto 0); + -- request signal for internal trap, active high + trap_req : std_logic; +end record; +\end{vhdl} + +\subsection{Interrupt Request} +The external world (i.e. the interrupt controller) can request an interrupt by writing the interrupt number, its priority to \inlinevhdl{in\_irq} and setting the \inlinevhdl{nmi} bit accordingly. +After these are set, \inlinevhdl{req} can be asserted and must be held high until the core acknowledges the interrupt request by asserting \inlinevhdl{ack} for one clock cycle (see Figure \ref{fig:signal_irq_req}). + +\begin{figure}[htb] + \center + \includegraphics[scale=1]{./figures/signal_irq_req.pdf} + \caption{Signal Pattern for Interrupt Requests} + \label{fig:signal_irq_req} +\end{figure} + +\subsection{Trap Implementation} +\label{sec:trap} +When executing a trap instruction, an interrupt line to the interrupt controller is asserted for one clock cycle with the interrupt number asserted as well, see Figure \ref{fig:signal_irq_trap}. +Note, that an arbitrary time (and number of instructions) may take place between a trap and the interrupt handler execution. +\begin{figure}[htb] + \centering + \includegraphics[scale=1]{./figures/signal_irq_trap.pdf} + \caption{Signal Pattern for Trap Instruction} + \label{fig:signal_irq_trap} +\end{figure} diff --git a/documentation/memory.tex b/documentation/memory.tex new file mode 100644 index 0000000..8210b05 --- /dev/null +++ b/documentation/memory.tex @@ -0,0 +1,130 @@ +\chapter{Memory} + +The \procname is connected to the memory through a harvard architecture style interface. +While the interface to the instruction memory is read only, the data memory interface must handle read and write transactions simultaneously. +Externally, both instruction and data memory can be mapped to a Von-Neumann architecture. +The implemented Harvard architecture is more general and allows for two caches to be implemented. + +\section{Endianess and Memory Width} +The memory width is defined in the \inlinevhdl{lt16x32\_internal} package. +Currently, memory widths of 32bits are supported only. +Of course, this memory width can be mapped to any other memory width by a memory controller. +The memory organizes data in big endian format. +This can be seen (and changed) in the memory controller, Listing \ref{lst:endianess}. +The same is valid for halfword-accesses. + +\begin{vhdl}[Byte-Order in Memory]{lst:endianess} +case byteaddress is +when "00" => + dmem_data(7 downto 0) <= word(7 downto 0); +when "01" => + dmem_data(7 downto 0) <= word(15 downto 8); +when "10" => + dmem_data(7 downto 0) <= word(23 downto 16); +when "11" => + dmem_data(7 downto 0) <= word(31 downto 24); +\end{vhdl} + +\section{Interface and Timing Description} +\subsection{Instruction Memory Interface} +The \procname is connected to the instruction memory through two ports, as seen in Listing \ref{lst:imem_interface}. +Their datatype definitions can be found in the \inlinevhdl{lt16x32\_global} package. +\begin{vhdl}[Instruction Memory Interface]{lst:imem_interface} +entity core is +port( + [...] + -- signals from instruction memory + in_imem : in imem_core; + -- signals to instruction memory + out_imem : out core_imem; + [...] +); +end entity core; +\end{vhdl} + +\subsubsection{Read Access} +As all clocked signals in this design, the address and data signals to the instruction memory must be read on each rising clock edge. +Data must be provided if enable (\inlinevhdl{en}) is asserted and the memory content is read on the next rising clock edge. +This single data rate scheme allows for double data rate memory access to allow for pseudo-simultaneous data and instruction memory access. +A standard signal pattern can found in Figure \ref{fig:signal_imem}. + +\begin{figure}[htb] +\centering +\includegraphics[scale=1]{./figures/signal_imem.pdf} +\caption{Signal Pattern for the Instruction Memory Interface} +\label{fig:signal_imem} +\end{figure} + +\subsection{Data Memory Interface} +The \procname is connected to the data memory through two ports, as seen in Listing \ref{lst:dmem_interface}, their datatype definitions can be found in the \inlinevhdl{lt16x32\_global} package. +The data memory interface must be able to handle simultaneous read and write accesses, as these are performed in different pipeline stages and can overlap. +This is good for memory transaction performance but introduces a high memory load. + +\begin{vhdl}[Data Memory Interface]{lst:dmem_interface} +entity core is +port( + [...] + -- signals from data memory + in_dmem : in dmem_core; + -- signals to data memory + out_dmem : out core_dmem; + [...] +); +end entity core; +\end{vhdl} + +\subsubsection{Read Access} +The read access to the data memory is similar to the instruction memory interface and a standard signal pattern is shown in Figure \ref{fig:signal_imem}. + +\subsubsection{Write Access} +In a write access, data and address are supplied at the same time and should be copied to the memory at the rising clock edge if enable is active, see Figure \ref{fig:signal_dmem_write}. +\begin{figure}[htb] + \centering + \includegraphics[scale=1]{./figures/signal_dmem_write.pdf} + \caption{Signal Pattern for Data Memory Write} + \label{fig:signal_dmem_write} +\end{figure} +\subsection{Memory Bandwidth Solutions} +As mentioned before, the very liberal memory interface demands high memory bandwidth. +In a worst-case scenario three memory accesses are needed per clockcycle (instruction read, data read and data write). + +\subsubsection{Instruction Alignment} +Fortunately this worst-case scenario can be avoided by clever instruction alignment. +As standard instructions are 16bit wide and the instruction memory is organized +in 32bit words the instruction memory must be read only once every two clock cycles\footnote{Branching may introduce additional read operations.}. +If memory access instructions are now aligned in such a way, that read/write actions are performed when the instruction memory is idle, a simple single data rate memory is sufficient. +An exemplatory signal pattern is shown in Figure \ref{fig:signal_mem_interlacing}. +Note, that the instruction memory enable must be asserted the whole time, +but the memory controller does not need to read the actual memory, +as the address is changed only every second clock cycle. + +\begin{figure}[htb] + \centering + \includegraphics[scale=1]{./figures/signal_mem_interlacing.pdf} + \caption{Signal Pattern for Memory Interlacing} + \label{fig:signal_mem_interlacing} +\end{figure} + +\subsubsection{Processor Stalling} +If instruction alignment is too cumbersome or the memory is too slow for any other reason, it can deassert the ready signal (\inlinevhdl{ready}) to the processor (per interface). +If \inlinevhdl{ready} is deasserted, the processor is stalled and waits for \inlinevhdl{ready} to become asserted again. + +\section{Memory Mapped I/O} +\label{sec:memmappedio} +In the concept of memory mapped input/output (I/O), the processor core does not distinguish between data memory transactions and transactions with other kinds of devices. +Writing to special memory addresses (i.e. outside of the memory range) are forwarded to a device, reading from these addresses means accessing the device's registers. + +The systems memory is defined as follows: +\begin{itemize} +\item The instruction memory starts at address zero, its length should be configured to a word boundary.\footnote{The default component uses is configured using a word count.} +\item The data memory starts after the instruction memory, its length is also configurable and should also end on a word boundary. +\item The address space of the peripheral components starts at address \verb=0x000F0000= +\end{itemize} + +\section{Memory Controller} +\label{sec:memoryctrl} +A generic memory controller named \verb=dmem= is given. +It has a size of 256 bytes, sectioned in four 64 byte blocks with an access size of one byte. +The default configuration is that its base address is directly after the instruction memory. +It can and should be used to maintain the stack, as frequent accesses to the instruction memory can slow down the performance. +The content of the memory at startup is undefined, and should not be used without initialization. \ No newline at end of file diff --git a/documentation/minted.sty b/documentation/minted.sty new file mode 100644 index 0000000..55ed062 --- /dev/null +++ b/documentation/minted.sty @@ -0,0 +1,998 @@ +%% +%% This is file `minted.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% minted.dtx (with options: `package') +%% Copyright 2013--2014 Geoffrey M. Poore +%% Copyright 2010--2011 Konrad Rudolph +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% Additionally, the project may be distributed under the terms of the new BSD +%% license. +%% +%% This work has the LPPL maintenance status `maintained'. +%% +%% The Current Maintainer of this work is Geoffrey Poore. +%% +%% This work consists of the files minted.dtx and minted.ins +%% and the derived file minted.sty. +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{minted}[2013/12/21 v2.0-alpha3 ] +\RequirePackage{keyval} +\RequirePackage{kvoptions} +\RequirePackage{fancyvrb} +\RequirePackage{float} +\RequirePackage{ifthen} +\RequirePackage{calc} +\RequirePackage{ifplatform} +\RequirePackage{pdftexcmds} +\RequirePackage{etoolbox} +\RequirePackage{xstring} +\RequirePackage{lineno} +\AtBeginDocument{\@ifpackageloaded{color}{}{\RequirePackage{xcolor}}} +\DeclareVoidOption{chapter}{\def\minted@float@within{chapter}} +\DeclareVoidOption{section}{\def\minted@float@within{section}} +\newboolean{minted@cache} +\DeclareVoidOption{cache}{% + \minted@cachetrue + \AtEndOfPackage{\ProvideDirectory{\minted@outputdir\minted@cachedir}}% +} +\StrSubstitute{\jobname}{ }{_}[\minted@jobname] +\StrSubstitute{\minted@jobname}{"}{}[\minted@jobname] +\StrSubstitute{\minted@jobname}{*}{-}[\minted@jobname] +\newcommand{\minted@cachedir}{.minted-\minted@jobname} +\let\minted@cachedir@windows\minted@cachedir +\define@key{minted}{cachedir}{% + \@namedef{minted@cachedir}{#1}% + \StrSubstitute{\minted@cachedir}{/}{\@backslashchar}[\minted@cachedir@windows]} +\let\minted@outputdir\@empty +\let\minted@outputdir@windows\@empty +\define@key{minted}{outputdir}{% + \@namedef{minted@outputdir}{#1/}% + \StrSubstitute{\minted@outputdir}{/}% + {\@backslashchar}[\minted@outputdir@windows]} +\newboolean{minted@langlinenos} +\DeclareVoidOption{langlinenos}{\minted@langlinenostrue} +\DeclareBoolOption{draft} +\ProcessKeyvalOptions* +\newcommand{\minted@infile}{\jobname.out.pyg} +\newcommand{\minted@cachefiles}{} +\newcommand{\minted@addcachefile}[1]{% + \expandafter\long\expandafter\gdef\expandafter\minted@cachefiles\expandafter{% + \minted@cachefiles,^^J% + \space\space#1}% + \expandafter\gdef\csname minted@current@#1\endcsname{}% +} +\newcommand{\minted@savecachefiles}{% + \immediate\write\@mainaux{% + \string\gdef\string\minted@oldcachefiles\string{% + \minted@cachefiles\string}}% +} +\newcommand{\minted@cleancache}{% + \ifthenelse{\boolean{minted@cache}}{% + \ifcsname minted@oldcachefiles\endcsname + \def\do##1{% + \ifthenelse{\equal{##1}{}}{}{% + \ifcsname minted@current@##1\endcsname\else + \DeleteFile[\minted@outputdir\minted@cachedir]{##1}% + \fi + }% + }% + \expandafter\docsvlist\expandafter{\minted@oldcachefiles}% + \else + \fi + }{}% +} +\ifthenelse{\boolean{minted@cache}}% + {\AtEndDocument{% + \ifthenelse{\boolean{minted@draft}}% + {\ifcsname minted@oldcachefiles\endcsname + \let\minted@cachefiles\minted@oldcachefiles + \minted@savecachefiles + \fi}% + {\minted@savecachefiles + \minted@cleancache}}% + }% + {}% +\ifwindows + \providecommand{\DeleteFile}[2][]{% + \ifthenelse{\equal{#1}{}}% + {\IfFileExists{#2}{\immediate\write18{del "#2"}}{}}% + {\IfFileExists{#1/#2}{% + \StrSubstitute{#1}{/}{\@backslashchar}[\minted@windir] + \immediate\write18{del "\minted@windir\@backslashchar #2"}}{}}} +\else + \providecommand{\DeleteFile}[2][]{% + \ifthenelse{\equal{#1}{}}% + {\IfFileExists{#2}{\immediate\write18{rm "#2"}}{}}% + {\IfFileExists{#1/#2}{\immediate\write18{rm "#1/#2"}}{}}} +\fi +\ifwindows + \newcommand{\ProvideDirectory}[1]{% + \StrSubstitute{#1}{/}{\@backslashchar}[\minted@windir] + \immediate\write18{if not exist "\minted@windir" mkdir "\minted@windir"}} +\else + \newcommand{\ProvideDirectory}[1]{% + \immediate\write18{mkdir -p "#1"}} +\fi +\newboolean{AppExists} +\newread\minted@appexistsfile +\newcommand{\TestAppExists}[1]{ + \ifwindows + \DeleteFile{\jobname.aex} + \immediate\write18{for \string^\@percentchar i in (#1.exe #1.bat #1.cmd) + do set >\jobname.aex >\jobname.aex} + %$ <- balance syntax highlighting + \immediate\openin\minted@appexistsfile\jobname.aex + \expandafter\def\expandafter\@tmp@cr\expandafter{\the\endlinechar} + \endlinechar=-1\relax + \readline\minted@appexistsfile to \minted@apppathifexists + \endlinechar=\@tmp@cr + \ifthenelse{\equal{\minted@apppathifexists}{}} + {\AppExistsfalse} + {\AppExiststrue} + \immediate\closein\minted@appexistsfile + \DeleteFile{\jobname.aex} + \immediate\typeout{file deleted} + \else + \immediate\write18{which #1 && touch \jobname.aex} + \IfFileExists{\jobname.aex} + {\AppExiststrue + \DeleteFile{\jobname.aex}} + {\AppExistsfalse} + \fi +} +\newcommand{\minted@optg}{} +\let\minted@lang\@empty +\newcommand{\minted@optlang}{} +\newcommand{\minted@optcmd}{} +\newcommand{\minted@checklang}{% + \ifcsname minted@optlang\minted@lang\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang\endcsname{}% + \fi + \ifcsname minted@optlang\minted@lang @extra\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang @extra\endcsname{}% + \fi +} +\newcommand{\minted@resetoptcmd}{% + \@namedef{minted@optcmd@extra}{}% + \let\minted@optcmd@autogobble\relax} +\newcommand{\minted@getoptg}[1]{% + \expandafter\detokenize% + \expandafter\expandafter\expandafter{\csname minted@optg@#1\endcsname}} +\newcommand{\minted@getoptlang}[1]{% + \expandafter\detokenize\expandafter\expandafter\expandafter{% + \csname minted@optlang\minted@lang @#1\endcsname}} +\newcommand{\minted@getoptcmd}[1]{% + \expandafter\detokenize% + \expandafter\expandafter\expandafter{\csname minted@optcmd@#1\endcsname}} +\newcommand{\minted@regoptg}[1]{% + \ifcsname minted@optg@#1@reg\endcsname\else + \expandafter\let\csname minted@optg@#1@reg\endcsname\@empty + \expandafter\def\expandafter\minted@optg\expandafter{% + \minted@optg\space\minted@getoptg{#1}}% + \fi +} +\newcommand{\minted@regoptlang}[1]{% + \ifcsname minted@optlang\minted@lang @#1@reg\endcsname\else + \ifcsname minted@optlang\minted@lang\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang\endcsname{}% + \fi + \expandafter\let\csname minted@optlang\minted@lang @#1@reg\endcsname\@empty + \expandafter\let\expandafter\minted@optlang% + \csname minted@optlang\minted@lang\endcsname + \expandafter\def\expandafter\minted@optlang\expandafter{% + \minted@optlang\space\minted@getoptlang{#1}}% + \expandafter\let\csname minted@optlang\minted@lang\endcsname\minted@optlang + \let\minted@optlang\@empty + \fi +} +\newcommand{\minted@regoptcmd}[1]{% + \ifcsname minted@optcmd@#1@reg\endcsname\else + \expandafter\let\csname minted@optcmd@#1@reg\endcsname\@empty + \expandafter\def\expandafter\minted@optcmd\expandafter{% + \minted@optcmd\space\minted@getoptcmd{#1}}% + \expandafter\def\expandafter\minted@resetoptcmd\expandafter{% + \minted@resetoptcmd + \@namedef{minted@optcmd@#1}{}}% + \fi +} +\newcommand{\minted@define@opt}[4][]{% + \ifthenelse{\equal{#1}{}}% + {\define@key{minted@optg}{#2}{\@namedef{minted@optg@#2}{#3=#4}% + \@namedef{minted@optg@#2@val}{#4}% + \minted@regoptg{#2}}% + \define@key{minted@optlang}{#2}{% + \@namedef{minted@optlang\minted@lang @#2}{#3=#4}% + \@namedef{minted@optlang\minted@lang @#2@val}{#4}% + \minted@regoptlang{#2}}% + \define@key{minted@optcmd}{#2}{\@namedef{minted@optcmd@#2}{#3=#4}% + \@namedef{minted@optcmd@#2@val}{#4}% + \minted@regoptcmd{#2}}}% + {\define@key{minted@optg}{#2}[#1]{\@namedef{minted@optg@#2}{#3=#4}% + \@namedef{minted@optg@#2@val}{#4}% + \minted@regoptg{#2}}% + \define@key{minted@optlang}{#2}[#1]{% + \@namedef{minted@optlang\minted@lang @#2}{#3=#4}% + \@namedef{minted@optlang\minted@lang @#2@val}{#4}% + \minted@regoptlang{#2}}% + \define@key{minted@optcmd}{#2}[#1]{\@namedef{minted@optcmd@#2}{#3=#4}% + \@namedef{minted@optcmd@#2@val}{#4}% + \minted@regoptcmd{#2}}}% +} +\newcommand{\minted@namexdef}[1]{\expandafter\xdef\csname #1\endcsname} +\edef\minted@hashchar{\string#} +\edef\minted@lbracechar{\string{} +\edef\minted@rbracechar{\string}} +\edef\minted@dollarchar{\string$} +\edef\minted@ampchar{\string&} +\edef\minted@uscorechar{\string_} +\newcommand{\minted@bechar}{% + \begingroup + \let\#\minted@hashchar + \let\%\@percentchar + \let\{\minted@lbracechar + \let\}\minted@rbracechar + \let\$\minted@dollarchar + \let\&\minted@ampchar + \let\_\minted@uscorechar +} +\newcommand{\minted@eechar}{\endgroup} +\newcommand{\minted@define@opt@escchar}[4][]{% + \ifthenelse{\equal{#1}{}}% + {\define@key{minted@optg}{#2}{\minted@bechar% + \minted@namexdef{minted@optg@#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optg@#2@val}{#4}% + \minted@regoptg{#2}}% + \define@key{minted@optlang}{#2}{% + \minted@bechar% + \minted@namexdef{minted@optlang\minted@lang @#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optlang\minted@lang @#2@val}{#4}% + \minted@regoptlang{#2}}% + \define@key{minted@optcmd}{#2}{\minted@bechar% + \minted@namexdef{minted@optcmd@#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optcmd@#2@val}{#4}% + \minted@regoptcmd{#2}}}% + {\define@key{minted@optg}{#2}[#1]{\minted@bechar% + \minted@namexdef{minted@optg@#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optg@#2@val}{#4}% + \minted@regoptg{#2}}% + \define@key{minted@optlang}{#2}[#1]{% + \minted@bechar% + \minted@namexdef{minted@optlang\minted@lang @#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optlang\minted@lang @#2@val}{#4}% + \minted@regoptlang{#2}}% + \define@key{minted@optcmd}{#2}[#1]{\minted@bechar% + \minted@namexdef{minted@optcmd@#2}{#3=#4}% + \minted@eechar% + \@namedef{minted@optcmd@#2@val}{#4}% + \minted@regoptcmd{#2}}}% +} +\newcommand{\minted@define@optstyle}{% + \define@key{minted@optg}{style}{% + \@namedef{minted@optg@style}{-P style=##1 -P commandprefix=PYG##1}% + \minted@regoptg{style}\minted@regstyle{##1}}% + \define@key{minted@optlang}{style}{% + \@namedef{minted@optlang\minted@lang @style}% + {-P style=##1 -P commandprefix=PYG##1}% + \minted@regoptlang{style}\minted@regstyle{##1}}% + \define@key{minted@optcmd}{style}{% + \@namedef{minted@optcmd@style}{-P style=##1 -P commandprefix=PYG##1}% + \minted@regoptcmd{style}\minted@regstyle{##1}}% +} +\newcommand{\minted@patchZsq}[1]{% + \ifx\upquote@cmtt\minted@undefined\else + \ifx\encodingdefault\upquote@OTone + \ifx\ttdefault\upquote@cmtt + \expandafter\ifdefstring\expandafter{\csname PYG#1Zsq\endcsname}{\char`\'}% + {\expandafter\gdef\csname PYG#1Zsq\endcsname{\char13 }}{}% + \else + \expandafter\ifdefstring\expandafter{\csname PYG#1Zsq\endcsname}{\char`\'}% + {\expandafter\gdef\csname PYG#1Zsq\endcsname{\textquotesingle}}{}% + \fi + \else + \expandafter\ifdefstring\expandafter{\csname PYG#1Zsq\endcsname}{\char`\'}% + {\expandafter\gdef\csname PYG#1Zsq\endcsname{\textquotesingle}}{}% + \fi + \fi +} +\newcommand{\minted@regstyle}[1]{% + \ifcsname minted@stylereg@#1\endcsname\else + \expandafter\global\expandafter% + \let\csname minted@stylereg@#1\endcsname\@empty + \ifthenelse{\boolean{minted@cache}}% + {\IfFileExists{\minted@outputdir\minted@cachedir/#1.pygstyle}{}{% + \ifwindows + \immediate\write18{\MintedPygmentize\space -S #1 -f latex + -P commandprefix=PYG#1 + > "\minted@outputdir@windows\minted@cachedir@windows\@backslashchar#1.pygstyle"}% + \else + \immediate\write18{\MintedPygmentize\space -S #1 -f latex + -P commandprefix=PYG#1 + > "\minted@outputdir\minted@cachedir/#1.pygstyle"}% + \fi + }% + \begingroup + \let\def\gdef + \endlinechar=-1\relax + \input{\minted@outputdir\minted@cachedir/#1.pygstyle}% + \endgroup + \minted@addcachefile{#1.pygstyle}}% + {\ifwindows + \immediate\write18{\MintedPygmentize\space -S #1 -f latex + -P commandprefix=PYG#1 > "\minted@outputdir@windows\jobname.out.pyg"}% + \else + \immediate\write18{\MintedPygmentize\space -S #1 -f latex + -P commandprefix=PYG#1 > "\minted@outputdir\jobname.out.pyg"}% + \fi + \begingroup + \let\def\gdef + \endlinechar=-1\relax + \input{\minted@outputdir\jobname.out.pyg}% + \endgroup}% + \ifx\@onlypreamble\@notprerr + \minted@patchZsq{#1}% + \else + \minted@patchZsq{#1}% + \AtBeginDocument{\minted@patchZsq{#1}}% + \fi + \fi +} +\ifthenelse{\boolean{minted@draft}}{\renewcommand{\minted@regstyle}[1]{}}{} +\newcommand{\minted@define@switch}[3][]{ + \define@booleankey{minted@optg}{#2} + {\@namedef{minted@optg@#2}{#3}\minted@regoptg{#2}} + {\@namedef{minted@optg@#2}{#1}\minted@regoptg{#2}} + \define@booleankey{minted@optlang}{#2} + {\@namedef{minted@optlang\minted@lang @#2}{#3}\minted@regoptlang{#2}} + {\@namedef{minted@optlang\minted@lang @#2}{#1}\minted@regoptlang{#2}} + \define@booleankey{minted@optcmd}{#2} + {\@namedef{minted@optcmd@#2}{#3}\minted@regoptcmd{#2}} + {\@namedef{minted@optcmd@#2}{#1}\minted@regoptcmd{#2}} +} +\newcommand{\minted@define@extra}[1]{ + \define@key{minted@optg}{#1}{% + \expandafter\def\expandafter\minted@optg@extra\expandafter{% + \minted@optg@extra,#1=##1}} + \@namedef{minted@optg@extra}{} + \define@key{minted@optlang}{#1}{% + \ifcsname minted@optlang\minted@lang @extra\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang @extra\endcsname{}% + \fi + \expandafter\let\expandafter\minted@optlang@extra% + \csname minted@optlang\minted@lang @extra \endcsname + \expandafter\def\expandafter\minted@optlang@extra\expandafter{% + \minted@optlang@extra,#1=##1}% + \expandafter\let\csname minted@optlang\minted@lang @extra\endcsname% + \minted@optlang@extra + \let\minted@optlang@extra\@empty}% + \@namedef{minted@optlang@extra}{} + \define@key{minted@optcmd}{#1}{% + \expandafter\def\expandafter\minted@optcmd@extra\expandafter{% + \minted@optcmd@extra,#1=##1}} + \@namedef{minted@optcmd@extra}{} +} +\newcommand{\minted@define@extra@switch}[1]{ + \define@booleankey{minted@optg}{#1} + {\expandafter\def\expandafter\minted@optg@extra\expandafter{% + \minted@optg@extra,#1}} + {\expandafter\def\expandafter\minted@optg@extra\expandafter{% + \minted@optg@extra,#1=false}} + \define@booleankey{minted@optlang}{#1} + {% + \ifcsname minted@optlang\minted@lang @extra\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang @extra\endcsname{}% + \fi + \expandafter\let\expandafter\minted@optlang@extra% + \csname minted@optlang\minted@lang @extra\endcsname + \expandafter\def\expandafter\minted@optlang@extra\expandafter{% + \minted@optlang@extra,#1}% + \expandafter\let\csname minted@optlang\minted@lang @extra\endcsname% + \minted@optlang@extra + \let\minted@optlang@extra\@empty} + {% + \ifcsname minted@optlang\minted@lang @extra\endcsname\else + \expandafter\def\csname minted@optlang\minted@lang @extra\endcsname{}% + \fi + \expandafter\let\expandafter\minted@optlang@extra% + \csname minted@optlang\minted@lang @extra\endcsname + \expandafter\def\expandafter\minted@optlang@extra\expandafter{% + \minted@optlang@extra,#1=false}% + \expandafter\let\csname minted@optlang\minted@lang @extra\endcsname% + \minted@optlang@extra + \let\minted@optlang@extra\@empty} + \define@booleankey{minted@optcmd}{#1} + {\expandafter\def\expandafter\minted@optcmd@extra\expandafter{% + \minted@optcmd@extra,#1}} + {\expandafter\def\expandafter\minted@optcmd@extra\expandafter{% + \minted@optcmd@extra,#1=false}} +} +\minted@define@opt{encoding}{-P encoding}{#1} +\minted@define@opt{outencoding}{-P outencoding}{#1} +\minted@define@opt@escchar{escapeinside}{-O escapeinside}{"#1"} +\minted@define@opt{stripnl}{-P stripnl}{#1} +\minted@define@switch[-P python3=False]{python3}{-P python3=True} +\minted@define@switch[-P funcnamehighlighting=False]% + {funcnamehighlighting}{-P funcnamehighlighting} +\minted@define@switch[-P startinline=False]{startinline}{-P startinline} +\ifthenelse{\boolean{minted@draft}}% + {\minted@define@extra{gobble}}% + {\minted@define@opt{gobble}{-F gobble:n}{#1}} +\minted@define@opt{codetagify}{-F codetagify:codetags}{#1} +\minted@define@opt{keywordcase}{-F keywordcase:case}{#1} +\minted@define@switch[-P texcomments=False]{texcl}{-P texcomments} +\minted@define@switch[-P texcomments=False]{texcomments}{-P texcomments} +\minted@define@switch[-P mathescape=False]{mathescape}{-P mathescape} +\ifthenelse{\boolean{minted@draft}}% + {\define@booleankey{FV}{linenos}{\@nameuse{FV@Numbers@left}}{\@nameuse{FV@Numbers@none}}% + \minted@define@extra@switch{linenos}}% + {\minted@define@switch[-P linenos=False]{linenos}{-P linenos}} +\minted@define@optstyle +\minted@define@extra{frame} +\minted@define@extra{framesep} +\minted@define@extra{framerule} +\minted@define@extra{rulecolor} +\minted@define@extra{numbersep} +\minted@define@extra{numbers} +\minted@define@extra{firstnumber} +\minted@define@extra{stepnumber} +\minted@define@extra{firstline} +\minted@define@extra{lastline} +\minted@define@extra{baselinestretch} +\minted@define@extra{xleftmargin} +\minted@define@extra{xrightmargin} +\minted@define@extra{fillcolor} +\minted@define@extra{tabsize} +\minted@define@extra{fontfamily} +\minted@define@extra{fontsize} +\minted@define@extra{fontshape} +\minted@define@extra{fontseries} +\minted@define@extra{formatcom} +\minted@define@extra{label} +\minted@define@extra@switch{numberblanklines} +\minted@define@extra@switch{showspaces} +\minted@define@extra@switch{resetmargins} +\minted@define@extra@switch{samepage} +\minted@define@extra@switch{showtabs} +\minted@define@extra@switch{obeytabs} +\minted@define@extra@switch{breaklines} +\minted@define@extra@switch{breakbytoken} +\minted@define@extra{breakindent} +\minted@define@extra@switch{breakautoindent} +\minted@define@extra{breaksymbol} +\minted@define@extra{breaksymbolsep} +\minted@define@extra{breaksymbolindent} +\let\minted@optcmd@bgcolor\@empty +\define@key{minted@optcmd}{bgcolor}{\@namedef{minted@optcmd@bgcolor}{#1}} +\newcommand{\minted@encoding}{% + \ifcsname minted@optcmd@encoding@val\endcsname + \csname minted@optcmd@encoding@val\endcsname + \else + \ifcsname minted@optlang\minted@lang @encoding@val\endcsname + \csname minted@optlang\minted@lang @encoding@val\endcsname + \else + \ifcsname minted@optg@encoding@val\endcsname + \csname minted@optg@encoding@val\endcsname + \else + UTF8% + \fi + \fi + \fi +} +\define@booleankey{minted@optg}{autogobble} + {\expandafter\let\csname minted@optg@autogobble\endcsname\@empty} + {\expandafter\let\csname minted@optg@autogobble\endcsname\relax} +\define@booleankey{minted@optlang}{autogobble} + {\expandafter\let\csname minted@optlang\minted@lang @autogobble\endcsname\@empty} + {\expandafter\let\csname minted@optlang\minted@lang @autogobble\endcsname\relax} +\define@booleankey{minted@optcmd}{autogobble} + {\expandafter\let\csname minted@optcmd@autogobble\endcsname\@empty} + {\expandafter\let\csname minted@optcmd@autogobble\endcsname\relax} +\newboolean{minted@autogobble} +\newcommand{\minted@set@autogobble}{% + \ifcsname minted@optg@autogobble\endcsname\else + \expandafter\let\csname minted@optg@autogobble\endcsname\relax + \fi + \ifcsname minted@optlang\minted@lang @autogobble\endcsname\else + \expandafter\let\csname minted@optlang\minted@lang @autogobble\endcsname\relax + \fi + \ifcsname minted@optcmd@autogobble\endcsname\else + \expandafter\let\csname minted@optcmd@autogobble\endcsname\relax + \fi + \expandafter\ifx\csname minted@optcmd@autogobble\endcsname\@empty + \setboolean{minted@autogobble}{true}% + \else + \expandafter\ifx\csname minted@optlang\minted@lang @autogobble\endcsname\@empty + \setboolean{minted@autogobble}{true}% + \else + \expandafter\ifx\csname minted@optg@autogobble\endcsname\@empty + \setboolean{minted@autogobble}{true}% + \else + \setboolean{minted@autogobble}{false}% + \fi + \fi + \fi +} +\let\FV@ListProcessLine@Orig\FV@ListProcessLine +\define@booleankey{FV}{breaklines}% + {\let\FV@ListProcessLine\FV@ListProcessLine@Break}% + {\let\FV@ListProcessLine\FV@ListProcessLine@Orig} +\define@booleankey{FV}{breakbytoken}% + {\let\minted@pyghook\minted@pyghook@breakbytoken}% + {\let\minted@pyghook\minted@pyghook@null} +\newdimen\FV@BreakIndent +\define@key{FV}{breakindent}{\FV@BreakIndent=#1} +\fvset{breakindent=0pt} +\newboolean{FV@BreakAutoIndent} +\define@booleankey{FV}{breakautoindent}% + {\FV@BreakAutoIndenttrue}{\FV@BreakAutoIndentfalse} +\fvset{breakautoindent=true} +\define@key{FV}{breaksymbol}{\def\FancyVerbBreakSymbol{#1}} +\fvset{breaksymbol=\ensuremath{\hookrightarrow}} +\newdimen\FV@BreakSymbolSep +\define@key{FV}{breaksymbolsep}{\FV@BreakSymbolSep=#1} +\fvset{breaksymbolsep=10pt} +\newdimen\FV@BreakSymbolIndent +\settowidth{\FV@BreakSymbolIndent}{\ttfamily xxxx} +\define@key{FV}{breaksymbolindent}{\FV@BreakSymbolIndent=#1} +\newsavebox{\FV@LineBox} +\newsavebox{\FV@IndentBox} +\newsavebox{\FV@LinenoBox} +\let\FV@LineIndentChars\@empty +\def\FV@GetNextChar{\let\FV@NextChar=} +\def\FV@CleanRemainingChars#1\FV@Undefined{} +\def\FV@GetLineIndent{\afterassignment\FV@CheckChar\FV@GetNextChar} +\def\FV@CheckChar{% + \ifx\FV@NextChar\FV@Undefined + \let\FV@Next=\relax + \else + \expandafter\ifx\FV@NextChar\FV@Space + \g@addto@macro{\FV@LineIndentChars}{\FV@Space}% + \let\FV@Next=\FV@GetLineIndent + \else + \expandafter\ifx\FV@NextChar\FV@Tab + \g@addto@macro{\FV@LineIndentChars}{\FV@Tab}% + \let\FV@Next=\FV@GetLineIndent + \else + \let\FV@Next=\FV@CleanRemainingChars + \fi + \fi + \fi + \FV@Next +} +\newcommand{\FancyVerbFormatBreakSymbol}{% + \ifnum\value{linenumber}=1\relax\else\FancyVerbBreakSymbol\fi}% +\AtBeginEnvironment{Verbatim}{\lineskip=0pt\xdef\FV@theprevdepth{0pt}} +\def\FV@ListProcessLine@Break#1{% + \hbox to \hsize{% + \kern\leftmargin + \hbox to \linewidth{% + \sbox{\FV@LineBox}{\FancyVerbFormatLine{#1}}% + \ifdim\wd\FV@LineBox>\linewidth + \let\FV@theprevdepth@temp\FV@theprevdepth + \savebox{\FV@LineBox}{% + \begingroup + \vbox{\hsize=\linewidth + \raggedright + \prevdepth\FV@theprevdepth + \leftlinenumbers* + \setcounter{linenumber}{1}% + \let\thelinenumber\FancyVerbFormatBreakSymbol + \begin{internallinenumbers}% + \linenumbersep=\FV@BreakSymbolSep + \advance\hsize by -\FV@BreakIndent + \advance\linewidth by -\FV@BreakIndent + \noindent\hspace*{-\FV@BreakIndent}% + \ifdefempty{\FancyVerbBreakSymbol}{}{% + \advance\hsize by -\FV@BreakSymbolIndent + \advance\linewidth by -\FV@BreakSymbolIndent + \hspace*{-\FV@BreakSymbolIndent}}% + \ifthenelse{\boolean{FV@BreakAutoIndent}}% + {\let\FV@LineIndentChars\@empty + \FV@GetLineIndent#1\FV@Undefined + \savebox{\FV@IndentBox}{\FV@LineIndentChars}% + \advance\hsize by -\wd\FV@IndentBox + \advance\linewidth by -\wd\FV@IndentBox + \hspace*{-\wd\FV@IndentBox}% + }{}% + \FancyVerbFormatLine{#1}% + \end{internallinenumbers}% + \par\xdef\FV@theprevdepth{\the\prevdepth}}% + \endgroup + }% + \savebox{\FV@LinenoBox}{\FV@LeftListNumber}% + \vbox to\ht\FV@LineBox{% + \prevdepth\FV@theprevdepth@temp\FV@LeftListNumber\vfill}% + \FV@LeftListFrame + \null\hfill\usebox{\FV@LineBox}\hss + \FV@RightListFrame + \vbox to\ht\FV@LineBox{% + \prevdepth\FV@theprevdepth@temp\FV@RightListNumber\vfill}% + \else + \FV@LeftListNumber + \FV@LeftListFrame + \vbox{\hsize=\linewidth + \prevdepth\FV@theprevdepth + \noindent\FancyVerbFormatLine{#1}% + \par\xdef\FV@theprevdepth{\the\prevdepth}}\hss + \FV@RightListFrame + \FV@RightListNumber + \fi}% + \hss}} +\newsavebox{\minted@bgbox} +\newenvironment{minted@colorbg}[1]{ + %\setlength{\fboxsep}{-\fboxrule} + \def\minted@bgcol{#1} + \noindent + \begin{lrbox}{\minted@bgbox} + \begin{minipage}{\linewidth-2\fboxsep}} + {\end{minipage} + \end{lrbox}% + \colorbox{\minted@bgcol}{\usebox{\minted@bgbox}}} +\newwrite\minted@code +\newcommand{\minted@savecode}[1]{ + \immediate\openout\minted@code\jobname.pyg\relax + \immediate\write\minted@code{\expandafter\detokenize\expandafter{#1}}% + \immediate\closeout\minted@code} +\newcommand{\minted@write@detok}[1]{% + \immediate\write\FV@OutFile{\detokenize{#1}}} +\newcommand{\minted@FVB@VerbatimOut}[1]{% + \@bsphack + \begingroup + \FV@UseKeyValues + \FV@DefineWhiteSpace + \def\FV@Space{\space}% + \FV@DefineTabOut + \let\FV@ProcessLine\minted@write@detok + \immediate\openout\FV@OutFile #1\relax + \let\FV@FontScanPrep\relax + \let\@noligs\relax + \FV@Scan} +\newcommand{\MintedPygmentize}{pygmentize} +\newcommand{\minted@pygmentize}[2][\jobname.pyg]{% + \minted@checklang + \minted@set@autogobble + \ifthenelse{\boolean{minted@autogobble}}% + {\def\minted@codefile{\jobname.pyg}}% + {\def\minted@codefile{#1}}% + \def\minted@cmd{\MintedPygmentize\space -l #2 + -f latex -F tokenmerge + \minted@optg \space \csname minted@optlang\minted@lang\endcsname + \space \minted@optcmd \space -P "verboptions=\minted@getoptg{extra}% + \minted@getoptlang{extra}\minted@getoptcmd{extra}" + -o "\minted@outputdir\minted@infile" \space + "\minted@outputdir\minted@codefile"}% + % For debugging, uncomment: %%%% + % \immediate\typeout{\minted@cmd}% + % %%%% + \ifthenelse{\boolean{minted@cache}}% + {% + \ifx\XeTeXinterchartoks\minted@undefined + \ifthenelse{\boolean{minted@autogobble}}% + {\edef\minted@hash{\pdf@filemdfivesum{#1}% + \pdf@mdfivesum{\minted@cmd autogobble}}}% + {\edef\minted@hash{\pdf@filemdfivesum{#1}% + \pdf@mdfivesum{\minted@cmd}}}% + \else + \immediate\openout\minted@code\jobname.mintedcmd\relax + \immediate\write\minted@code{\minted@cmd}% + \ifthenelse{\boolean{minted@autogobble}}% + {\immediate\write\minted@code{autogobble}}{}% + \immediate\closeout\minted@code + %Cheating a little here by using ASCII codes to write `{` and `}` + %in the Python code + \def\minted@hashcmd{% + \detokenize{python -c "import hashlib; + hasher = hashlib.sha1(); + f = open(\"}\minted@outputdir\jobname.mintedcmd\detokenize{\", \"rb\"); + hasher.update(f.read()); + f.close(); + f = open(\"}\minted@outputdir#1\detokenize{\", \"rb\"); + hasher.update(f.read()); + f.close(); + f = open(\"}\minted@outputdir\jobname.mintedmd5\detokenize{\", \"w\"); + macro = \"\\edef\\minted@hash\" + chr(123) + hasher.hexdigest() + chr(125) + \"\"; + f.write(\"\\makeatletter\" + macro + \"\\makeatother\\endinput\n\"); + f.close();"}}% + \immediate\write18{\minted@hashcmd}% + \input{\minted@outputdir\jobname.mintedmd5}% + \fi + \ifwindows + \edef\minted@infile{% + \minted@cachedir@windows\@backslashchar\minted@hash.pygtex}% + \else + \edef\minted@infile{% + \minted@cachedir/\minted@hash.pygtex}% + \fi + \IfFileExists{\minted@cachedir/\minted@hash.pygtex}{}{% + \ifthenelse{\boolean{minted@autogobble}}{% + %Need a version of open() that supports encoding under Python 2 + \edef\minted@autogobblecmd{% + \detokenize{python -c "import sys; + import textwrap; + from io import open; + f = open(\"}\minted@outputdir#1\detokenize{\", \"r\", encoding=\"}\minted@encoding\detokenize{\"); + t = f.read(); + f.close(); + f = open(\"}\minted@outputdir\jobname.pyg\detokenize{\", \"w\", encoding=\"}\minted@encoding\detokenize{\"); + f.write(textwrap.dedent(t)); + f.close();"}% + }% + \immediate\write18{\minted@autogobblecmd}}{}% + \immediate\write18{\minted@cmd}}% + \expandafter\minted@addcachefile\expandafter{\minted@hash.pygtex}% + \minted@inputpyg}% + {% + \ifthenelse{\boolean{minted@autogobble}}{% + %Need a version of open() that supports encoding under Python 2 + \edef\minted@autogobblecmd{% + \detokenize{python -c "import sys; + import textwrap; + from io import open; + f = open(\"}\minted@outputdir#1\detokenize{\", \"r\", encoding=\"}\minted@encoding\detokenize{\"); + t = f.read(); + f.close(); + f = open(\"}\minted@outputdir\jobname.pyg\detokenize{\", \"w\", encoding=\"}\minted@encoding\detokenize{\"); + f.write(textwrap.dedent(t)); + f.close();"}% + }% + \immediate\write18{\minted@autogobblecmd}}{}% + \immediate\write18{\minted@cmd}% + \minted@inputpyg}% +} +\newcommand{\minted@inputpyg}{% + \ifthenelse{\equal{\minted@optcmd@bgcolor}{}}% + {}% + {\begin{minted@colorbg}{\minted@optcmd@bgcolor}}% + \input{\minted@outputdir\minted@infile}% + \ifthenelse{\equal{\minted@optcmd@bgcolor}{}}% + {}% + {\end{minted@colorbg}}% +} +\newcounter{minted@FancyVerbLineTemp} +\newcommand{\minted@langlinenoson}{% + \ifcsname c@minted@lang\minted@lang\endcsname\else + \newcounter{minted@lang\minted@lang}% + \fi + \setcounter{minted@FancyVerbLineTemp}{\value{FancyVerbLine}}% + \setcounter{FancyVerbLine}{\value{minted@lang\minted@lang}}% +} +\newcommand{\minted@langlinenosoff}{% + \setcounter{minted@lang\minted@lang}{\value{FancyVerbLine}}% + \setcounter{FancyVerbLine}{\value{minted@FancyVerbLineTemp}}% +} +\ifthenelse{\boolean{minted@langlinenos}}{}{% + \let\minted@langlinenoson\relax + \let\minted@langlinenosoff\relax +} +\newcommand{\setminted}[2][]{% + \ifthenelse{\equal{#1}{}}% + {\setkeys{minted@optg}{#2}}% + {\def\minted@lang{#1}\setkeys{minted@optlang}{#2}}% +} +\newcommand{\usemintedstyle}[2][]{\setminted[#1]{style=#2}} +\newrobustcmd{\mintinline}[2][]{% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \def\minted@lang{#2}% + \begingroup + \let\do\@makeother\dospecials + \catcode`\{=1 + \catcode`\}=2 + \catcode`\^^I=\active + \@ifnextchar\bgroup + {\minted@inline@iii}% + {\catcode`\{=12\catcode`\}=12 + \minted@inline@i}} +\def\minted@inline@i#1{% + \endgroup + \def\minted@inline@ii##1#1{% + \minted@inline@iii{##1}}% + \begingroup + \let\do\@makeother\dospecials + \minted@inline@ii} +\ifthenelse{\boolean{minted@draft}}% + {\newcommand{\minted@inline@iii}[1]{% + \endgroup + \def\minted@argretok{% + \begingroup + \everyeof{\noexpand}% + \endlinechar-1\relax + \let\do\@makeother\dospecials + \catcode`\ =\active + \catcode`\^^I=\active + \scantokens{#1}% + \endgroup}% + \begingroup + \expandafter\fvset\expandafter{\minted@optg@extra}% + \minted@checklang + \expandafter\let\expandafter\minted@optlang@extra\csname minted@optlang\minted@lang @extra\endcsname + \expandafter\fvset\expandafter{\minted@optlang@extra}% + \expandafter\fvset\expandafter{\minted@optcmd@extra}% + \FV@BeginVBox + \frenchspacing + \FV@SetupFont + \FV@DefineWhiteSpace + \FancyVerbDefineActive + \FancyVerbFormatCom + \FV@ObeyTabsInit + \hbox{\FancyVerbFormatLine{\minted@argretok}}% + \FV@EndVBox + \endgroup}}% + {\newcommand{\minted@inline@iii}[1]{% + \endgroup + \immediate\openout\minted@code\jobname.pyg\relax + \immediate\write\minted@code{\detokenize{#1}}% + \immediate\closeout\minted@code + \begingroup + \RecustomVerbatimEnvironment{Verbatim}{BVerbatim}{}% + \minted@pygmentize{\minted@lang}% + \endgroup}} +\ifthenelse{\boolean{minted@draft}}% + {\newcommand{\mint}[3][]{% + \def\minted@lang{#2}% + \DefineShortVerb{#3}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \minted@langlinenoson + \begingroup + \expandafter\fvset\expandafter{\minted@optg@extra}% + \minted@checklang + \expandafter\let\expandafter\minted@optlang@extra\csname minted@optlang\minted@lang @extra\endcsname + \expandafter\fvset\expandafter{\minted@optlang@extra}% + \expandafter\fvset\expandafter{\minted@optcmd@extra}% + \SaveVerb[aftersave={% + \UndefineShortVerb{#3}% + \let\FV@Line\FV@SV@minted@verb + \FV@VerbatimBegin\FV@PreProcessLine\FV@VerbatimEnd + \endgroup + \UndefineShortVerb{#3}% + \minted@langlinenosoff + \@doendpe\global\@ignorefalse\ignorespaces}]{minted@verb}#3}}% + {\newcommand{\mint}[3][]{% + \def\minted@lang{#2}% + \DefineShortVerb{#3}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \SaveVerb[aftersave={% + \UndefineShortVerb{#3}% + \minted@langlinenoson + \minted@savecode{\FV@SV@minted@verb}% + \minted@pygmentize{#2}% + \minted@langlinenosoff}]{minted@verb}#3}} +\ifthenelse{\boolean{minted@draft}}% + {\newenvironment{minted}[2][] + {\VerbatimEnvironment + \let\FVB@VerbatimOut\minted@FVB@VerbatimOut + \def\minted@lang{#2}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \expandafter\fvset\expandafter{\minted@optg@extra}% + \minted@checklang + \expandafter\let\expandafter\minted@optlang@extra\csname minted@optlang\minted@lang @extra\endcsname + \expandafter\fvset\expandafter{\minted@optlang@extra}% + \expandafter\fvset\expandafter{\minted@optcmd@extra}% + \minted@langlinenoson + \begin{Verbatim}}% + {\end{Verbatim}% + \minted@langlinenosoff}}% + {\newenvironment{minted}[2][] + {\VerbatimEnvironment + \let\FVB@VerbatimOut\minted@FVB@VerbatimOut + \def\minted@lang{#2}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \begin{VerbatimOut}[codes={\catcode`\^^I=12}]{\jobname.pyg}}% + {\end{VerbatimOut}% + \minted@langlinenoson + \minted@pygmentize{\minted@lang}% + \minted@langlinenosoff}} +\ifthenelse{\boolean{minted@draft}}% + {\newcommand{\inputminted}[3][]{% + \def\minted@lang{#2}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \begingroup + \expandafter\fvset\expandafter{\minted@optg@extra}% + \minted@checklang + \expandafter\let\expandafter\minted@optlang@extra\csname minted@optlang\minted@lang @extra\endcsname + \expandafter\fvset\expandafter{\minted@optlang@extra}% + \expandafter\fvset\expandafter{\minted@optcmd@extra}% + \VerbatimInput{#3}% + \endgroup}}% + {\newcommand{\inputminted}[3][]{% + \def\minted@lang{#2}% + \minted@resetoptcmd + \setkeys{minted@optcmd}{#1}% + \minted@pygmentize[#3]{#2}}} +\newcommand{\newminted}[3][]{ + \ifthenelse{\equal{#1}{}} + {\def\minted@envname{#2code}} + {\def\minted@envname{#1}} + \newenvironment{\minted@envname} + {\VerbatimEnvironment + \begin{minted}[#3]{#2}} + {\end{minted}} + \newenvironment{\minted@envname *}[1] + {\VerbatimEnvironment\begin{minted}[#3,##1]{#2}} + {\end{minted}}} +\newcommand{\newmint}[3][]{ + \ifthenelse{\equal{#1}{}} + {\def\minted@shortname{#2}} + {\def\minted@shortname{#1}} + \expandafter\newcommand\csname\minted@shortname\endcsname[2][]{ + \mint[#3,##1]{#2}##2}} +\newcommand{\newmintedfile}[3][]{ + \ifthenelse{\equal{#1}{}} + {\def\minted@shortname{#2file}} + {\def\minted@shortname{#1}} + \expandafter\newcommand\csname\minted@shortname\endcsname[2][]{ + \inputminted[#3,##1]{#2}{##2}}} +\newcommand{\newmintinline}[3][]{% + \ifthenelse{\equal{#1}{}}% + {\def\minted@shortname{#2inline}}% + {\def\minted@shortname{#1}}% + \expandafter\newrobustcmd\csname\minted@shortname\endcsname{% + \begingroup + \let\do\@makeother\dospecials + \catcode`\{=1 + \catcode`\}=2 + \@ifnextchar[{\endgroup\minted@inliner[#3][#2]}% + {\endgroup\minted@inliner[#3][#2][]}}% + \def\minted@inliner[##1][##2][##3]{\mintinline[##1,##3]{##2}}% +} +\@ifundefined{minted@float@within} + {\newfloat{listing}{h}{lol}} + {\newfloat{listing}{h}{lol}[\minted@float@within]} +\newcommand{\listingscaption}{Listing} +\floatname{listing}{\listingscaption} +\newcommand{\listoflistingscaption}{List of listings} +\providecommand{\listoflistings}{\listof{listing}{\listoflistingscaption}} +\AtEndOfPackage{% + \ifthenelse{\boolean{minted@draft}}{}{% + \ifnum\pdf@shellescape=1\relax\else + \PackageError{minted}% + {You must invoke LaTeX with the + -shell-escape flag}% + {Pass the -shell-escape flag to LaTeX. Refer to the minted.sty + documentation for more information.}% + \fi + \TestAppExists{pygmentize} + \ifAppExists\else + \PackageError{minted}% + {You must have `pygmentize' installed + to use this package}% + {Refer to the installation instructions in the minted + documentation for more information.}% + \fi + \setminted{style=default}% + }% +} +\AtEndDocument{ + \ifx\XeTeXinterchartoks\minted@undefined + \else + \DeleteFile[\minted@outputdir]{\jobname.mintedcmd}% + \DeleteFile[\minted@outputdir]{\jobname.mintedmd5}% + \fi + \DeleteFile[\minted@outputdir]{\jobname.pyg}% + \DeleteFile[\minted@outputdir]{\jobname.out.pyg}% +} +%% \Finale +\endinput +%% +%% End of file `minted.sty'. diff --git a/documentation/soc.tex b/documentation/soc.tex new file mode 100644 index 0000000..e4c302a --- /dev/null +++ b/documentation/soc.tex @@ -0,0 +1,167 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% To make formatting easy tell LaTeX what kind of document you want to write +% by changing the according {} to {#1} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Which language do you want to write in +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%English +\newcommand{\EN}[1]{#1} +%German +\newcommand{\DE}[1]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% For print single or double page? +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\newcommand{\single}[1]{#1} +\newcommand{\double}[1]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Now this is followed by a lot of page and command definitions. For the beginning you +% should be able to continue where you find the next comment section like this one. +% However, you might want to take a look a the definitions sometime to be able to use +% them. Of course you can also add the defintions you needed yourself. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\single{\documentclass[12pt,a4paper,oneside,english]{book}} +\double{\documentclass[12pt,a4paper,twoside,english]{book}} + +\usepackage[english]{babel} +%\usepackage[draft,breaklinks=true,colorlinks=false,dvips,bookmarks,pdffitwindow,pdfcenterwindow=true,pdfstartview=Fit]{hyperref} +%\usepackage[breaklinks=true,colorlinks=false,dvips,bookmarks,pdffitwindow,pdfcenterwindow=true,pdfstartview=Fit]{hyperref} +\usepackage{graphicx} +\usepackage{xcolor} +\usepackage{caption} +\usepackage{subcaption} +\usepackage{setspace} +\usepackage{cite} +\usepackage{float,times} +\usepackage[utf8x]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{amsmath,amsthm,latexsym} +\usepackage[dvips]{epsfig} +%\usepackage{subfigure} +\usepackage{rotating} +\usepackage{afterpage} +\usepackage{multirow} +\usepackage{array} + +\usepackage{minted} +\usepackage{newfloat} +\usepackage{xspace} +%! put the new-command after the inputenc package use, so 'ü' will not be shown as abomination ASCII -TF + +\input{globalcommands.tex} +\newcommand{\DocuTitle}{Documentation of the LT16x32 System-on-Chip} + +% format page layout. +\setlength{\topmargin}{0cm} +\setlength{\textwidth}{15cm} +\setlength{\textheight}{22cm} +\setlength{\oddsidemargin}{1cm} +\setlength{\evensidemargin}{0cm} + +\setlength{\headheight}{15pt} +% \setlength{\voffset}{-0cm} +% \setlength{\topmargin}{0cm} +% \setlength{\headheight}{0.54cm} +% \setlength{\textheight}{23cm} +% % \setlength{\headsep}{1.5cm} +% %\setlength{\hoffset}{-2.54cm} +% \setlength{\hoffset}{0cm} +% \setlength{\oddsidemargin}{0.46cm} +% \setlength{\evensidemargin}{0.46cm} +% \setlength{\textwidth}{15cm} +% \setlength{\marginparsep}{0cm} +% \setlength{\marginparwidth}{1.54cm} + +\setcounter{secnumdepth}{3} + + +% \setlength{\footskip}{1cm} +% \setlength{\parindent}{0cm} +% \setlength{\parskip}{1em} + +\usepackage{fancyhdr} +\pagestyle{fancy} +\fancyhead{} % clear all header fields +%\fancyhead[LO, RE]{\slshape \nouppercase{\leftmark}} % chapter titles +%\fancyhead[LE, RO]{\slshape \nouppercase{\leftmark}\\\nouppercase{\rightmark}} % section titles +\double{\fancyhead[LE]{\slshape \nouppercase{\leftmark}}} % chapter titles +\fancyhead[RO]{\slshape \nouppercase{\rightmark}} % section titles +\fancyfoot{} % clear all footer fields +\fancyfoot[C]{\thepage} + + +\usepackage[%dvips, + colorlinks=false, + bookmarks, + pdffitwindow, + pdfcenterwindow=true, + pdfstartview=Fitpdftex, + pdfauthor={Lasse Schnepel, Thomas Fehmel}, + pdftitle={\DocuTitle}, + pdfsubject={LT16x32 Documentation}, % one sentence summery + pdfkeywords={Processor,Firmware-based Verification,Architecture design}, %comma-seperated keywords + pdfproducer={Latex with hyperref}, + pdfcreator={}]{hyperref} + +\begin{document} + +% \EN{\selectlanguage{english}} +% \DE{\selectlanguage{german}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Here you have to start editing +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\title{\DocuTitle} +\author{Lasse Schnepel, Thomas Fehmel} +\date{2015} +\pagenumbering{arabic} +\hyphenation{Bit-ebenen Gateprop Bit-ebene Fanin Boole-sche + Partial-produkt-generator + Code-inspektion + Verifika-tions-ablauf + IPC-Verifika-tions-ablauf + Abhangig-keiten +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% title page +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\frontmatter +\maketitle +\tableofcontents + +\mainmatter + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Now this is followed by your chapters +% this usually starts with introduction and Fundamentals and then +% continues with whatever you need or did +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\input{socscope} +\input{socarch} +\input{architecture} +\input{instructionset} +\input{interrupts} +\input{memory} +\input{guides} + +\backmatter +\listoffigures +\listoftables +%\listofcodefloat %triggers Errors for me, for whatever reason, but the pdf is generated nonetheless -TF + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\bibliographystyle{alphadin} +\bibliography{refs3} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\end{document} diff --git a/documentation/socarch.tex b/documentation/socarch.tex new file mode 100644 index 0000000..d9d588e --- /dev/null +++ b/documentation/socarch.tex @@ -0,0 +1,134 @@ +\chapter{SoC Architecture}\label{chap:socarch} +The supplied ESyLab-SoC plattform is implemented by the \verb=top.vhd=, +which can be found in the \verb=/soc/top= directory. +Its structure is illustrated by Figure~\ref{fig:socoverview}. +\begin{figure}[htb] + \centering + \includegraphics[scale=0.55]{./figures/soc_overview.pdf} + \caption{Block diagram of the ESyLab-SoC} + \label{fig:socoverview} +\end{figure} + +The interface of the minimal top level entity of the \procname system is shown in Listing~\ref{lst:top_interface}. +\begin{vhdl}[Top Level Entity]{lst:top_interface} +entity lt16soc_top is +generic( + programfilename : string := "programs/program.ram" +); +port( + clk : in std_logic; + rst : in std_logic; + + led : out std_logic_vector(7 downto 0) +); +end entity lt16soc_top; +\end{vhdl} + +The inputs \inlinevhdl{clk}, which denote the clock input, and \inlinevhdl{rst}, which is the active high reset, are system-wide signals. +The minimal system features only one output signal, which is \inlinevhdl{led}. +This signal should be connected to a set of leds and is connected to a generic I/O-controller on the bus. + +The individual components of the minimal system are described in the following sections. + +\section{Interconnect} +\label{chap:socarch:interconnect} +The system utilizes a synchronous Wishbone bus. +To ease integration of new bus components, a Wishbone bus interconnect component is provided. +The interconnect module currently implements only the synchronous Whisbone protocol. +Its interface is given in Listing~\ref{lst:wb_interconnect_interface}. + +\begin{vhdl}[Top Level Entity]{lst:wb_interconnect_interface} +entity wb_intercon is +generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := 0; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := 0 +); +port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector +); +\end{vhdl} +The system is configured to a certain maximum number of slave and master modules as \inlinevhdl{NWBSLV} and \inlinevhdl{NWBMST} respectively. +The configuration can be found in \verb=config.vhd=. + +These constants are used to define a the length of two generic parameters of the module, +the mask vectors \verb=slv_mask_vector= and \verb=mst_mask_vector=, +and also define how many elements the input and output arrays have. +As for the mask vectors, as indicated in the \verb=wishbone.vhd= file. +The mask vectors are used to indicate to the interconnect if a module should be connected to the input/output port indicated by the bit position in the mask vector. +A '1' at a position in the mask vector indicates that at the respective position in the the input/output arrays, +a module should be connected. +A '0' at a position in the mask vector will facilitate that the control logic for that position in the respective input/output array is omitted. + +The inputs \inlinevhdl{clk} and \inlinevhdl{rst} are currently not used, but might be in the future when synchronous wishbone transfer is implemented. + +The wishbone bus signals are separated in arrays of master and slave signals. +Array of master signals is in the output \inlinevhdl{msti}, which are the inputs to the connected masters, and the input \inlinevhdl{msto}, which are the outputs of the connected master. +Analogously, \inlinevhdl{slvi} and \inlinevhdl{slvo} follow the same principle for the connected slave modules. + +\subsection{Integration of new components} +To instantiate a new component in the system, +a few steps must be undertaken. + +\paragraph{The component declaration}% +should not be put in the top level module, +but in the appropriate package. +This makes the top level module more readable. + +\paragraph{The component instantiation}% +in the top level module must be connected to the bus interconnect system. +To do this, the port map must connect its inputs and outputs of its bus interface to a free element of the \verb=slvi= and \verb=slvo= array signals in the top level architecture. +Any element in that vector must obviously only be assigned once. + +To select to which of those signals you should connect, +consult the file \verb=soc/lib/config.vhd=. +A number of of slave index constants like shown in Listing~\ref{lst:config_constants} are defined there. +Add your own by adding one to the last defined constant, +then use the defined constant to select the element of the bus slave signal arrays, as illustrated in Listing.~\ref{lst:slave_port_assignment}. + +\begin{vhdl}[Slave bus indexes]{lst:config_constants} +-- >> Slave index << +constant CFG_MEM : integer := 0; +constant CFG_LED : integer := CFG_MEM+1; +constant CFG_DMEM : integer := CFG_LED+1; +... +\end{vhdl} +\begin{vhdl}[Slave bus connection]{lst:slave_port_assignment} +... port map( ... +wslvi => slvi(CFG_FOO), +wslvo => slvo(CFG_FOO) +... +\end{vhdl} + +\paragraph{The slave masking vector}% +is a constant which configures the interconnect system to only consider certain slave bus interface elements. +A slave mask vector \verb=slv_mask_vector= is defined in the top level architecture, see Listing~\ref{lst:slave_mask}. +To enable any connection on the interconnect, +the bit in the slave mask vector must be set to '1' at the same position as the targeted elements in the slave connector arrays. + +Setting any bit in the slave mask vector to '0' will disable the corresponding connection to the interconnection in the way that the logic to evaluate the inputs is not generated. + +\begin{vhdl}[Slave bus indexes]{lst:slave_mask} +architecture RTL of lt16soc_top is +... +constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0000_0000_0000"; +... +\end{vhdl} + +\section{Processor Core Wrapper} +The processor core has a data and instruction memory interface, as per standard Harvard architecture. +The instruction memory interface is unchanged, but the data memory interface is wrapped in a piece of control logic translating the processor interface to wishbone signals and takes care of timing. + +\section{Instruction memory} +The instruction memory component is configurable to load a file into its memory during elaboration. +The loaded file needs to contain legal values of the type std\_logic\_vector with a length of 32 characters per line. +If the content of the file is illegal, an error in the elaboration tool will likely occur. + +It has two interfaces, one for instruction read access by the processor, one for a read and write access by the Wishbone bus. +The Wishbone interface takes priority over the instruction read. +The whole range of the memory can be written, so care should be exercised when writing to the instruction memory, +so code or 'constants' are not unintentionally overwritten. diff --git a/documentation/socscope.tex b/documentation/socscope.tex new file mode 100644 index 0000000..d7ca62c --- /dev/null +++ b/documentation/socscope.tex @@ -0,0 +1,62 @@ +\chapter{Scope of Delivery} +\section{Products} +Containing in the ESyLab-SoC are the the processor core \procname, +a configurable Wishbone bus interconnect module, +a minimal interrupt controller and peripheral devices. + +An instruction memory is also supplied. +It reads a file with machine code during elaboration, +so the SoC can both be simulated and synthesized. +The assembler to produce that machine code is also supplied in source. + +\section{HowTo: Build Products} +\label{sec:scope_build} +The products are delivered as HDL source code. +This allows adaptation to any platform, for which the needed tools are available (see sections below). + +\subsection{Processor} +The processor is delivered as a set of VHDL files, including one top entity (processor in \filename{processor.vhd}) which can be used in any VHDL synthesis tool. +For simulation, the entity \inlinevhdl{core\_tb} (in \filename{core\_tb.vhd}) can be used. Both architectures instantiate the core, a memory controller and a interrupt controller. +The filename of the used program can be set in these files in the generic map of the memory controller instantiation (see Listing \ref{lst:memory_file}). +Here, also the memory size can be determined (as number of stored words). For details on the memory controller see Section \ref{sec:memoryctrl}. + +\begin{vhdl}[Generic Map Extract of Memory Controller]{lst:memory_file} +memory_inst : component memory + generic map(filename => "../programs/test.ram", + size => 32, + [...] + ) +\end{vhdl} + +The processor is wrapped in another module, +which implements the Wishbone bus-interface for the data memory interface of the processor. + +\subsection{Bus Interconnect} +The bus interconnect system is configureable to any number of slave and master modules, +the appropriate configuration values (see Listing~\ref{lst:wishbone_config}) can be found in the file \verb=lib/wishbone.vhd=. +\begin{vhdl}[Wishbone interconnect configuration]{lst:wishbone_config} +... +constant NWBMST: integer :=4; + --Number of Wishbone master connectors on the Interconnect +constant NWBSLV: integer :=16; + --Number of Wishbone slave connectors on the Interconnect +... +\end{vhdl} +All connections can be masked during its instantiation, +using the slave and master mask vectors (see Listing~\ref{lst:wishbone_mask_config}). +They are declared in the top level architecture and are used during instantiation of the interconnection component. +\begin{vhdl}[Wishbone interconnect configuration]{lst:wishbone_mask_config} +... + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; +... +\end{vhdl} +The component handles synchronous Wishbone cycle termination. + +\subsection{Assembler} +For building the assembler the GNU tools \filename{gcc}, \filename{make}, \filename{bison} and \filename{flex} are needed. With these tools installed, the \filename{make} script can be used to generate an executable called \filename{asm}: +\begin{verbatim} + ($SOCROOT)/assembler/$ make all +\end{verbatim} + +It is recommended to either copy or dynamically link the assembler executable in a directory in your \verb=$PATH= or directly referenced by in your build tool chain. diff --git a/documentation/testcase/Testcase.xlsx b/documentation/testcase/Testcase.xlsx new file mode 100644 index 0000000..ffbe904 Binary files /dev/null and b/documentation/testcase/Testcase.xlsx differ diff --git a/programs/Makefile b/programs/Makefile new file mode 100644 index 0000000..3feaec3 --- /dev/null +++ b/programs/Makefile @@ -0,0 +1,22 @@ + +AS=../assembler/asm +RM= rm -f + +SRCS= $(wildcard *.prog) +OBJS= $(SRCS:.prog=.ram) +MAPS= $(SRCS:.prog=.map) + +all: $(OBJS) + +maps: $(MAPS) + +%.ram: %.prog + $(AS) $< -o $@ + +%.map: %.prog + $(AS) $< -m $@ -o $*.ram + +clean: + $(RM) $(OBJS) $(MAPS) + +.PHONY: all maps diff --git a/programs/blinky.prog b/programs/blinky.prog new file mode 100644 index 0000000..db00409 --- /dev/null +++ b/programs/blinky.prog @@ -0,0 +1,64 @@ +reset: +br always >main +nop +hardfault: +reti +nop +memfault: +reti +nop + +.align +addr: +.word 0x000F0000 +w_cnt_top: .word 0x1FC000 +//w_cnt_top: .word 0x1 //for simulation only + +main: +ldr r0,>addr //LED addr +addi r6,8 //outer counter top +clr r7 //wait counter +ldr r8,>w_cnt_top + +out_loop: +clr r1 +st08 r0,r1 +call >wait +nop + +fill: + lsh r1,r1,1 + addi r1,1 + st08 r0,r1 + call >wait + nop + + addi r5,1 + cmp neq r5,r6 + br true >fill + nop + clr r5 + +flush: + lsh r1,r1,1 + st08 r0,r1 + call >wait + nop + + addi r5,1 + cmp neq r5,r6 + br true >flush + nop + clr r5 + br always >out_loop + nop + +//subroutine to iterate until counter overflow +wait: + clr r7 //inititalize inner counter + inc_i: + cmp neq r7,r8 + br true >inc_i //if i=cnt_top + addi r7,1 + ret //else + nop diff --git a/programs/dmem_test.prog b/programs/dmem_test.prog new file mode 100644 index 0000000..d5899e0 --- /dev/null +++ b/programs/dmem_test.prog @@ -0,0 +1,165 @@ +//big endian data memory test +//after the initialization, should the LED become a value differnt from 0, an error occured +reset: +br always >main +nop +hardfault: +reti +nop +memfault: +reti +nop + +.align +pointer: +.word =constants + +constants: +.word 256 +.word 0x00010203 +.word 0x04040404 +.word 0x000000FF + +main: + clr r10 +call_1: + clr r0 //error msg / state + call always >echo_error + nop + + ldr r11,>pointer + ld32 r1,r11 //DMEM addr + addi r11,4 + ld32 r2,r11 + addi r11,4 + ld32 r3,r11 //increment + addi r11,4 + ld32 r8,r11 //mask + + addi r11,-12 + + //test 1: store 32 bit, load bytes +test1: + mov r4,r2 + st32 r1,r4 + + addi r1,3 //check the LSB first + + ld08 r6,r1 //r6: loaded value + and r5,r4,r8 //r5: masked constant + cmp neq r5,r6 + call true >echo_error + addi r10,1 + + addi r1,-1 + rsh r4,r4,8 + + ld08 r6,r1 //r6: loaded value + and r5,r4,r8 //r5: masked constant + cmp neq r5,r6 + call true >echo_error + addi r10,1 + + addi r1,-1 + rsh r4,r4,8 + + ld08 r6,r1 //r6: loaded value + and r5,r4,r8 //r5: masked constant + cmp neq r5,r6 + call true >echo_error + addi r10,1 + + addi r1,-1 + rsh r4,r4,8 + + ld08 r6,r1 //r6: loaded value + and r5,r4,r8 //r5: masked constant + cmp neq r5,r6 + call true >echo_error + addi r10,1 + + //test 1 end + + add r2,r2,r3 + addi r1,4 + +//test 2: store bytes, load word +test2: + mov r4,r2 + addi r1,3 + + st08 r1,r4 + rsh r4,r4,8 + addi r1,-1 + st08 r1,r4 + rsh r4,r4,8 + addi r1,-1 + st08 r1,r4 + rsh r4,r4,8 + addi r1,-1 + st08 r1,r4 + rsh r4,r4,8 + + ld32 r6,r1 + cmp neq r6,r2 + call true >echo_error + addi r10,1 + + ldr r9,>LEDaddr + st08 r9,r8 + +//test 3 +// prewrite memory with value==baseaddress+offset, +// load 32 bit values and check if correct +test3: + ld32 r1,r11 //DMEM base address + add r8,r1,r1 //out-of-range address, incidentally equals baseaddress*2 since baseaddress==length + clr r2 +test3_prewrite_mem_loop: + st08 r1,r2 + addi r1,1 + cmp neq r1,r8 + br true >test3_prewrite_mem_loop + addi r2,1 + + ld32 r1,r11 //DMEM addr + addi r11,4 + ld32 r2,r11 //CMP value + addi r11,4 + ld32 r3,r11 //increment + addi r11,-8 + add r8,r1,r1 //out-of-range address, incidentally equals baseaddress*2 since baseaddress==length +test3_loop: + ld32 r4,r1 + cmp neq r4,r2 + call true >echo_error + addi r0,1 + + addi r1,4 + add r2,r2,r3 + + cmp neq r1,r8 + br true >test3_loop + nop +//end test3 + +end: + nop + br >end + nop + +.align +LEDaddr: +.word 0x000F0000 + +//expects an error code in r0 +echo_error: + nop + ldr r9,>LEDaddr + st08 r9,r0 + ret + nop + + + + diff --git a/programs/example_irq.prog b/programs/example_irq.prog new file mode 100644 index 0000000..ab75a7e --- /dev/null +++ b/programs/example_irq.prog @@ -0,0 +1,33 @@ +// Interrupt Table +reset: br >main + nop +hardfault: br >hardfault_handler + nop +memfault: br >memfault_handler + nop +irq3: br >irq3_handler + nop + +// Main Function +main: + ldr sp, >sp_init + clr sr + +// endless loop to stop program +final: + br >final + nop + +// Interrupt Handler +hardfault_handler: + reti + +memfault_handler: + reti + +irq3_handler: + reti + +// Constant Declaration +.align +sp_init: .word 0x400 // Stackpointer Initial Value diff --git a/programs/example_led.prog b/programs/example_led.prog new file mode 100644 index 0000000..a279daf --- /dev/null +++ b/programs/example_led.prog @@ -0,0 +1,47 @@ +// +// This program let's the connected LEDs flash +// with a duty cycle of 50% and +// a period of approx. 1s +// +// r0: counter top +// r1: counter +// r2: LED address +// r3: ones (0xFF) +// r4: LED values + +irq0: br always >main +nop + +// initialization constants +.align +sp_init: .word 0x200 // Stack pointer +top: .word 16000000 // Counter top +ptr: .word 0x0 // pointer to I/O device + +// main procedure +main: + +// init registers +ldr sp, >sp_init +ldr r0, >top +ldr r2, >ptr +clr r1 +clr r3 +clr r4 +addi r3, -1 + +// loop +loop: + +cmp neq r1, r0 +br true >loop // loop if not equal (BDS!) +addi r1, 1 // increment counter + +// counter top reached, set LEDs and clear counter +xor r4, r4, r3 // invert last byte of r4 +st08 r2, r4 // write byte to I/O device +br always >loop // branch back to loop (BDS!) +clr r1 // reset counter + +nop +nop diff --git a/programs/example_minimal.prog b/programs/example_minimal.prog new file mode 100644 index 0000000..ecdd9f4 --- /dev/null +++ b/programs/example_minimal.prog @@ -0,0 +1,2 @@ +reset: br always >reset + nop diff --git a/programs/ld08test.prog b/programs/ld08test.prog new file mode 100644 index 0000000..f4b36a9 --- /dev/null +++ b/programs/ld08test.prog @@ -0,0 +1,19 @@ +addi r0,0x50 +addi r1,7 +st08 r0,r1 + +nop +nop +clr r1 + +ld08 r2,r0 + +nop +nop + +st08 r3,r2 +nop +end: +nop +br always >end +nop diff --git a/programs/ld16test.prog b/programs/ld16test.prog new file mode 100644 index 0000000..ff3c511 --- /dev/null +++ b/programs/ld16test.prog @@ -0,0 +1,21 @@ +addi r0,0x50 +addi r1,-3 +nop +nop +st16 r0,r1 + +nop +nop +clr r1 + +ld16 r2,r0 + +nop +nop + +st16 r3,r2 +nop +end: +nop +br always >end +nop diff --git a/programs/ld32test.prog b/programs/ld32test.prog new file mode 100644 index 0000000..183aaeb --- /dev/null +++ b/programs/ld32test.prog @@ -0,0 +1,21 @@ +addi r0,0x50 +addi r1,-3 +nop +nop +st32 r0,r1 + +nop +nop +clr r1 + +ld32 r2,r0 + +nop +nop + +st32 r3,r2 +nop +end: +nop +br always >end +nop diff --git a/programs/ldrtest.prog b/programs/ldrtest.prog new file mode 100644 index 0000000..8910ccd --- /dev/null +++ b/programs/ldrtest.prog @@ -0,0 +1,10 @@ +main: +ldr r0, >dmemaddr +clr r1 +nop +st08 r1,r0 +br always >main +nop + +.align +dmemaddr: .word 0xFFFF diff --git a/programs/ledtest.prog b/programs/ledtest.prog new file mode 100644 index 0000000..0087b9b --- /dev/null +++ b/programs/ledtest.prog @@ -0,0 +1,63 @@ +reset: +br always >main +nop +hardfault: +reti +nop +memfault: +reti +nop + +.align +addr: .word 0x000F0000 +//w_cnt_top: .word 0x717D7840 //250 ms @ 100MHz +w_cnt_top: .word 0x40 //for simulation only + +main: +ldr r0,>addr //LED addr +addi r6,8 //outer counter top +clr r7 //wait counter +ldr r8,>w_cnt_top + +out_loop: +clr r1 +st08 r0,r1 +call >wait +nop + +fill: +lsh r1,r1,1 +addi r1,1 +st08 r0,r1 +call >wait +nop + +addi r5,1 +cmp neq r5,r6 +br true >fill +nop +clr r5 + +flush: +lsh r1,r1,1 +st08 r0,r1 +call >wait +nop + +addi r5,1 +cmp neq r5,r6 +br true >flush +nop +clr r5 +br always >out_loop +nop + +//subroutine that iterates until counter overflow +wait: +clr r7 //inititalize inner counter +inc_i: +cmp neq r7,r8 +br true >inc_i //if i=cnt_top +addi r7,1 +reti //else +nop diff --git a/programs/new.prog b/programs/new.prog new file mode 100644 index 0000000..26be4d4 --- /dev/null +++ b/programs/new.prog @@ -0,0 +1,30 @@ +addi r0,0 +addi r1,0 +addi r2,127 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 +add r2,r2,r2 + +addi r3,7 +st08 r0,r3 +clr r3 + +loopout: +loopin: +addi r1,1 +cmp neq r2,r1 +br true >loopin +nop + +clr r1 +addi r3,1 +st08 r0,r3 +br always >loopout +nop diff --git a/programs/rawhztest.prog b/programs/rawhztest.prog new file mode 100644 index 0000000..d30dacd --- /dev/null +++ b/programs/rawhztest.prog @@ -0,0 +1,35 @@ +reset: +br >main +nop +hardfault: +reti +nop +memfault: +reti +nop + +.align +adr_a: .word 0x3C0 // actual adr at mem 0xF0 (0x3C0>>2 bits) +adr_b: .word 0x3F0 // actual adr at mem 0xFC (0x3F0>>2 bits) + +main: +ldr r5, >adr_a +//wait for one cycle after a load is necessary +nop +ldr r1, >adr_b + +addi r6,-2 +addi r8, 0x50 +nop + +st32 r5, r6 +//waiting for one cycle when re-accessing a stored value is in accordance with design +nop +ld32 r7,r5 +addi r9,0x50 +ld32 r8,r5 +addi r8,1 +st32 r5,r8 + +end: br always >end +nop diff --git a/programs/rdins.prog b/programs/rdins.prog new file mode 100644 index 0000000..e326c23 --- /dev/null +++ b/programs/rdins.prog @@ -0,0 +1,29 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +.align +adr_a: .word 0x3C0 // (30b adr), actual adr at mem 0xF00 (0x3C0<<2 bits) +adr_b: .word 0x3F0 // (30b adr), actual adr at mem 0xFC0 (0x3F0<<2 bits) + + +main: +clr r0 +clr r1 +clr r2 +clr r3 + +//------------------------------ +// read only ins test +//------------------------------ + +addi r1, 0x01 //expected r1 = 0x01 +addi r2, 0x02 //expected r1 = 0x02 +add r0, r1, r2 // expected r0 = 0x03 +add r3, r0, r1 // expected r3 = 3 + 1 = 0x4 + +end: br always >end +nop diff --git a/programs/rdmem.prog b/programs/rdmem.prog new file mode 100644 index 0000000..c2cbef9 --- /dev/null +++ b/programs/rdmem.prog @@ -0,0 +1,31 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +.align +adr_i0: .word 0x001 // (30b adr), actual adr at mem 0x004 (0x001<<2 bits) +adr_a: .word 0x3C0 // (30b adr), actual adr at mem 0xF00 (0x3C0<<2 bits) +adr_b: .word 0x3F0 // (30b adr), actual adr at mem 0xFC0 (0x3F0<<2 bits) + + +main: +clr r0 +clr r1 +clr r2 +clr r3 + +//------------------------------ +// read only mem from ins addr range +//------------------------------ +addi r3, 0x10 //32 bit adr +ld32 r0, r3 // val at addr 0x04 (30 bits) = 0x000003C0 (b0 = x00, b1 = x00, b2 = x03, b3 = xC0) +add r1, r0, r0 //expected r1 = 0x3C0 + 0x3C0 = 780 + +addi r4, 0x12 +ld08 r5, r4 // get Byte2, r5 = 0x03 + +end: br always >end +nop diff --git a/programs/rdwrmem.prog b/programs/rdwrmem.prog new file mode 100644 index 0000000..7f5b96f --- /dev/null +++ b/programs/rdwrmem.prog @@ -0,0 +1,33 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +.align +adr_a: .word 0x3C0 // (30b adr), actual adr at mem 0xF00 (0x3C0<<2 bits) +adr_b: .word 0x3F0 // (30b adr), actual adr at mem 0xFC0 (0x3F0<<2 bits) +adr_c: .word 0x09 + +main: +//------------------------------ +// read only mem from ins addr range +//------------------------------ +addi r3, 0x10 //32 bit adr +ld32 r0, r3 // val at addr 0x04 (30 bits) = 0x000003C0 (b0 = x00, b1 = x00, b2 = x03, b3 = xC0) +add r1, r0, r0 //expected r1 = 0x3C0 + 0x3C0 = 780 + +addi r4, 0x12 +ld08 r5, r4 // get Byte2, r5 = 0x03 + +//------------------------------ +// write mem test +//------------------------------ +addi r8, 0x77 +addi r7, 0x51 //32 bit adr , write to Byte 1 > xx77_xxxx at mem[0x14] +st08 r7, r8 + + +end: br always >end +nop diff --git a/programs/simple.prog b/programs/simple.prog new file mode 100644 index 0000000..a06ac68 --- /dev/null +++ b/programs/simple.prog @@ -0,0 +1,35 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +main: // actual start of program + +clr r0 +clr r1 +clr r2 +clr r3 +clr r4 + +//test move = or +addi r0, 0x55 // expected r0 = 0x55 +mov r1, r0 // expected r1 = 0x55 + +//test shift +addi r2, 0x0A //expected r2 = 0x0A +lsh r3, r2, 16 //expected r3 = 0xA_0000 +lsh r3, r3, 12 //expected r3 = 0xA000_0000 + +// test write +ldr r4, >adr_a //expected r4 = 0x3C0 +st32 r4, r3 //expected value at addr 0xF00 = 0xA000_0000 + +end: br always >end +nop + + .align +adr_a: .word 0x3C0 // actual adr at mem 0xF00 (0x3C0<<2 bits) +//adr_a: .word 0x3F8 +//adr_a: .word 0x20C diff --git a/programs/subseqtest.prog b/programs/subseqtest.prog new file mode 100644 index 0000000..9351119 --- /dev/null +++ b/programs/subseqtest.prog @@ -0,0 +1,43 @@ +reset: + br always >main + nop + +hardfault: + br always >main + reti + +memfault: + br always >main + reti + +.align +t1: .word 0xA0B0C0D0 +t2: .word 0xF0AB2FB9 +t3: .word 0xCCCCCCCC +adr1: .word 0x150 +adr2: .word 0x144 +adr3: .word 0x10F + +main: + ldr r1, >adr1 + ldr r2, >adr2 + ldr r3, >adr3 + + addi r0,-1 + + ldr r4,>t1 + st16 r1,r0 //mem() = 0x0000FFFF + st08 r2,r0 //mem() = 0x000000FF + st32 r3,r0 //mem() = 0xFFFFFFFF + ldr r11,>t1 + ldr r10,>t2 + ldr r9,>t3 + ldr r7,>t1 + ldr r6,>t2 + ld16 r11,r1 + ld08 r10,r2 + ld32 r9,r3 + +end: + br always >end + nop diff --git a/programs/test-trap.prog b/programs/test-trap.prog new file mode 100644 index 0000000..f6a71e5 --- /dev/null +++ b/programs/test-trap.prog @@ -0,0 +1,39 @@ +irq0: +br always >main +nop +irq1: +br always >irq +nop +irq2: +br always >irq +nop + + +main: +ldr sp, >sp_init +nop +clr sr + +addi r2, 1 +addi r2, 2 +addi r2, 3 +trap 1 +addi r2, 4 +addi r2, 5 + +loop: +addi r10, 1 +foo: br always >loop +nop + +end: br always >end +nop + +irq: addi r0, 5 +reti +nop + +.address 100 +.word 499 +sp_init: .word 500 +.word 501 diff --git a/programs/test.prog b/programs/test.prog new file mode 100644 index 0000000..d16e98b --- /dev/null +++ b/programs/test.prog @@ -0,0 +1,46 @@ +// +// This program let's the connected LEDs flash +// with a duty cycle of 50%. +// +// r0: counter top +// r1: counter +// r2: LED address +// r3: ones (0xFF) +// r4: LED values + +irq0: br always >main +nop + +// initialization constants +.align +sp_init: .word 0x200 // Stack pointer +top: .word 160000 // Counter top +ptr: .word 0x0 // pointer to I/O device + +// main procedure +main: + +// init registers +ldr sp, >sp_init +ldr r0, >top +ldr r2, >ptr +clr r1 +clr r3 +clr r4 +addi r3, -1 + +// loop +loop: + +cmp neq r1, r0 +br true >loop // loop if not equal (BDS!) +addi r1, 1 // increment counter + +// counter top reached, set LEDs and clear counter +xor r4, r4, r3 // invert last byte of r4 +st08 r2, r4 // write byte to I/O device +br always >loop // branch back to loop (BDS!) +clr r1 // reset counter + +nop +nop diff --git a/programs/test2.prog b/programs/test2.prog new file mode 100644 index 0000000..7aca8e7 --- /dev/null +++ b/programs/test2.prog @@ -0,0 +1,50 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop +irq3: br >irq_handler +nop + +main: // actual start of program +ldr sp, >sp_init + +ldr r1, >startvalue +clr r2 +clr sr + +test: mov r1, pc + +loop: addi r2, 1 +cmp ll r2, r1 +br true >loop +nop + +cmp le r2, r1 + +call true >final +addi r3, 1 + +end: br >end +nop + +final: addi r10, 1 +cmp eq r10, r1 +ret true +nop +br >final +nop + +irq_handler: addi r4, 1 +reti + + +nop +nop +nop +nop +.align +sp_init: .word 1020 +startvalue: .word 15 + diff --git a/programs/test_endianess.prog b/programs/test_endianess.prog new file mode 100644 index 0000000..9315bdc --- /dev/null +++ b/programs/test_endianess.prog @@ -0,0 +1,44 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +main: // actual start of program +ldr sp, >sp_init + +clr r5 +clr r6 +clr r7 +clr r8 +clr r9 + +ldr r0, >addr +addi r1, 0x01 +st08 r0, r1 +ld08 r5, r0 + +addi r0, 1 +addi r1, 1 +st08 r0, r1 +ld08 r6, r0 + +addi r0, 1 +addi r1, 1 +st08 r0, r1 +ld08 r7, r0 + +addi r0, 1 +addi r1, 1 +st08 r0, r1 +ld08 r8, r0 + +addi r0, 1 +addi r1, 1 +st08 r0, r1 +ld08 r9, r0 +.align +sp_init: .word 1020 // 0x3FC +addr: .word 0x101 + diff --git a/programs/test_endianess2.prog b/programs/test_endianess2.prog new file mode 100644 index 0000000..ee50b29 --- /dev/null +++ b/programs/test_endianess2.prog @@ -0,0 +1,45 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +main: // actual start of program +ldr sp, >sp_init + +clr r5 +clr r6 +clr r7 +clr r8 +clr r9 + +ldr r0, >addr +addi r1, 0x01 +st32 r0, r1 +ld32 r5, r0 + +addi r0, 1 +addi r1, 1 +st32 r0, r1 +ld32 r6, r0 + +addi r0, 1 +addi r1, 1 +st32 r0, r1 +ld32 r7, r0 + +addi r0, 1 +addi r1, 1 +st32 r0, r1 +ld32 r8, r0 + +addi r0, 1 +addi r1, 1 +st32 r0, r1 +ld32 r9, r0 + +.align +sp_init: .word 1020 // 0x3FC +addr: .word 0x101 + diff --git a/programs/test_sync.prog b/programs/test_sync.prog new file mode 100644 index 0000000..e7614a1 --- /dev/null +++ b/programs/test_sync.prog @@ -0,0 +1,52 @@ +reset: br >main +nop +hardfault: reti +nop +memfault: reti +nop + +.align +sp_init: .word 0x400 // Stackpointer Initial Value + +main: + ldr sp, >sp_init + clr sr + +//base addr +add r0,r0,sp +//addi r0,0x40 +addi r10,4 +add r1,r0,r10 +add r2,r1,r10 + +//values t.b. stored +addi r3,-1 +addi r4,-2 +addi r5,-3 + +//store values +st32 r0,r3 +st32 r1,r4 +st32 r2,r5 + +//retrieve values + +ld32 r6,r0 +ld32 r7,r1 +ld32 r8,r2 +nop +nop +nop +nop + +ld32 r6,r0 +st32 r1,r6 +ld32 r7,r0 +ld32 r7,r0 +st32 r1,r6 +st32 r1,r6 +ld32 r7,r0 + +end: +br always >end +nop diff --git a/project.pdf b/project.pdf new file mode 100644 index 0000000..7ae9433 Binary files /dev/null and b/project.pdf differ diff --git a/projects/lt16lab/.gitignore b/projects/lt16lab/.gitignore new file mode 100644 index 0000000..bd417de --- /dev/null +++ b/projects/lt16lab/.gitignore @@ -0,0 +1,37 @@ +### TEX Temps +*.out +*.toc +*.aux +*.log +*.pdf +*.synctex.gz +*.lof +*.lot +*.lol +*.dvi +*.bbl +*.ps +*.blg +*.loc +*.pyg + +### Other Files +*~ +*.kate-swp +*.patch +*.orig + +### Assembler Eclipse Stuff +assembler/.cproject +assembler/.project +assembler/.settings/org.eclipse.cdt.managedbuilder.core.prefs + +### Assembler Project Compiles +assembler/obj/* +assembler/asm +assembler/test.ram +assembler/test.map + +### test program files +*.ram +*.map diff --git a/soc/core/alu.vhd b/soc/core/alu.vhd new file mode 100644 index 0000000..176798f --- /dev/null +++ b/soc/core/alu.vhd @@ -0,0 +1,124 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the ALU offers various two-input arithmetic and logic operations and is fully combinatoric +entity alu is + port( + -- Data Input + in_a : in signed(reg_width - 1 downto 0); + in_b : in signed(reg_width - 1 downto 0); + + -- Truth Flag + t_out : out std_logic; + + -- Overflow Flag + ovf_out : out std_logic; + + -- Mode of Operation + mode : in alu_mode_type; + + -- Data Output + data_out : out signed(reg_width - 1 downto 0) + ); +end entity alu; + +architecture RTL of alu is +begin + + -- calculate the result + calc_out : process(in_a, in_b, mode) is + -- used to store the result temporarily (e.g. if needed for flag calculation) + variable result : signed(reg_width - 1 downto 0); + begin + -- default outputs + data_out <= (others => '0'); + ovf_out <= '0'; + t_out <= '0'; + + -- different result for each mode + case mode is + -- arithmetic modes + + when alu_add => -- addition + result := in_a + in_b; + + data_out <= result; + ovf_out <= (in_a(reg_width - 1) AND in_b(reg_width - 1) AND not result(reg_width - 1)) OR (not in_a(reg_width - 1) AND not in_b(reg_width - 1) AND result(reg_width - 1)); + + when alu_sub => -- subtraction + result := in_a - in_b; + + data_out <= result; + ovf_out <= (in_a(reg_width - 1) AND not in_b(reg_width - 1) AND not result(reg_width - 1)) OR (not in_a(reg_width - 1) AND in_b(reg_width - 1) AND result(reg_width - 1)); + + when alu_and => -- bitwise and + data_out <= in_a and in_b; + + when alu_or => -- bitwise or + data_out <= in_a or in_b; + + when alu_xor => -- bitwise xor + data_out <= in_a xor in_b; + + when alu_lsh => -- logic left shift + data_out <= in_a sll (to_integer(unsigned(in_b(3 downto 0))) + 1); + + when alu_rsh => -- logic right shift + data_out <= in_a srl (to_integer(unsigned(in_b(3 downto 0))) + 1); + + -- compare modes + when alu_cmp_eq => -- compare for A = B + if (in_a = in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_neq => -- compare for not equal + if (in_a /= in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_ge => -- compare for greater than or equal + if (in_a >= in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_gg => -- compare for greater than + if (in_a > in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_le => -- compare for less than or equal + if (in_a <= in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_ll => -- compare for less than + if (in_a < in_b) then + t_out <= '1'; + else + t_out <= '0'; + end if; + + when alu_cmp_true => -- always set truth-flag + t_out <= '1'; + + when alu_cmp_false => -- always reset truth-flag + t_out <= '0'; + end case; + end process calc_out; + +end architecture RTL; diff --git a/soc/core/controlpath.vhd b/soc/core/controlpath.vhd new file mode 100644 index 0000000..a9a3007 --- /dev/null +++ b/soc/core/controlpath.vhd @@ -0,0 +1,130 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the controlpath mostly covers the pipelining of control signals, but also includes some "glue"-logic +entity controlpath is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal, active high + stall : in std_logic; + + -- signals from decoder + in_dec : in dec_cp; + -- signals to decoder + out_dec : out cp_dec; + + -- signals to datapath + out_dp : out cp_dp; + + -- signals to PC counter + out_pc : out cp_pc; + + -- signals to data memory + out_dmem : out cp_dmem; + + -- signals from datapath + in_dp : in dp_cp; + + -- hardfault, active high + hardfault : out std_logic + ); +end entity controlpath; + +architecture RTL of controlpath is + + -- pipelined signals + -- decoder information for dp-stage 2 in stage 2 + signal in_dec_2_s2 : dec_cp_s2; + -- decoder information for dp-stage 3 in stage 2 + signal in_dec_3_s2 : dec_cp_s3; + -- decoder information for dp-stage 3 in stage 3 + signal in_dec_3_s3 : dec_cp_s3; + +begin + -- forward internal signals to ports + hardfault <= in_dec.hardfault; + + out_pc.instruction_width <= in_dec.s1.instruction_width; + + out_dp.s1.register_read_number_a <= in_dec.s1.register_read_number_a; + out_dp.s1.register_read_number_b <= in_dec.s1.register_read_number_b; + + out_dp.s2.alu_input_data_select <= in_dec_2_s2.alu_input_data_select; + out_dp.s2.alu_mode <= in_dec_2_s2.alu_mode; + out_dp.s2.immediate <= in_dec_2_s2.immediate; + out_dp.s2.memory_read_addr_select <= in_dec_2_s2.dmem_read_addr_select; + + out_dmem.read_en <= in_dec_2_s2.dmem_read_en; + out_dmem.read_size <= in_dec_2_s2.dmem_read_size; + + out_dmem.write_en <= in_dec_3_s3.dmem_write_en; + out_dmem.write_size <= in_dec_3_s3.dmem_write_size; + + out_dp.s3.ovfflag_write_enable <= in_dec_3_s3.ovfflag_write_enable; + out_dp.s3.memory_write_data_select <= in_dec_3_s3.dmem_write_data_select; + out_dp.s3.register_write_data_select <= in_dec_3_s3.register_write_data_select; + out_dp.s3.register_write_enable <= in_dec_3_s3.register_write_enable; + out_dp.s3.register_write_number <= in_dec_3_s3.register_write_number; + out_dp.s3.register_write_size <= in_dec_3_s3.register_write_size; + out_dp.s3.tflag_write_data_select <= in_dec_3_s3.tflag_write_data_select; + out_dp.s3.tflag_write_enable <= in_dec_3_s3.tflag_write_enable; + + -- pipeline register stage 1 -> 2 + pipeline_s1_s2 : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + in_dec_2_s2 <= get_default_dec_cp_s2; + in_dec_3_s2 <= get_default_dec_cp_s3; + elsif (stall = '0') then + in_dec_2_s2 <= in_dec.s2; + in_dec_3_s2 <= in_dec.s3; + end if; + end if; + end process pipeline_s1_s2; + + -- pipeline register stage 2 -> 3 + pipeline_s2_s3 : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + in_dec_3_s3 <= get_default_dec_cp_s3; + elsif (stall = '0') then + in_dec_3_s3 <= in_dec_3_s2; + end if; + end if; + end process pipeline_s2_s3; + + -- PC signal combinatorics and condition holds flag for decoder + pc_comb : process(in_dec_2_s2.pc_summand_select, in_dec_2_s2.pc_mode_select, in_dec_2_s2.pc_condition, in_dp.s2.tflag) is + begin + case in_dec_2_s2.pc_condition is + when sel_unconditional => + -- without condition, always use proposed pc options + out_pc.summand_select <= in_dec_2_s2.pc_summand_select; + out_pc.mode_select <= in_dec_2_s2.pc_mode_select; + out_dec.condition_holds <= '1'; + when sel_true => + -- with condition = true + if (in_dp.s2.tflag = '1') then + -- if condition is true (as needed), use proposed pc options + out_pc.summand_select <= in_dec_2_s2.pc_summand_select; + out_pc.mode_select <= in_dec_2_s2.pc_mode_select; + out_dec.condition_holds <= '1'; + else + -- if condition is false (opposed to what is needed) resume normal pc operation + out_pc.summand_select <= sel_run; + out_pc.mode_select <= sel_relative; + out_dec.condition_holds <= '0'; + end if; + end case; + end process pc_comb; + +end architecture RTL; diff --git a/soc/core/core.vhd b/soc/core/core.vhd new file mode 100644 index 0000000..e00e1de --- /dev/null +++ b/soc/core/core.vhd @@ -0,0 +1,244 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +-- the core bundles all entities inside the core itself +entity core is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- external stall signal, active high, synchronous + stall : in std_logic; + + -- signals from data memory + in_dmem : in dmem_core; + -- signals to data memory + out_dmem : out core_dmem; + + -- signals from instruction memory + in_imem : in imem_core; + -- signals to instruction memory + out_imem : out core_imem; + + -- signals from interrupt controller + in_irq : in irq_core; + -- signals to interrupt controller + out_irq : out core_irq; + + -- hardfault signal, active high + hardfault : out std_logic + ); +end entity core; + +architecture RTL of core is + component datapath + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + out_dec : out dp_dec; + in_cp : in cp_dp; + out_cp : out dp_cp; + in_pc : in pc_dp; + out_pc : out dp_pc; + in_dmem : in dmem_dp; + out_dmem : out dp_dmem; + hardfault : out std_logic); + end component datapath; + component controlpath + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_dec : in dec_cp; + out_dec : out cp_dec; + out_dp : out cp_dp; + out_pc : out cp_pc; + out_dmem : out cp_dmem; + in_dp : in dp_cp; + hardfault : out std_logic); + end component controlpath; + component decoder + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_imem : in imem_dec; + in_dp : in dp_dec; + in_cp : in cp_dec; + out_cp : out dec_cp; + out_pc : out dec_pc; + out_imem : out dec_imem; + in_irq : in irq_dec; + out_irq : out dec_irq); + end component decoder; + component programcounter + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_cp : in cp_pc; + in_dp : in dp_pc; + in_dec : in dec_pc; + out_dp : out pc_dp; + out_imem : out pc_imem); + end component programcounter; + + -- signals between instances + signal dp_cp_signal : dp_cp; + signal dp_dmem_signal : dp_dmem; + signal dmem_dp_signal : dmem_dp; + signal imem_dec_signal : imem_dec; + signal dec_cp_signal : dec_cp; + signal dec_imem_signal : dec_imem; + signal cp_dp_signal : cp_dp; + signal cp_dmem_signal : cp_dmem; + signal cp_dec_signal : cp_dec; + signal pc_dp_signal : pc_dp; + signal dp_pc_signal : dp_pc; + signal dec_pc_signal : dec_pc; + signal pc_imem_signal : pc_imem; + signal cp_pc_signal : cp_pc; + signal irq_dec_signal : irq_dec; + signal dec_irq_signal : dec_irq; + signal dp_dec_signal : dp_dec; + + signal hardfault_dp : std_logic; + signal hardfault_cp : std_logic; + + -- general halt signal + signal stall_internal : std_logic; +begin + -- configuration tests + + -- irq_num_width must be smaller than or equal to 6 to fit into first byte of SR + assert (irq_prio_width <= 6) report "irq_prio_width must be <= 6." severity failure; + -- irq_num_width must fit into immediate + assert (irq_num_width < dec_cp_signal.s2.immediate'high) report "irq_num_width must be <= " & integer'image(dec_cp_signal.s2.immediate'high - 1) & "." severity failure; + -- reg_width must be 8, 16 or 32bit + assert ((reg_width = 8) or (reg_width = 16) or (reg_width = 32)) report "selected reg_width is not allowed. allowed values are 8, 16, 32, 64." severity failure; + -- pc must fit into register + assert (pc_width <= reg_width) report "pc_width must be smaller than or equal to reg_width." severity failure; + + -- component instantiation + datapath_inst : component datapath + port map(clk => clk, + rst => rst, + stall => stall_internal, + out_dec => dp_dec_signal, + in_cp => cp_dp_signal, + out_cp => dp_cp_signal, + in_pc => pc_dp_signal, + out_pc => dp_pc_signal, + in_dmem => dmem_dp_signal, + out_dmem => dp_dmem_signal, + hardfault => hardfault_dp); + + controlpath_inst : component controlpath + port map(clk => clk, + rst => rst, + stall => stall_internal, + in_dec => dec_cp_signal, + out_dec => cp_dec_signal, + out_dp => cp_dp_signal, + out_pc => cp_pc_signal, + out_dmem => cp_dmem_signal, + in_dp => dp_cp_signal, + hardfault => hardfault_cp); + + decoder_inst : component decoder + port map(clk => clk, + rst => rst, + stall => stall_internal, + in_imem => imem_dec_signal, + in_dp => dp_dec_signal, + in_cp => cp_dec_signal, + out_cp => dec_cp_signal, + out_pc => dec_pc_signal, + out_imem => dec_imem_signal, + in_irq => irq_dec_signal, + out_irq => dec_irq_signal); + + programcounter_inst : component programcounter + port map(clk => clk, + rst => rst, + stall => stall_internal, + in_cp => cp_pc_signal, + in_dp => dp_pc_signal, + in_dec => dec_pc_signal, + out_dp => pc_dp_signal, + out_imem => pc_imem_signal); + + -- signals from data memory + dmem_dp_signal.read_data <= in_dmem.read_data; + + -- signals to data memory + out_dmem.read_addr <= dp_dmem_signal.read_addr; + out_dmem.read_size <= to_stdlogicvector(cp_dmem_signal.read_size); + out_dmem.write_addr <= dp_dmem_signal.write_addr; + out_dmem.write_data <= dp_dmem_signal.write_data; + out_dmem.write_size <= to_stdlogicvector(cp_dmem_signal.write_size); + + -- dmem read enable is overwritten if stall is active + dmem_read_en : with stall select out_dmem.read_en <= + '0' when '1', + cp_dmem_signal.read_en when others; + -- dmem write enable is overwritten if stall is active + dmem_write_en : with stall select out_dmem.write_en <= + '0' when '1', + cp_dmem_signal.write_en when others; + + -- signals from instruction memory + imem_dec_signal.read_data <= in_imem.read_data; + imem_dec_signal.ready <= in_imem.ready; + + -- signals to instruction memory + + -- fill imem address, if pc width is smaller than memory width + -- all warnings of the type "Null range" can be safely ignored for pc_width = mem_width + imem_addr_fill : if (pc_width < mem_width) generate + out_imem.read_addr(mem_width - 1 downto pc_width) <= (others => '0'); + end generate imem_addr_fill; + + out_imem.read_addr(pc_width - 1 downto 0) <= std_logic_vector(pc_imem_signal.value); + -- imem read enable is overwritten if stall is active + imem_read_en : with stall_internal select out_imem.read_en <= + '0' when '1', + dec_imem_signal.en when others; + + -- the halfword flag needs a delay as it refers to last clock cycles imem address + -- (the corresponding data is read in this clock cycle) + halfword_delay : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- reset to zero + imem_dec_signal.instruction_halfword_select <= '0'; + elsif (stall_internal = '0') then + -- set to pc_value(1) + imem_dec_signal.instruction_halfword_select <= pc_imem_signal.value(1); + --! else? --TF + end if; + end if; + end process halfword_delay; + + -- signals from interrupt controller + irq_dec_signal.num <= in_irq.num; + irq_dec_signal.priority <= in_irq.priority; + irq_dec_signal.req <= in_irq.req; + irq_dec_signal.nmi <= in_irq.nmi; + + -- signals to interrupt controller + out_irq.ack <= dec_irq_signal.ack; + out_irq.trap_num <= dec_irq_signal.trap_num; + out_irq.trap_req <= dec_irq_signal.trap_req; + + -- stall if dmem not ready, imem not ready is handled in decoder_fsm + stall_internal <= (not in_dmem.ready) or stall; + + -- hardfault logic + hardfault <= hardfault_cp or hardfault_dp; + +end architecture RTL; diff --git a/soc/core/core2wb.vhd b/soc/core/core2wb.vhd new file mode 100644 index 0000000..188e639 --- /dev/null +++ b/soc/core/core2wb.vhd @@ -0,0 +1,132 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +entity core2wb is + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out dmem_core; + out_dmem : in core_dmem; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); +end core2wb; + +architecture Behavioral of core2wb is + signal msto : wb_mst_out_type := wbm_out_none; + + type STATE_TYPE IS (ONEACC, SIMACCWR, SIMACCRD); + signal state, nstate: STATE_TYPE; + + +begin + + reg: process(clk) + begin + if rst = '1' then + state <= ONEACC; + in_dmem.read_data <= (others => '0'); + elsif rising_edge(clk) then + state <= nstate; + if wmsti.ack = '1' then + in_dmem.read_data <= dec_wb_dat(msto.sel, wmsti.dat); + end if; + end if; + end process; + + nscl: process(state, out_dmem, wmsti.ack) + begin + case state is + when ONEACC => + if out_dmem.read_en = '1' and out_dmem.write_en = '1' then + nstate <= SIMACCWR; + else + nstate <= state; + end if; + when SIMACCWR => + if wmsti.ack = '1' then + nstate <= SIMACCRD; + else + nstate <= state; -- wait til get ack from wr request + end if; + when SIMACCRD => + if wmsti.ack = '1' then -- read_ack + nstate <= ONEACC; + else + nstate <= state; -- feed the old read value from previous sim request + end if; + end case; + end process; + + ocl: process(state, out_dmem, wmsti.ack) + begin + msto.dat <= (others => '0'); + case state is + when ONEACC => + if(out_dmem.write_en = '1') then + msto.we <= '1'; + msto.stb <= '1'; + msto.cyc <= '1'; + msto.adr <= out_dmem.write_addr(memory_width - 1 downto WB_ADR_BOUND); + msto.sel <= gen_select(out_dmem.write_addr(1 downto 0), out_dmem.write_size); + msto.dat <= enc_wb_dat(out_dmem.write_addr(1 downto 0), out_dmem.write_size, out_dmem.write_data); + elsif(out_dmem.read_en = '1' and out_dmem.write_en = '0') then + msto.we <= '0'; + msto.stb <= '1'; + msto.cyc <= '1'; + msto.adr <= out_dmem.read_addr(memory_width - 1 downto WB_ADR_BOUND); + msto.sel <= gen_select(out_dmem.read_addr(1 downto 0), out_dmem.read_size); + else + msto <= wbm_out_none; + end if; + when SIMACCRD => -- using previous address from sim request, no need since core will keep holding the value + msto.we <= '0'; + msto.stb <= '1'; + msto.cyc <= '1'; + msto.adr <= out_dmem.read_addr(memory_width - 1 downto WB_ADR_BOUND); + msto.sel <= gen_select(out_dmem.read_addr(1 downto 0), out_dmem.read_size); + when SIMACCWR => + msto.we <= '1'; + msto.stb <= '1'; + msto.cyc <= '1'; + msto.adr <= out_dmem.write_addr(memory_width - 1 downto WB_ADR_BOUND); + msto.sel <= gen_select(out_dmem.write_addr(1 downto 0), out_dmem.write_size); + msto.dat <= enc_wb_dat(out_dmem.write_addr(1 downto 0), out_dmem.write_size, out_dmem.write_data); + end case; + end process; + wmsto <= msto; + + ----------------------------- + -- wbmi 2 core + ----------------------------- + wb2core_reg: process(wmsti, state, out_dmem) + begin + in_dmem.ready <= '0'; + if state = SIMACCWR then + in_dmem.ready <= '0'; + elsif state = SIMACCRD then + in_dmem.ready <= wmsti.ack; + elsif state = ONEACC then + if (out_dmem.write_en xor out_dmem.read_en)='1' then + in_dmem.ready <= wmsti.ack; + --elsif out_dmem.write_en='0' and out_dmem.read_en='0' then + -- indmem.ready <= '1'; + --elsif out_dmem.write_en='1' and out_dmem.read_en='1' then + -- indmem.ready <= '0'; + else --instead of the fancy stuff above: + in_dmem.ready <= out_dmem.write_en nand out_dmem.read_en; + end if; + end if; + end process; + +end Behavioral; diff --git a/soc/core/core_tb.vhd b/soc/core/core_tb.vhd new file mode 100644 index 0000000..70c1fac --- /dev/null +++ b/soc/core/core_tb.vhd @@ -0,0 +1,141 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; + +-- this testbench testes the core in total +entity core_tb is +end entity core_tb; + +architecture RTL of core_tb is + -- clock period, f = 1/period + constant period : time := 10 ns; + + component core + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_dmem : in dmem_core; + out_dmem : out core_dmem; + in_imem : in imem_core; + out_imem : out core_imem; + in_irq : in irq_core; + out_irq : out core_irq; + hardfault : out std_logic); + end component core; + + component memory + generic(filename : string := "program.ram"; + size : integer := 256; + imem_latency : time := 5 ns; + dmem_latency : time := 5 ns); + port(clk : in std_logic; + rst : in std_logic; + in_dmem : in core_dmem; + out_dmem : out dmem_core; + in_imem : in core_imem; + out_imem : out imem_core; + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0)); + end component memory; + + component irq_controller + port(clk : in std_logic; + rst : in std_logic; + in_proc : in core_irq; + out_proc : out irq_core; + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0)); + end component irq_controller; + + -- clock signal + signal clk : std_logic := '0'; + -- reset signal, active high + signal rst : std_logic := '1'; + -- outbyte signal + signal out_byte : std_logic_vector(7 downto 0); + + -- signals between instances + signal dmem_proc_signal : dmem_core; + signal proc_dmem_signal : core_dmem; + signal imem_proc_signal : imem_core; + signal proc_imem_signal : core_imem; + signal irq_proc_signal : irq_core; + signal proc_irq_signal : core_irq; + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0); +begin + core_inst : component core + port map(clk => clk, + rst => rst, + stall => '0', + in_dmem => dmem_proc_signal, + out_dmem => proc_dmem_signal, + in_imem => imem_proc_signal, + out_imem => proc_imem_signal, + in_irq => irq_proc_signal, + out_irq => proc_irq_signal, + hardfault => irq_lines(1)); + + memory_inst : component memory + generic map(--filename => "sample-programs\test_endianess2.ram", + --filename => "sample-programs\rawhztest.ram", + filename => "sample-programs\rdmem.ram", + size => 256, + imem_latency => 0 ns, + dmem_latency => 0 ns) + port map(clk => clk, + rst => rst, + in_dmem => proc_dmem_signal, + out_dmem => dmem_proc_signal, + in_imem => proc_imem_signal, + out_imem => imem_proc_signal, + fault => irq_lines(2), + out_byte => out_byte); + + irq_controller_inst : component irq_controller + port map(clk => clk, + rst => rst, + in_proc => proc_irq_signal, + out_proc => irq_proc_signal, + irq_lines => irq_lines); + + -- irq line stimuli + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + -- irq0 is reset + -- irq1 is hardfault + -- irq2 is memfault + + -- wait for 600 ns; + + -- wait until rising_edge(clk); + -- irq_lines(3) <= '1'; + -- irq_lines(4) <= '1'; + -- wait until rising_edge(clk); + -- irq_lines(3) <= '0'; + -- irq_lines(4) <= '0'; + + wait; + + end process irq_stimuli; + + -- clock stimuli + clock : process is + begin + clk <= not clk; + wait for period / 2; + end process clock; + + -- reset stimuli + reset : process is + begin + rst <= '1'; + wait for 3.5 * period; + rst <= '0'; + wait; + end process reset; + +end architecture RTL; diff --git a/soc/core/core_wave.wcfg b/soc/core/core_wave.wcfg new file mode 100644 index 0000000..9cecfa2 --- /dev/null +++ b/soc/core/core_wave.wcfg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + out_byte[7:0] + out_byte[7:0] + + + D mem + label + + dmem_proc_signal + dmem_proc_signal + + .read_data + dmem_proc_signal.read_data + HEXRADIX + + + .ready + dmem_proc_signal.ready + + + + proc_dmem_signal + proc_dmem_signal + + .write_data + proc_dmem_signal.write_data + HEXRADIX + + + .write_addr + proc_dmem_signal.write_addr + HEXRADIX + + + .write_size + proc_dmem_signal.write_size + + + .write_en + proc_dmem_signal.write_en + + + .read_addr + proc_dmem_signal.read_addr + HEXRADIX + + + .read_size + proc_dmem_signal.read_size + + + .read_en + proc_dmem_signal.read_en + + + + + I mem + label + + imem_proc_signal + imem_proc_signal + + .read_data + imem_proc_signal.read_data + HEXRADIX + + + .ready + imem_proc_signal.ready + + + + proc_imem_signal + proc_imem_signal + + .read_addr + proc_imem_signal.read_addr + HEXRADIX + + + .read_en + proc_imem_signal.read_en + + + + + IRQ + label + + irq_proc_signal + irq_proc_signal + + + proc_irq_signal + proc_irq_signal + + + irq_lines[15:0] + irq_lines[15:0] + + + diff --git a/soc/core/corewrapper.vhd b/soc/core/corewrapper.vhd new file mode 100644 index 0000000..ea2381b --- /dev/null +++ b/soc/core/corewrapper.vhd @@ -0,0 +1,142 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +-- TODO: check core(big/little endian) -> assume as little !! +entity corewrapper is + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); +end entity corewrapper; + +architecture RTL of corewrapper is + signal wbmo : wb_mst_out_type := wbm_out_none; + --signal indmem : dmem_core; + signal in_dmem : dmem_core; + signal out_dmem : core_dmem; + +-- signal inimem : imem_core; +-- signal outimem : core_imem; + + +--////////////////////////////////////////////////////// +-- component +--////////////////////////////////////////////////////// +component core + port( + clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + + in_dmem : in dmem_core; + out_dmem : out core_dmem; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_irq : in irq_core; + out_irq : out core_irq; + + hardfault : out std_logic + ); +end component; + +component core2wb + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out dmem_core; + out_dmem : in core_dmem; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); +end component; + +begin + +--////////////////////////////////////////////////////// +-- Instantiate +--////////////////////////////////////////////////////// +-- + core_inst: core + port map( + clk => clk, + rst => rst, + stall => '0', -- no stall for now -- wmsti.stall + + in_dmem => in_dmem, + out_dmem => out_dmem, + + in_imem => in_imem, -- inimem, + out_imem => out_imem, -- outimem, + in_irq => in_proc, + out_irq => out_proc, + hardfault => hardfault + ); + + core2wb_inst: core2wb + port map( + clk => clk, + rst => rst, + + in_dmem => in_dmem, + out_dmem => out_dmem, + + -- wb master port + wmsti => wmsti, + wmsto => wmsto + ); + + +--////////////////////////////////////////////////////// +-- I - mem +--////////////////////////////////////////////////////// + + + -- core connect directly to the mem + +-- imem: process(clk) +-- begin +-- if rising_edge(clk) then +-- if rst = '1' then +-- -- to core +-- inimem.read_data <= (others=>'-'); +-- inimem.ready <= '0'; +-- -- out from core +-- outimem.read_addr <= (others=>'0'); +-- outimem.read_en <= '0'; +-- +-- out_imem.read_addr <= (others=>'0'); +-- out_imem.read_en <= '0'; +-- else +-- -- to core +-- inimem <= in_imem; +-- -- out from core +-- out_imem <= outimem; +-- end if; +-- end if; +-- end process; + +end architecture RTL; diff --git a/soc/core/datapath.vhd b/soc/core/datapath.vhd new file mode 100644 index 0000000..d417217 --- /dev/null +++ b/soc/core/datapath.vhd @@ -0,0 +1,332 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +-- the datapath handles all data interactions, including the registerfile and the ALU +entity datapath is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal (halts pipelines and all flipflops), active high, synchronous + stall : in std_logic; + + -- signals to decoder + out_dec : out dp_dec; + + -- signals from control path + in_cp : in cp_dp; + -- signals to control path + out_cp : out dp_cp; + + -- signals from PC counter + in_pc : in pc_dp; + -- signals to PC counter + out_pc : out dp_pc; + + -- signals from data memory + in_dmem : in dmem_dp; + -- signals to data memory + out_dmem : out dp_dmem; + + -- hardfault signal + hardfault : out std_logic + ); +end entity datapath; + +architecture RTL of datapath is + component alu + port(in_a : in signed(reg_width - 1 downto 0); + in_b : in signed(reg_width - 1 downto 0); + t_out : out std_logic; + ovf_out : out std_logic; + mode : in alu_mode_type; + data_out : out signed(reg_width - 1 downto 0)); + end component alu; + + component registerfile + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + a_num : in reg_number; + a_out : out signed(reg_width - 1 downto 0); + b_num : in reg_number; + b_out : out signed(reg_width - 1 downto 0); + pc_in : in unsigned(pc_width - 1 downto 0); + write_data : in signed(reg_width - 1 downto 0); + write_num : in reg_number; + write_en : in std_logic; + true_writeenable : in std_logic; + true_in : in std_logic; + true_out : out std_logic; + ovf_writeenable : in std_logic; + ovf_in : in std_logic; + runtime_priority : out unsigned(irq_prio_width - 1 downto 0)); + end component registerfile; + + -- signals from register file + signal regfile_reg_a : signed(reg_width - 1 downto 0); + signal regfile_reg_b : signed(reg_width - 1 downto 0); + signal regfile_tflag : std_logic; + + -- signals from ALU + signal alu_result : signed(reg_width - 1 downto 0); + signal alu_tflag : std_logic; + signal alu_ovfflag : std_logic; + + -- mux output signals + -- data written to register file (if registerfile.we = '1') + signal reg_write_data : signed(reg_width - 1 downto 0); + -- second alu input data + signal alu_input_b : signed(reg_width - 1 downto 0); + -- bit saved as truth-flag (if registerfile.tflag_we = '1') + signal tflag_write_data : std_logic; + + -- forwarded register values + -- register a value after forwarding unit + signal regfile_reg_a_fwd : signed(reg_width - 1 downto 0); + -- register b value after forwarding unit + signal regfile_reg_b_fwd : signed(reg_width - 1 downto 0); + -- truth-flag after forwarding + signal regfile_tflag_fwd : std_logic; + + -- pipelined signals + signal register_number_a_s2 : reg_number; + signal register_number_b_s2 : reg_number; + + signal regfile_reg_a_s3 : signed(reg_width - 1 downto 0); + signal regfile_reg_b_s3 : signed(reg_width - 1 downto 0); + + signal alu_result_s3 : signed(reg_width - 1 downto 0); + signal alu_tflag_s3 : std_logic; + signal alu_ovfflag_s3 : std_logic; + + signal pc_value_s2 : unsigned(pc_width - 1 downto 0); + + signal immediate_signext_s3 : signed(reg_width - 1 downto 0); + + -- signals calculated internally in datapath + + -- LDR address + signal ldr_address : signed(reg_width - 1 downto 0); + + -- immediate value with signextension for use as alu input + signal immediate_signext : signed(reg_width - 1 downto 0); + + -- write data to register file including masking for size + signal reg_write_data_sized : signed(reg_width - 1 downto 0); + + -- dmem read data or'ed with 0xF0 + signal dmemORx80 : std_logic_vector(reg_width - 1 downto 0); + + -- hardfault signals + signal regwrite_size_error : std_logic; + + -- returns minimum of (a, b). needed, since XILINX does not support constant conditional syntax + function minval(a : integer; b : integer) return integer is + begin + if (a <= b) then + return a; + else + return b; + end if; + end function minval; + +begin + registerfile_inst : component registerfile + port map(clk => clk, + rst => rst, + stall => stall, + a_num => in_cp.s1.register_read_number_a, + a_out => regfile_reg_a, + b_num => in_cp.s1.register_read_number_b, + b_out => regfile_reg_b, + pc_in => pc_value_s2, + write_data => reg_write_data_sized, + write_num => in_cp.s3.register_write_number, + write_en => in_cp.s3.register_write_enable, + true_writeenable => in_cp.s3.tflag_write_enable, + true_in => tflag_write_data, + true_out => regfile_tflag, + ovf_writeenable => in_cp.s3.ovfflag_write_enable, + ovf_in => alu_ovfflag_s3, + runtime_priority => out_dec.runtime_priority); + + alu_inst : component alu + port map(in_a => regfile_reg_a_fwd, + in_b => alu_input_b, + t_out => alu_tflag, + ovf_out => alu_ovfflag, + mode => in_cp.s2.alu_mode, + data_out => alu_result); + + -- simple output assignments + out_pc.register_value <= regfile_reg_a_fwd(regfile_reg_a_fwd'high downto 1); -- last bit ignored for PC + hardfault <= regwrite_size_error; + out_dmem.write_addr(reg_width - 1 downto 0) <= std_logic_vector(regfile_reg_a_s3); + out_cp.s2.tflag <= regfile_tflag_fwd; + + -- create signextended immediate + -- sign extension + immediate_signext(immediate_signext'left downto (in_cp.s2.immediate'left + 1)) <= (others => in_cp.s2.immediate(7)); + -- actual data + immediate_signext(in_cp.s2.immediate'range) <= in_cp.s2.immediate; + + -- ldr address calculation + -- ldr_address = PC + (immediate << 1) + ldr_address <= signed(pc_value_s2) + signed(immediate_signext(reg_width - 2 downto 0) & "0"); + + -- create immediate value for pc block + -- sign extension + pc_imm_fill : if (reg_width > 8) generate + out_pc.immediate_value(out_pc.immediate_value'left downto (in_cp.s2.immediate'left + 1)) <= (others => in_cp.s2.immediate(7)); + end generate; + -- actual data, (left shift by one is performed by PC) + out_pc.immediate_value(minval(out_pc.immediate_value'high, in_cp.s2.immediate'left) downto 0) <= in_cp.s2.immediate(minval(out_pc.immediate_value'high, in_cp.s2.immediate'left) downto 0); + + + -- fill dmem read/write address and dmem write data, if reg width is smaller than memory width + -- all warnings of the type "Null range" can be safely ignored for reg_width = mem_width + dmem_fill : if (reg_width < mem_width) generate + out_dmem.write_addr(mem_width - 1 downto reg_width) <= (others => '0'); + out_dmem.write_data(mem_width - 1 downto reg_width) <= (others => '0'); + out_dmem.read_addr(mem_width - 1 downto reg_width) <= (others => '0'); + end generate dmem_fill; + + -- dmem data or'ing (dmemORx80 = dmem.read_data or 0x80) + dmemORx80_calc : process(in_dmem.read_data) is + begin + dmemORx80 <= in_dmem.read_data(reg_width - 1 downto 0); + dmemORx80(7) <= '1'; + end process dmemORx80_calc; + + -- multiplexer + + regfile_write_data_mux : with in_cp.s3.register_write_data_select select reg_write_data <= + signed(in_dmem.read_data(reg_width - 1 downto 0)) when sel_memory, + alu_result_s3 when sel_alu_result, + immediate_signext_s3 when sel_immediate; + + alu_in_b_mux : with in_cp.s2.alu_input_data_select select alu_input_b <= + regfile_reg_b_fwd when sel_register_b, + immediate_signext when sel_imm; + + dmem_write_data_mux : with in_cp.s3.memory_write_data_select select out_dmem.write_data(reg_width - 1 downto 0) <= + std_logic_vector(regfile_reg_b_s3) when sel_register_value, + dmemORx80 when sel_dmemORx80; + + dmem_read_addr_mux : with in_cp.s2.memory_read_addr_select select out_dmem.read_addr(reg_width - 1 downto 0) <= + std_logic_vector(regfile_reg_a_fwd) when sel_register_a, + std_logic_vector(regfile_reg_b_fwd) when sel_register_b, + std_logic_vector(ldr_address) when sel_ldr_address; + + tflag_write_data_mux : with in_cp.s3.tflag_write_data_select select tflag_write_data <= + (not in_dmem.read_data(7)) when sel_dmem7, + alu_tflag_s3 when sel_alu; + + -- forwarding units + + forward_register_a : process(in_cp.s3.register_write_number, register_number_a_s2, reg_write_data_sized, regfile_reg_a, in_cp.s3.register_write_enable) is + begin + if ((in_cp.s3.register_write_enable = '1') and (in_cp.s3.register_write_number = register_number_a_s2)) then + -- next cycle, there's a write to register number a, forward new value + regfile_reg_a_fwd <= reg_write_data_sized; + else + -- next cycle is no write to register number a, no forwarding + regfile_reg_a_fwd <= regfile_reg_a; + end if; + end process forward_register_a; + + forward_register_b : process(in_cp.s3.register_write_number, register_number_b_s2, reg_write_data_sized, regfile_reg_b, in_cp.s3.register_write_enable) is + begin + if ((in_cp.s3.register_write_enable = '1') and (in_cp.s3.register_write_number = register_number_b_s2)) then + -- next cycle, there's a write to register number b, forward new value + regfile_reg_b_fwd <= reg_write_data_sized; + else + -- next cycle is no write to register number b, no forwarding + regfile_reg_b_fwd <= regfile_reg_b; + end if; + end process forward_register_b; + + forward_tflag : process(tflag_write_data, regfile_tflag, in_cp.s3.tflag_write_enable) is + begin + if (in_cp.s3.tflag_write_enable = '1') then + -- next cycle, there's a write to the truth flag, forward new value + regfile_tflag_fwd <= tflag_write_data; + else + -- next cycle is no write to the truth flag + regfile_tflag_fwd <= regfile_tflag; + end if; + end process forward_tflag; + + -- generate size-matched data for the register file and forwarding units from the full-word write data + reg_write_data_sized_calc : process(reg_write_data, in_cp.s3.register_write_size) is + variable error : boolean; + begin + error := false; + reg_write_data_sized <= (others => '0'); + + case in_cp.s3.register_write_size is + when size_byte => + reg_write_data_sized(7 downto 0) <= reg_write_data(7 downto 0); + when size_halfword => + if (reg_width >= 16) then + reg_write_data_sized(minval(reg_width - 1, 15) downto 0) <= reg_write_data(minval(reg_width - 1, 15) downto 0); + else + error := true; + end if; + when size_word => + if (reg_width >= 32) then + reg_write_data_sized(minval(reg_width - 1, 31) downto 0) <= reg_write_data(minval(reg_width - 1, 31) downto 0); + else + error := true; + end if; + end case; + + if (error) then + -- synthesis translate_off + assert false report "size not supported" severity warning; + -- synthesis translate_on + regwrite_size_error <= '1'; + else + regwrite_size_error <= '0'; + end if; + + end process reg_write_data_sized_calc; + + -- pipelining + pipeline : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- default values in reset state + pc_value_s2 <= (others => '0'); + alu_result_s3 <= (others => '0'); + alu_tflag_s3 <= '0'; + alu_ovfflag_s3 <= '0'; + register_number_a_s2 <= (others => '0'); + register_number_b_s2 <= (others => '0'); + regfile_reg_a_s3 <= (others => '0'); + regfile_reg_b_s3 <= (others => '0'); + immediate_signext_s3 <= (others => '0'); + elsif (stall = '0') then + -- if stall is not active, pipeline values + pc_value_s2 <= in_pc.value; + alu_result_s3 <= alu_result; + alu_tflag_s3 <= alu_tflag; + alu_ovfflag_s3 <= alu_ovfflag; + register_number_a_s2 <= in_cp.s1.register_read_number_a; + register_number_b_s2 <= in_cp.s1.register_read_number_b; + regfile_reg_a_s3 <= regfile_reg_a_fwd; + regfile_reg_b_s3 <= regfile_reg_b_fwd; + immediate_signext_s3 <= immediate_signext; + end if; + end if; + end process pipeline; + +end architecture RTL; diff --git a/soc/core/decoder.vhd b/soc/core/decoder.vhd new file mode 100644 index 0000000..ac2f977 --- /dev/null +++ b/soc/core/decoder.vhd @@ -0,0 +1,125 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use work.lt16x32_internal.all; + +-- the decoder translates instructions from the memory into control signals. +-- it bundles pre-stage, finite stage machine and multiple instruction decoder (16bit, 32bit, shadow) +entity decoder is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal, active high, synchronous + stall : in std_logic; + + -- signals from instruction memory + in_imem : in imem_dec; + -- signals to instruction memory + out_imem : out dec_imem; + + -- signals from datapath + in_dp : in dp_dec; + + -- signals from controlpath + in_cp : in cp_dec; + -- signals to controlpath + out_cp : out dec_cp; + + -- signals to PC + out_pc : out dec_pc; + + -- signals from interrupt controller + in_irq : in irq_dec; + -- signals to interrupt controller + out_irq : out dec_irq + ); +end entity decoder; + +architecture RTL of decoder is + component decoder_pre + port(input : in imem_dec; + output : out pre_fsm); + end component decoder_pre; + component decoder_16bit + port(input : in fsm_dec16; + output : out dec_cp); + end component decoder_16bit; + component decoder_32bit + port(input : in fsm_dec32; + output : out dec_cp); + end component decoder_32bit; + component decoder_shadow + port(input : in fsm_decshd; + output : out dec_cp); + end component decoder_shadow; + component decoder_fsm + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_pre : in pre_fsm; + in_cp : in cp_dec; + in_dp : in dp_dec; + out_16 : out fsm_dec16; + out_32 : out fsm_dec32; + out_shd : out fsm_decshd; + out_mux : out fsm_decmux; + out_pc : out dec_pc; + out_imem : out dec_imem; + in_irq : in irq_dec; + out_irq : out dec_irq); + end component decoder_fsm; + + -- signals between instances + signal pre_fsm_signal : pre_fsm; + signal fsm_dec16_signal : fsm_dec16; + signal fsm_dec32_signal : fsm_dec32; + signal fsm_decshd_signal : fsm_decshd; + signal fsm_mux_signal : fsm_decmux; + signal fsm_pc_signal : dec_pc; + signal fsm_imem_signal : dec_imem; + signal dec16_mux_signal : dec_cp; + signal dec32_mux_signal : dec_cp; + signal decshd_mux_signal : dec_cp; + +begin + decoder_pre_inst : component decoder_pre + port map(input => in_imem, + output => pre_fsm_signal); + decoder_fsm_inst : component decoder_fsm + port map(clk => clk, + rst => rst, + stall => stall, + in_pre => pre_fsm_signal, + in_cp => in_cp, + in_dp => in_dp, + in_irq => in_irq, + out_irq => out_irq, + out_16 => fsm_dec16_signal, + out_32 => fsm_dec32_signal, + out_shd => fsm_decshd_signal, + out_mux => fsm_mux_signal, + out_pc => fsm_pc_signal, + out_imem => fsm_imem_signal); + decoder_16_inst : component decoder_16bit + port map(input => fsm_dec16_signal, + output => dec16_mux_signal); + decoder_32_inst : component decoder_32bit + port map(input => fsm_dec32_signal, + output => dec32_mux_signal); + decoder_shd_inst : component decoder_shadow + port map(input => fsm_decshd_signal, + output => decshd_mux_signal); + + -- multiplexer + mux_output : with fsm_mux_signal.mode select out_cp <= + dec16_mux_signal when sel_ir16, + dec32_mux_signal when sel_ir32, + decshd_mux_signal when sel_irshadow; + + -- simple signal assignments + out_pc <= fsm_pc_signal; + out_imem <= fsm_imem_signal; +end architecture RTL; diff --git a/soc/core/decoder_16bit.vhd b/soc/core/decoder_16bit.vhd new file mode 100644 index 0000000..455f74d --- /dev/null +++ b/soc/core/decoder_16bit.vhd @@ -0,0 +1,229 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the decoder_16bit decodes all 16bit instructions and is fully combinatoric +entity decoder_16bit is + port( + -- input signals from decoder_fsm + input : in fsm_dec16; + -- output signals to controlpath (or decoder mux) + output : out dec_cp + ); +end entity decoder_16bit; + +architecture RTL of decoder_16bit is +begin + + -- decode instruction + decode : process(input) is + begin + -- set defaults to prevent taking values from previous operations + output.s1 <= get_default_dec_cp_s1; + output.s2 <= get_default_dec_cp_s2; + output.s3 <= get_default_dec_cp_s3; + output.hardfault <= '0'; + + -- directly forwarded instruction parts + output.s1.register_read_number_a <= reg_number(input.instruction(7 downto 4)); + output.s1.register_read_number_b <= reg_number(input.instruction(3 downto 0)); + output.s3.register_write_number <= reg_number(input.instruction(11 downto 8)); + + -- set opcode specific signals + case input.instruction(15 downto 12) is + when op_add => -- add instruction + output.s2.alu_mode <= alu_add; + output.s3.register_write_enable <= '1'; + output.s3.ovfflag_write_enable <= '1'; + when op_sub => -- subtract instruction + output.s2.alu_mode <= alu_sub; + output.s3.register_write_enable <= '1'; + output.s3.ovfflag_write_enable <= '1'; + when op_or => -- bitwise or instruction + output.s2.alu_mode <= alu_or; + output.s3.register_write_enable <= '1'; + when op_and => -- bitwise and instruction + output.s2.alu_mode <= alu_and; + output.s3.register_write_enable <= '1'; + when op_xor => -- bitwise xor instruction + output.s2.alu_mode <= alu_xor; + output.s3.register_write_enable <= '1'; + when op_lsh => -- logic left shift instruction + output.s2.alu_mode <= alu_lsh; + output.s2.alu_input_data_select <= sel_imm; + output.s2.immediate <= signed("0000" & input.instruction(3 downto 0)); + output.s3.register_write_enable <= '1'; + when op_rsh => -- logic right shift instruction + output.s2.alu_mode <= alu_rsh; + output.s2.alu_input_data_select <= sel_imm; + output.s2.immediate <= signed("0000" & input.instruction(3 downto 0)); + output.s3.register_write_enable <= '1'; + when op_addi => -- add immediate instruction + output.s1.register_read_number_a <= reg_number(input.instruction(11 downto 8)); + output.s2.alu_mode <= alu_add; + output.s2.alu_input_data_select <= sel_imm; + output.s2.immediate <= signed(input.instruction(7 downto 0)); + output.s3.register_write_enable <= '1'; + output.s3.ovfflag_write_enable <= '1'; + when op_cmp => -- compare instruction + output.s3.tflag_write_enable <= '1'; + case input.instruction(11 downto 8) is + when op_cmp_eq => -- compare for equal + output.s2.alu_mode <= alu_cmp_eq; + when op_cmp_neq => -- compare for not equal + output.s2.alu_mode <= alu_cmp_neq; + when op_cmp_ge => -- compare for greater than or equal + output.s2.alu_mode <= alu_cmp_ge; + when op_cmp_ll => -- compare for less than + output.s2.alu_mode <= alu_cmp_ll; + when op_cmp_gg => -- compare for greater than + output.s2.alu_mode <= alu_cmp_gg; + when op_cmp_le => -- compare for less than or equal + output.s2.alu_mode <= alu_cmp_le; + when op_cmp_true => -- set truth flag + output.s2.alu_mode <= alu_cmp_true; + when op_cmp_false => -- reset truth flag + output.s2.alu_mode <= alu_cmp_false; + when others => + -- unknown compare mode, throw hardfault + output.hardfault <= '1'; + + -- synthesis translate_off + assert false report "cmp mode not supported" severity error; + -- synthesis translate_on + end case; + when op_bct => -- branch, call, trap, reti instruction + if (input.instruction(11 downto 9) = op_bct_reti) then + -- it's reti instruction, which is not allowed here (as it is handled earlier in decoder) + output.hardfault <= '1'; + + -- synthesis translate_off + assert false report "reti operation not allowed in 16 bit decoder stage" severity error; + -- synthesis translate_on + + else -- table / branch / (call) / trap + -- decode source bit + if (input.instruction(9) = '0') then -- bct to immediate + if (input.instruction(11 downto 10) = op_bct_trap) then + -- trap is absolute to immediate + output.s2.pc_mode_select <= sel_absolute; + else + -- all other branches to immediate are relative + output.s2.pc_mode_select <= sel_relative; + end if; + -- immediate parameters + output.s2.pc_summand_select <= sel_immediate; + output.s2.immediate <= signed(input.instruction(7 downto 0)); + + else -- bct to register + if (input.instruction(11 downto 10) = op_bct_table) then + -- branch to table is pc relative + output.s2.pc_mode_select <= sel_relative; + else + -- all other branches to register are absolute + output.s2.pc_mode_select <= sel_absolute; + end if; + -- register parameters + output.s2.pc_summand_select <= sel_register_a; + end if; + + -- decode conditional bit + if (input.instruction(8) = '1') then + output.s2.pc_condition <= sel_true; + else + output.s2.pc_condition <= sel_unconditional; + end if; + end if; + + when op_mem => -- memory instructions + case input.instruction(11 downto 8) is + when op_mem_ld08 => -- load byte + output.s2.dmem_read_addr_select <= sel_register_b; + output.s2.dmem_read_en <= '1'; + output.s2.dmem_read_size <= size_byte; + output.s3.register_write_data_select <= sel_memory; + output.s3.register_write_enable <= '1'; + output.s3.register_write_size <= size_byte; + output.s3.register_write_number <= reg_number(input.instruction(7 downto 4)); + when op_mem_ld16 => -- load halfword + output.s2.dmem_read_addr_select <= sel_register_b; + output.s2.dmem_read_en <= '1'; + output.s2.dmem_read_size <= size_halfword; + output.s3.register_write_data_select <= sel_memory; + output.s3.register_write_enable <= '1'; + output.s3.register_write_size <= size_halfword; + output.s3.register_write_number <= reg_number(input.instruction(7 downto 4)); + when op_mem_ld32 => -- load word + output.s2.dmem_read_addr_select <= sel_register_b; + output.s2.dmem_read_en <= '1'; + output.s2.dmem_read_size <= size_word; + output.s3.register_write_data_select <= sel_memory; + output.s3.register_write_enable <= '1'; + output.s3.register_write_size <= size_word; + output.s3.register_write_number <= reg_number(input.instruction(7 downto 4)); + + when op_mem_st08 => -- store byte + output.s3.dmem_write_en <= '1'; + output.s3.dmem_write_size <= size_byte; + output.s3.dmem_write_data_select <= sel_register_value; + when op_mem_st16 => -- store halfword + output.s3.dmem_write_en <= '1'; + output.s3.dmem_write_size <= size_halfword; + output.s3.dmem_write_data_select <= sel_register_value; + when op_mem_st32 => -- store word + output.s3.dmem_write_en <= '1'; + output.s3.dmem_write_size <= size_word; + output.s3.dmem_write_data_select <= sel_register_value; + + when others => + -- unknown memory mode, throw hardfault + output.hardfault <= '1'; + + -- synthesis translate_off + assert false report "memory mode not supported" severity error; + -- synthesis translate_on + end case; + + when op_ldr => -- load pc relative (full register width) + output.s2.immediate <= signed(input.instruction(7 downto 0)); + output.s2.dmem_read_addr_select <= sel_ldr_address; + output.s2.dmem_read_en <= '1'; + output.s2.dmem_read_size <= reg_size; + output.s3.register_write_data_select <= sel_memory; + output.s3.register_write_enable <= '1'; + output.s3.register_write_size <= reg_size; + + when op_tst => -- test and set + output.s2.dmem_read_addr_select <= sel_register_a; + output.s2.dmem_read_en <= '1'; + output.s2.dmem_read_size <= size_byte; + output.s3.register_write_data_select <= sel_memory; + output.s3.register_write_enable <= '1'; + output.s3.register_write_size <= size_byte; + output.s3.dmem_write_en <= '1'; + output.s3.dmem_write_size <= size_byte; + output.s3.dmem_write_data_select <= sel_dmemORx80; + output.s3.tflag_write_data_select <= sel_dmem7; + output.s3.tflag_write_enable <= '1'; + + -- synthesis translate_off + when "UUUU" => + null; -- ignore startup + when "XXXX" => + null; -- ignore IM delay + -- synthesis translate_on + + when others => + -- unkwown operation, throw hardfault + output.hardfault <= '1'; + -- synthesis translate_off + assert false report "unknown operation not implemented" severity error; + -- synthesis translate_on + + end case; + end process decode; + +end architecture RTL; diff --git a/soc/core/decoder_32bit.vhd b/soc/core/decoder_32bit.vhd new file mode 100644 index 0000000..397c782 --- /dev/null +++ b/soc/core/decoder_32bit.vhd @@ -0,0 +1,28 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the decoder_32bit decodes all 32bit instructions and is fully combinatoric +entity decoder_32bit is + port( + -- input signals from decoder finite state machine + input : in fsm_dec32; + -- output signals to control path (or decoder mux) + output : out dec_cp + ); +end entity decoder_32bit; + +architecture RTL of decoder_32bit is +begin + + -- currently, there are no 32bit instructions, so output is + -- always nop and hardfault + output.s1 <= get_default_dec_cp_s1; + output.s2 <= get_default_dec_cp_s2; + output.s3 <= get_default_dec_cp_s3; + output.hardfault <= '1'; + +end architecture RTL; diff --git a/soc/core/decoder_fsm.vhd b/soc/core/decoder_fsm.vhd new file mode 100644 index 0000000..fb6d432 --- /dev/null +++ b/soc/core/decoder_fsm.vhd @@ -0,0 +1,319 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +-- the decoder_fsm is the finite state machine handling multi-cycle operation and interrupt acknowledgement +entity decoder_fsm is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal, active high + stall : in std_logic; + + -- signals from pre-decoder + in_pre : in pre_fsm; + -- signals from control path + in_cp : in cp_dec; + -- signals from datapath + in_dp : in dp_dec; + + -- signals to 16bit decoder + out_16 : out fsm_dec16; + -- signals to 32bit decoder + out_32 : out fsm_dec32; + -- signals to shadow decoder + out_shd : out fsm_decshd; + -- signals to decoder mux + out_mux : out fsm_decmux; + + -- signals to pc counter + out_pc : out dec_pc; + -- signals to instruction memory + out_imem : out dec_imem; + + -- signals from interrupt controller + in_irq : in irq_dec; + -- signals to interrupt controller + out_irq : out dec_irq + ); +end entity decoder_fsm; + +architecture RTL of decoder_fsm is + -- possible states of fsm + type state_type is (normal, reset, reset2, copyPCtoLR, branchdelay, irq_decSP1, irq_pushSR, irq_pushLR, irq_setSR, irq_setPC, reti_popLR, reti_incSP1, reti_popSR, reti_incSP2); --add irq_decSP2 for 4 instruction irq stack solution + -- current state + signal state : state_type := normal; + + -- temporary storage for multicycle operations + signal multicycleinstruction : std_logic_vector(31 downto 0); +begin + + -- the finite state machine is modelled as mealy-machine + + -- generate output (combinatoric part) + output : process(in_pre, state, multicycleinstruction, in_cp.condition_holds) is + variable state_variable : state_type; + begin + -- standard output + out_16.instruction <= nop16; + out_32.instruction <= in_pre.instruction; + out_shd.instruction(31 downto 28) <= op_shd_push; + out_shd.instruction(27 downto 0) <= (others => '0'); + + out_mux.mode <= sel_ir16; + out_pc.stall <= '0'; + + out_imem.en <= '1'; + + out_irq.ack <= '0'; + out_irq.trap_req <= '0'; + out_irq.trap_num <= (others => '0'); + + -- copy state to variable for further processing + state_variable := state; + + -- don't insert nop in branch delay if no branch taken + -- happens only, if execute_branch_delay_slot is false + if ((state = branchdelay) and (in_cp.condition_holds = '0')) then + state_variable := normal; + end if; + + -- don't write LR if no call happens + if ((state = copyPCtoLR) and (in_cp.condition_holds = '0')) then + state_variable := normal; + end if; + + -- generate state dependend output + case state_variable is + when reset => -- first cycle in reset + out_pc.stall <= '1'; + out_shd.instruction(31 downto 28) <= op_shd_reset; + out_mux.mode <= sel_irshadow; + + when reset2 => -- second cycle in reset + out_pc.stall <= '0'; + out_16.instruction <= nop16; + out_mux.mode <= sel_ir16; + + when normal => -- standard mode + out_pc.stall <= '0'; + + case in_pre.mode is -- check decoder_pre mode output + when sel_normal16 => -- normal 16 bit instruction + out_mux.mode <= sel_ir16; + out_16.instruction <= in_pre.instruction(15 downto 0); + when sel_normal32 => -- normal 32 bit instruction + out_mux.mode <= sel_ir32; + out_32.instruction <= in_pre.instruction; + when sel_branch => -- branch instruction + out_mux.mode <= sel_ir16; + out_16.instruction <= in_pre.instruction(15 downto 0); + when sel_call => -- call instruction + out_mux.mode <= sel_ir16; + out_16.instruction <= op_bct & "01" & in_pre.instruction(9 downto 0); + --out_imem.en <= '0'; -- imem must be read in case that condition does not hold and next instruction should be executed + when sel_trap => -- trap instruction + out_mux.mode <= sel_ir16; + out_16.instruction <= nop16; + out_irq.trap_num <= unsigned(in_pre.instruction(irq_num_width - 1 downto 0)); + out_irq.trap_req <= '1'; + when sel_reti => -- reti instruction + out_mux.mode <= sel_ir16; + out_16.instruction <= op_bct & "0110" & std_logic_vector(lr_num) & "0000"; + out_imem.en <= '0'; + when sel_stall => -- stall (i.e. imem not ready) + out_mux.mode <= sel_ir16; + out_16.instruction <= in_pre.instruction(15 downto 0); + out_pc.stall <= '1'; + end case; + + when copyPCtoLR => -- LR = PC, used in call and irq + -- only if condition true, else normal instruction (this check is done in state transition) + out_mux.mode <= sel_ir16; + out_16.instruction <= op_or & std_logic_vector(lr_num) & std_logic_vector(pc_num) & std_logic_vector(pc_num); + out_imem.en <= '1'; + + when branchdelay => -- insert NOP to branch delay slot if enabled in configuration + out_pc.stall <= '0'; + out_mux.mode <= sel_ir16; + out_imem.en <= '1'; + + --when irq_pushLR => -- irq: push LR + -- out_pc.stall <= '1'; + -- out_mux.mode <= sel_irshadow; + -- out_shd.instruction(31 downto 28) <= op_shd_push; + -- out_shd.instruction(3 downto 0) <= std_logic_vector(lr_num); + -- out_imem.en <= '0'; + when irq_pushLR => + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_mem & op_mem_st32 & std_logic_vector(sp_num) & std_logic_vector(lr_num); + out_imem.en <= '1'; + + when irq_setSR => -- irq: push SR and set new SR value + out_pc.stall <= '1'; + out_mux.mode <= sel_irshadow; + out_shd.instruction(31 downto 28) <= op_shd_setsr; + -- new runtime priority, other SR flags all zero + out_shd.instruction(7 downto (8 - irq_prio_width)) <= multicycleinstruction(16 + irq_prio_width - 1 downto 16); + out_imem.en <= '0'; + + when irq_setPC => -- irq: branch to irq address + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_bct & "11" & multicycleinstruction(9 downto 0); + out_imem.en <= '0'; + + when reti_popLR => -- reti: load LR from stack + out_pc.stall <= '0'; --former 1 + out_mux.mode <= sel_ir16; + out_16.instruction <= op_mem & op_mem_ld32 & std_logic_vector(lr_num) & std_logic_vector(sp_num); + out_imem.en <= '0'; + + when reti_popSR => -- reti: load SR from stack + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_mem & op_mem_ld32 & std_logic_vector(sr_num) & std_logic_vector(sp_num); + out_imem.en <= '1'; + + when reti_incSP1 => -- reti: increment SP + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(4, 8)); + out_imem.en <= '0'; + + when reti_incSP2 => -- reti increment SP + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(4, 8)); + out_imem.en <= '0'; + + when irq_pushSR => -- irq: push SR (store and decrement SP afterwards) + out_mux.mode <= sel_irshadow; + out_shd.instruction(31 downto 28) <= op_shd_push; + out_shd.instruction(3 downto 0) <= std_logic_vector(sr_num); + out_irq.ack <= '1'; + out_pc.stall <= '1'; + --when irq_pushSR => + -- out_pc.stall <= '1'; + -- out_mux.mode <= sel_ir16; + -- out_16.instruction <= op_mem & op_mem_st32 & std_logic_vector(sp_num) & std_logic_vector(sr_num); + -- out_imem.en <= '1'; + -- out_irq.ack <= '1'; + when irq_decSP1 => + out_pc.stall <= '1'; + out_mux.mode <= sel_ir16; + out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(-4, 8)); + out_imem.en <= '0'; + --when irq_decSP2 => + -- out_pc.stall <= '1'; + -- out_mux.mode <= sel_ir16; + --out_16.instruction <= op_addi & std_logic_vector(sp_num) & std_logic_vector(to_signed(-4, 8)); + --out_imem.en <= '0'; + + end case; + + end process output; + + -- state transition (clocked part) + state_transition : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + state <= reset; + elsif (stall = '0') then + state <= state; -- in default: keep state + + -- check for interrupt request + if ( + -- not near branch and not in multicycle operation + (in_pre.mode /= sel_branch) and (state = normal) + -- interrupt request + and (in_irq.req = '1') + -- priority higher than runtime priority or non maskable interrupt + and ((unsigned(in_irq.priority) > in_dp.runtime_priority) or (in_irq.nmi = '1')) + ) then + -- in normal mode and irq request + --state <= irq_pushSR; + state <= irq_decSP1; + + multicycleinstruction <= (others => '0'); + multicycleinstruction(16 + irq_prio_width - 1 downto 16) <= std_logic_vector(in_irq.priority); + multicycleinstruction(irq_num_width downto 0) <= std_logic_vector(in_irq.num) & "0"; + + -- synthesis translate_off + assert false report "current runtime priority is " & integer'image(to_integer(in_dp.runtime_priority)) & ". IRQ priority is " & integer'image(to_integer(unsigned(in_irq.priority))) & "." severity note; + assert false report "handle irq request #" & integer'image(to_integer(unsigned(in_irq.num))) severity note; + -- synthesis translate_on + + else + -- no irq request valid + + -- for state transition diagram see documentation + case state is + when normal => + case in_pre.mode is + when sel_normal16 => + state <= normal; + when sel_normal32 => + state <= normal; + when sel_call => + state <= copyPCtoLR; + when sel_branch => + if (execute_branch_delay_slot) then + state <= normal; + else + state <= branchdelay; + end if; + when sel_trap => + state <= normal; + when sel_reti => + --state <= reti_incSP1; + state <= reti_popLR; + when sel_stall => + state <= normal; + end case; + when copyPCtoLR => + state <= normal; + when branchdelay => + state <= normal; + --! group by multicycle opertation/pseudo-instruction -TF + -- i.e. IRQ entry (multicycle) + when irq_decSP1 => + state <= irq_pushSR; + when irq_pushSR => + --state <= irq_decSP2; + state <= irq_pushLR; + --when irq_decSP2 => + -- state <= irq_pushLR; + when irq_pushLR => + state <= irq_setSR; + when irq_setSR => + state <= irq_setPC; + when irq_setPC => + state <= copyPCtoLR; + when reti_popLR => + state <= reti_incSP1; + when reti_incSP1 => + state <= reti_popSR; + when reti_popSR => + state <= reti_incSP2; + when reti_incSP2 => + state <= normal; + when reset => + state <= reset2; + when reset2 => + state <= normal; + end case; + end if; + end if; + end if; + end process state_transition; + +end architecture RTL; diff --git a/soc/core/decoder_pre.vhd b/soc/core/decoder_pre.vhd new file mode 100644 index 0000000..ce19105 --- /dev/null +++ b/soc/core/decoder_pre.vhd @@ -0,0 +1,103 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use work.lt16x32_internal.all; + +-- the decoder_pre checks the new instruction for basic data, which is needed in the finite state machine as input. +-- it is fully combinatoric +entity decoder_pre is + port( + -- signals from instruction memory + input : in imem_dec; + -- signals to decoder finite state machine + output : out pre_fsm + ); +end entity decoder_pre; + +architecture RTL of decoder_pre is +begin + -- decodes instruction memory input and outputs signals to finite state machine + decode : process(input) is + -- fetched instruction, 16 bit instructions stored in (15 downto 0) bits + variable instruction : std_logic_vector(31 downto 0); + -- width of fetched instruction + variable instruction_width : instruction_width_type; + -- instruction mode, temporary storage for clean logic/output seperation + variable instruction_mode : instruction_mode_type; + + begin + -- needed to avoid latch generation for upper half word + instruction := (others => '0'); + + if (input.ready = '1') then + -- instruction memory is ready + + -- get relevant instruction from instruction word and extract instruction width + case input.instruction_halfword_select is + when '0' => -- 32bit aligned, might be 32bit instruction + if (input.read_data(31 downto 28) = "1111") then + -- is 32 bit instruction + instruction_width := sel_32bit; + instruction(31 downto 0) := std_logic_vector(input.read_data(31 downto 0)); + else + -- is 16 bit instruction + instruction_width := sel_16bit; + instruction(15 downto 0) := std_logic_vector(input.read_data(31 downto 16)); + end if; + + when '1' => -- lower 16bit, always 16 bit instruction + instruction_width := sel_16bit; + instruction(15 downto 0) := std_logic_vector(input.read_data(15 downto 0)); + + when others => + instruction_width := sel_16bit; + instruction(15 downto 0) := op_or & "0000" & "0000" & "0000"; + assert false report "instruction halfword select must be either 0 or 1" severity warning; + end case; + + -- check for special, multicycle or normal instructions + if (instruction_width = sel_16bit) then + -- 16 bit instructions + + if (instruction(15 downto 10) = op_bct & op_bct_call) then + -- instruction is call + instruction_mode := sel_call; + + elsif (instruction(15 downto 10) = op_bct & op_bct_trap) then + -- instruction is trap + instruction_mode := sel_trap; + + elsif (instruction(15 downto 9) = op_bct & op_bct_reti) then + -- instruction is reti + instruction_mode := sel_reti; + + elsif (instruction(15 downto 10) = op_bct & op_bct_branch) then + -- instruction is branch + instruction_mode := sel_branch; + + elsif (instruction(15 downto 10) = op_bct & op_bct_table) then + -- instruction is branch to table + instruction_mode := sel_branch; + else + + -- no special instruction + instruction_mode := sel_normal16; + end if; + + else + -- 32bit instructions + instruction_mode := sel_normal32; + end if; + else + -- imem not ready + instruction(15 downto 0) := nop16; + instruction_mode := sel_stall; + end if; + + -- output + output.instruction <= instruction; + output.mode <= instruction_mode; + end process decode; + +end architecture RTL; diff --git a/soc/core/decoder_shadow.vhd b/soc/core/decoder_shadow.vhd new file mode 100644 index 0000000..ea65097 --- /dev/null +++ b/soc/core/decoder_shadow.vhd @@ -0,0 +1,74 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the decoder_shadow decodes instructions which are needed but not part of user-available instruction set (e.g. push). +-- it is fully combinatoric. +entity decoder_shadow is + port( + -- input signals from decoder finite state machine + input : in fsm_decshd; + -- output signals to control path (or decoder mux) + output : out dec_cp + ); +end entity decoder_shadow; + +architecture RTL of decoder_shadow is +begin + + -- decode instruction + decode : process(input.instruction) is + begin + -- set defaults to prevent taking values from previous operations + output.s1 <= get_default_dec_cp_s1; + output.s2 <= get_default_dec_cp_s2; + output.s3 <= get_default_dec_cp_s3; + output.hardfault <= '0'; + + -- set instruction specific signals + case input.instruction(31 downto 28) is + when op_shd_push => -- push instruction + -- write to mem + output.s1.register_read_number_b <= reg_number(input.instruction(3 downto 0)); + output.s3.dmem_write_en <= '1'; + output.s3.dmem_write_size <= size_word; + output.s3.dmem_write_data_select <= sel_register_value; + -- decrement SP + output.s1.register_read_number_a <= sp_num; + output.s2.alu_mode <= alu_sub; + output.s2.alu_input_data_select <= sel_imm; + output.s2.immediate <= to_signed(4, 8); + output.s3.register_write_number <= sp_num; + output.s3.register_write_enable <= '1'; + when op_shd_setsr => -- set SR instruction + output.s3.register_write_data_select <= sel_immediate; + output.s3.register_write_number <= sr_num; + output.s3.register_write_size <= size_byte; + output.s3.register_write_enable <= '1'; + output.s2.immediate <= signed(input.instruction(7 downto 0)); + when op_shd_reset => -- reset instruction + -- PC = zero + output.s2.pc_summand_select <= sel_immediate; + output.s2.pc_mode_select <= sel_absolute; + output.s2.pc_condition <= sel_unconditional; + output.s2.immediate <= (others => '0'); + + -- synthesis translate_off + when "UUUU" => + null; -- ignore startup + -- synthesis translate_on + + when others => + -- unknown operation, throw hardfault + output.hardfault <= '1'; + + -- synthesis translate_off + assert false report "unknown shadow operation not implemented" severity error; + -- synthesis translate_on + end case; + end process decode; + +end architecture RTL; diff --git a/soc/core/irq_controller.vhd b/soc/core/irq_controller.vhd new file mode 100644 index 0000000..6023907 --- /dev/null +++ b/soc/core/irq_controller.vhd @@ -0,0 +1,135 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; + +-- the interrupt controller constantly checks interrupt lines for interrupt signals, +-- which then are send to the processor. +entity irq_controller is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + + -- signals from the processor + in_proc : in core_irq; + -- signals to the processor + out_proc : out irq_core; + + -- irq lines from the "outside world" + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); +end entity irq_controller; + +architecture RTL of irq_controller is + -- interrupt number of current request, valid if req = '1' + signal num : unsigned(irq_num_width - 1 downto 0); + -- interrupt priority of current request, valid if req = '1' + signal priority : unsigned(irq_prio_width - 1 downto 0); + -- request signal, active high + signal req : std_logic; + -- non maskable interrupt signal, active high + signal nmi : std_logic; + + -- storage of all interrupts that are pending currently + signal pending : std_logic_vector(irq_lines'range); + + -- returns the priority of a given interrupt number, which + -- is - for simplicity - calculated as + -- priority = number modulo maximum priority + -- this could be extended/changed for each application + function get_priority(num : unsigned(irq_num_width - 1 downto 0)) return unsigned is + variable result : unsigned(irq_prio_width - 1 downto 0); + begin + result := num(result'range); + + return result; + end function get_priority; + +begin + -- simple signal forwarding + out_proc.req <= req; + out_proc.num <= num; + out_proc.nmi <= nmi; + out_proc.priority <= priority; + + -- reading in both trap signal and external interrupt lines, setting the signal pending + read_in : process(clk) is + variable pendingVar : std_logic_vector(pending'range); + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset, all pending interrupts are cleared + pending <= (others => '0'); + else + -- read in current pending interrupts + pendingVar := pending; + + -- clear acknowledged interrupt + if (req = '1') and (in_proc.ack = '1') then + pendingVar(to_integer(num)) := '0'; + end if; + + -- read in trap request + if (in_proc.trap_req = '1') then + pendingVar(to_integer(unsigned(in_proc.trap_num))) := '1'; + end if; + + -- read in external interrupt request + if (irq_lines /= (irq_lines'range => '0')) then + pendingVar := pendingVar or irq_lines; + end if; + + -- output variable to signal + pending <= pendingVar; + end if; + end if; + end process read_in; + + -- generate request signals + request_gen : process(pending, rst) is + -- highest priority in search process + variable prio_highest : unsigned(irq_prio_width - 1 downto 0) := (others => '0'); + -- number of interrupt with highes priority + variable num_highest : unsigned(irq_num_width - 1 downto 0) := (others => '0'); + begin + -- if not in request, and something is pending (ignoring startup uninitialized state) + if ((rst = '0') and ((pending /= (pending'range => '0')) and (pending /= (pending'range => 'U')))) then + -- something is pending + + -- initialize variables before loop + prio_highest := to_unsigned(0, irq_prio_width); + num_highest := to_unsigned(0, irq_num_width); + + -- get highest prioritized pending interrupt + for i in pending'range loop + if (pending(i) = '1') and (get_priority(to_unsigned(i, irq_num_width)) >= prio_highest) then + num_highest := to_unsigned(i, irq_num_width); + prio_highest := get_priority(to_unsigned(i, irq_num_width)); + end if; + end loop; + + -- output next interrupt + num <= num_highest; + priority <= prio_highest; + req <= '1'; + + -- interrupt 2 is NMI + if (num_highest = to_unsigned(2, irq_num_width)) then + nmi <= '1'; + else + nmi <= '0'; + end if; + else + -- nothing is pending + num <= to_unsigned(1, irq_num_width); + priority <= to_unsigned(2, irq_prio_width); + req <= '0'; + nmi <= '0'; + end if; + end process request_gen; + +end architecture RTL; diff --git a/soc/core/lt16x32_global.vhd b/soc/core/lt16x32_global.vhd new file mode 100644 index 0000000..4500d34 --- /dev/null +++ b/soc/core/lt16x32_global.vhd @@ -0,0 +1,91 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package lt16x32_global is + -- width of the memory, the core supports 32 only + constant memory_width : integer := 32; + -- width of the vector holding the interrupt number, maximum 7 due to processor architecture + constant irq_num_width : integer := 4; + -- width of the vector holding the interrupt priority, maximum 6 due to processor architecture + constant irq_prio_width : integer := 4; + + -- collection of all signals from the core to the data memory + type core_dmem is record + -- data written to the memory + write_data : std_logic_vector(memory_width - 1 downto 0); + -- address to which the data is written + write_addr : std_logic_vector(memory_width - 1 downto 0); + -- size of the written data + -- 00: byte (8bits) + -- 01: halfword (16bits) + -- 10: word (32bits) + -- 11: longword (64bits, currently not featured) + write_size : std_logic_vector(1 downto 0); + -- write enable signal, active high + write_en : std_logic; + + -- address from which data is read + read_addr : std_logic_vector(memory_width - 1 downto 0); + -- size of the read data + -- 00: byte (8bits) + -- 01: halfword (16bits) + -- 10: word (32bits) + -- 11: longword (64bits, currently not featured) + read_size : std_logic_vector(1 downto 0); + -- read enable signal, active high + read_en : std_logic; + end record; + + -- collection of all signals from the data memory to the core + type dmem_core is record + -- read data, right aligned and zero-filled + read_data : std_logic_vector(memory_width - 1 downto 0); + -- ready signal, high if read data is valid + ready : std_logic; + end record; + + -- collection of all signals from the core to the instruction memory + type core_imem is record + -- address from which the instruction should be read + read_addr : std_logic_vector(memory_width - 1 downto 0); + -- read enable signal, active high + read_en : std_logic; + end record; + + -- collection of all signals from the instruction memory to the core + type imem_core is record + -- read data + read_data : std_logic_vector(memory_width - 1 downto 0); + -- ready signal, high if read data is valid + ready : std_logic; + end record; + + -- collection of all signals from the interrupt controller to the core + type irq_core is record + -- interrupt number of requested interrupt + num : unsigned(irq_num_width - 1 downto 0); + -- priority of requested interrupt (higher number means higher priority) + priority : unsigned(irq_prio_width - 1 downto 0); + -- request signal, active high + req : std_logic; + -- non maskable interrupt flag, active high + nmi : std_logic; + end record; + + -- collection of all signals from the core to the interrupt controller + type core_irq is record + -- interrupt acknowledge, high if requested interrupt is processed + ack : std_logic; + -- number of interrupt requested by internal trap instruction + trap_num : unsigned(irq_num_width - 1 downto 0); + -- request signal for internal trap, active high + trap_req : std_logic; + end record; + +end package lt16x32_global; + +package body lt16x32_global is +end package body lt16x32_global; diff --git a/soc/core/lt16x32_internal.vhd b/soc/core/lt16x32_internal.vhd new file mode 100644 index 0000000..94361e6 --- /dev/null +++ b/soc/core/lt16x32_internal.vhd @@ -0,0 +1,700 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; + +package lt16x32_internal is + + -- PACKAGE CONFIGURATION + + -- execute branch delay slot. if set to true, the first operation behind + -- any type of branch is executed. if set to false, stalls are inserted + constant execute_branch_delay_slot : boolean := TRUE; + -- register width + constant reg_width : integer := 32; + -- pc width (should be smaller or equal to register width) + constant pc_width : integer := 32; + + -- CONSTANT DECLARATIONS (part 1) + -- memory access width (must be 32 in all conditions) + constant mem_width : integer := 32; + -- 16bit nop + constant nop16 : std_logic_vector(15 downto 0) := "0000000000000000"; + + -- constants for register numbers are found below function declaration + + -- TYPE DEFINITIONS + + -- type register numbers + subtype reg_number is unsigned(3 downto 0); + + -- type for data size + type size_type is ( + -- 8 bit + size_byte, + -- 16 bit + size_halfword, + -- 32 bit + size_word + ); + + -- type for ALU operation + type alu_mode_type is ( + + -- calculations + + -- perform an addition + alu_add, + -- perform a subtraction + alu_sub, + -- perform a binary and + alu_and, + -- perform a binary or + alu_or, + -- perform a binary xor + alu_xor, + -- perform a left shift + alu_lsh, + -- perform a right shift + alu_rsh, + + -- comparisons + + -- compare for equal + alu_cmp_eq, + -- compare for not equal + alu_cmp_neq, + -- compare for greater than or equal + alu_cmp_ge, + -- compare for greater than + alu_cmp_gg, + -- compare for less then or equal + alu_cmp_le, + -- compare for less than + alu_cmp_ll, + -- always return true + alu_cmp_true, + -- always return false + alu_cmp_false + ); + + -- type for mode of current instruction + type instruction_mode_type is ( + -- instruction is normal 16bit instruction + sel_normal16, + -- instruction is normal 32bit instruction + sel_normal32, + -- instruction is call + sel_call, + -- instruction is trap + sel_trap, + -- instruction is branch (needed for optional branch delay) + sel_branch, + -- instruction is reti + sel_reti, + -- stall, insert nop without pc increment + sel_stall + ); + + -- type for selecting mux input in decoder mux + type dec_mux_control_type is ( + -- select 16bit decoder output + sel_ir16, + -- select 32bit decoder output + sel_ir32, + -- select shadow decoder output + sel_irshadow + ); + + -- type for selecting which data is used for data memory write + type memory_write_data_select_type is ( + -- use register value for data memory write + sel_register_value, + -- use memory read data or'ed with 0x80 for data memory write + sel_dmemORx80 + ); + + -- type for selecting from which address the data memory is read + type memory_read_addr_select_type is ( + -- use value of register a as data memory read address + sel_register_a, + -- use value of register b as data memory read address + sel_register_b, + -- use ldr-address as data memory read address + sel_ldr_address + ); + + -- type for selecting which register number is used to write to register file + type register_write_number_select_type is ( + -- use register number a + sel_register_a, + -- use register number d + sel_register_d, + -- use link register + sel_lr, + -- use status register + sel_sr + ); + + -- type for selecting which data is written to register file + type register_write_data_select_type is ( + -- use data memory read value + sel_memory, + -- use alu result + sel_alu_result, + -- use immediate value + sel_immediate + ); + + -- type for selecting which bit is written to trueth flag + type tflag_write_data_select_type is ( + -- use the 7th bit of data read from data memory + sel_dmem7, + -- use alu compare result + sel_alu + ); + + -- type for selecting which data is used as second alu input + type alu_input_data_select_type is ( + -- use value of register b as second alu input + sel_register_b, + -- use immediate value as second alu input + sel_imm + ); + + -- type for selecting the pc increment + type pc_summand_select_type is ( + -- use normal command width + sel_run, + -- use immediate value + sel_immediate, + -- use value of register a + sel_register_a + ); + + -- type for selecting the mode of the pc + type pc_mode_select_type is ( + -- increment relative to old pc + sel_relative, + -- set pc to an absolute value + sel_absolute + ); + + -- type for selecting the width of the current operation + type instruction_width_type is ( + -- operation is 16 bit wide + sel_16bit, + -- operation is 32 bit wide + sel_32bit + ); + + -- type for selecting if pc jump is conditional + type pc_condition_type is ( + -- always perform the pc jump + sel_unconditional, + -- perform the pc jump only if trueth flag is set + sel_true + ); + + -- RECORD DECLARATIONS + + -- type for signals from controlpath to PC + type cp_pc is record + -- select signal for the pc increment + summand_select : pc_summand_select_type; + -- select signal for the mode of the PC + mode_select : pc_mode_select_type; + -- width of current instruction + instruction_width : instruction_width_type; + end record; + + -- type for signals from datapath to PC + type dp_pc is record + -- immediate value for PC calculation + immediate_value : signed(reg_width - 2 downto 0); + -- register value for PC calculation + register_value : signed(reg_width - 2 downto 0); + end record; + + -- type for signals from decoder to PC + type dec_pc is record + -- stall signal, active high + stall : std_logic; + end record; + + -- type for signals from datapath to decoder + type dp_dec is record + -- current runtime priority + runtime_priority : unsigned(irq_prio_width - 1 downto 0); + end record; + + -- type for signals from decoder to instruction memory + type dec_imem is record + -- enable signal, active high + en : std_logic; + end record; + + -- type for signals from PC to datapath + type pc_dp is record + -- current PC value + value : unsigned(pc_width - 1 downto 0); + end record; + + -- type for signals from PC to instruction memory + type pc_imem is record + -- current PC value + value : unsigned(pc_width - 1 downto 0); + end record; + + -- type for signals from interrupt controller to decoder + type irq_dec is record + -- interrupt number of requested interrupt + num : unsigned(irq_num_width - 1 downto 0); + -- priority of requested interrupt (higher number means higher priority) + priority : unsigned(irq_prio_width - 1 downto 0); + -- request signal, active high + req : std_logic; + -- non maskable interrupt flag, active high + nmi : std_logic; + end record; + + -- type for signals from decoder to interrupt controller + type dec_irq is record + -- interrupt acknowledge, high if requested interrupt is processed + ack : std_logic; + -- number of interrupt requested by internal trap instruction + trap_num : unsigned(irq_num_width - 1 downto 0); + -- request signal for internal trap, active high + trap_req : std_logic; + end record; + + -- type for signals from decoder pre stage to decoder finite state machine + type pre_fsm is record + -- instruction bits, as from imem. For 16bit instructions only instruction(15 downto 0) is used. + instruction : std_logic_vector(31 downto 0); + -- mode of this instruction + mode : instruction_mode_type; + end record; + + -- type for signals from decoder finite state machine to decoder for 16bit instructions + type fsm_dec16 is record + -- 16bit instruction + instruction : std_logic_vector(15 downto 0); + end record; + + -- type for signals from decoder finite state machine to decoder for 32bit instructions + type fsm_dec32 is record + -- 32bit instruction + instruction : std_logic_vector(31 downto 0); + end record; + + -- type for signals from decoder finite state machine to decoder for shadow instructions + type fsm_decshd is record + -- shadow instruction + instruction : std_logic_vector(31 downto 0); + end record; + + -- type for signals from decoder finite state machine to decoder mux + type fsm_decmux is record + -- control signal of decoder mux + mode : dec_mux_control_type; + end record; + + -- type for signals from control path to decoder + type cp_dec is record + -- condition signal, high if given condition holds, always high if no condition given + condition_holds : std_logic; + end record; + + -- type for signals from control path to data path in first stage + type cp_dp_s1 is record + -- register number of register a (first read register) + register_read_number_a : reg_number; + -- register number of register b (second read register) + register_read_number_b : reg_number; + end record; + + -- type for signals from control path to datapath in second stage + type cp_dp_s2 is record + -- 8 bit immediate value + immediate : signed(8 - 1 downto 0); + -- control signal to select which address is used for data memory read + memory_read_addr_select : memory_read_addr_select_type; + -- control signal to select which data is used as second alu input + alu_input_data_select : alu_input_data_select_type; + -- mode of alu operation + alu_mode : alu_mode_type; + end record; + + -- type for signals from control path to datapath in third stage + type cp_dp_s3 is record + -- control signal to select which data is used for data memory write + memory_write_data_select : memory_write_data_select_type; + -- control signal to select which data is used for register file write + register_write_data_select : register_write_data_select_type; + -- register number of register that will be written to + register_write_number : reg_number; + -- enable write to register file, active high + register_write_enable : std_logic; + -- size of register write, standard size data + register_write_size : size_type; + -- enable tflag write, active high + tflag_write_enable : std_logic; + -- control signal, which data is used for tflag write + tflag_write_data_select : tflag_write_data_select_type; + -- enable ovffag write, active high + ovfflag_write_enable : std_logic; + end record; + + -- type for signals from control path to data memory + type cp_dmem is record + -- size of data memory read, standard size data + read_size : size_type; + -- enable data memory read, active high + read_en : std_logic; + -- size of data memory write, standard size data + write_size : size_type; + -- enable data memory write, active high + write_en : std_logic; + end record; + + -- type for signals from decoder to controlpath for first stage + type dec_cp_s1 is record + -- register number of register a (first read register) + register_read_number_a : reg_number; + -- register number of register b (second read register) + register_read_number_b : reg_number; + -- instruction width of current instruction + instruction_width : instruction_width_type; + end record; + + -- type for signals from decoder to controlpath for second stage + type dec_cp_s2 is record + -- these signals are forwarded to datapath + + -- 8 bit immediate value + immediate : signed(8 - 1 downto 0); + -- control signal to select which address is used for data memory read + dmem_read_addr_select : memory_read_addr_select_type; + -- control signal to select which data is used as second alu input + alu_input_data_select : alu_input_data_select_type; + -- mode of alu operation + alu_mode : alu_mode_type; + + -- these signals are forwarded to dmem + + -- size of data memory read, standard size data + dmem_read_size : size_type; + -- enable data memory read, active high + dmem_read_en : std_logic; + + -- these signals are modified in controlpath + + -- control signal to select which increment is used for pc calculation + pc_summand_select : pc_summand_select_type; + -- control signal to select the mode of the pc + pc_mode_select : pc_mode_select_type; + -- control signal to select conditionality of pc jump + pc_condition : pc_condition_type; + end record; + + -- type for signals from decoder to controlpath for third stage + type dec_cp_s3 is record + -- these signals are forwarded to datapath + + -- control signal to select which data is used for data memory write + dmem_write_data_select : memory_write_data_select_type; + -- control signal to select which data is used for register file write + register_write_data_select : register_write_data_select_type; + -- register number of register that will be written to + register_write_number : reg_number; + -- enable write to register file, active high + register_write_enable : std_logic; + -- size of register write, standard size data + register_write_size : size_type; + -- enable tflag write, active high + tflag_write_enable : std_logic; + -- control signal, which data is used for tflag write + tflag_write_data_select : tflag_write_data_select_type; + -- enable clfag write, active high + ovfflag_write_enable : std_logic; + + -- these signals are forwarded to dmem + + -- size of data memory write, standard size data + dmem_write_size : size_type; + -- enable data memory write, active high + dmem_write_en : std_logic; + end record; + + -- type for signals from datapath to controlpath in second stage + type dp_cp_s2 is record + -- value of truth flag + tflag : std_logic; + end record; + + -- type for signals from datapath to data memory + type dp_dmem is record + -- data for data memory write access + write_data : std_logic_vector(mem_width - 1 downto 0); + -- address for data memory write access + write_addr : std_logic_vector(mem_width - 1 downto 0); + -- address for data memory read access + read_addr : std_logic_vector(mem_width - 1 downto 0); + end record; + + -- type for signals from data memory to datapath + type dmem_dp is record + -- data read + read_data : std_logic_vector(mem_width - 1 downto 0); + end record; + + -- type for signals from instruction memory to decoder + type imem_dec is record + -- instruction read + read_data : std_logic_vector(mem_width - 1 downto 0); + -- ready signal, active high + ready : std_logic; + -- low/high half-word access (i.e. second bit of imem address) + instruction_halfword_select : std_logic; + end record; + + -- Pipeline Stages Combinations + + -- type for signals from decoder to controlpath in all stages + type dec_cp is record + -- first stage signals + s1 : dec_cp_s1; + -- second stage signals + s2 : dec_cp_s2; + -- third stage signals + s3 : dec_cp_s3; + -- hardfault signal, active high + hardfault : std_logic; + end record; + + -- type for signals from controlpath to datapath in all stages + type cp_dp is record + -- first stage signals + s1 : cp_dp_s1; + -- second stage signals + s2 : cp_dp_s2; + -- third stage signals + s3 : cp_dp_s3; + end record; + + -- type for signals from datapath to controlpath in all stages + type dp_cp is record + -- second stage signals + s2 : dp_cp_s2; + end record; + + -- FUNCTION DECLARATIONS + + -- Conversion Functions + function to_reg_number(i : integer) return reg_number; + function to_stdlogicvector(s : size_type) return std_logic_vector; + function reg_size return size_type; + + -- Default Value Functions + function get_default_dec_cp_s1 return dec_cp_s1; + function get_default_dec_cp_s2 return dec_cp_s2; + function get_default_dec_cp_s3 return dec_cp_s3; + + -- CONSTANT DECLARATIONS (part 2) + + -- register number for stack pointer + constant sp_num : reg_number := to_reg_number(12); + -- register number for link register + constant lr_num : reg_number := to_reg_number(13); + -- register number for status register + constant sr_num : reg_number := to_reg_number(14); + -- register number for pc register + constant pc_num : reg_number := to_reg_number(15); + + -- OPCODE AND MODE CONSTANT DECLARATIONS + + -- 16 BIT INSTRUCTION OPCODES + + -- opcode of addition (register,register) + constant op_add : std_logic_vector(3 downto 0) := "0011"; + -- opcode of subtraction + constant op_sub : std_logic_vector(3 downto 0) := "0001"; + -- opcode of binary and + constant op_and : std_logic_vector(3 downto 0) := "0010"; + -- opcode of binary or + constant op_or : std_logic_vector(3 downto 0) := "0000"; + -- opcode of binary xor + constant op_xor : std_logic_vector(3 downto 0) := "0100"; + -- opcode of left shift + constant op_lsh : std_logic_vector(3 downto 0) := "0101"; + -- opcode of right shift + constant op_rsh : std_logic_vector(3 downto 0) := "0110"; + -- opcode of addition with immediate + constant op_addi : std_logic_vector(3 downto 0) := "0111"; + -- opcode of compare + constant op_cmp : std_logic_vector(3 downto 0) := "1000"; + -- opcode of set status register + constant op_tst : std_logic_vector(3 downto 0) := "1001"; + -- opcode of load pc-relative + constant op_ldr : std_logic_vector(3 downto 0) := "1010"; + -- opcode of memory operations (load and store) + constant op_mem : std_logic_vector(3 downto 0) := "1011"; + -- opcode of branch/call/trap + constant op_bct : std_logic_vector(3 downto 0) := "1100"; + + -- SHADOW INSTRUCTION OPCODES + + -- opcode of push + constant op_shd_push : std_logic_vector(3 downto 0) := "0001"; + -- opcode of set SR + constant op_shd_setsr : std_logic_vector(3 downto 0) := "0010"; + -- opcode of reset instruction + constant op_shd_reset : std_logic_vector(3 downto 0) := "1111"; + + -- COMPARE MODES + + -- compare-mode "is equal" + constant op_cmp_eq : std_logic_vector(3 downto 0) := "0000"; + -- compare-mode "is not equal" + constant op_cmp_neq : std_logic_vector(3 downto 0) := "1000"; + -- compare-mode "is greater or equal" + constant op_cmp_ge : std_logic_vector(3 downto 0) := "0001"; + -- compare-mode "is less than" + constant op_cmp_ll : std_logic_vector(3 downto 0) := "1001"; + -- compare-mode "is greater than" + constant op_cmp_gg : std_logic_vector(3 downto 0) := "0010"; + -- compare-mode "is less or equal" + constant op_cmp_le : std_logic_vector(3 downto 0) := "1010"; + -- compare-mode "always true" + constant op_cmp_true : std_logic_vector(3 downto 0) := "0011"; + -- compare-mode "always false" + constant op_cmp_false : std_logic_vector(3 downto 0) := "1011"; + + -- BRANCH/CALL/TRAP/RETI MODES + + -- bct-mode "return from interrupt", NB: three bit long! + constant op_bct_reti : std_logic_vector(2 downto 0) := "000"; + -- bct-mode "branch to table" + constant op_bct_table : std_logic_vector(1 downto 0) := "00"; + -- bct-mode "branch" (pc=newvalue) + constant op_bct_branch : std_logic_vector(1 downto 0) := "01"; + -- bct-mode "call" (lr=pc, pc=newvalue) + constant op_bct_call : std_logic_vector(1 downto 0) := "10"; + -- bct-mode "trap" (trigger interrupt) + constant op_bct_trap : std_logic_vector(1 downto 0) := "11"; + + -- MEMORY MODES + + -- mem-mode "load 8 bit" + constant op_mem_ld08 : std_logic_vector(3 downto 0) := "0000"; + -- mem-mode "load 16 bit" + constant op_mem_ld16 : std_logic_vector(3 downto 0) := "0001"; + -- mem-mode "load 32 bit" + constant op_mem_ld32 : std_logic_vector(3 downto 0) := "0010"; + -- mem-mode "store 8 bit" + constant op_mem_st08 : std_logic_vector(3 downto 0) := "1000"; + -- mem-mode "store 16 bit" + constant op_mem_st16 : std_logic_vector(3 downto 0) := "1001"; + -- mem-mode "store 32 bit" + constant op_mem_st32 : std_logic_vector(3 downto 0) := "1010"; + +end package lt16x32_internal; + +package body lt16x32_internal is + + -- CONVERSION FUNCTIONS + + -- returns parameter i as reg_number type + function to_reg_number(i : integer) return reg_number is + begin + if ((i >= 0) and (i <= 15)) then + -- in valid range + return to_unsigned(i, 4); + else + -- in invalid range + assert false report "register number must be between 0 and 15" severity error; + return to_unsigned(0, 4); + end if; + end function to_reg_number; + + -- returns size as stdlogicvector + function to_stdlogicvector(s : size_type) return std_logic_vector is + begin + case s is + when size_byte => return "00"; + when size_halfword => return "01"; + when size_word => return "10"; + end case; + + end function; + + -- returns register width as size type + function reg_size return size_type is + begin + case reg_width is + when 8 => + return size_byte; + when 16 => + return size_halfword; + when 32 => + return size_word; + when others => -- will not happen due to assert in core + return size_byte; + end case; + end function reg_size; + + -- DEFAULT VALUE PARAMETERS + + -- returns default (nop) configuration for all stage one signals + function get_default_dec_cp_s1 return dec_cp_s1 is + variable defaults : dec_cp_s1; + begin + defaults.register_read_number_a := to_reg_number(0); + defaults.register_read_number_b := to_reg_number(0); + defaults.instruction_width := sel_16bit; + + return defaults; + end function get_default_dec_cp_s1; + + -- returns default (nop) configuration for all stage two signals + function get_default_dec_cp_s2 return dec_cp_s2 is + variable defaults : dec_cp_s2; + begin + defaults.immediate := to_signed(0, 8); + defaults.dmem_read_addr_select := sel_register_a; + defaults.alu_input_data_select := sel_register_b; + defaults.alu_mode := alu_or; + + defaults.dmem_read_size := reg_size; + defaults.dmem_read_en := '0'; + + defaults.pc_summand_select := sel_run; + defaults.pc_mode_select := sel_relative; + defaults.pc_condition := sel_unconditional; + + return defaults; + end function get_default_dec_cp_s2; + + -- returns default (nop) configuration for all stage three signals + function get_default_dec_cp_s3 return dec_cp_s3 is + variable defaults : dec_cp_s3; + begin + defaults.dmem_write_data_select := sel_register_value; + defaults.register_write_data_select := sel_alu_result; + defaults.register_write_enable := '0'; + defaults.register_write_number := to_reg_number(0); + defaults.register_write_size := reg_size; + + defaults.tflag_write_data_select := sel_alu; + defaults.tflag_write_enable := '0'; + defaults.ovfflag_write_enable := '0'; + + defaults.dmem_write_size := reg_size; + defaults.dmem_write_en := '0'; + return defaults; + end function get_default_dec_cp_s3; + +end package body lt16x32_internal; diff --git a/soc/core/processor.vhd b/soc/core/processor.vhd new file mode 100644 index 0000000..abd01a8 --- /dev/null +++ b/soc/core/processor.vhd @@ -0,0 +1,118 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; + +-- the processor bundles all entities needed for a running system, including the core itself, the interrupt controller and the memory. +entity processor is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + + -- interrupt lines + -- three interrupts are used internally + irq : in std_logic_vector(2 ** irq_num_width - 4 downto 0); + -- out_byte to communicate to extern world + out_byte : out std_logic_vector(7 downto 0) + ); +end entity processor; + +architecture RTL of processor is + component core + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_dmem : in dmem_core; + out_dmem : out core_dmem; + in_imem : in imem_core; + out_imem : out core_imem; + in_irq : in irq_core; + out_irq : out core_irq; + hardfault : out std_logic); + end component core; + + component memory + generic(filename : string := "program.ram"; + size : integer := 256; + imem_latency : in time := 5 ns; + dmem_latency : in time := 5 ns); + port(clk : in std_logic; + rst : in std_logic; + in_dmem : in core_dmem; + out_dmem : out dmem_core; + in_imem : in core_imem; + out_imem : out imem_core; + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0)); + end component memory; + + component irq_controller + port(clk : in std_logic; + rst : in std_logic; + in_proc : in core_irq; + out_proc : out irq_core; + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0)); + end component irq_controller; + + -- signals between instances + signal dmem_core_signal : dmem_core; + signal core_dmem_signal : core_dmem; + signal imem_core_signal : imem_core; + signal core_imem_signal : core_imem; + signal irq_core_signal : irq_core; + signal core_irq_signal : core_irq; + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0); + + -- fault signal from core + signal core_fault : std_logic; + -- fault signal from memory + signal mem_fault : std_logic; +begin + -- fixed interrupt lines + -- irq0 is reset + irq_lines(0) <= '0'; -- reset + -- irq1 is core fault + irq_lines(1) <= core_fault; + -- irq2 is memory fault + irq_lines(2) <= mem_fault; + -- other lines can be used from the outside + irq_lines(irq_lines'high downto 3) <= irq; + + core_inst : component core + port map(clk => clk, + rst => rst, + stall => '0', + in_dmem => dmem_core_signal, + out_dmem => core_dmem_signal, + in_imem => imem_core_signal, + out_imem => core_imem_signal, + in_irq => irq_core_signal, + out_irq => core_irq_signal, + hardfault => core_fault); + + memory_inst : component memory + generic map(filename => "../programs/example_led.ram", + size => 32, + imem_latency => 0 ns, + dmem_latency => 0 ns) + port map(clk => clk, + rst => rst, + in_dmem => core_dmem_signal, + out_dmem => dmem_core_signal, + in_imem => core_imem_signal, + out_imem => imem_core_signal, + fault => mem_fault, + out_byte => out_byte); + + irq_controller_inst : component irq_controller + port map(clk => clk, + rst => rst, + in_proc => core_irq_signal, + out_proc => irq_core_signal, + irq_lines => irq_lines); + +end architecture RTL; diff --git a/soc/core/programcounter.vhd b/soc/core/programcounter.vhd new file mode 100644 index 0000000..4603691 --- /dev/null +++ b/soc/core/programcounter.vhd @@ -0,0 +1,100 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; + +-- the pc counter counts the current programm address up, but also offers +-- various different run- and set-modes +entity programcounter is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal, active high + stall : in std_logic; + + -- signals from control path + in_cp : in cp_pc; + -- signals from data path + in_dp : in dp_pc; + -- signals from decoder + in_dec : in dec_pc; + + -- signals to datapath + out_dp : out pc_dp; + -- signals to instruction memory + out_imem : out pc_imem + ); + + -- internal width of calculation, last pc bit is always zero and is hence not needed in the calculations here + constant internal_width : natural := pc_width - 1; +end entity programcounter; + +architecture RTL of programcounter is + -- increment for normal operation (16 / 32 bits) + signal run_increment : signed(internal_width - 1 downto 0); + -- second input of the internal adder + signal adder_input_b : signed(internal_width - 1 downto 0); + -- result of the internal adder + signal adder_result : unsigned(internal_width - 1 downto 0); + + -- new pc value (used in two ports) + signal pc_value : unsigned(internal_width - 1 downto 0); + -- old pc value + signal pc_value_old : unsigned(internal_width - 1 downto 0); +begin + + -- simple forwarding + out_dp.value <= pc_value & '0'; -- always half-word aligned + out_imem.value <= pc_value & '0'; -- always half-word aligned + + -- multiplexer for the run increment + run_inc : with in_cp.instruction_width select run_increment <= + to_signed(1, internal_width) when sel_16bit, + to_signed(2, internal_width) when sel_32bit; + + -- multiplexer for the secondary input of the internal adder + adder_input : with in_cp.summand_select select adder_input_b <= + run_increment when sel_run, + signed(in_dp.immediate_value(adder_input_b'range)) when sel_immediate, + signed(in_dp.register_value(adder_input_b'range)) when sel_register_a; + + -- pc value output combinatoric process + pc_output : process(in_dec.stall, stall, in_cp.mode_select, pc_value_old, adder_result, adder_input_b) is + begin + if ((in_dec.stall = '1') or (stall = '1')) then + -- if stalling, do not update output + pc_value <= pc_value_old; + + else + -- not stalling + case in_cp.mode_select is + when sel_relative => + -- if in relative mode use the result of the internal adder + pc_value <= unsigned(adder_result); + when sel_absolute => + -- if in absolute mode use the secondary input of the internal adder directly + pc_value <= unsigned(adder_input_b); + end case; + end if; + end process pc_output; + + -- adder + adder_result <= unsigned(signed(pc_value_old) + adder_input_b); + + -- storage element + pc_register : process(clk) is + begin + if rising_edge(clk) then + if rst = '1' then + pc_value_old <= to_unsigned(0, internal_width); + else -- stall is done in combinatoric part already, not needed here additionally + pc_value_old <= pc_value; + end if; + end if; + end process pc_register; + +end architecture RTL; diff --git a/soc/core/registerfile.vhd b/soc/core/registerfile.vhd new file mode 100644 index 0000000..538f84b --- /dev/null +++ b/soc/core/registerfile.vhd @@ -0,0 +1,213 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +-- the registerfile contains memory for all registers and flags +-- two registers can be read and one register can be written per clock cycle +-- reading and writing of flags is independent +entity registerfile is + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + -- stall signal, active high + stall : in std_logic; + + -- number of register a + a_num : in reg_number; + -- content of register a + a_out : out signed(reg_width - 1 downto 0); + -- number of register b + b_num : in reg_number; + -- content of register b + b_out : out signed(reg_width - 1 downto 0); + + -- current pc value + pc_in : in unsigned(pc_width - 1 downto 0); + + -- data that will be written to register file (if write_en = '1') + write_data : in signed(reg_width - 1 downto 0); + -- number of register that will be written to + write_num : in reg_number; + -- write enable, active high + write_en : in std_logic; + + -- write enable for truth flag + true_writeenable : in std_logic; + -- input for truth flag write + true_in : in std_logic; + -- output of current truth flag + true_out : out std_logic; + + -- write enable for carry flag, active high + ovf_writeenable : in std_logic; + -- input for carry flag write + ovf_in : in std_logic; + + -- output of current runtime priority + runtime_priority : out unsigned(irq_prio_width - 1 downto 0) + ); +end entity registerfile; + +architecture RTL of registerfile is + -- type for memory + type reg_array_type is array (0 to 13) of signed(reg_width - 1 downto 0); + -- memory array for the registers + signal reg_array : reg_array_type; + + -- runtime priority + signal runtime_priority_internal : unsigned(irq_prio_width - 1 downto 0); + -- truth flag + signal t_flag : std_logic; + -- carry flag + signal ovf_flag : std_logic; + -- status register + signal sreg : std_logic_vector(reg_width - 1 downto 0); +begin + -- minimum reg_width is 8 to have enough space for SR + assert (reg_width >= 8) report "Register width (reg_width) must be >= 8." severity failure; + + -- output signals + output_t : true_out <= t_flag; + output_prio : runtime_priority <= runtime_priority_internal; + + -- status register generation + sreg_out : process(ovf_flag, t_flag, true_writeenable, ovf_writeenable, true_in, ovf_in, runtime_priority_internal) is + begin + -- standard output + sreg <= (others => '0'); + + -- runtime priority + sreg(7 downto (8 - irq_prio_width)) <= std_logic_vector(runtime_priority_internal); + + -- truth flag with write before read + if (true_writeenable = '1') then + sreg(1) <= true_in; + else + sreg(1) <= t_flag; + end if; + + -- carry flag + if (ovf_writeenable = '1') then + sreg(0) <= ovf_in; + else + sreg(0) <= ovf_flag; + end if; + end process sreg_out; + + -- register a output + read_a : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset, output zeros + a_out <= (others => '0'); + elsif (stall = '0') then + -- if not stalling, output new value + + if (a_num <= 13) then + -- standard register + + if ((a_num = write_num) and (write_en = '1')) then + -- write before read + a_out <= write_data; + else + -- no write + a_out <= reg_array(to_integer(a_num)); + end if; + + elsif (a_num = 14) then + -- SR, write to SR is catched combinatorically in sreg_out process + a_out <= signed(sreg); + elsif (a_num = 15) then + -- PC, write to PC is not catched, old values may be seen here + a_out <= (others => '0'); + a_out(pc_width - 1 downto 0) <= signed(pc_in); + end if; + end if; + end if; + end process read_a; + + -- register b output + read_b : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset output zeros + b_out <= (others => '0'); + + elsif (stall = '0') then + -- if not stalling, output new value + if (b_num <= 13) then + -- standard register + if ((b_num = write_num) and (write_en = '1')) then + -- write before read + b_out <= write_data; + else + b_out <= reg_array(to_integer(b_num)); + end if; + elsif (b_num = 14) then + -- SR, write to SR is catched combinatorically in sreg_out process + b_out <= signed(sreg); + elsif (b_num = 15) then + -- PC, write to PC is not catched, old values may be seen here + b_out <= (others => '0'); + b_out(pc_width - 1 downto 0) <= signed(pc_in); + end if; + end if; + end if; + end process read_b; + + -- write to register + write : process(clk) is + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- do not reset register array, it's bad for synthesis. + -- TODO: make sure, it's initialized correctly in synthesis + -- synthesis translate_off + for i in 0 to 13 loop + reg_array(i) <= (others => '0'); + end loop; + -- synthesis translate_on + + -- PC is resetted in pc_counter + -- reset SR contents + ovf_flag <= '0'; + t_flag <= '0'; + runtime_priority_internal <= (others => '1'); -- set runtime priority to maximum + + elsif ((write_en = '1') and (stall = '0')) then + -- if write enabled and not stalling + + if (write_num <= 13) then + -- write to normal register + reg_array(to_integer(write_num)) <= write_data; + + elsif (write_num = sr_num) then + -- write to SR + runtime_priority_internal <= unsigned(write_data(7 downto (8 - irq_prio_width))); + t_flag <= write_data(1); + ovf_flag <= write_data(0); + end if; + -- write to PC ignored + end if; + + -- write carry flag + if ((ovf_writeenable = '1') and (stall = '0')) then + ovf_flag <= ovf_in; + end if; + + -- write truth flag + if ((true_writeenable = '1') and (stall = '0')) then + t_flag <= true_in; + end if; + end if; + end process write; + +end architecture RTL; diff --git a/soc/lib/can_tp.vhd b/soc/lib/can_tp.vhd new file mode 100644 index 0000000..8ffe6d3 --- /dev/null +++ b/soc/lib/can_tp.vhd @@ -0,0 +1,381 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wishbone.all; +use std.textio.all; +use ieee.std_logic_textio.all; + +package can_tp is + + type rx_check_result is (success, can_error, arbitration_lost, no_ack); + + procedure can_wb_write_reg( + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + constant addr : in integer; + constant data : in std_logic_vector(7 downto 0); + signal clk : in std_logic); + + procedure can_wb_read_reg( + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + constant addr : in integer; + signal clk : in std_logic); + + procedure write_regs_from_file( + constant filename : in string; + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + signal clk : in std_logic); + + procedure read_regs_with_fileaddr( + constant filename : in string; + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + signal clk : in std_logic); + + function canint2addr( + constant intaddr : integer + ) return std_logic_vector; + + function canint2sel( + constant intaddr : integer + ) return std_logic_vector; + + function data2canwb( + constant data : std_logic_vector(7 downto 0) + ) return std_logic_vector; + + function can_crc( + constant data: in std_logic_vector(0 to 63); + constant datasize: in integer)return std_logic_vector; + + function buildframe( + constant id: in std_logic_vector(10 downto 0); + constant data: in std_logic_vector(0 to 63); + constant datasize: in integer) return std_logic_vector; + + function select_bit( + constant tx_frame_pointer: in integer; + constant datasize: in integer; + constant tx_frame: in std_logic_vector(0 to 108)) return std_logic_vector; + + procedure set_bit( + signal tx: out std_logic; + constant tx_bit: in std_logic_vector(0 to 4); + constant t_bit: in time; + variable tx_history: inout std_logic_vector(4 downto 0)); + + procedure simulate_can_transmission( + constant id : in std_logic_vector(10 to 0); + constant data: in std_logic_vector (0 to 63); + constant datasize: in integer; + constant t_bit: in time; + signal rx: in std_logic; + signal tx: inout std_logic; + signal test_result: out rx_check_result); + +end can_tp; + +package body can_tp is + + -- convertes the input register address to addr + function canint2addr( + constant intaddr : integer + ) return std_logic_vector is variable addr: std_logic_vector(7 downto 0); + begin + addr := std_logic_vector(to_unsigned(intaddr, 8)); + return addr; + end canint2addr; + + -- convertes the input register address to select signal + function canint2sel( + constant intaddr : integer + ) return std_logic_vector is + variable sel: std_logic_vector(3 downto 0); + variable addr : std_logic_vector(7 downto 0) := std_logic_vector(to_unsigned(intaddr, 8)); + begin + + case addr (1 downto 0) is + when "00" => sel := "1000"; + when "01" => sel := "0100"; + when "10" => sel := "0010"; + when "11" => sel := "0001"; + when others => sel := "1000"; + end case; + return sel; + end canint2sel; + + --copies the input data to all four possible byte possitions + function data2canwb( + constant data : std_logic_vector(7 downto 0) + ) return std_logic_vector is + variable wbcan_data: std_logic_vector(31 downto 0); + begin + wbcan_data(31 downto 24) := data; + wbcan_data(23 downto 16) := data; + wbcan_data(15 downto 8) := data; + wbcan_data(7 downto 0) := data; + return wbcan_data; + end data2canwb; + + --does a asynchronous wb-single-write-handshake and writes to an register of the can controller + procedure can_wb_write_reg( + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + constant addr : integer; + constant data : in std_logic_vector(7 downto 0); + signal clk : in std_logic) is + begin + wbs_in.dat <= data2canwb(data); + wbs_in.sel <= canint2sel(addr); + wbs_in.adr(7 downto 2) <= canint2addr(addr)(7 downto 2); + wbs_in.stb <= '1'; + wbs_in.cyc <= '1'; + wbs_in.we <= '1'; + + wait until wbs_out.ack = '1'; --for 1 ps; + wait until rising_edge(clk); + + wbs_in.cyc <= '0'; + wbs_in.stb <= '0'; + wbs_in.we <= '-'; + wbs_in.sel <= (others=>'-'); + wbs_in.dat <= (others=>'-'); + wbs_in.adr <= (others=>'-'); + + end can_wb_write_reg; + + + procedure can_wb_read_reg( + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + constant addr : integer; + signal clk : in std_logic) is + begin + wbs_in.sel <= canint2sel(addr); + wbs_in.adr(7 downto 2) <= canint2addr(addr)(7 downto 2); + wbs_in.stb <= '1'; + wbs_in.cyc <= '1'; + wbs_in.we <= '0'; + + wait until wbs_out.ack = '1'; --for 1 ps; + wait until rising_edge(clk); + + wbs_in.cyc <= '0'; + wbs_in.stb <= '0'; + wbs_in.we <= '-'; + wbs_in.sel <= (others=>'-'); + wbs_in.dat <= (others=>'-'); + wbs_in.adr <= (others=>'-'); + + end can_wb_read_reg; + + + procedure write_regs_from_file( + constant filename : in string; + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + signal clk : in std_logic) is + + file sourcefile : text open read_mode is filename; + variable input_line : line; + variable data : std_logic_vector(7 downto 0); + variable addr : integer; + begin + while not endfile(sourcefile) loop + readline(sourcefile, input_line); --read line + read(input_line, addr); --read addr of register + read(input_line, data); --read data + can_wb_write_reg(wbs_in, wbs_out, addr, data, clk); + wait for 50 ns; + end loop; + end procedure write_regs_from_file; + + + procedure read_regs_with_fileaddr( + constant filename : in string; + signal wbs_in : out wb_slv_in_type; + signal wbs_out : in wb_slv_out_type; + signal clk : in std_logic) is + + file sourcefile : text open read_mode is filename; + variable input_line : line; + variable addr : integer; + begin + while not endfile(sourcefile) loop + readline(sourcefile, input_line); --read line + read(input_line, addr); --read addr of register + can_wb_read_reg(wbs_in, wbs_out, addr, clk); + wait for 50 ns; + end loop; + end procedure read_regs_with_fileaddr; + + function can_crc( + constant stream_vector: in std_logic_vector(0 to 82);--(0 to (0 to 19+datasize*8-1); + constant datasize: in integer)return std_logic_vector is + + variable crc: std_logic_vector(14 downto 0) := (others=>'0'); + variable crc_tmp: std_logic_vector(14 downto 0); + begin + for i in 0 to 19+datasize*8 - 1 loop + crc_tmp(14 downto 1) := crc(13 downto 0); + crc_tmp(0) := '0'; + if (stream_vector(i) xor crc(14)) = '1' then + crc := crc_tmp xor "100010110011001";--x"4599"; + else + crc := crc_tmp; --110110001111111 + end if; + end loop; + return crc; + end function can_crc; + + + function buildframe( + constant id: in std_logic_vector(10 downto 0); + constant data: in std_logic_vector(0 to 63); + constant datasize: in integer) return std_logic_vector is + + variable tx_frame: std_logic_vector(0 to 108); + variable tmp_stream: std_logic_vector(0 to 82) := (others=>'0'); + begin + tx_frame(0) := '0'; --start of frame + tx_frame(1 to 11) := id(10 downto 0); + tx_frame(12) := '0'; -- RTR bit (dominant for dataframes) + tx_frame(13 to 14) := "00"; --reseserved/extended bits + --error if datasize is to big + tx_frame(15 to 18) := std_logic_vector(to_unsigned(datasize,4)); -- # of bytes to be transmitted (DLC) + tx_frame(19 to 19+datasize*8-1) := data(0 to datasize*8-1); + tmp_stream(0 to 19+datasize*8-1) := tx_frame(0 to 19+datasize*8-1); -- setup stream for crc calculation + tx_frame(20+datasize*8-1 to 34+datasize*8-1) := can_crc(tmp_stream, datasize); + tx_frame(35+datasize*8-1) := '1'; --CRC delimiter (must be recessiv) + tx_frame(36+datasize*8-1 to 37+datasize*8-1) := "11"; -- ACK and delemiter: ack must be sent as recessiv bit + tx_frame(38+datasize*8-1 to 44+datasize*8-1) := "1111111"; -- end of frame(EOF): 7 recessiv bits + --tx_frame(45+datasize*8 to 110) := (others=>X); -- + return tx_frame; + end function buildframe; + + + function select_bit( + constant tx_frame_pointer: in integer; + constant datasize: in integer; + constant tx_frame: in std_logic_vector(0 to 108)) return std_logic_vector is + + variable tx_bit: std_logic_vector(0 to 4); + begin + tx_bit(0) := tx_frame(tx_frame_pointer); --actual bit to be sent + if ((tx_frame_pointer <= 11) and (tx_frame_pointer /= 0)) then -- arbitration flag + tx_bit(1) := '1'; + else + tx_bit(1) := '0'; + end if; + + if (tx_frame_pointer <= 34+datasize*8-1) then -- stuffing flag is set, if bitstuffing is enabled in this part of the frame + tx_bit(2) := '1'; + else + tx_bit(2) := '0'; + end if; + + if (tx_frame_pointer = 36+datasize*8-1) then -- ack flag is set if the ack bit in the frame is reached + tx_bit(3) := '1'; + else + tx_bit(3) := '0'; + end if; + + if (tx_frame_pointer = 44+datasize*8-1) then -- last bit flag is set when the last bit is reached + tx_bit(4) := '1'; + else + tx_bit(4) := '0'; + end if; + + return tx_bit; + end function select_bit; + + + procedure set_bit( + signal tx: out std_logic; + constant tx_bit: in std_logic_vector(0 to 4); + constant t_bit: in time; + variable tx_history: inout std_logic_vector(3 downto 0)) is + begin + --bit stuffing is enabled when flag is set + tx <= tx_bit(0); + wait for t_bit/2; + + if (tx_bit(2) = '1') and (tx_history(0) = tx_history(1)) and (tx_history(1) = tx_history(2)) and (tx_history(2) = tx_history(3)) and (tx_history(3) = tx_bit(0)) then + + tx_history(0) := tx_history(1); + tx_history(1) := tx_history(2); + tx_history(2) := tx_history(3); + tx_history(3) := tx_bit(0); + + wait for t_bit/2; + report "stuffing now"; + tx <= not(tx_bit(0)); + wait for t_bit/2; + + tx_history(0) := tx_history(1); + tx_history(1) := tx_history(2); + tx_history(2) := tx_history(3); + tx_history(3) := not(tx_bit(0)); + else + tx_history(0) := tx_history(1); + tx_history(1) := tx_history(2); + tx_history(2) := tx_history(3); + tx_history(3) := tx_bit(0); + end if; + + --report "tx_history(0) " & std_logic'image(tx_history(0)); + --report "tx_history(1) " & std_logic'image(tx_history(1)); + --report "tx_history(2) " & std_logic'image(tx_history(2)); + --report "tx_history(3) " & std_logic'image(tx_history(3)); + + + end procedure set_bit; + + + procedure simulate_can_transmission( + constant id : in std_logic_vector(10 downto 0); + constant data: in std_logic_vector (0 to 63); + constant datasize: in integer; + constant t_bit: in time; + signal rx: in std_logic; + signal tx: inout std_logic; + signal test_result: out rx_check_result) is + + variable tx_frame: std_logic_vector(0 to 108); + variable tx_bit: std_logic_vector(0 to 4):= "00000"; --0: actualmachine bit, 1: arbitration flag, 2: stuffing flag, 3: ack flag, 4:last bit flag + variable tx_frame_pointer: integer := 0; + variable tx_history: std_logic_vector(3 downto 0); + --variable rx_history: std_logic_vector(5 downto 0); + begin + tx_frame := buildframe(id, data, datasize); + while tx_bit(4) = '0' loop --while last bit is not yet reached + tx_bit := select_bit(tx_frame_pointer, datasize, tx_frame); --selects next bit to be sent and sets flags + --report "txbit " & std_logic'image(tx_bit(2)); + set_bit(tx, tx_bit, t_bit, tx_history); --handles bit stuffing and tx signal interaction + --check if arbitration is lostmachine + if tx_bit(1) = '1' and rx /= tx then + test_result <= arbitration_lost; + return; + end if; + -- check if ack is sent by the receiver + if tx_bit(3) = '1' and rx /= '0' then + test_result <= no_ack; + return; + end if; + --check if rx = tx if not: error; ausnahmen: arbitration lost, ack + if tx_bit(1) = '0' and tx_bit(3) = '0' and rx /= tx then + test_result <= can_error; + return; + end if; + + wait for t_bit/2; + + tx_frame_pointer := tx_frame_pointer + 1; + end loop; + test_result <= success; + + end procedure simulate_can_transmission; + --TODO: +end can_tp; \ No newline at end of file diff --git a/soc/lib/config.vhd b/soc/lib/config.vhd new file mode 100644 index 0000000..42d346a --- /dev/null +++ b/soc/lib/config.vhd @@ -0,0 +1,49 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use work.wishbone.all; + +package config is + +----------------------------- +-- RST active level override +----------------------------- + constant RST_ACTIVE_HIGH : boolean := false; + +----------------------------- +-- mem size (dmem, imem) +----------------------------- + constant IMEMSZ : integer := 256; --this is actually WORD-size! + +----------------------------- +-- index assignment +----------------------------- +-- >> Master indx << + constant CFG_LT16 : integer := 0; -- LT16SOC processor core + constant CFG_MST_TEST : integer := 1; + +-- >> Slave indx << + constant CFG_MEM : integer := 0; + constant CFG_DMEM : integer := CFG_MEM+1; + constant CFG_LED : integer := CFG_DMEM+1; + +----------------------------- +-- base address (BADR) & mask address (MADR) +----------------------------- +-- test slv_base_addr (30bits) + constant CFG_BADR_MEM : generic_addr_type := 16#00000000#; -- fixed, must start from 0 + constant CFG_BADR_DMEM : generic_addr_type := CFG_BADR_MEM + IMEMSZ*4; --16#00000400#; + --constant CFG_BADR_NEXTFREEADDRESS : generic_addr_type := 16#00000800#; + constant CFG_BADR_LED : generic_addr_type := 16#000F0000#; +-- mask addr + constant CFG_MADR_ZERO : generic_mask_type := 0; + constant CFG_MADR_FULL : generic_mask_type := 16#3FFFFF#; + constant CFG_MADR_MEM : generic_mask_type := 16#3FFFFF# - (IMEMSZ*4 -1); + constant CFG_MADR_DMEM : generic_mask_type := 16#3FFFFF# - (256 -1); -- uses 6 word-bits, size 256 byte + constant CFG_MADR_LED : generic_mask_type := 16#3FFFFF#; -- size=1 byte + +end package config; + +package body config is +end config; diff --git a/soc/lib/txt_util.vhd b/soc/lib/txt_util.vhd new file mode 100644 index 0000000..fc2b9ce --- /dev/null +++ b/soc/lib/txt_util.vhd @@ -0,0 +1,588 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use std.textio.all; + + +package txt_util is + + -- prints a message to the screen + procedure print(text: string); + + -- prints the message when active + -- useful for debug switches + procedure print(active: boolean; text: string); + + -- converts std_logic into a character + function chr(sl: std_logic) return character; + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string; + + -- converts std_logic_vector into a string (binary base) + function str(slv: std_logic_vector) return string; + + -- converts boolean into a string + function str(b: boolean) return string; + + -- converts an integer into a single character + -- (can also be used for hex conversion and other bases) + function chr(int: integer) return character; + + -- converts integer into string using specified base + function str(int: integer; base: integer) return string; + + -- converts integer to string, using base 10 + function str(int: integer) return string; + + -- convert std_logic_vector into a string in hex format + function hstr(slv: std_logic_vector) return string; + + + -- functions to manipulate strings + ----------------------------------- + + -- convert a character to upper case + function to_upper(c: character) return character; + + -- convert a character to lower case + function to_lower(c: character) return character; + + -- convert a string to upper case + function to_upper(s: string) return string; + + -- convert a string to lower case + function to_lower(s: string) return string; + + + + -- functions to convert strings into other formats + -------------------------------------------------- + + -- converts a character into std_logic + function to_std_logic(c: character) return std_logic; + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector; + + + + -- file I/O + ----------- + + -- read variable length string from input file + procedure str_read(file in_file: TEXT; + res_string: out string); + + -- print string to a file and start new line + procedure print(file out_file: TEXT; + new_string: in string); + + -- print character to a file and start new line + procedure print(file out_file: TEXT; + char: in character); + +end txt_util; + + + + +package body txt_util is + + + + + -- prints text to the screen + + procedure print(text: string) is + variable msg_line: line; + begin + write(msg_line, text); + writeline(output, msg_line); + end print; + + + + + -- prints text to the screen when active + + procedure print(active: boolean; text: string) is + begin + if active then + print(text); + end if; + end print; + + + -- converts std_logic into a character + + function chr(sl: std_logic) return character is + variable c: character; + begin + case sl is + when 'U' => c:= 'U'; + when 'X' => c:= 'X'; + when '0' => c:= '0'; + when '1' => c:= '1'; + when 'Z' => c:= 'Z'; + when 'W' => c:= 'W'; + when 'L' => c:= 'L'; + when 'H' => c:= 'H'; + when '-' => c:= '-'; + end case; + return c; + end chr; + + + + -- converts std_logic into a string (1 to 1) + + function str(sl: std_logic) return string is + variable s: string(1 to 1); + begin + s(1) := chr(sl); + return s; + end str; + + + + -- converts std_logic_vector into a string (binary base) + -- (this also takes care of the fact that the range of + -- a string is natural while a std_logic_vector may + -- have an integer range) + + function str(slv: std_logic_vector) return string is + variable result : string (1 to slv'length); + variable r : integer; + begin + r := 1; + for i in slv'range loop + result(r) := chr(slv(i)); + r := r + 1; + end loop; + return result; + end str; + + + function str(b: boolean) return string is + + begin + if b then + return "true"; + else + return "false"; + end if; + end str; + + + -- converts an integer into a character + -- for 0 to 9 the obvious mapping is used, higher + -- values are mapped to the characters A-Z + -- (this is usefull for systems with base > 10) + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function chr(int: integer) return character is + variable c: character; + begin + case int is + when 0 => c := '0'; + when 1 => c := '1'; + when 2 => c := '2'; + when 3 => c := '3'; + when 4 => c := '4'; + when 5 => c := '5'; + when 6 => c := '6'; + when 7 => c := '7'; + when 8 => c := '8'; + when 9 => c := '9'; + when 10 => c := 'A'; + when 11 => c := 'B'; + when 12 => c := 'C'; + when 13 => c := 'D'; + when 14 => c := 'E'; + when 15 => c := 'F'; + when 16 => c := 'G'; + when 17 => c := 'H'; + when 18 => c := 'I'; + when 19 => c := 'J'; + when 20 => c := 'K'; + when 21 => c := 'L'; + when 22 => c := 'M'; + when 23 => c := 'N'; + when 24 => c := 'O'; + when 25 => c := 'P'; + when 26 => c := 'Q'; + when 27 => c := 'R'; + when 28 => c := 'S'; + when 29 => c := 'T'; + when 30 => c := 'U'; + when 31 => c := 'V'; + when 32 => c := 'W'; + when 33 => c := 'X'; + when 34 => c := 'Y'; + when 35 => c := 'Z'; + when others => c := '?'; + end case; + return c; + end chr; + + + + -- convert integer to string using specified base + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function str(int: integer; base: integer) return string is + + variable temp: string(1 to 10); + variable num: integer; + variable abs_int: integer; + variable len: integer := 1; + variable power: integer := 1; + + begin + + -- bug fix for negative numbers + abs_int := abs(int); + + num := abs_int; + + while num >= base loop -- Determine how many + len := len + 1; -- characters required + num := num / base; -- to represent the + end loop ; -- number. + + for i in len downto 1 loop -- Convert the number to + temp(i) := chr(abs_int/power mod base); -- a string starting + power := power * base; -- with the right hand + end loop ; -- side. + + -- return result and add sign if required + if int < 0 then + return '-'& temp(1 to len); + else + return temp(1 to len); + end if; + + end str; + + + -- convert integer to string, using base 10 + function str(int: integer) return string is + + begin + + return str(int, 10) ; + + end str; + + + + -- converts a std_logic_vector into a hex string. + function hstr(slv: std_logic_vector) return string is + variable hexlen: integer; + variable longslv : std_logic_vector(67 downto 0) := (others => '0'); + variable hex : string(1 to 16); + variable fourbit : std_logic_vector(3 downto 0); + begin + hexlen := (slv'left+1)/4; + if (slv'left+1) mod 4 /= 0 then + hexlen := hexlen + 1; + end if; + longslv(slv'left downto 0) := slv; + for i in (hexlen -1) downto 0 loop + fourbit := longslv(((i*4)+3) downto (i*4)); + case fourbit is + when "0000" => hex(hexlen -I) := '0'; + when "0001" => hex(hexlen -I) := '1'; + when "0010" => hex(hexlen -I) := '2'; + when "0011" => hex(hexlen -I) := '3'; + when "0100" => hex(hexlen -I) := '4'; + when "0101" => hex(hexlen -I) := '5'; + when "0110" => hex(hexlen -I) := '6'; + when "0111" => hex(hexlen -I) := '7'; + when "1000" => hex(hexlen -I) := '8'; + when "1001" => hex(hexlen -I) := '9'; + when "1010" => hex(hexlen -I) := 'A'; + when "1011" => hex(hexlen -I) := 'B'; + when "1100" => hex(hexlen -I) := 'C'; + when "1101" => hex(hexlen -I) := 'D'; + when "1110" => hex(hexlen -I) := 'E'; + when "1111" => hex(hexlen -I) := 'F'; + when "ZZZZ" => hex(hexlen -I) := 'z'; + when "UUUU" => hex(hexlen -I) := 'u'; + when "XXXX" => hex(hexlen -I) := 'x'; + when others => hex(hexlen -I) := '?'; + end case; + end loop; + return hex(1 to hexlen); + end hstr; + + + + -- functions to manipulate strings + ----------------------------------- + + + -- convert a character to upper case + + function to_upper(c: character) return character is + + variable u: character; + + begin + + case c is + when 'a' => u := 'A'; + when 'b' => u := 'B'; + when 'c' => u := 'C'; + when 'd' => u := 'D'; + when 'e' => u := 'E'; + when 'f' => u := 'F'; + when 'g' => u := 'G'; + when 'h' => u := 'H'; + when 'i' => u := 'I'; + when 'j' => u := 'J'; + when 'k' => u := 'K'; + when 'l' => u := 'L'; + when 'm' => u := 'M'; + when 'n' => u := 'N'; + when 'o' => u := 'O'; + when 'p' => u := 'P'; + when 'q' => u := 'Q'; + when 'r' => u := 'R'; + when 's' => u := 'S'; + when 't' => u := 'T'; + when 'u' => u := 'U'; + when 'v' => u := 'V'; + when 'w' => u := 'W'; + when 'x' => u := 'X'; + when 'y' => u := 'Y'; + when 'z' => u := 'Z'; + when others => u := c; + end case; + + return u; + + end to_upper; + + + -- convert a character to lower case + + function to_lower(c: character) return character is + + variable l: character; + + begin + + case c is + when 'A' => l := 'a'; + when 'B' => l := 'b'; + when 'C' => l := 'c'; + when 'D' => l := 'd'; + when 'E' => l := 'e'; + when 'F' => l := 'f'; + when 'G' => l := 'g'; + when 'H' => l := 'h'; + when 'I' => l := 'i'; + when 'J' => l := 'j'; + when 'K' => l := 'k'; + when 'L' => l := 'l'; + when 'M' => l := 'm'; + when 'N' => l := 'n'; + when 'O' => l := 'o'; + when 'P' => l := 'p'; + when 'Q' => l := 'q'; + when 'R' => l := 'r'; + when 'S' => l := 's'; + when 'T' => l := 't'; + when 'U' => l := 'u'; + when 'V' => l := 'v'; + when 'W' => l := 'w'; + when 'X' => l := 'x'; + when 'Y' => l := 'y'; + when 'Z' => l := 'z'; + when others => l := c; + end case; + + return l; + + end to_lower; + + + + -- convert a string to upper case + + function to_upper(s: string) return string is + + variable uppercase: string (s'range); + + begin + + for i in s'range loop + uppercase(i):= to_upper(s(i)); + end loop; + return uppercase; + + end to_upper; + + + + -- convert a string to lower case + + function to_lower(s: string) return string is + + variable lowercase: string (s'range); + + begin + + for i in s'range loop + lowercase(i):= to_lower(s(i)); + end loop; + return lowercase; + + end to_lower; + + + +-- functions to convert strings into other types + + +-- converts a character into a std_logic + +function to_std_logic(c: character) return std_logic is + variable sl: std_logic; + begin + case c is + when 'U' => + sl := 'U'; + when 'X' => + sl := 'X'; + when '0' => + sl := '0'; + when '1' => + sl := '1'; + when 'Z' => + sl := 'Z'; + when 'W' => + sl := 'W'; + when 'L' => + sl := 'L'; + when 'H' => + sl := 'H'; + when '-' => + sl := '-'; + when others => + sl := 'X'; + end case; + return sl; + end to_std_logic; + + +-- converts a string into std_logic_vector + +function to_std_logic_vector(s: string) return std_logic_vector is + variable slv: std_logic_vector(s'high-s'low downto 0); + variable k: integer; +begin + k := s'high-s'low; + for i in s'range loop + slv(k) := to_std_logic(s(i)); + k := k - 1; + end loop; + return slv; +end to_std_logic_vector; + + + + + + +---------------- +-- file I/O -- +---------------- + + + +-- read variable length string from input file + +procedure str_read(file in_file: TEXT; + res_string: out string) is + + variable l: line; + variable c: character; + variable is_string: boolean; + + begin + + readline(in_file, l); + -- clear the contents of the result string + for i in res_string'range loop + res_string(i) := ' '; + end loop; + -- read all characters of the line, up to the length + -- of the results string + for i in res_string'range loop + read(l, c, is_string); + res_string(i) := c; + if not is_string then -- found end of line + exit; + end if; + end loop; + +end str_read; + + +-- print string to a file +procedure print(file out_file: TEXT; + new_string: in string) is + + variable l: line; + + begin + + write(l, new_string); + writeline(out_file, l); + +end print; + + +-- print character to a file and start new line +procedure print(file out_file: TEXT; + char: in character) is + + variable l: line; + + begin + + write(l, char); + writeline(out_file, l); + +end print; + + + +-- appends contents of a string to a file until line feed occurs +-- (LF is considered to be the end of the string) + +procedure str_write(file out_file: TEXT; + new_string: in string) is + begin + + for i in new_string'range loop + print(out_file, new_string(i)); + if new_string(i) = LF then -- end of string + exit; + end if; + end loop; + +end str_write; + + + + +end txt_util; + + + + diff --git a/soc/lib/wb_tp.vhd b/soc/lib/wb_tp.vhd new file mode 100644 index 0000000..4b6fcd3 --- /dev/null +++ b/soc/lib/wb_tp.vhd @@ -0,0 +1,1250 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +-- Whishbone Testing Package +package wb_tp is + constant READY: std_logic := '1'; --ready signal from mem which will be converted to msti.ack + constant NREADY: std_logic := '0'; + type access_type is (NO_ACC, RD_ACC, WR_ACC, SIM_ACC); +--------------------------------------------------------------- +-- +-- Prototype: Function +-- +--------------------------------------------------------------- + + function slvi_chk_quiet( + signal slvi_vector : wb_slv_in_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "slvi_chk_quiet " + ) return boolean; + + function msti_chk_quiet( + signal msti_vector : wb_mst_in_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "msti_chk_quiet " + ) return boolean; + + function msto_chk_quiet( + signal msto_vector : wb_mst_out_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "msto_chk_quiet " + ) return boolean ; + + function core2wbmo_chk( + signal wbadr : std_logic_vector(31 downto 0); + signal wbsz : std_logic_vector(1 downto 0); + signal wbwrdat : std_logic_vector(31 downto 0); + signal msto : wb_mst_out_type; + constant we : access_type := NO_ACC; + constant ScrnOut : boolean := false; + constant InstancePath: string := "core2wbmo_chk " + ) return boolean ; + + function slvi_chk_all( + signal slvo : wb_slv_out_vector; -- for address map check + signal msto : wb_mst_out_vector; + signal slvi : wb_slv_in_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "slvi_chk_all " + + ) return boolean; + + function msti_chk_all ( + signal msti : wb_mst_in_vector; + signal msto : wb_mst_out_vector; + signal slvo : wb_slv_out_vector; -- response from selected slave (if no addr map, no slave never been selected !!) + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "msti_chk_all " + ) return boolean; + + function wbmi2core_chk( + signal wb2core : dmem_core; + constant we : access_type := NO_ACC; + signal mo_sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + signal mi_ack : std_logic; + signal resp_rddat : std_logic_vector(memory_width - 1 downto 0); + constant ScrnOut : boolean := false; + constant InstancePath: string := "wbmi2core_chk " + ) return boolean; + + function wb2mem_chk( + signal wb2mem : core_dmem; + signal slvi : wb_slv_in_type; + constant we : access_type := NO_ACC; + constant ScrnOut : boolean := false; + constant InstancePath: string := "wb2mem_chk " + ) return boolean; + + function gmst_idx_fn ( + signal msto : wb_mst_out_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "gmst_idx_fn " + ) return integer ; + + function wbszconv_chk( + signal size : in std_logic_vector(1 downto 0); + constant ScrnOut : boolean := false; + constant InstancePath: string := "wbszconv_chk" + ) return boolean; + +--------------------------------------------------------------- +-- +-- Prototype: Procedure +-- +--------------------------------------------------------------- + procedure gencore2mem_req ( + signal core2dmem :out core_dmem; + -- + constant req_acc :in access_type := NO_ACC; + constant rd_adr :in std_logic_vector(memory_width - 1 downto 0) := (others=>'0'); + constant rd_sz :in std_logic_vector(1 downto 0) := "00"; + -- + constant wr_adr :in std_logic_vector(memory_width - 1 downto 0):= (others=>'0'); + constant wr_sz :in std_logic_vector(1 downto 0):= "00"; + constant wr_dat :in std_logic_vector(memory_width - 1 downto 0):= (others=>'-'); + -- + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "gencore2mem_req " + + ); +-- + procedure genwb2core ( + signal msti :out wb_mst_in_type; + -- + constant req_acc :in access_type := NO_ACC; + constant rd_sz :in std_logic_vector(1 downto 0) := "00"; + constant wb_sel :in std_logic_vector(WB_SEL_WIDTH-1 downto 0); + -- + constant read_data :in std_logic_vector(memory_width - 1 downto 0); + constant ready :in std_logic := '0'; + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "genwb2core" + ); +-- + procedure genmst_req ( + signal mst_out :out wb_mst_out_type; + constant req_idx :in integer := 0; + constant we :in std_logic; + constant adr :in std_logic_vector(WB_ADR_WIDTH-1 downto 0); + constant dat :in std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant sel :in std_logic_vector(WB_SEL_WIDTH-1 downto 0); + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "genmst_req " + ); +-- + procedure list_all_mst_req ( + signal msto : in wb_mst_out_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "list_all_mst_req " + ); + + procedure generate_sync_wb_single_write( + signal msto : out wb_mst_out_type; + signal slvo : in wb_slv_out_type; + signal clk : in std_logic; + signal writedata : std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10"; + constant ADR_OFFSET : integer := 0 -- Offset added to the access address + ); + + procedure generate_sync_wb_burst_write( + signal msto : out wb_mst_out_type; + signal slvo : in wb_slv_out_type; + signal clk : in std_logic; + signal writedata : std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant NUMBURSTS : positive := 4; + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10"; + constant ADR_OFFSET : integer := 0 -- Offset added to the access address + ); + + procedure generate_sync_wb_single_read( + signal msto : out wb_mst_out_type; -- Slave input + signal slvo : in wb_slv_out_type; -- Slave output + signal clk : in std_logic; + signal readdata : out std_logic_vector(WB_PORT_SIZE -1 downto 0); + constant ADR_OFFSET : integer := 0; -- Offset added to the access address + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10" + ); + + procedure generate_sync_wb_burst_read( + signal msto : out wb_mst_out_type; -- Slave input + signal slvo : in wb_slv_out_type; -- Slave output + signal clk : in std_logic; + signal readdata : out std_logic_vector(WB_PORT_SIZE -1 downto 0); + constant NUMBURSTS : positive := 4; + constant ADR_OFFSET : integer := 0; -- Offset added to the access address + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10" + ); + +end wb_tp; + +package body wb_tp is + +--------------------------------------------------------------- +-- Function: slvi_chk_quiet(slvi_vector) +-- +-- Check if there is any request (cyc) to any slave +--------------------------------------------------------------- + function slvi_chk_quiet( + signal slvi_vector : wb_slv_in_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "slvi_chk_quiet " + ) return boolean is + variable L: Line; + begin + for i in 0 to NWBSLV-1 loop + if slvi_vector(i).cyc /= '0' then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: slv(" & integer'image(i) & ") should not get any request !!!")); + writeline(output, L); + end if; + return false; + end if; + end loop; + + return true; + end function; + +--------------------------------------------------------------- +-- Function: msti_chk_quiet(msti_vector) +-- +-- Check if there is any request (ack) to any master +--------------------------------------------------------------- + function msti_chk_quiet( + signal msti_vector : wb_mst_in_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "msti_chk_quiet " + ) return boolean is + variable L: Line; + begin + for i in 0 to NWBMST-1 loop + if msti_vector(i).ack /= '0' then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: mst(" & integer'image(i) & ") should not get any ack !!!")); + writeline(output, L); + end if; + return false; + end if; + end loop; + + return true; + end function; + +--------------------------------------------------------------- +-- Function: msto_chk_quiet(mst_mask_vector) +-- +-- check if there is any master request (no need to assert error as it will be handle in fn caller) +-- Any master that is disable, wb_intercon will not assert the request (cyc) for that master +-- true = wb_intercon will consider that master as quiet as it either is inactive or sends no request (cyc= 0) +--------------------------------------------------------------- + function msto_chk_quiet( + signal msto_vector : wb_mst_out_vector; + constant ScrnOut : boolean := false; + constant InstancePath: string := "msto_chk_quiet " + ) return boolean is + variable L: Line; + begin + for i in 0 to NWBMST-1 loop + if msto_vector(i).cyc = '1' then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: mst(" & integer'image(i) & ") should not send any request!!!")); + writeline(output, L); + end if; + return false; + end if; + end loop; + + return true; + end function; + +--------------------------------------------------------------- +-- Function: core2wbmo_chk(wbadr, wbsz, wb_wrdat, msto, ACC) +-- This function checks control signals (stb, cyc, we) of core-to-wb conversion for single master(core) +-- Esp made for module "core2wb.vhd" +-- +-- SIM_ACC handles same as WR_ACC +--------------------------------------------------------------- + function core2wbmo_chk( + signal wbadr : std_logic_vector(31 downto 0); + signal wbsz : std_logic_vector(1 downto 0); + signal wbwrdat : std_logic_vector(31 downto 0); + signal msto : wb_mst_out_type; + constant we : access_type := NO_ACC; + constant ScrnOut : boolean := false; + constant InstancePath: string := "core2wbmo_chk " + ) return boolean is + variable L: Line; + begin + if we = RD_ACC then -- read + if msto.stb = '1' and msto.cyc = '1' and msto.we = '0' and + msto.adr = wbadr(memory_width - 1 downto WB_ADR_BOUND) and + msto.sel = gen_select(wbadr(1 downto 0), wbsz) + then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: Read req - ")); + if not(msto.stb = '1' and msto.cyc = '1' and msto.we = '0') then + write(L, String'("(msto.stb, msto.cyc, msto.we) should be (1, 1, 0) ")); + end if; + if (msto.adr /= wbadr(memory_width - 1 downto WB_ADR_BOUND)) then + write(L, String'("Mismatch addr: (msto.adr, wbadr) = (" & + hstr(msto.adr) & ", " & + hstr(wbadr(memory_width - 1 downto WB_ADR_BOUND)) & ") ")); + end if; + if (msto.sel /= gen_select(wbadr(1 downto 0), wbsz)) then + write(L, String'("Mismatch sel: (msto.sel, wbadr(1:0)) = (" & + str(msto.sel) & ", " & + str(gen_select(wbadr(1 downto 0), wbsz)) & ")")); + end if; + writeline(output, L); + end if; + end if; + elsif we = WR_ACC or we = SIM_ACC then -- write/sim + if msto.stb = '1' and msto.cyc = '1' and msto.we = '1' and + msto.adr = wbadr(memory_width - 1 downto WB_ADR_BOUND) and + msto.sel = gen_select(wbadr(1 downto 0), wbsz) and + msto.dat = enc_wb_dat(wbadr(1 downto 0), wbsz, wbwrdat) -- optional since mainly check from sel signal + then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + if we = WR_ACC then + write(L, String'("E01: Write req - ")); + else + write(L, String'("E02: Simultaneous req - ")); + end if; + if not(msto.stb = '1' and msto.cyc = '1' and msto.we = '1') then + write(L, String'("(msto.stb, msto.cyc, msto.we) should be (1, 1, 1) ")); + end if; + if (msto.adr /= wbadr(memory_width - 1 downto WB_ADR_BOUND)) then + write(L, String'("Mismatch addr: (msto.adr, wbadr) = (" & + hstr(msto.adr) & ", " & + hstr(wbadr(memory_width - 1 downto WB_ADR_BOUND)) & ") ")); + end if; + if (msto.sel /= gen_select(wbadr(1 downto 0), wbsz)) then + write(L, String'("Mismatch sel: (msto.sel, wbadr(1:0)) = (" & + str(msto.sel) & ", " & + str(gen_select(wbadr(1 downto 0), wbsz)) & ") ")); + end if; + if (msto.dat /= enc_wb_dat(wbadr(1 downto 0), wbsz, wbwrdat)) then + write(L, String'("Mismatch data: (msto.dat, wb_wrdat) = (" & + hstr(msto.dat) & ", " & + hstr(enc_wb_dat(wbadr(1 downto 0), wbsz, wbwrdat)) & ")")); + end if; + writeline(output, L); + end if; + end if; + else + if msto.stb = '0' and msto.cyc = '0' and msto.we = '0' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E03: No request - (msto.stb, msto.cyc, msto.we) should be (0, 0, 0)")); + writeline(output, L); + end if; + end if; + end if; + + return false; + end function; + + +--------------------------------------------------------------- +-- Function: slvi_chk_all(slvo_vector, msto_vector, slvi_vector, mst_mask_vector, opt:instancepath, opt:scrnout) +-- +-- slv_in check (out from wb_intercon) +-- This function checks if there is only selected slave from granted master gets the request signal (adr map) (cyc = 1) +-- Other slaves whose address is not mapped then should receive nothing (cyc = 0) +-- slv exist check by slvo(i).wbcfg(31 downto 24) must be x"FF" which will be called by wb_membar in order to reformat the mask addr of the slave +--------------------------------------------------------------- + function slvi_chk_all( + signal slvo : wb_slv_out_vector; -- for address map check + signal msto : wb_mst_out_vector; + signal slvi : wb_slv_in_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "slvi_chk_all " + ) return boolean is + variable madr, sadr : std_logic_vector(31 downto 0) := (others=>'0'); -- for display purpose only + variable gmst_idx : integer range 0 to NWBMST-1; + variable ssel_idx : integer range 0 to NWBSLV-1; + variable slv_found : boolean := false; + variable L : Line; + begin + + if msto_chk_quiet(msto) = true then -- No request from all master, No need to continue check slvi + if slvi_chk_quiet(slvi) = false then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: No request from any master")); + writeline(output, L); + end if; + return false; + end if; + else + gmst_idx := gmst_idx_fn(msto, mst_mask_vector); + madr := msto(gmst_idx).adr & "00"; + + -- compare, search for selected slave + for i in 0 to NWBSLV-1 loop + sadr := slvo(i).wbcfg(63 downto 34) & "00" ; + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'( + "[addr_cmp] slv(" & integer'image(i) & + ") with its address: " & hstr(sadr) & + " mst(" & integer'image(gmst_idx) & + ") with its address: " & hstr(madr))); + writeline(output, L); + end if; + if (slvadrmap(slvo(i).wbcfg, msto(gmst_idx).adr) = true) and slvo(i).wbcfg(31 downto 24) = x"FF" then + slv_found := true; + ssel_idx := i; + end if; + + end loop; + -- end compare + + if (slv_found = true) then + if (slvi(ssel_idx).cyc /= '1') then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E01: No request from master(" & integer'image(gmst_idx) & + ") for slv(" & integer'image(ssel_idx) & ")")); + writeline(output, L); + end if; + return false; + end if; + else + if (slvi(ssel_idx).cyc /= '0') then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E02: request address " & hstr(madr) & " not map with any slave, there should be no request signal " & + "from the granted master (" & integer'image(gmst_idx) & ")")); + writeline(output, L); + end if; + return false; + end if; + end if; + + end if; + + return true; + end function; + +--------------------------------------------------------------- +-- Function: msti_chk_all(msti_vector, msto_vector, slvo_vector, mst_mask_vector) +-- +-- Check msti +-- This function check if there is only granted master get the ack from selected slave (ack = 1) +-- Other master should not receive asserted ack signal from all slave (ack = 0) +-- slv exist check by slvo(i).wbcfg(31 downto 24) must be x"FF" which will be called by wb_membar in order to reformat the mask addr of the slave +--------------------------------------------------------------- + function msti_chk_all ( + signal msti : wb_mst_in_vector; + signal msto : wb_mst_out_vector; + signal slvo : wb_slv_out_vector; -- response from selected slave (if no addr map, no slave never been selected !!) + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "msti_chk_all " + ) return boolean is + variable madr, sadr : std_logic_vector(31 downto 0) := (others=>'0'); -- for display purpose only + variable gmst_idx : integer range 0 to NWBMST-1; + variable ssel_idx : integer range 0 to NWBSLV-1; + variable slv_found : boolean := false; + variable L : Line; + begin + + if (msto_chk_quiet(msto) = true) then -- No request from all master, No need to continue check slvi + if msti_chk_quiet(msti) = false then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: No request from any master")); + writeline(output, L); + end if; + return false; + end if; + else + -- Get master index of granted master + gmst_idx := gmst_idx_fn(msto, mst_mask_vector); + madr := msto(gmst_idx).adr & "00"; + + -- compare, search for selected slave + for i in 0 to NWBSLV-1 loop + sadr := slvo(i).wbcfg(63 downto 34) & "00" ; -- for disp on report only + + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("[addr_cmp] slv(" & integer'image(i) & + ") with its address: " & hstr(sadr) & + " mst(" & integer'image(gmst_idx) & + ") with its address: " & hstr(madr))); + writeline(output, L); + end if; + + if (slvadrmap(slvo(i).wbcfg, msto(gmst_idx).adr) = true) and slvo(i).wbcfg(31 downto 24) = x"FF" then + slv_found := true; + ssel_idx := i; -- ssel_idx wont update immediately need to be next iteration ?? + end if; + end loop; + -- end compare + + for i in 0 to NWBMST-1 loop + if (i = gmst_idx) then + -- handle for no grant like this case m3 = disable, cyc = 1 and m2 = enable, cyc = 0 -> no grant (correct) => no need to assert the error + -- for master that really request although it's inactive, + if msto(i).cyc = '1' then + if slv_found = true then + --if msti(i).ack /= '1' and slvo(ssel_idx).ack /= '1' and slv_found /= true then + if msti(i).ack /= '1' and slvo(ssel_idx).ack /= '1' then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E01: no Ack to granted master(" & integer'image(i) & ") from slv (" & integer'image(ssel_idx) & ")")); + writeline(output, L); + end if; + return false; + end if; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E02: request address " & hstr(madr) & " not map with any slave, there should be no request signal " & + "from the granted master (" & integer'image(gmst_idx) & ")")); + writeline(output, L); + end if; + return false; + end if; + end if; + else -- non grant master (ack must be 0) + if msti(i).ack /= '0' then + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E03: mst(" & integer'image(i) & ") should not have any response from any slv !!!")); + writeline(output, L); + end if; + return false; + end if; + end if; + end loop; + end if; + return true; + end function; + +--------------------------------------------------------------- +-- Function: wbmi2core_chk(wb2core, we, mo_sel, mo_dat, mi_ack, resp_rddat) +-- +-- This function checks response signal conversion from memory(wb_msti) to core(in_dmem_core) +-- esp made for core2wb.vhd testing +-- *** For SIM_ACC, the function has not supported so far. It MUST be manually put either RD_ACC or WR_ACC +-- 1st ack of SIM_ACC, fn should verify as write (ack) +-- 2nd ack of SIM_ACC, fn should verify as read (ack, rd_dat) +--------------------------------------------------------------- + function wbmi2core_chk( + signal wb2core : dmem_core; + constant we : access_type := NO_ACC; + signal mo_sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + signal mi_ack : std_logic; + signal resp_rddat : std_logic_vector(memory_width - 1 downto 0); + constant ScrnOut : boolean := false; + constant InstancePath: string := "wbmi2core_chk " + ) return boolean is + variable L: Line; + begin + if we = RD_ACC then -- read + if wb2core.ready = mi_ack and + wb2core.read_data = dec_wb_dat(mo_sel, resp_rddat) -- optional since mainly check from sel signal + then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + if we = RD_ACC then + write(L, String'("E00: Read req - ")); + else + write(L, String'("E00: Sim req (read) - ")); + end if; + if wb2core.ready = mi_ack then + write(L, String'("Mismacth read data: msti.dat = " & hstr(wb2core.read_data) & ", resp_rddat = " & hstr(dec_wb_dat(mo_sel, resp_rddat)))); + end if; + if wb2core.read_data /= dec_wb_dat(mo_sel, resp_rddat) then + write(L, String'(" Incorrect ack. ready = " & str(wb2core.ready) & ", msti.ack = "& str(mi_ack))); + end if; + writeline(output, L); + end if; + end if; + elsif we = WR_ACC then -- write + if wb2core.ready = mi_ack then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E01: Write req - Incorrect ack. (ready = " & str(wb2core.ready) & ", msti.ack = "& str(mi_ack))); + writeline(output, L); + end if; + end if; + elsif we = SIM_ACC then -- check only SIMACC_WR and for SIMACC_RD, use same as RD_ACC + if wb2core.ready = '0' and mi_ack = '1' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E02: Write req - Incorrect ack. (in_dmem.ready, msti.ack) should be = (0, 1) since the request is not complete yet")); + writeline(output, L); + end if; + end if; + else -- we = NO_ACC + if wb2core.ready = '1' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E03: No request - wb2core.ready should always assert")); + writeline(output, L); + end if; + end if; + end if; + + return false; + end function; +--------------------------------------------------------------- +-- Function: wb2mem_chk(wb2mem, slvi, we) +-- +-- This function checks control signals (stb, cyc, we) of wb-to-mem conversion for single slave(memory) +-- Esp made for mem2wb.vhd testing +--------------------------------------------------------------- + function wb2mem_chk( + signal wb2mem : core_dmem; + signal slvi : wb_slv_in_type; + constant we : access_type := NO_ACC; + constant ScrnOut : boolean := false; + constant InstancePath: string := "wb2mem_chk " + ) return boolean is + variable L: Line; + begin + if we = RD_ACC then -- read + if wb2mem.read_en = '1' and + wb2mem.read_addr(WB_ADR_WIDTH-1 downto WB_ADR_BOUND) = slvi.adr and + wbszconv_chk(wb2mem.read_size) and + wb2mem.write_en = '0' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'( "E00: Read req - wrong conversion from WB to MEMORY. wb_adr = " & + hstr(wb2mem.read_addr) & + " ,slvi.adr = " & + hstr(slvi.adr) & + " ,wb.read_en = " + )); + writeline(output, L); + end if; + end if; + elsif we = WR_ACC then -- write + if wb2mem.write_en = '1' and + wb2mem.write_addr(WB_ADR_WIDTH-1 downto WB_ADR_BOUND) = slvi.adr and + wbszconv_chk(wb2mem.write_size) and + wb2mem.write_data = dec_wb_dat(slvi.sel, slvi.dat) and + wb2mem.read_en = '0' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E01: Write req - ")); + if wb2mem.write_en /= '1' then + write(L, String'("Write_en should be active, ")); + end if; + + writeline(output, L); + end if; + end if; + elsif we = NO_ACC then + if wb2mem.read_en = '0' and + wb2mem.write_en = '0' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E02: No request")); + writeline(output, L); + end if; + end if; + else + if wb2mem.read_en = '1' and + wb2mem.write_en = '1' then + return true; + else + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E03: Sim request")); + writeline(output, L); + end if; + end if; + end if; + + return false; + end function; + +--------------------------------------------------------------- +-- Function: gmst_idx = gmst_idx_fn(msto, mst_mask_vector, grant) +-- +-- return: index of master that get the grant (highest priority/index number) +-- this index get the highest priority w/o checking active status (mst_mask_vector) ??? +--------------------------------------------------------------- + function gmst_idx_fn ( + signal msto : wb_mst_out_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "gmst_idx_fn " + ) return integer is + variable gnt_idx :integer range 0 to NWBMST-1; + variable L : Line; + begin + + for i in 0 to NWBMST-1 loop + if(msto(i).cyc='1' and mst_mask_vector(i) = '1' )then + gnt_idx := i; + end if; + end loop; + + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("master grant idx: "& integer'image(gnt_idx))); + writeline(output, L); + end if; + + return gnt_idx; + end function; + +--------------------------------------------------------------- +-- Function: wbszconv_chk = wbszconv_chk(size) +-- +-- return: +-- +-- remark: Internal use in wb_tp itself +--------------------------------------------------------------- + function wbszconv_chk( + signal size : in std_logic_vector(1 downto 0); + constant ScrnOut : boolean := false; + constant InstancePath: string := "wbszconv_chk" + ) return boolean is + variable L: Line; + begin + case WB_PORT_GRAN is + when 8 => + if size = "00" then return true; end if; + when 16 => + if size = "01" then return true; end if; + when 32 => + if size = "10" then return true; end if; + when 64 => + if size = "11" then return true; end if; + end case; + + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("E00: wb port gran doesn't match with port gran of core or memory")); + writeline(output, L); + end if; + + return false; + end function; +--------------------------------------------------------------- +-- Function: corewb_conv_chk(core2wb_in, msto) +-- +--------------------------------------------------------------- +-- function corewb_conv_chk( +-- core2wb_in : core_dmem; +-- msto : wb_mst_out_type; +-- constant InstancePath : string := "corewb_conv_chk"; +-- constant ScrnOut : boolean := false +-- ) return boolean is +-- variable result : boolean := false; +-- variable L : Line; +-- begin +-- +-- --check enable +-- +-- +-- write_data : std_logic_vector(memory_width - 1 downto 0); +-- write_addr : std_logic_vector(memory_width - 1 downto 0); +-- write_size : std_logic_vector(1 downto 0); +-- write_en : std_logic; +-- +-- +-- read_addr : std_logic_vector(memory_width - 1 downto 0); +-- read_size : std_logic_vector(1 downto 0); +-- read_en : std_logic; +-- +-- if ScrnOut then +-- write(L, Now, Right, 15); +-- write(L, " : " & InstancePath); +-- write(L, String'(" xxxxx")); +-- writeline(output, L); +-- end if; +-- return false; +-- end if; +-- +-- +-- return result; +-- end function; +-- + +--------------------------------------------------------------- +-- Procedure: gencore2mem_req(req_acc, rd_adr, rd_sz, wr_adr, wr_sz, wr_dat) +-- gencore2mem_req(XX_ACC, x"AAAAAAAA", "00", x"AAAAAAAA", "00", x"DDDDDDDD") +-- +--------------------------------------------------------------- + procedure gencore2mem_req ( + signal core2dmem :out core_dmem; + -- + constant req_acc :in access_type := NO_ACC; + constant rd_adr :in std_logic_vector(memory_width - 1 downto 0) := (others=>'0'); + constant rd_sz :in std_logic_vector(1 downto 0) := "00"; + -- + constant wr_adr :in std_logic_vector(memory_width - 1 downto 0):= (others=>'0'); + constant wr_sz :in std_logic_vector(1 downto 0):= "00"; + constant wr_dat :in std_logic_vector(memory_width - 1 downto 0):= (others=>'-'); + -- + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "gencore2mem_req " + ) is + variable L: Line; + begin + + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + case(req_acc) is + when RD_ACC => + write(L, String'("RD request: adr: " & hstr(rd_adr))); + when WR_ACC => + write(L, String'("WR request: adr: " & hstr(wr_adr) & " WR data: " & hstr(wr_dat))); + when SIM_ACC => + write(L, String'("SIM, RD request: adr: " & hstr(rd_adr))); + write(L, String'("SIM, WR request: adr: " & hstr(wr_adr) & " WR data: " & hstr(wr_dat))); + when others => + write(L, String'("NO request")); + end case; + writeline(output, L); + end if; + + case(req_acc) is + when RD_ACC => + core2dmem.read_en <= '1'; core2dmem.write_en <= '0'; + when WR_ACC => + core2dmem.read_en <= '0'; core2dmem.write_en <= '1'; + when SIM_ACC => + core2dmem.read_en <= '1'; core2dmem.write_en <= '1'; + when others => + core2dmem.read_en <= '0'; core2dmem.write_en <= '0'; + end case; + + -- leave data and adr as it is, although enable = 0 + core2dmem.read_addr <= rd_adr; + core2dmem.read_size <= rd_sz; + -- + core2dmem.write_addr <= wr_adr; + core2dmem.write_size <= wr_sz; + core2dmem.write_data <= wr_dat; + + end gencore2mem_req; + +--------------------------------------------------------------- +-- Procedure: genwb2core(msti, req_acc, rd_sz, wb_sel, read_data, ready) +-- +-- similar to function 'dec_wb_dat' in wishbone.vhd +--------------------------------------------------------------- + procedure genwb2core ( + signal msti :out wb_mst_in_type; + -- + constant req_acc :in access_type := NO_ACC; + constant rd_sz :in std_logic_vector(1 downto 0) := "00"; + constant wb_sel :in std_logic_vector(WB_SEL_WIDTH-1 downto 0); + -- + constant read_data :in std_logic_vector(memory_width - 1 downto 0); + constant ready :in std_logic := '0'; + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "genwb2core" + ) is + variable L :Line; + variable mi :wb_mst_in_type; + begin + mi.ack := ready; + --gen data based on sel and size + mi.dat := (others=>'0'); + if req_acc = RD_ACC then + --read + case (rd_sz) is + when "00" => + mi.dat( 7 downto 0) := read_data( 7 downto 0); + if wb_sel = "0001" then mi.dat( 7 downto 0) := read_data( 7 downto 0); + elsif wb_sel = "0010" then mi.dat(15 downto 8) := read_data(15 downto 8); + elsif wb_sel = "0100" then mi.dat(23 downto 16) := read_data(23 downto 16); + elsif wb_sel = "1000" then mi.dat(31 downto 24) := read_data(31 downto 24); + else mi.dat := (others=>'0'); + end if; + when "01" => + if wb_sel = "0001" then mi.dat(15 downto 0) := read_data(15 downto 0); + elsif wb_sel = "0010" then mi.dat(31 downto 16) := read_data(31 downto 16); + elsif wb_sel = "0011" then mi.dat(23 downto 8) := read_data(23 downto 8); + else mi.dat := (others=>'0'); + end if; + when "10" => + mi.dat := read_data; + when others => + mi.dat := (others=>'0'); + end case; + + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("RD resp: RD data: " & + hstr(mi.dat) & ", sel: " & + str(wb_sel) & ", rd_sz: " & + str(rd_sz) & ", ack = " & + str(mi.ack))); + writeline(output, L); + end if; + + else + mi.dat := (others=>'0'); + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("WR resp: ack = " & str(mi.ack))); + writeline(output, L); + end if; + + end if; + + msti <= mi; + + + end genwb2core; +--------------------------------------------------------------- +-- Procedure: genmst_req(msto(req_mst_idx),req_mst_idx, we, adr, dat, sel) +-- +-- Master read/Write req function for wb_intercon_tb +-- CAUTION: input slave address as 32 bits instaed of 30 bits to be readable +--------------------------------------------------------------- + procedure genmst_req ( + signal mst_out :out wb_mst_out_type; + constant req_idx :in integer := 0; + constant we :in std_logic; + constant adr :in std_logic_vector(WB_ADR_WIDTH-1 downto 0); + constant dat :in std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant sel :in std_logic_vector(WB_SEL_WIDTH-1 downto 0); + constant ScrnOut :in boolean := false; + constant InstancePath :in string := "genmst_req " + ) is + variable L: Line; + begin + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("Master(" & integer'image(req_idx) &") Request address: " & hstr(adr))); + writeline(output, L); + end if; + + mst_out <= wbm_out_none; -- initial + mst_out.adr <= adr(31 downto 2); + mst_out.sel <= sel; + mst_out.stb <= '1'; + mst_out.cyc <= '1'; +-- mst_out.wbidx <= req_idx; + + if we = '0' then -- read + mst_out.we <= '0'; + mst_out.dat <= (others=>'-'); + else -- write + mst_out.we <= '1'; + mst_out.dat <= dat; + end if; + end genmst_req; + +--------------------------------------------------------------- +-- Procedure: list_all_mst_req(msto_vector, mst_mask_vector); +-- +-- Utility procedure to list all master request(s) +--------------------------------------------------------------- + procedure list_all_mst_req ( + signal msto : in wb_mst_out_vector; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + constant ScrnOut : boolean := false; + constant InstancePath : string := "list_all_mst_req " + ) is + variable mstat :integer range 0 to 1 := 0; -- for disp purpose + variable madr : std_logic_vector(31 downto 0) := (others=> '0'); + variable noreq: boolean := true; + variable L : Line; + begin + + for i in 0 to NWBMST-1 loop + if msto(i).cyc = '1' then + if mst_mask_vector(i) = '0' then + mstat := 0; + else + mstat := 1; + end if; + madr := msto(i).adr & "00"; + if ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("Request mst(" & integer'image(i) & "), addr: " & hstr(madr) & " with status: " & integer'image(mstat))); + writeline(output, L); + end if; + noreq := false; + end if; + end loop; + + if noreq and ScrnOut then + write(L, Now, Right, 15); + write(L, " : " & InstancePath); + write(L, String'("No request")); + writeline(output, L); + end if; + + end list_all_mst_req; + + procedure generate_sync_wb_single_write( + signal msto : out wb_mst_out_type; + signal slvo : in wb_slv_out_type; + signal clk : in std_logic; + signal writedata : std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant size : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10"; + constant adr_offset : integer := 0 -- Offset added to the access address + ) is + variable adr : std_logic_vector(31 downto 0); + variable sel : std_logic_vector(WB_SEL_WIDTH downto 0); + begin + adr := slvo.wbcfg(63 downto 32); + adr := std_logic_vector(unsigned(adr) + adr_offset); + + --continue if rising edge active, else wait for it + --allows subsequent procedure calls without waiting for next edge + if not rising_edge(clk) then + wait until rising_edge(clk); + end if; + + msto <= wbm_out_none; + msto.cyc <= '1'; + msto.stb <= '1'; + msto.we <= '1'; + msto.sel <= gen_select(adr(1 downto 0),size); + msto.adr <= adr(31 downto 2); + msto.dat <= enc_wb_dat(adr(1 downto 0),size,writedata); + + wait until rising_edge(clk); + wait until slvo.ack = '1' for 1 ps; + assert slvo.ack = '1' report "Slave did not ACK the write properly"; + + wait until rising_edge(clk); + + msto.cyc <= '0'; + msto.stb <= '0'; + msto.we <= '-'; + msto.sel <= (others=>'-'); + msto.dat <= (others=>'-'); + msto.adr <= (others=>'-'); + end procedure; + + procedure generate_sync_wb_burst_write( + signal msto : out wb_mst_out_type; + signal slvo : in wb_slv_out_type; + signal clk : in std_logic; + signal writedata : std_logic_vector(WB_PORT_SIZE-1 downto 0); + constant NUMBURSTS : positive := 4; + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10"; + constant ADR_OFFSET : integer := 0 -- Offset added to the access address + ) is + variable adr : std_logic_vector(31 downto 0); + variable sel : std_logic_vector(WB_SEL_WIDTH downto 0); + variable i : integer := 1; + begin + adr := slvo.wbcfg(63 downto 32); + adr := std_logic_vector(unsigned(adr) + ADR_OFFSET); + + --continue if rising edge active, else wait for it + --allows subsequent procedure calls without waiting for next edge + if not rising_edge(clk) then + wait until rising_edge(clk); + end if; + + msto <= wbm_out_none; + msto.cyc <= '1'; + msto.stb <= '1'; + msto.we <= '1'; + msto.sel <= gen_select(adr(1 downto 0),SIZE); + msto.adr <= adr(31 downto 2); + msto.dat <= enc_wb_dat(adr(1 downto 0),SIZE,writedata); + msto.cti <= "010"; + + while i /= NUMBURSTS loop + wait until rising_edge(clk); + wait until slvo.ack = '1' for 1 ps; + adr := std_logic_vector(unsigned(adr) + 4); + msto.adr <= adr(31 downto 2); + msto.dat <= enc_wb_dat(adr(1 downto 0),SIZE,std_logic_vector(unsigned(writedata)+i)); + i := i+1; + end loop; + + msto.cti <= "111"; + wait until rising_edge(clk); + msto.stb <= '0'; + msto.cti <= (others => '-'); + msto.dat <= (others => '-'); + msto.sel <= (others => '-'); + wait until rising_edge(clk); + if slvo.ack = '1' then + msto <= wbm_out_none; + end if; + + end procedure; + + procedure generate_sync_wb_single_read( + signal msto : out wb_mst_out_type; -- Slave input + signal slvo : in wb_slv_out_type; -- Slave output + signal clk : in std_logic; + signal readdata : out std_logic_vector(WB_PORT_SIZE -1 downto 0); + constant adr_offset : integer := 0; -- Offset added to the access address + constant size : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10" + ) is + variable sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + variable adr : std_logic_vector(31 downto 0); + begin + adr := slvo.wbcfg(63 downto 32); + adr := std_logic_vector(unsigned(adr) + adr_offset); + sel := gen_select(adr(1 downto 0),size); + + --allow subsequent reads + if not rising_edge(clk) then + wait until rising_edge(clk); + end if; + + msto <= wbm_out_none; + msto.cyc <= '1'; + msto.stb <= '1'; + msto.we <= '0'; + msto.sel <= sel; + msto.adr <= adr; + + wait until rising_edge(clk); + wait until slvo.ack='1' for 1 ps; + assert slvo.ack='1' report "Slave did not ACK the read properly"; + if slvo.ack='1' then + readdata <= dec_wb_dat(sel,slvo.dat); + else + readdata <= (others=>'X'); + end if; + wait until rising_edge(clk); + msto.cyc <= '0'; + msto.stb <= '0'; + msto.we <= '-'; + msto.sel <= (others=>'-'); + msto.dat <= (others=>'-'); + msto.adr <= (others=>'-'); + end procedure; + + procedure generate_sync_wb_burst_read( + signal msto : out wb_mst_out_type; -- Slave input + signal slvo : in wb_slv_out_type; -- Slave output + signal clk : in std_logic; + signal readdata : out std_logic_vector(WB_PORT_SIZE -1 downto 0); + constant NUMBURSTS : positive := 4; + constant ADR_OFFSET : integer := 0; -- Offset added to the access address + constant SIZE : std_logic_vector(WB_ADR_BOUND-1 downto 0) := "10" + ) is + variable sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + variable adr : std_logic_vector(31 downto 0); + variable i : integer := 1; + begin + adr := slvo.wbcfg(63 downto 32); + adr := std_logic_vector(unsigned(adr) + ADR_OFFSET); + sel := gen_select(adr(1 downto 0),SIZE); + + --allow subsequent reads + if not rising_edge(clk) then + wait until rising_edge(clk); + end if; + + msto <= wbm_out_none; + msto.cyc <= '1'; + msto.stb <= '1'; + msto.we <= '0'; + msto.sel <= sel; + msto.adr <= adr; + msto.cti <= "010"; + + while i /= NUMBURSTS loop + wait until rising_edge(clk); + adr := std_logic_vector(unsigned(adr) + 4); + msto.adr <= adr(31 downto 2); + readdata <= dec_wb_dat(sel,slvo.dat); + i := i+1; + end loop; + + msto.cti <= "111"; + wait until rising_edge(clk); + msto.stb <= '0'; + msto.cti <= (others => '-'); + msto.dat <= (others => '-'); + msto.sel <= (others => '-'); + if slvo.ack = '1' then + readdata <= dec_wb_dat(sel,slvo.dat); + end if; + wait until rising_edge(clk); + msto <= wbm_out_none; + end procedure; + +end wb_tp; diff --git a/soc/lib/wishbone.vhd b/soc/lib/wishbone.vhd new file mode 100644 index 0000000..0f3de5d --- /dev/null +++ b/soc/lib/wishbone.vhd @@ -0,0 +1,707 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +-- This is a Package defining the Internal Interfaces and Constants of the Bus Bridge +-- Signal naming conventions: input signals end with _i, output signals end with _o +-- Signals inside of Records do not have these endings +-- +-- Constants names are written uppercase + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; +use work.lt16x32_global.all; + +package wishbone is + constant DEBUG: boolean := true; + + type endian_type is (big, little); + + -- Configuration of the Wishbone Bus (every non-derived constant must be a power of 2) + constant WB_PORT_SIZE: integer := 32; -- Data Port Bitwidth + constant WB_PORT_GRAN: integer := 8; -- Data Port Granularity (Bitsize of smallest addressable unit) + constant WB_MAX_OPSIZE: integer := WB_PORT_SIZE; -- Maximum Operand Size + constant WB_ENDIANESS: endian_type := big; -- Endianess, 0 => Little Endian, 1 => Big Endian + constant WB_ADR_WIDTH: integer := 32; -- Length of Bus Addresses + constant WB_ADR_BOUND: integer := 2; -- lower boundary of Address, derived from PORT_SIZE and PORT_GRAN ( log2(SEL_WIDTH) ), number of Adress Bits which can not be used + constant WB_SEL_WIDTH: integer := WB_PORT_SIZE/WB_PORT_GRAN; -- Bitwidth of the select signal (sel_I/O), number of min size units that fit on data bus (WB_PORT_SIZE/WB_PORT_GRAN) + + constant NWBMST: integer :=4; --Number of Wishbone master connectors on the Interconnect + constant NWBSLV: integer :=16; --Number of Wishbone slave connectors on the Interconnect + + subtype wb_addr_type is std_logic_vector(WB_ADR_WIDTH-1 downto WB_ADR_BOUND); + + constant zadr : wb_addr_type := (others => '0'); + constant zdat : std_logic_vector(WB_PORT_SIZE-1 downto 0):= (others=>'0'); + constant zslv22: std_logic_vector(21 downto 0) := (others=>'0'); + + constant zadr32 : std_logic_vector(31 downto 0):= (others=>'0'); + constant dc32: std_logic_vector(31 downto 0):= (others=>'-'); + +-- +-- ---------------------------------------------------------------------------------------- +-- -- master:data tag signals (input and output) +-- type wb_tag_mst_i_data_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_mst_o_data_type is record +-- dc: std_logic; +-- end record; +-- +-- -- address tag signals (input and output) +-- type wb_tag_mst_i_adr_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_mst_o_adr_type is record +-- dc: std_logic; +-- end record; +-- +-- -- cycle tag signals (input and output) +-- type wb_tag_mst_i_cyc_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_mst_o_cyc_type is record +-- dc: std_logic; +-- end record; +-- -- slv:data tag signals (input and output) +-- type wb_tag_slv_i_data_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_slv_o_data_type is record +-- dc: std_logic; +-- end record; +-- +-- -- address tag signals (input and output) +-- type wb_tag_slv_i_adr_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_slv_o_adr_type is record +-- dc: std_logic; +-- end record; +-- +-- -- cycle tag signals (input and output) +-- type wb_tag_slv_i_cyc_type is record +-- dc: std_logic; +-- end record; +-- +-- type wb_tag_slv_o_cyc_type is record +-- dc: std_logic; +-- end record; +-- ---------------------------------------------------------------------------------------- +-- -- tag types +-- ---------------------------------------------------------------------------------------- +-- -- master input tag signals +-- type wb_tag_mst_i_type is record +-- tgd: wb_tag_mst_i_data_type; +-- tga: wb_tag_mst_i_adr_type; +-- tgc: wb_tag_mst_i_cyc_type; +-- end record; +-- +-- -- master output tag signals +-- type wb_tag_mst_o_type is record +-- tgd: wb_tag_mst_o_data_type; +-- tga: wb_tag_mst_o_adr_type; +-- tgc: wb_tag_mst_o_cyc_type; +-- end record; +-- +-- -- slave input tag signals +-- type wb_tag_slv_i_type is record +-- tgd: wb_tag_slv_i_data_type; +-- tga: wb_tag_slv_i_adr_type; +-- tgc: wb_tag_slv_i_cyc_type; +-- end record; +-- +-- -- slave output tag signals +-- type wb_tag_slv_o_type is record +-- tgd: wb_tag_slv_o_data_type; +-- tga: wb_tag_slv_o_adr_type; +-- tgc: wb_tag_slv_o_cyc_type; +-- end record; +-- +-- ---------------------------------------------------------------------------------------- +-- -- Wishbone Clock and Reset +-- type wb_sys_type is record +-- rst: std_logic; +-- clk: std_logic; +-- end record; + + subtype wb_config_type is std_logic_vector(63 downto 0); + + --Cycle type identifier: + --000: Classic cycle, 001: Constant address burst, 010: Incrementing burst + --111: End-of-Burst + subtype wb_tag_cti_io is std_logic_vector(2 downto 0); + + --Burst type extension: + --00: Linear burst, 01: 4-beat wrap burst + --10: 8-beat wrap burst, 11: 16-beat wrap burst + subtype wb_tag_bte_io is std_logic_vector(1 downto 0); + + -- Wishbone Master Input Signals + type wb_mst_in_type is record + dat: std_logic_vector(WB_PORT_SIZE-1 downto 0); + ack: std_logic; + --tagn: wb_tag_mst_i_type; + --stall: std_logic; + --err: std_logic; + --rty: std_logic; + end record; + + -- Wishbone Master Output Signals + type wb_mst_out_type is record + adr : wb_addr_type; + dat : std_logic_vector(WB_PORT_SIZE-1 downto 0); + we : std_logic; + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + stb : std_logic; + cyc : std_logic; + cti : wb_tag_cti_io; + bte : wb_tag_bte_io; + --tagn: wb_tag_mst_o_type; + --lock: std_logic; + --wbcfg: wb_config_type; -- memory access reg. + end record; + + -- Wishbone Slave Input Signals +-- type wb_slv_in_type is record +-- adr : wb_addr_type; +-- dat : std_logic_vector(WB_PORT_SIZE-1 downto 0); +-- we : std_logic; +-- sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); +-- stb : std_logic; +-- cyc : std_logic; +-- cti : wb_tag_cti_io; +-- bte : wb_tag_bte_io; +-- --tagn: wb_tag_slv_o_type; +-- --lock: std_logic; +-- end record; + subtype wb_slv_in_type is wb_mst_out_type; + + -- Wishbone Slave Output Signals + type wb_slv_out_type is record + dat: std_logic_vector(WB_PORT_SIZE-1 downto 0); + ack: std_logic; + --tagn: wb_tag_slv_i_type; + --stall: std_logic; + --err: std_logic; + --rty: std_logic; + wbcfg : wb_config_type; -- memory access reg. + end record; + -- + --array types + -- + type wb_mst_out_vector_type is array (natural range <>) of wb_mst_out_type; + type wb_mst_in_vector_type is array (natural range <>) of wb_mst_in_type; + type wb_slv_out_vector_type is array (natural range <>) of wb_slv_out_type; + type wb_slv_in_vector_type is array (natural range <>) of wb_slv_in_type; + + subtype wb_mst_out_vector is wb_mst_out_vector_type(NWBMST-1 downto 0); + subtype wb_slv_out_vector is wb_slv_out_vector_type(NWBSLV-1 downto 0); + subtype wb_mst_in_vector is wb_mst_in_vector_type(NWBMST-1 downto 0); + subtype wb_slv_in_vector is wb_slv_in_vector_type(NWBSLV-1 downto 0); + --30 bits + subtype generic_addr_type is integer range 0 to 16#7fffffff#; + subtype generic_mask_type is integer range 0 to 16#7fffffff#; --lowest 2 get disregarded + + + + constant wbm_in_none : wb_mst_in_type := + ( zdat, --data + '0' --ack + --(others=>'0'), --tagn + --'0' --stall + --'0', --err + --'0' --rty + ); + + constant wbm_out_none : wb_mst_out_type := + ( zadr, -- adr + zdat, -- dat + '0', -- we + (others => '0'), -- sel + '0', -- stb + '0', -- cyc + "000", -- cti + "00" -- bte + --(others => '0'), -- tagn + --'0' --lock + ); + + constant wbs_in_none: wb_slv_in_type := + ( zadr, -- adr + zdat, -- dat + '0', -- we + (others => '0'), -- sel + '0', -- stb + '0', -- cyc + "000", -- cti + "00" -- bte + --(others => '0'), -- tagn + --'0' --lock + ); + + constant wbs_out_none: wb_slv_out_type := + ( zdat, -- dat + '0', -- ack + --(others=>'0'), --tagn + --'0', --stall + --'0', --err + --'0', --rty + (others=>'1') --cfg + ); + + -- function to calculate a valid sel signal (see Wishbone Specification B4 Page 58 ff.) + function select_bytes( + address: std_logic_vector; + len: std_logic_vector; -- number of Granularity sized Units transferred + sel: std_logic_vector + ) return std_logic_vector; + + function wb_membar( + memaddr : generic_addr_type; + addrmask : generic_mask_type) + return std_logic_vector; + + function slvadrmap( + cfg : std_logic_vector(63 downto 0); + mstadr : wb_addr_type + ) + return boolean; + + function gen_select( + adr : std_logic_vector(1 downto 0); -- core_adr + sz : std_logic_vector(1 downto 0) + ) + return std_logic_vector; + + function decsz( + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0) + ) + return std_logic_vector; + + function sel2adr( + sel: std_logic_vector(WB_SEL_WIDTH-1 downto 0) + ) + return std_logic_vector; + + function enc_wb_dat( + wradr : std_logic_vector(1 downto 0); + wrsz : std_logic_vector(1 downto 0); + din : std_logic_vector(memory_width - 1 downto 0) + ) + return std_logic_vector; + + function dec_wb_dat( + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + din : std_logic_vector(WB_PORT_SIZE-1 downto 0) + ) + return std_logic_vector; + +---------------------------------------------------------------------------------------- +-- end package definition +---------------------------------------------------------------------------------------- +end; + +package body wishbone is + + function select_bytes( + address: std_logic_vector; -- least significant bits which determine the select signal + len: std_logic_vector; -- number of Granularity sized Units transferred + sel: std_logic_vector -- signal which is to set + ) return std_logic_vector is + + -- declarate and initialize variables + -- initialize result with 1 (dec) + variable res: unsigned(sel'range) := (others => '0'); + + -- convert length to unsigned + variable len_u: unsigned(WB_ADR_BOUND-1 downto 0) := unsigned(len); + + -- zero vector for comparison with 0 + variable len_zero: unsigned(WB_ADR_BOUND-1 downto 0) := (others => '0'); + + -- full select signal + variable sel_full: std_logic_vector(sel'range) := (others => '1'); + + begin + -- initialization + res(0) := '1'; + + -- handle special case: len=0 = max length + if (len_u = len_zero) then + return std_logic_vector(sel_full); + end if; + + -- check if Bitwidths are valid + --if (DEBUG = true) then + assert (sel'length = 2**address'length) + report "Wishbone, function select_byte: array lengths of address and sel argument do not match, please check your Bitwidths configuration" + severity failure; + --end if; + + -- create result vector for case len = 1 (dec) + for i in address'range loop + if (address(i) = '1') then + res := res sll i+1; + end if; + end loop; + + -- exponentially expand result vector ones when length > 1 (dec) + for j in address'range loop + len_u := len_u sll 1; + if not(len_u = len_zero) then + for i in 0 to (WB_SEL_WIDTH/2)-1 loop + res(2*i+1 downto 2*i) := ( others => ( res(2*i) OR res(2*i+1) ) ); + end loop; + end if; + end loop; + + return std_logic_vector(res); + end; -- end function + +--------------------------------------------------------------- +-- Function: wb_membar(memaddr, addrmask) +-- +-- This function reformat the slave address and mask to support address mapping in slvadrmap function +-- The function will put both the mem address and mask into a field. +-- input: memaddr(30 bits) = base address, addrmask(22 bits) +-- output: cfg (64 bits) +-- +-- base_addr[63:34], 30b +-- mask_addr[31: 2], 30b = {FF, 22b} +--------------------------------------------------------------- + function wb_membar( + memaddr : generic_addr_type; + addrmask : generic_mask_type) + return std_logic_vector is + variable cfg : std_logic_vector(63 downto 0); + begin + --base_addr[63:34], 30b + --mask_addr[31: 2], 30b = {FF, 22b} + --slv_exist = cfg(0); + cfg(63 downto 32) := std_logic_vector(to_unsigned(memaddr , WB_ADR_WIDTH)); -- 31 b + --cfg(33 downto 32) := (others=>'0'); --2 bits (free) + --cfg(31 downto 24) := x"FF"; -- fixed, nonmaskable + cfg(31 downto 0) := std_logic_vector(to_unsigned(addrmask, WB_ADR_WIDTH)); --31b + --cfg( 1 downto 0) := "00"; --(free) + + return(cfg); + end; + +--------------------------------------------------------------- +-- Function: slvadrmap(cfg, mstadr) +-- +-- This function compares the request address from master to slave address (slvo.cfg) +-- slvo.cfg contains its address and mask to identify its address range +-- For non-exist slave, there will be no wb_membar function call in order to format the cfg e.g. setting cfg(31 downto 24) = x"FF" +-- therefore the cfg always return all zeros including the default masking portion +-- besides checking nonexist slave from cfg(31 downto 24) = x"00", slave_mask_vector is another alternative way +-- but the function need to input slave_mask_vector +--------------------------------------------------------------- + + function slvadrmap( + cfg : std_logic_vector(63 downto 0); + mstadr : wb_addr_type + ) + return boolean is + variable mmap: std_logic_vector(29 downto 0) := (others=>'0'); + variable addrmapflag: boolean := false; + begin + --base_addr = cfg[63:34], 30b + --mask_addr = cfg[31: 2], 30b + --mmap = (base_addr ^ mstreq_baseaddr) and mask_addr) + ----------------------------------------------------- + mmap := (cfg(63 downto 34) xor mstadr) and cfg(31 downto 2); + if (mmap = (mmap'range => '0')) then + addrmapflag := true; + else + addrmapflag := false; + end if; + return(addrmapflag); + end; + +--------------------------------------------------------------- +-- Function: gen_select(Address(1 downto 0),ACCESS_SIZE) +-- for the 2 LSBs of an address, returns the WB select signal +-- for a given ACCESS_SIZE{BYTE,HALFWORD,WORD} +--------------------------------------------------------------- + function gen_select( + adr : std_logic_vector(1 downto 0); + sz : std_logic_vector(1 downto 0) + ) + return std_logic_vector is + variable sel_out :std_logic_vector(WB_SEL_WIDTH-1 downto 0) := (others=>'0'); + begin + + if WB_ENDIANESS = big then + --if WB_ENDIANESS = little then + case (sz) is + when "00" => + --SIZE: BYTE + if (adr = "11") then sel_out := "0001"; + elsif (adr = "10") then sel_out := "0010"; + elsif (adr = "01") then sel_out := "0100"; + elsif (adr = "00") then sel_out := "1000"; + else sel_out := (others=>'0'); + end if; + when "01" => + --SIZE: HALFWORD + if (adr = "10") then sel_out := "0011"; + elsif (adr = "11") then sel_out := "0011"; + elsif (adr = "01") then sel_out := "1100"; + elsif (adr = "00") then sel_out := "1100"; + else sel_out := (others=>'0'); + end if; + when "10" => + --SIZE: WORD + sel_out := (others => '1'); + when others => + sel_out := (others=>'0'); + end case; + else + case (sz) is + when "00" => + --SIZE: BYTE + if (adr = "00") then sel_out := "0001"; + elsif (adr = "01") then sel_out := "0010"; + elsif (adr = "10") then sel_out := "0100"; + elsif (adr = "11") then sel_out := "1000"; + else sel_out := (others=>'0'); + end if; + when "01" => + --SIZE: HALFWORD + if (adr = "00") then sel_out := "0011"; + elsif (adr = "01") then sel_out := "0011"; + elsif (adr = "10") then sel_out := "1100"; + elsif (adr = "11") then sel_out := "1100"; + else sel_out := (others=>'0'); + end if; + when "10" => + --SIZE: WORD + sel_out := (others => '1'); + when others => + sel_out := (others=>'0'); + end case; + end if; + + return(sel_out); + end; + +--------------------------------------------------------------- +-- Function: sel2adr(port_gran, wbsel) - decselwb2mem +-- to retrieve last 2 bits address for core +-- big endian +--------------------------------------------------------------- + function sel2adr( + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0) + ) + return std_logic_vector is + variable adr :std_logic_vector(1 downto 0) := (others=>'0'); + begin + if WB_ENDIANESS = big then + case WB_PORT_GRAN is + when 8 => + case sel is + when "1000" => adr := "00"; + when "0100" => adr := "01"; + when "0010" => adr := "10"; + when "0001" => adr := "11"; + when "1100" => adr := "00"; + when "0011" => adr := "10"; + when "1111" => adr := "00"; + when others => adr := "11"; + end case; + + when 16 => + --untested! do not use without (extensive) testing + if sel(1 downto 0) = "10" then adr := "00"; + elsif sel(1 downto 0) = "11" then adr := "01"; + elsif sel(1 downto 0) = "01" then adr := "10"; + else adr := "00"; + end if; + when others => + --untested! do not use without (extensive) testing + adr := "00"; + end case; + else + case WB_PORT_GRAN is + when 8 => + case sel is + when "0001" => adr := "00"; + when "0010" => adr := "01"; + when "0100" => adr := "10"; + when "1000" => adr := "11"; + when "0011" => adr := "00"; + when "1100" => adr := "10"; + when "1111" => adr := "00"; + when others => adr := "00"; + end case; + + when 16 => + --untested! do not use without (extensive) testing + if sel(1 downto 0) = "01" then adr := "00"; + elsif sel(1 downto 0) = "11" then adr := "01"; + elsif sel(1 downto 0) = "10" then adr := "10"; + else adr := "00"; + end if; + when others => + --untested! do not use without (extensive) testing + adr := "00"; + end case; + end if; + + return(adr); + end; + +--------------------------------------------------------------- +-- Function: enc_wb_dat (byte addr,ACCESS_SIZE,DATA) +-- Encodes a 32-bit input vector to a WB data word, +-- depending on the provided byte address and ACCESS_SIZE +--------------------------------------------------------------- + function enc_wb_dat( + wradr : std_logic_vector(1 downto 0); + wrsz : std_logic_vector(1 downto 0); + din : std_logic_vector(memory_width - 1 downto 0) + ) + return std_logic_vector is + variable dword :std_logic_vector(WB_PORT_SIZE-1 downto 0) := (others=>'0'); + begin + if WB_ENDIANESS = big then + --if WB_ENDIANESS = little then + case wrsz is + when "00" => + if wradr = "11" then dword( 7 downto 0) := din(7 downto 0); + elsif wradr = "10" then dword(15 downto 8) := din(7 downto 0); + elsif wradr = "01" then dword(23 downto 16) := din(7 downto 0); + elsif wradr = "00" then dword(31 downto 24) := din(7 downto 0); + else dword := (others=>'0'); + end if; + when "01" => + if wradr = "10" or wradr = "11" then dword(15 downto 0) := din(15 downto 0); + elsif wradr = "00" or wradr = "01" then dword(31 downto 16):= din(15 downto 0); + else dword:= (others=>'0'); + end if; + when "10" => + dword := din; + when others => + dword := (others=>'0'); + end case; + else + case wrsz is + when "00" => + if wradr = "00" then dword( 7 downto 0) := din(7 downto 0); + elsif wradr = "01" then dword(15 downto 8) := din(7 downto 0); + elsif wradr = "10" then dword(23 downto 16) := din(7 downto 0); + elsif wradr = "11" then dword(31 downto 24) := din(7 downto 0); + else dword := (others=>'0'); + end if; + when "01" => + if wradr = "00" or wradr = "01" then dword(15 downto 0) := din(15 downto 0); + elsif wradr = "10" or wradr = "11" then dword(31 downto 16):= din(15 downto 0); + else dword:= (others=>'0'); + end if; + when "10" => + dword := din; + when others => + dword := (others=>'0'); + end case; + end if; + + return(dword); + end; + +--------------------------------------------------------------- +-- Function: dec_wb_dat(select,dword) +-- Decodes a WB data word using the given select signal +-- +--------------------------------------------------------------- + function dec_wb_dat( + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0); + din : std_logic_vector(WB_PORT_SIZE-1 downto 0) + ) + return std_logic_vector is + variable dword :std_logic_vector(WB_PORT_SIZE-1 downto 0) := (others=>'0'); + begin + case WB_PORT_GRAN is + when 8 => + case sel is + when "0001" => + dword(7 downto 0) := din( 7 downto 0); + when "0010" => + dword(7 downto 0) := din(15 downto 8); + when "0100" => + dword(7 downto 0) := din(23 downto 16); + when "1000" => + dword(7 downto 0) := din(31 downto 24); + when "1100" => + dword(15 downto 0) := din(31 downto 16); + when "0011" => + dword(15 downto 0) := din(15 downto 0); + when "1111" => + dword := din; + when others => + dword := (others => '0'); + end case; + + when 16 => + --untested! do not use without (extensive) testing + if sel = "0011" then dword(15 downto 0):= din(15 downto 0) ; + elsif sel = "1100" then dword(15 downto 0):= din(31 downto 16); + else dword := (others=>'0'); + end if; + when 32 => + --untested! do not use without (extensive) testing + dword := din; + when others => + dword := (others=>'0'); + end case; + + return(dword); + end; + +--------------------------------------------------------------- +-- Function: decsz(port_gran) equivalent to "decselwb2mem" +-- +-- +--------------------------------------------------------------- + function decsz( + sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0) + ) + return std_logic_vector is + variable sz :std_logic_vector(1 downto 0) := (others=>'0'); + begin + case WB_PORT_GRAN is + when 8 => + case sel is + when "0001" => + sz := "00"; + when "0010" => + sz := "00"; + when "0100" => + sz := "00"; + when "1000" => + sz := "00"; + when "1100" => + sz := "01"; + when "0011" => + sz := "01"; + when "1111" => + sz := "10"; + when others => + sz := "11"; + end case; + when 16 => sz := "01"; + --untested! do not use without (extensive) testing + when 32 => sz := "10"; + --untested! do not use without (extensive) testing + when others => sz := "00"; + end case; + return(sz); + end; + +end; -- end package body diff --git a/soc/mem/blockram.vhd b/soc/mem/blockram.vhd new file mode 100644 index 0000000..5f564f2 --- /dev/null +++ b/soc/mem/blockram.vhd @@ -0,0 +1,35 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +--Generic BRAM with 64 Byte + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity blockram is +port ( + clk : in std_logic; + we : in std_logic; + en : in std_logic; + addr : in std_logic_vector(5 downto 0); + di : in std_logic_vector(7 downto 0); + do : out std_logic_vector(7 downto 0)); +end blockram; + +architecture syn of blockram is + type ram_type is array (63 downto 0) of std_logic_vector (7 downto 0); + signal RAM: ram_type; +begin + process (clk) + begin + if clk'event and clk = '1' then + if en = '1' then + if we = '1' then + RAM(conv_integer(addr)) <= di; + end if; + do <= RAM(conv_integer(addr)) ; + end if; + end if; + end process; +end syn; + diff --git a/soc/mem/dmem.vhd b/soc/mem/dmem.vhd new file mode 100644 index 0000000..17962c7 --- /dev/null +++ b/soc/mem/dmem.vhd @@ -0,0 +1,120 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +-- a small 4x64 byte memory. byte-addressable +entity wb_dmem is + generic( + memaddr : generic_addr_type; + addrmask : generic_mask_type := CFG_MADR_DMEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end wb_dmem; + +architecture Behavioral of wb_dmem is + + component blockram + port ( + clk : in std_logic; + we : in std_logic; + en : in std_logic; + addr : in std_logic_vector(5 downto 0); + di : in std_logic_vector(7 downto 0); + do : out std_logic_vector(7 downto 0)); + end component blockram; + + signal we : std_logic_vector(3 downto 0); + signal en : std_logic; + signal addr : std_logic_vector(5 downto 0); + signal cached_addr : std_logic_vector(5 downto 0); + type di_t is array (3 downto 0) of std_logic_vector (7 downto 0); + signal di : di_t; + type do_t is array (3 downto 0) of std_logic_vector (7 downto 0); + signal do : do_t; + + type burst_t is (CLASSIC,BURST,ENDOFBURST); + signal burst_state : burst_t; + + signal ack : std_logic; + +begin + + process(wslvi.sel, wslvi.we) + begin + for i in 3 downto 0 loop + we(i) <= wslvi.sel(i) and wslvi.we; + end loop; + end process; + +-- we(3) <= wslvi.sel(0) and wslvi.we; +-- we(2) <= wslvi.sel(1) and wslvi.we; +-- we(1) <= wslvi.sel(2) and wslvi.we; +-- we(0) <= wslvi.sel(3) and wslvi.we; + + en <= wslvi.stb and wslvi.cyc; + addr <= wslvi.adr(7 downto 2); + + block3 : blockram + port map(clk,we(0),en,addr,di(3),do(3)); + block2 : blockram + port map(clk,we(1),en,addr,di(2),do(2)); + block1 : blockram + port map(clk,we(2),en,addr,di(1),do(1)); + block0 : blockram + port map(clk,we(3),en,addr,di(0),do(0)); + + di(3) <= wslvi.dat(7 downto 0); + di(2) <= wslvi.dat(15 downto 8); + di(1) <= wslvi.dat(23 downto 16); + di(0) <= wslvi.dat(31 downto 24); + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + ack <= '0'; + burst_state <= CLASSIC; + else + case burst_state is + when CLASSIC => + if wslvi.stb = '1' and wslvi.cyc = '1' then + if ack = '0' then + ack <= '1'; + elsif wslvi.cti = "010" then + burst_state <= BURST; + ack <= '1'; + else + ack <= '0'; + end if; + else + ack <= '0'; + end if; + when BURST => + if wslvi.cti = "111" then + burst_state <= ENDOFBURST; + ack <= '1'; + end if; + when ENDOFBURST => + burst_state <= CLASSIC; + ack <= '0'; + end case; + end if; + end if; + end process; + + wslvo.ack <= ack; + wslvo.dat <= do(0) & do(1) & do(2) & do(3); + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + +END ARCHITECTURE; diff --git a/soc/mem/mem2wb.vhd b/soc/mem/mem2wb.vhd new file mode 100644 index 0000000..83ea1ac --- /dev/null +++ b/soc/mem/mem2wb.vhd @@ -0,0 +1,93 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +entity mem2wb is + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out core_dmem; + out_dmem : in dmem_core; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end mem2wb; + +ARCHITECTURE Behavioral OF mem2wb IS + + signal indmem : core_dmem; + signal ack : std_logic; + +BEGIN + wbs2dmem: process(wslvi) + begin + --init + indmem.write_en <= '0'; + indmem.write_addr(memory_width - 1 downto WB_ADR_BOUND) <= (others=>'0'); + indmem.write_addr(1 downto 0) <= "00"; + indmem.write_data <= (others=>'0'); + indmem.write_size <= "00"; + -- + indmem.read_en <= '0'; + indmem.read_addr(memory_width - 1 downto WB_ADR_BOUND) <= (others=>'0'); + indmem.read_addr(1 downto 0) <= "00"; + indmem.read_size <= "00"; + --end init + + if wslvi.stb = '1' and wslvi.cyc = '1' then + if wslvi.we = '1' then + indmem.write_en <= '1'; + indmem.write_addr <= wslvi.adr & sel2adr(wslvi.sel); + indmem.write_data <= dec_wb_dat(wslvi.sel, wslvi.dat); + indmem.write_size <= decsz(wslvi.sel); + else + indmem.read_en <= '1'; + indmem.read_addr <= wslvi.adr & sel2adr(wslvi.sel); + indmem.read_size <= decsz(wslvi.sel); + end if; + end if; + end process; + --- + in_dmem <= indmem; + + dmem2wbs:process(out_dmem, indmem.read_addr, indmem.read_size) + begin + --init + wslvo.dat <= (others=>'0'); + --end init + wslvo.dat <= enc_wb_dat(indmem.read_addr(1 downto 0), indmem.read_size, out_dmem.read_data); + + + end process; + + process(clk, rst) + begin + if rising_edge(clk) then + if rst = '1' then + ack <= '0'; + else + if wslvi.stb = '1' and wslvi.cyc = '1' and ack = '0' then + ack <= '1'; + else + ack <= '0'; + end if; + end if; + end if; + end process; + + wslvo.ack <= ack; + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + +END ARCHITECTURE; diff --git a/soc/mem/memdiv.vhd b/soc/mem/memdiv.vhd new file mode 100644 index 0000000..e4aac17 --- /dev/null +++ b/soc/mem/memdiv.vhd @@ -0,0 +1,405 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use std.textio.all; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.config.all; + +-- the memory handles all memory transactions from the processor +-- it could be extended to have bus accesses to communicate to the outside world. +-- also, artificial latency can be inserted for simulation purposes. +entity memdiv is + generic( + -- name of file for initialization, formatted as lines of 32 ones or zeroes, each describing one word. + filename : in string := "program.ram"; + -- size in words (32bit) + size : in integer := IMEMSZ; + -- latency of the instruction memory interface + imem_latency : in time := 5 ns; + -- latency of the data memory interface + dmem_latency : in time := 5 ns + ); + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + + -- dmem signals from the processor + in_dmem : in core_dmem; + -- dmem signals to the processor + out_dmem : out dmem_core; + + -- imem signals from the processor + in_imem : in core_imem; + -- imem signals to the processor + out_imem : out imem_core; + + -- fault signal, active high + fault : out std_logic + ); +end entity memdiv; + +architecture RTL of memdiv is + constant width : integer := 32; + + -- construct to have in_simulation and in_synthesis for generates in this module + constant in_simulation : boolean := false + -- synthesis translate_off + or true + -- synthesis translate_on + ; + constant in_synthesis : boolean := not in_simulation; + + -- type for the memory signal + type memory_type is array (0 to size - 1) of std_logic_vector(width - 1 downto 0); + + -- this function initializes an array of memory_type with the contents of a given file + -- function from http://myfpgablog.blogspot.de/2011/12/memory-initialization-methods.html + -- and from http://www.stefanvhdl.com/vhdl/html/file_read.html + -- and from http://www.ee.sunysb.edu/~jochoa/vhd_writefile_tutorial.htm + impure function init_mem(mif_file_name : in string) return memory_type is + -- input file + file mif_file : text open read_mode is mif_file_name; + -- input file read line + variable mif_line : line; + + -- temporary bit vector for data read from file + variable temp_bv : bit_vector(width - 1 downto 0); + -- temporary memory array + variable temp_mem : memory_type; + -- read function success value + variable good : boolean; + begin + for i in memory_type'range loop + if not endfile(mif_file) then + -- if no end of input file, read next line + readline(mif_file, mif_line); + -- match line into bit vector + read(mif_line, temp_bv, good); + + -- synthesis translate_off + assert good report ("Non-good word in memory location " & integer'image(i)) severity warning; --! give a warning when readline is no good -TF 2014-05-20 + -- synthesis translate_on + + -- copy temporary bit vector into temporary memory array + temp_mem(i) := to_stdlogicvector(temp_bv); + else + -- EOF but memory not yet full, fill up with zeros + temp_mem(i) := (others => '0'); + end if; + end loop; + + -- check if program fit into memory + if not endfile(mif_file) then + assert false report "memory not large enough for loaded program." severity failure; + end if; + + -- give back filled array + return temp_mem; + end function; + + -- memory array + signal memory : memory_type := init_mem(filename); + + -- internal data signals for use with ready signals in simulation + signal imem_data : std_logic_vector(width - 1 downto 0); + signal dmem_data : std_logic_vector(width - 1 downto 0); + + -- fault signal for dmem read fault + signal dmem_read_fault : std_logic; + -- fault signal for dmem write fault + signal dmem_write_fault : std_logic; + -- fault signal for imem read faults + signal imem_read_fault : std_logic; +begin + + -- fault logic + fault <= dmem_read_fault or dmem_write_fault or imem_read_fault; + + -- imem read + imem_read : process(clk) is + -- calculated word address + variable wordaddress : integer; + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset zero output and no fault + imem_data <= (others => '0'); + imem_read_fault <= '0'; + + elsif (in_imem.read_en = '1') then + -- if read enabled + + -- standard output + imem_read_fault <= '0'; + + -- word address calculation + wordaddress := to_integer(unsigned(in_imem.read_addr(in_imem.read_addr'high downto 2))); -- always 32bit aligned + + -- read data + if (wordaddress < size) then + -- always return full word + imem_data <= memory(wordaddress)(width - 1 downto 0); + else + -- memory access out of bounds + imem_read_fault <= '1'; + imem_data <= (others => 'X'); + end if; + end if; + end if; + end process imem_read; + + -- dmem read + dmem_read : process(clk) is + -- calculated word address + variable wordaddress : integer; + -- calculated byte address inside of word + variable byteaddress : std_logic_vector(1 downto 0); + -- read full word + variable word : std_logic_vector(width - 1 downto 0); + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset zero output and no fault + dmem_data <= (others => '0'); + dmem_read_fault <= '0'; + else + -- standard output + dmem_read_fault <= '0'; + + if (in_dmem.read_en = '1') then + -- if read enabled, otherwise keep up old data + + -- calculate word address and address of byte inside of word + wordaddress := to_integer(unsigned(in_dmem.read_addr(in_dmem.read_addr'high downto 2))); + byteaddress := in_dmem.read_addr(1 downto 0); + + if (wordaddress = 0) then + dmem_data <= (others => '0'); + + elsif (wordaddress < size) then -- data can be accessed full range of address + -- in memory range + + -- read word from memory array + word := memory(wordaddress); + + -- get correct bits from full word + case in_dmem.read_size is + when "00" => -- byte access + -- clear non-byte bits + dmem_data(width - 1 downto 8) <= (others => '0'); + + -- fill last byte of output word with read data + case byteaddress is + when "00" => + dmem_data(7 downto 0) <= word(31 downto 24); + when "01" => + dmem_data(7 downto 0) <= word(23 downto 16); + when "10" => + dmem_data(7 downto 0) <= word(15 downto 8); + when "11" => + dmem_data(7 downto 0) <= word(7 downto 0); + when others => + -- will not happen in synthesis, but might in simulation + dmem_data(7 downto 0) <= (others => 'X'); + end case; + + when "01" => -- halfword access + -- clear non-halfword bits + dmem_data(width - 1 downto 16) <= (others => '0'); + + -- fill last halfword of output word with read data + case byteaddress is + when "00" => + dmem_data(15 downto 0) <= word(31 downto 16); + when "01" => + --alignment to lower half word + dmem_data(15 downto 0) <= word(31 downto 16); + when "10" => + dmem_data(15 downto 0) <= word(15 downto 0); + when "11" => + --alignment to lower half word + dmem_data(15 downto 0) <= word(15 downto 0); + when others => + -- memory access exceeds word boundaries + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (16bit dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + end case; + + when "10" => -- word access + -- fill all bits of output word with read data + if (byteaddress = "00") then + dmem_data <= word; + else + -- memory access exceeds word boundaries + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (32bit dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + end if; + when others => + -- memory size not implemented + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory size not implemented" severity error; + -- synthesis translate_on + end case; + + else -- (wordaddress >= size) + -- memory access out of bounds + dmem_read_fault <= '1'; + dmem_data <= (others => 'X'); + -- synthesis translate_off + assert false report "memory access out of bounds (dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + + end if; + end if; + end if; + end if; + end process dmem_read; + + -- dmem write + dmem_write : process(clk) is + -- calculated word address + variable wordaddress : integer; + -- calculated byte address inside of word + variable byteaddress : std_logic_vector(1 downto 0); + -- read full word + variable word : std_logic_vector(width - 1 downto 0); + begin + if rising_edge(clk) then + if rst = '1' then + dmem_write_fault <= '0'; + elsif (in_dmem.write_en = '1') then + dmem_write_fault <= '0'; + wordaddress := to_integer(unsigned(in_dmem.write_addr(in_dmem.write_addr'high downto 2))); + byteaddress := in_dmem.write_addr(1 downto 0); + + if (wordaddress < size) then -- in memory range and no special word + -- read old word + word := memory(wordaddress)(31 downto 0); + + -- modify word + case in_dmem.write_size is + when "00" => -- byte access + case byteaddress is + when "00" => + word(31 downto 24) := in_dmem.write_data(7 downto 0); + when "01" => + word(23 downto 16) := in_dmem.write_data(7 downto 0); + when "10" => + word(15 downto 8) := in_dmem.write_data(7 downto 0); + when "11" => + word(7 downto 0) := in_dmem.write_data(7 downto 0); + when others => + -- will not happen in synthesis, but might in simulation + word(7 downto 0) := (others => 'X'); + end case; + when "01" => -- halfword access + case byteaddress is + when "00" => + word(31 downto 16) := in_dmem.write_data(15 downto 0); + when "01" => + word(23 downto 8) := in_dmem.write_data(15 downto 0); + when "10" => + word(15 downto 0) := in_dmem.write_data(15 downto 0); + when others => + -- memory access exceeds word boundaries + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (16bit dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end case; + when "10" => + if (byteaddress = "00") then + word := in_dmem.write_data; + else + -- memory access exceeds word boundaries + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (32bit dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end if; + + when others => + -- memory size not implemented + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory size not implemented" severity error; + -- synthesis translate_on + end case; + + memory(wordaddress) <= word; + + else + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access out of bounds (dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end if; + end if; + end if; + end process dmem_write; + + -- in synthesis, data is always valid in next clock cycle + synthesis_only : if (in_synthesis) generate + out_imem.read_data <= imem_data; + out_imem.ready <= '1'; + out_dmem.read_data <= dmem_data; + out_dmem.ready <= '1'; + end generate synthesis_only; + + -- add latency in simulation only + + -- synthesis translate_off + simulation_only : if (in_simulation) generate + -- instruction memory latency + imem_delay : process is + begin + wait until imem_data'event; + + -- wait artificial delay + if (imem_latency > 0 ns) then + -- show not ready-yet data as XX + out_imem.ready <= '0'; + out_imem.read_data <= (others => 'X'); + wait for imem_latency; + end if; + + -- output data + out_imem.read_data <= imem_data; + + -- now we're ready + out_imem.ready <= '1'; + end process imem_delay; + + -- data memory latency + dmem_delay : process is + begin + wait until dmem_data'event; + + -- wait artificial delay + if (dmem_latency > 0 ns) then + -- show not ready-yet data as XX + out_dmem.ready <= '0'; + out_dmem.read_data <= (others => 'X'); + wait for dmem_latency; + end if; + + -- output data + out_dmem.read_data <= dmem_data; + + -- now we're ready + out_dmem.ready <= '1'; + end process dmem_delay; + + end generate simulation_only; +-- synthesis translate_on + +end architecture RTL; diff --git a/soc/mem/memories.vhd b/soc/mem/memories.vhd new file mode 100644 index 0000000..3c019a2 --- /dev/null +++ b/soc/mem/memories.vhd @@ -0,0 +1,60 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; + +library work; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +-- package to incorperate memory modules +package lt16soc_memories is + + --insert components and used functions for the memory modules + + component wb_dmem is + generic( + memaddr : generic_addr_type := CFG_BADR_DMEM; + addrmask : generic_mask_type := CFG_MADR_DMEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component wb_dmem; + + component memwrapper + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + filename : in string := "programs/program.ram"; + size : in integer := IMEMSZ + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + + -- wb slv port + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component; +end lt16soc_memories; + +package body lt16soc_memories is + + --insert function bodies + +end lt16soc_memories; + diff --git a/soc/mem/memory.vhd b/soc/mem/memory.vhd new file mode 100644 index 0000000..25fc1b8 --- /dev/null +++ b/soc/mem/memory.vhd @@ -0,0 +1,413 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use std.textio.all; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; + +-- the memory handles all memory transactions from the processor +-- it could be extended to have bus accesses to communicate to the outside world. +-- this is currently possible via port out_byte, which can be written to at address 0x04000000. +-- also, artificial latency can be inserted for simulation purposes. +entity memory is + generic( + -- name of file for initialization, formatted as lines of 32 ones or zeroes, each describing one word. + filename : in string := "program.ram"; + -- size in words (32bit) + size : in integer := 256; + -- latency of the instruction memory interface + imem_latency : in time := 5 ns; + -- latency of the data memory interface + dmem_latency : in time := 5 ns + ); + port( + -- clock signal + clk : in std_logic; + -- reset signal, active high, synchronous + rst : in std_logic; + + -- dmem signals from the processor + in_dmem : in core_dmem; + -- dmem signals to the processor + out_dmem : out dmem_core; + + -- imem signals from the processor + in_imem : in core_imem; + -- imem signals to the processor + out_imem : out imem_core; + + -- fault signal, active high + fault : out std_logic; + + -- out_byte port to access "outer world" + out_byte : out std_logic_vector(7 downto 0)); +end entity memory; + +architecture RTL of memory is + constant width : integer := 32; + + -- construct to have in_simulation and in_synthesis for generates in this module + constant in_simulation : boolean := false + -- synthesis translate_off + or true + -- synthesis translate_on + ; + constant in_synthesis : boolean := not in_simulation; + + -- type for the memory signal + type memory_type is array (0 to size - 1) of std_logic_vector(width - 1 downto 0); + + -- this function initializes an array of memory_type with the contents of a given file + -- function from http://myfpgablog.blogspot.de/2011/12/memory-initialization-methods.html + -- and from http://www.stefanvhdl.com/vhdl/html/file_read.html + -- and from http://www.ee.sunysb.edu/~jochoa/vhd_writefile_tutorial.htm + impure function init_mem(mif_file_name : in string) return memory_type is + -- input file + file mif_file : text open read_mode is mif_file_name; + -- input file read line + variable mif_line : line; + + -- temporary bit vector for data read from file + variable temp_bv : bit_vector(width - 1 downto 0); + -- temporary memory array + variable temp_mem : memory_type; + -- read function success value + variable good : boolean; + begin + for i in memory_type'range loop + if not endfile(mif_file) then + -- if no end of input file, read next line + readline(mif_file, mif_line); + -- match line into bit vector + read(mif_line, temp_bv, good); + + -- synthesis translate_off + assert good report ("Non-good word in memory location " & integer'image(i)) severity warning; --! give a warning when readline is no good -TF 2014-05-20 + -- synthesis translate_on + + -- copy temporary bit vector into temporary memory array + temp_mem(i) := to_stdlogicvector(temp_bv); + else + -- EOF but memory not yet full, fill up with zeros + temp_mem(i) := (others => '0'); + end if; + end loop; + + -- check if program fit into memory + if not endfile(mif_file) then + assert false report "memory not large enough for loaded program." severity failure; + end if; + + -- give back filled array + return temp_mem; + end function; + + -- memory array + signal memory : memory_type := init_mem(filename); + + -- internal data signals for use with ready signals in simulation + signal imem_data : std_logic_vector(width - 1 downto 0); + signal dmem_data : std_logic_vector(width - 1 downto 0); + + -- fault signal for dmem read fault + signal dmem_read_fault : std_logic; + -- fault signal for dmem write fault + signal dmem_write_fault : std_logic; + -- fault signal for imem read faults + signal imem_read_fault : std_logic; +begin + + -- fault logic + fault <= dmem_read_fault or dmem_write_fault or imem_read_fault; + + -- imem read + imem_read : process(clk) is + -- calculated word address + variable wordaddress : integer; + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset zero output and no fault + imem_data <= (others => '0'); + imem_read_fault <= '0'; + + elsif (in_imem.read_en = '1') then + -- if read enabled + + -- standard output + imem_read_fault <= '0'; + + -- word address calculation + wordaddress := to_integer(unsigned(in_imem.read_addr(in_imem.read_addr'high downto 2))); -- always 32bit aligned + + -- read data + if (wordaddress < size) then + -- always return full word + imem_data <= memory(wordaddress)(width - 1 downto 0); + else + -- memory access out of bounds + imem_read_fault <= '1'; + imem_data <= (others => 'X'); + end if; + end if; + end if; + end process imem_read; + + -- dmem read + dmem_read : process(clk) is + -- calculated word address + variable wordaddress : integer; + -- calculated byte address inside of word + variable byteaddress : std_logic_vector(1 downto 0); + -- read full word + variable word : std_logic_vector(width - 1 downto 0); + begin + if (rising_edge(clk)) then + if (rst = '1') then + -- in reset zero output and no fault + dmem_data <= (others => '0'); + dmem_read_fault <= '0'; + else + -- standard output + dmem_read_fault <= '0'; + + if (in_dmem.read_en = '1') then + -- if read enabled, otherwise keep up old data + + -- calculate word address and address of byte inside of word + wordaddress := to_integer(unsigned(in_dmem.read_addr(in_dmem.read_addr'high downto 2))); + byteaddress := in_dmem.read_addr(1 downto 0); + + if (wordaddress = 0) then + dmem_data <= (others => '0'); + + elsif (wordaddress < size) then + -- in memory range + + -- read word from memory array + word := memory(wordaddress); + + -- get correct bits from full word + case in_dmem.read_size is + when "00" => -- byte access + -- clear non-byte bits + dmem_data(width - 1 downto 8) <= (others => '0'); + + -- fill last byte of output word with read data + case byteaddress is + when "00" => + dmem_data(7 downto 0) <= word(7 downto 0); + when "01" => + dmem_data(7 downto 0) <= word(15 downto 8); + when "10" => + dmem_data(7 downto 0) <= word(23 downto 16); + when "11" => + dmem_data(7 downto 0) <= word(31 downto 24); + when others => + -- will not happen in synthesis, but might in simulation + dmem_data(7 downto 0) <= (others => 'X'); + end case; + + when "01" => -- halfword access + -- clear non-halfword bits + dmem_data(width - 1 downto 16) <= (others => '0'); + + -- fill last halfword of output word with read data + case byteaddress is + when "00" => + dmem_data(15 downto 0) <= word(15 downto 0); + when "01" => + dmem_data(15 downto 0) <= word(23 downto 8); + when "10" => + dmem_data(15 downto 0) <= word(31 downto 16); + when others => + -- memory access exceeds word boundaries + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (16bit dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + end case; + + when "10" => -- word access + -- fill all bits of output word with read data + if (byteaddress = "00") then + dmem_data <= word; + else + -- memory access exceeds word boundaries + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (32bit dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + end if; + when others => + -- memory size not implemented + dmem_read_fault <= '1'; + -- synthesis translate_off + assert false report "memory size not implemented" severity error; + -- synthesis translate_on + end case; + + else -- (wordaddress >= size) + -- memory access out of bounds + dmem_read_fault <= '1'; + dmem_data <= (others => 'X'); + -- synthesis translate_off + assert false report "memory access out of bounds (dmem read at " & integer'image(to_integer(unsigned(in_dmem.read_addr))) & ")" severity error; + -- synthesis translate_on + + end if; + end if; + end if; + end if; + end process dmem_read; + + -- dmem write + dmem_write : process(clk) is + -- calculated word address + variable wordaddress : integer; + -- calculated byte address inside of word + variable byteaddress : std_logic_vector(1 downto 0); + -- read full word + variable word : std_logic_vector(width - 1 downto 0); + begin + if rising_edge(clk) then + if rst = '1' then + dmem_write_fault <= '0'; + out_byte <= (others => '0'); + elsif (in_dmem.write_en = '1') then + dmem_write_fault <= '0'; + wordaddress := to_integer(unsigned(in_dmem.write_addr(in_dmem.write_addr'high downto 2))); + byteaddress := in_dmem.write_addr(1 downto 0); + + if (wordaddress = 0) then + + out_byte <= in_dmem.write_data(7 downto 0); + + elsif (wordaddress < size) then -- in memory range and no special word + -- read old word + word := memory(wordaddress)(31 downto 0); + + -- modify word + case in_dmem.write_size is + when "00" => -- byte access + case byteaddress is + when "00" => + word(7 downto 0) := in_dmem.write_data(7 downto 0); + when "01" => + --word(15 downto 8) := in_dmem.write_data(7 downto 0); + word(15 downto 8) := in_dmem.write_data(15 downto 8); + when "10" => + --word(23 downto 16) := in_dmem.write_data(7 downto 0); + word(23 downto 16) := in_dmem.write_data(23 downto 16); + when "11" => + --word(31 downto 24) := in_dmem.write_data(7 downto 0); + word(31 downto 24) := in_dmem.write_data(31 downto 24); + when others => + -- will not happen in synthesis, but might in simulation + word(7 downto 0) := (others => 'X'); + end case; + when "01" => -- halfword access + case byteaddress is + when "00" => + word(15 downto 0) := in_dmem.write_data(15 downto 0); + when "01" => + --word(23 downto 8) := in_dmem.write_data(15 downto 0); + word(23 downto 8) := in_dmem.write_data(23 downto 8); + when "10" => + --word(31 downto 16) := in_dmem.write_data(15 downto 0); + word(31 downto 16) := in_dmem.write_data(31 downto 16); + when others => + -- memory access exceeds word boundaries + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (16bit dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end case; + when "10" => + if (byteaddress = "00") then + word := in_dmem.write_data; + else + -- memory access exceeds word boundaries + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access exceeds word boundaries (32bit dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end if; + + when others => + -- memory size not implemented + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory size not implemented" severity error; + -- synthesis translate_on + end case; + + memory(wordaddress) <= word; + + else + dmem_write_fault <= '1'; + -- synthesis translate_off + assert false report "memory access out of bounds (dmem write at " & integer'image(to_integer(unsigned(in_dmem.write_addr))) & ")" severity error; + -- synthesis translate_on + end if; + end if; + end if; + end process dmem_write; + + -- in synthesis, data is always valid in next clock cycle + synthesis_only : if (in_synthesis) generate + out_imem.read_data <= imem_data; + out_imem.ready <= '1'; + out_dmem.read_data <= dmem_data; + out_dmem.ready <= '1'; + end generate synthesis_only; + + -- add latency in simulation only + + -- synthesis translate_off + simulation_only : if (in_simulation) generate + -- instruction memory latency + imem_delay : process is + begin + wait until imem_data'event; + + -- wait artificial delay + if (imem_latency > 0 ns) then + -- show not ready-yet data as XX + out_imem.ready <= '0'; + out_imem.read_data <= (others => 'X'); + wait for imem_latency; + end if; + + -- output data + out_imem.read_data <= imem_data; + + -- now we're ready + out_imem.ready <= '1'; + end process imem_delay; + + -- data memory latency + dmem_delay : process is + begin + wait until dmem_data'event; + + -- wait artificial delay + if (dmem_latency > 0 ns) then + -- show not ready-yet data as XX + out_dmem.ready <= '0'; + out_dmem.read_data <= (others => 'X'); + wait for dmem_latency; + end if; + + -- output data + out_dmem.read_data <= dmem_data; + + -- now we're ready + out_dmem.ready <= '1'; + end process dmem_delay; + + end generate simulation_only; +-- synthesis translate_on + +end architecture RTL; diff --git a/soc/mem/memwrapper.vhd b/soc/mem/memwrapper.vhd new file mode 100644 index 0000000..774147f --- /dev/null +++ b/soc/mem/memwrapper.vhd @@ -0,0 +1,149 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + + +entity memwrapper is + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + filename : string := "program.ram"; + size : integer := IMEMSZ + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + --out_byte : out std_logic_vector(7 downto 0); + + -- wb master port + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end entity memwrapper; + +architecture RTL of memwrapper is + +--////////////////////////////////////////////////////// +-- component +--////////////////////////////////////////////////////// +component memdiv + generic( + filename : in string := "program.ram"; + size : in integer := IMEMSZ; + imem_latency : in time := 5 ns; + dmem_latency : in time := 5 ns + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : in core_dmem; + out_dmem : out dmem_core; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic + ); +end component; + + +component mem2wb + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out core_dmem; + out_dmem : in dmem_core; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end component; +--////////////////////////////////////////////////////// +-- signal +--////////////////////////////////////////////////////// + signal outimem : imem_core; + signal in_dmem : core_dmem; + signal out_dmem : dmem_core; +begin + +--////////////////////////////////////////////////////// +-- Instantiate +--////////////////////////////////////////////////////// + mem_inst: memdiv + generic map( + filename => filename, + size => size, + imem_latency => 1 ns, + dmem_latency => 1 ns + ) + port map( + clk => clk, + rst => rst, + in_dmem => in_dmem, + out_dmem => out_dmem, + in_imem => in_imem, + out_imem => outimem, + fault => fault + ); + + ------------------------------------ + -- wb_slv coversion (dmem) + ------------------------------------ + mem2wb_inst: mem2wb + generic map( + memaddr => memaddr, + addrmask => addrmask + ) + port map( + clk => clk, + rst => rst, + + in_dmem => in_dmem, + out_dmem => out_dmem, + + wslvi => wslvi, + wslvo => wslvo + ); + + ------------------------------------ + -- mem ctrl block + + out_imem.read_data <= outimem.read_data; + + memctrl_reg:process(clk) + begin + if rst = '1' then + out_imem.ready <= '0'; + elsif(rising_edge(clk)) then + -- TODO: dmem is going to access in imem data portion : how about write ??, can slv overwrite ins (Read only ) ? + if (in_dmem.read_en = '1' and (to_integer(unsigned(in_dmem.read_addr )) <= IMEMSZ)) or + (in_dmem.write_en = '1' and (to_integer(unsigned(in_dmem.write_addr)) <= IMEMSZ)) + then + out_imem.ready <= '0'; + else + out_imem.ready <= outimem.ready; + end if; + end if; + end process; + ------------------------------------ + -- E N D mem ctrl block + ------------------------------------ + +end architecture RTL; diff --git a/soc/peripheral/LCDController.vhd b/soc/peripheral/LCDController.vhd new file mode 100644 index 0000000..23d37d1 --- /dev/null +++ b/soc/peripheral/LCDController.vhd @@ -0,0 +1,74 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE ieee.numeric_std.all; +USE work.lt16x32_global.all; +USE work.wishbone.all; +USE work.config.all; + +ENTITY wb_lcd IS + generic( + memaddr : generic_addr_type; + addrmask : generic_mask_type + ); + port( + clk : IN std_logic; + rst : IN std_logic; + + dataLCD : INOUT std_logic_vector(7 downto 0); + enableLCD : OUT std_logic; + rsLCD : OUT std_logic; + rwLCD : OUT std_logic; + + wslvi : IN wb_slv_in_type; + wslvo : OUT wb_slv_out_type + ); +END ENTITY; + +ARCHITECTURE behav OF wb_lcd IS + + signal lcd_reg : std_logic_vector(10 downto 0); + signal ack : std_logic; + +BEGIN + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + ack <= '0'; + lcd_reg <= (others => '0'); + else + if wslvi.stb = '1' and wslvi.cyc = '1' then + + if wslvi.we = '1' then + lcd_reg <= dec_wb_dat(wslvi.sel,wslvi.dat)(10 downto 0); + end if; + + if ack = '0' then + ack <= '1'; + else + ack <= '0'; + end if; + else + ack <= '0'; + end if; + end if; + end if; + end process; + + wslvo.dat(10 downto 0) <= lcd_reg when wslvi.adr(2) = '0' + else "000" & dataLCD when wslvi.adr(2) = '1' and lcd_reg(8) = '1' + else (others => '0'); + + wslvo.dat(31 downto 11) <= (others=>'0'); + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + wslvo.ack <= ack; + + enableLCD <= lcd_reg(10); + rsLCD <= lcd_reg(9); + rwLCD <= lcd_reg(8); + dataLCD <= lcd_reg(7 downto 0) when lcd_reg(8) = '0' else "ZZZZZZZZ"; + +END ARCHITECTURE; diff --git a/soc/peripheral/can_acf.v b/soc/peripheral/can_acf.v new file mode 100644 index 0000000..bfe069a --- /dev/null +++ b/soc/peripheral/can_acf.v @@ -0,0 +1,345 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_acf.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on +`include "can_defines.v" + +module can_acf +( + clk, + rst, + + id, + + /* Mode register */ + reset_mode, + acceptance_filter_mode, + + extended_mode, + + acceptance_code_0, + acceptance_code_1, + acceptance_code_2, + acceptance_code_3, + acceptance_mask_0, + acceptance_mask_1, + acceptance_mask_2, + acceptance_mask_3, + + go_rx_crc_lim, + go_rx_inter, + go_error_frame, + + data0, + data1, + rtr1, + rtr2, + ide, + no_byte0, + no_byte1, + + + id_ok + + +); + +parameter Tp = 1; + +input clk; +input rst; +input [28:0] id; +input reset_mode; +input acceptance_filter_mode; +input extended_mode; + +input [7:0] acceptance_code_0; +input [7:0] acceptance_code_1; +input [7:0] acceptance_code_2; +input [7:0] acceptance_code_3; +input [7:0] acceptance_mask_0; +input [7:0] acceptance_mask_1; +input [7:0] acceptance_mask_2; +input [7:0] acceptance_mask_3; +input go_rx_crc_lim; +input go_rx_inter; +input go_error_frame; +input [7:0] data0; +input [7:0] data1; +input rtr1; +input rtr2; +input ide; +input no_byte0; +input no_byte1; + + +output id_ok; + +reg id_ok; + +wire match; +wire match_sf_std; +wire match_sf_ext; +wire match_df_std; +wire match_df_ext; + + +// Working in basic mode. ID match for standard format (11-bit ID). +assign match = ( (id[3] == acceptance_code_0[0] | acceptance_mask_0[0] ) & + (id[4] == acceptance_code_0[1] | acceptance_mask_0[1] ) & + (id[5] == acceptance_code_0[2] | acceptance_mask_0[2] ) & + (id[6] == acceptance_code_0[3] | acceptance_mask_0[3] ) & + (id[7] == acceptance_code_0[4] | acceptance_mask_0[4] ) & + (id[8] == acceptance_code_0[5] | acceptance_mask_0[5] ) & + (id[9] == acceptance_code_0[6] | acceptance_mask_0[6] ) & + (id[10] == acceptance_code_0[7] | acceptance_mask_0[7] ) + ); + + +// Working in extended mode. ID match for standard format (11-bit ID). Using single filter. +assign match_sf_std = ( (id[3] == acceptance_code_0[0] | acceptance_mask_0[0] ) & + (id[4] == acceptance_code_0[1] | acceptance_mask_0[1] ) & + (id[5] == acceptance_code_0[2] | acceptance_mask_0[2] ) & + (id[6] == acceptance_code_0[3] | acceptance_mask_0[3] ) & + (id[7] == acceptance_code_0[4] | acceptance_mask_0[4] ) & + (id[8] == acceptance_code_0[5] | acceptance_mask_0[5] ) & + (id[9] == acceptance_code_0[6] | acceptance_mask_0[6] ) & + (id[10] == acceptance_code_0[7] | acceptance_mask_0[7] ) & + + (rtr1 == acceptance_code_1[4] | acceptance_mask_1[4] ) & + (id[0] == acceptance_code_1[5] | acceptance_mask_1[5] ) & + (id[1] == acceptance_code_1[6] | acceptance_mask_1[6] ) & + (id[2] == acceptance_code_1[7] | acceptance_mask_1[7] ) & + + (data0[0] == acceptance_code_2[0] | acceptance_mask_2[0] | no_byte0) & + (data0[1] == acceptance_code_2[1] | acceptance_mask_2[1] | no_byte0) & + (data0[2] == acceptance_code_2[2] | acceptance_mask_2[2] | no_byte0) & + (data0[3] == acceptance_code_2[3] | acceptance_mask_2[3] | no_byte0) & + (data0[4] == acceptance_code_2[4] | acceptance_mask_2[4] | no_byte0) & + (data0[5] == acceptance_code_2[5] | acceptance_mask_2[5] | no_byte0) & + (data0[6] == acceptance_code_2[6] | acceptance_mask_2[6] | no_byte0) & + (data0[7] == acceptance_code_2[7] | acceptance_mask_2[7] | no_byte0) & + + (data1[0] == acceptance_code_3[0] | acceptance_mask_3[0] | no_byte1) & + (data1[1] == acceptance_code_3[1] | acceptance_mask_3[1] | no_byte1) & + (data1[2] == acceptance_code_3[2] | acceptance_mask_3[2] | no_byte1) & + (data1[3] == acceptance_code_3[3] | acceptance_mask_3[3] | no_byte1) & + (data1[4] == acceptance_code_3[4] | acceptance_mask_3[4] | no_byte1) & + (data1[5] == acceptance_code_3[5] | acceptance_mask_3[5] | no_byte1) & + (data1[6] == acceptance_code_3[6] | acceptance_mask_3[6] | no_byte1) & + (data1[7] == acceptance_code_3[7] | acceptance_mask_3[7] | no_byte1) + ); + + + +// Working in extended mode. ID match for extended format (29-bit ID). Using single filter. +assign match_sf_ext = ( (id[21] == acceptance_code_0[0] | acceptance_mask_0[0] ) & + (id[22] == acceptance_code_0[1] | acceptance_mask_0[1] ) & + (id[23] == acceptance_code_0[2] | acceptance_mask_0[2] ) & + (id[24] == acceptance_code_0[3] | acceptance_mask_0[3] ) & + (id[25] == acceptance_code_0[4] | acceptance_mask_0[4] ) & + (id[26] == acceptance_code_0[5] | acceptance_mask_0[5] ) & + (id[27] == acceptance_code_0[6] | acceptance_mask_0[6] ) & + (id[28] == acceptance_code_0[7] | acceptance_mask_0[7] ) & + + (id[13] == acceptance_code_1[0] | acceptance_mask_1[0] ) & + (id[14] == acceptance_code_1[1] | acceptance_mask_1[1] ) & + (id[15] == acceptance_code_1[2] | acceptance_mask_1[2] ) & + (id[16] == acceptance_code_1[3] | acceptance_mask_1[3] ) & + (id[17] == acceptance_code_1[4] | acceptance_mask_1[4] ) & + (id[18] == acceptance_code_1[5] | acceptance_mask_1[5] ) & + (id[19] == acceptance_code_1[6] | acceptance_mask_1[6] ) & + (id[20] == acceptance_code_1[7] | acceptance_mask_1[7] ) & + + (id[5] == acceptance_code_2[0] | acceptance_mask_2[0] ) & + (id[6] == acceptance_code_2[1] | acceptance_mask_2[1] ) & + (id[7] == acceptance_code_2[2] | acceptance_mask_2[2] ) & + (id[8] == acceptance_code_2[3] | acceptance_mask_2[3] ) & + (id[9] == acceptance_code_2[4] | acceptance_mask_2[4] ) & + (id[10] == acceptance_code_2[5] | acceptance_mask_2[5] ) & + (id[11] == acceptance_code_2[6] | acceptance_mask_2[6] ) & + (id[12] == acceptance_code_2[7] | acceptance_mask_2[7] ) & + + (rtr2 == acceptance_code_3[2] | acceptance_mask_3[2] ) & + (id[0] == acceptance_code_3[3] | acceptance_mask_3[3] ) & + (id[1] == acceptance_code_3[4] | acceptance_mask_3[4] ) & + (id[2] == acceptance_code_3[5] | acceptance_mask_3[5] ) & + (id[3] == acceptance_code_3[6] | acceptance_mask_3[6] ) & + (id[4] == acceptance_code_3[7] | acceptance_mask_3[7] ) + + ); + + +// Working in extended mode. ID match for standard format (11-bit ID). Using double filter. +assign match_df_std = (((id[3] == acceptance_code_0[0] | acceptance_mask_0[0] ) & + (id[4] == acceptance_code_0[1] | acceptance_mask_0[1] ) & + (id[5] == acceptance_code_0[2] | acceptance_mask_0[2] ) & + (id[6] == acceptance_code_0[3] | acceptance_mask_0[3] ) & + (id[7] == acceptance_code_0[4] | acceptance_mask_0[4] ) & + (id[8] == acceptance_code_0[5] | acceptance_mask_0[5] ) & + (id[9] == acceptance_code_0[6] | acceptance_mask_0[6] ) & + (id[10] == acceptance_code_0[7] | acceptance_mask_0[7] ) & + + (rtr1 == acceptance_code_1[4] | acceptance_mask_1[4] ) & + (id[0] == acceptance_code_1[5] | acceptance_mask_1[5] ) & + (id[1] == acceptance_code_1[6] | acceptance_mask_1[6] ) & + (id[2] == acceptance_code_1[7] | acceptance_mask_1[7] ) & + + (data0[0] == acceptance_code_3[0] | acceptance_mask_3[0] | no_byte0) & + (data0[1] == acceptance_code_3[1] | acceptance_mask_3[1] | no_byte0) & + (data0[2] == acceptance_code_3[2] | acceptance_mask_3[2] | no_byte0) & + (data0[3] == acceptance_code_3[3] | acceptance_mask_3[3] | no_byte0) & + (data0[4] == acceptance_code_1[0] | acceptance_mask_1[0] | no_byte0) & + (data0[5] == acceptance_code_1[1] | acceptance_mask_1[1] | no_byte0) & + (data0[6] == acceptance_code_1[2] | acceptance_mask_1[2] | no_byte0) & + (data0[7] == acceptance_code_1[3] | acceptance_mask_1[3] | no_byte0) ) + + | + + ((id[3] == acceptance_code_2[0] | acceptance_mask_2[0] ) & + (id[4] == acceptance_code_2[1] | acceptance_mask_2[1] ) & + (id[5] == acceptance_code_2[2] | acceptance_mask_2[2] ) & + (id[6] == acceptance_code_2[3] | acceptance_mask_2[3] ) & + (id[7] == acceptance_code_2[4] | acceptance_mask_2[4] ) & + (id[8] == acceptance_code_2[5] | acceptance_mask_2[5] ) & + (id[9] == acceptance_code_2[6] | acceptance_mask_2[6] ) & + (id[10] == acceptance_code_2[7] | acceptance_mask_2[7] ) & + + (rtr1 == acceptance_code_3[4] | acceptance_mask_3[4] ) & + (id[0] == acceptance_code_3[5] | acceptance_mask_3[5] ) & + (id[1] == acceptance_code_3[6] | acceptance_mask_3[6] ) & + (id[2] == acceptance_code_3[7] | acceptance_mask_3[7] ) ) + + ); + + +// Working in extended mode. ID match for extended format (29-bit ID). Using double filter. +assign match_df_ext = (((id[21] == acceptance_code_0[0] | acceptance_mask_0[0] ) & + (id[22] == acceptance_code_0[1] | acceptance_mask_0[1] ) & + (id[23] == acceptance_code_0[2] | acceptance_mask_0[2] ) & + (id[24] == acceptance_code_0[3] | acceptance_mask_0[3] ) & + (id[25] == acceptance_code_0[4] | acceptance_mask_0[4] ) & + (id[26] == acceptance_code_0[5] | acceptance_mask_0[5] ) & + (id[27] == acceptance_code_0[6] | acceptance_mask_0[6] ) & + (id[28] == acceptance_code_0[7] | acceptance_mask_0[7] ) & + + (id[13] == acceptance_code_1[0] | acceptance_mask_1[0] ) & + (id[14] == acceptance_code_1[1] | acceptance_mask_1[1] ) & + (id[15] == acceptance_code_1[2] | acceptance_mask_1[2] ) & + (id[16] == acceptance_code_1[3] | acceptance_mask_1[3] ) & + (id[17] == acceptance_code_1[4] | acceptance_mask_1[4] ) & + (id[18] == acceptance_code_1[5] | acceptance_mask_1[5] ) & + (id[19] == acceptance_code_1[6] | acceptance_mask_1[6] ) & + (id[20] == acceptance_code_1[7] | acceptance_mask_1[7] ) ) + + | + + ((id[21] == acceptance_code_2[0] | acceptance_mask_2[0] ) & + (id[22] == acceptance_code_2[1] | acceptance_mask_2[1] ) & + (id[23] == acceptance_code_2[2] | acceptance_mask_2[2] ) & + (id[24] == acceptance_code_2[3] | acceptance_mask_2[3] ) & + (id[25] == acceptance_code_2[4] | acceptance_mask_2[4] ) & + (id[26] == acceptance_code_2[5] | acceptance_mask_2[5] ) & + (id[27] == acceptance_code_2[6] | acceptance_mask_2[6] ) & + (id[28] == acceptance_code_2[7] | acceptance_mask_2[7] ) & + + (id[13] == acceptance_code_3[0] | acceptance_mask_3[0] ) & + (id[14] == acceptance_code_3[1] | acceptance_mask_3[1] ) & + (id[15] == acceptance_code_3[2] | acceptance_mask_3[2] ) & + (id[16] == acceptance_code_3[3] | acceptance_mask_3[3] ) & + (id[17] == acceptance_code_3[4] | acceptance_mask_3[4] ) & + (id[18] == acceptance_code_3[5] | acceptance_mask_3[5] ) & + (id[19] == acceptance_code_3[6] | acceptance_mask_3[6] ) & + (id[20] == acceptance_code_3[7] | acceptance_mask_3[7] ) ) + ); + + + +// ID ok signal generation +always @ (posedge clk or posedge rst) +begin + if (rst) + id_ok <= 1'b0; + else if (go_rx_crc_lim) // sample_point is already included in go_rx_crc_lim + begin + if (extended_mode) + begin + if (~acceptance_filter_mode) // dual filter + begin + if (ide) // extended frame message + id_ok <=#Tp match_df_ext; + else // standard frame message + id_ok <=#Tp match_df_std; + end + else // single filter + begin + if (ide) // extended frame message + id_ok <=#Tp match_sf_ext; + else // standard frame message + id_ok <=#Tp match_sf_std; + end + end + else + id_ok <=#Tp match; + end + else if (reset_mode | go_rx_inter | go_error_frame) // sample_point is already included in go_rx_inter + id_ok <=#Tp 1'b0; +end + + + + + + + + + +endmodule diff --git a/soc/peripheral/can_bsp.v b/soc/peripheral/can_bsp.v new file mode 100644 index 0000000..50127fd --- /dev/null +++ b/soc/peripheral/can_bsp.v @@ -0,0 +1,1961 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_bsp.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on +`include "can_defines.v" + +module can_bsp +( + clk, + rst, + + sample_point, + sampled_bit, + sampled_bit_q, + tx_point, + hard_sync, + + addr, + data_in, + data_out, + fifo_selected, + + + + /* Mode register */ + reset_mode, + listen_only_mode, + acceptance_filter_mode, + self_test_mode, + + /* Command register */ + release_buffer, + tx_request, + abort_tx, + self_rx_request, + single_shot_transmission, + tx_state, + tx_state_q, + overload_request, + overload_frame, + + /* Arbitration Lost Capture Register */ + read_arbitration_lost_capture_reg, + + /* Error Code Capture Register */ + read_error_code_capture_reg, + error_capture_code, + + /* Error Warning Limit register */ + error_warning_limit, + + /* Rx Error Counter register */ + we_rx_err_cnt, + + /* Tx Error Counter register */ + we_tx_err_cnt, + + /* Clock Divider register */ + extended_mode, + + rx_idle, + transmitting, + transmitter, + go_rx_inter, + not_first_bit_of_inter, + rx_inter, + set_reset_mode, + node_bus_off, + error_status, + rx_err_cnt, + tx_err_cnt, + transmit_status, + receive_status, + tx_successful, + need_to_tx, + overrun, + info_empty, + set_bus_error_irq, + set_arbitration_lost_irq, + arbitration_lost_capture, + node_error_passive, + node_error_active, + rx_message_counter, + + /* This section is for BASIC and EXTENDED mode */ + /* Acceptance code register */ + acceptance_code_0, + + /* Acceptance mask register */ + acceptance_mask_0, + /* End: This section is for BASIC and EXTENDED mode */ + + /* This section is for EXTENDED mode */ + /* Acceptance code register */ + acceptance_code_1, + acceptance_code_2, + acceptance_code_3, + + /* Acceptance mask register */ + acceptance_mask_1, + acceptance_mask_2, + acceptance_mask_3, + /* End: This section is for EXTENDED mode */ + + /* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ + tx_data_0, + tx_data_1, + tx_data_2, + tx_data_3, + tx_data_4, + tx_data_5, + tx_data_6, + tx_data_7, + tx_data_8, + tx_data_9, + tx_data_10, + tx_data_11, + tx_data_12, + /* End: Tx data registers */ + + /* Tx signal */ + tx, + tx_next, + bus_off_on, + + go_overload_frame, + go_error_frame, + go_tx, + send_ack + + /* Bist */ +`ifdef CAN_BIST + , + mbist_si_i, + mbist_so_o, + mbist_ctrl_i +`endif +); + +parameter Tp = 1; + +input clk; +input rst; +input sample_point; +input sampled_bit; +input sampled_bit_q; +input tx_point; +input hard_sync; +input [7:0] addr; +input [7:0] data_in; +output [7:0] data_out; +input fifo_selected; + +input reset_mode; +input listen_only_mode; +input acceptance_filter_mode; +input extended_mode; +input self_test_mode; + +/* Command register */ +input release_buffer; +input tx_request; +input abort_tx; +input self_rx_request; +input single_shot_transmission; +output tx_state; +output tx_state_q; +input overload_request; // When receiver is busy, it needs to send overload frame. Only 2 overload frames are allowed to +output overload_frame; // be send in a row. This is not implemented, yet, because host can not send an overload request. + +/* Arbitration Lost Capture Register */ +input read_arbitration_lost_capture_reg; + +/* Error Code Capture Register */ +input read_error_code_capture_reg; +output [7:0] error_capture_code; + +/* Error Warning Limit register */ +input [7:0] error_warning_limit; + +/* Rx Error Counter register */ +input we_rx_err_cnt; + +/* Tx Error Counter register */ +input we_tx_err_cnt; + +output rx_idle; +output transmitting; +output transmitter; +output go_rx_inter; +output not_first_bit_of_inter; +output rx_inter; +output set_reset_mode; +output node_bus_off; +output error_status; +output [8:0] rx_err_cnt; +output [8:0] tx_err_cnt; +output transmit_status; +output receive_status; +output tx_successful; +output need_to_tx; +output overrun; +output info_empty; +output set_bus_error_irq; +output set_arbitration_lost_irq; +output [4:0] arbitration_lost_capture; +output node_error_passive; +output node_error_active; +output [6:0] rx_message_counter; + + +/* This section is for BASIC and EXTENDED mode */ +/* Acceptance code register */ +input [7:0] acceptance_code_0; + +/* Acceptance mask register */ +input [7:0] acceptance_mask_0; + +/* End: This section is for BASIC and EXTENDED mode */ + + +/* This section is for EXTENDED mode */ +/* Acceptance code register */ +input [7:0] acceptance_code_1; +input [7:0] acceptance_code_2; +input [7:0] acceptance_code_3; + +/* Acceptance mask register */ +input [7:0] acceptance_mask_1; +input [7:0] acceptance_mask_2; +input [7:0] acceptance_mask_3; +/* End: This section is for EXTENDED mode */ + +/* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ +input [7:0] tx_data_0; +input [7:0] tx_data_1; +input [7:0] tx_data_2; +input [7:0] tx_data_3; +input [7:0] tx_data_4; +input [7:0] tx_data_5; +input [7:0] tx_data_6; +input [7:0] tx_data_7; +input [7:0] tx_data_8; +input [7:0] tx_data_9; +input [7:0] tx_data_10; +input [7:0] tx_data_11; +input [7:0] tx_data_12; +/* End: Tx data registers */ + +/* Tx signal */ +output tx; +output tx_next; +output bus_off_on; + +output go_overload_frame; +output go_error_frame; +output go_tx; +output send_ack; + +/* Bist */ +`ifdef CAN_BIST +input mbist_si_i; +output mbist_so_o; +input [`CAN_MBIST_CTRL_WIDTH - 1:0] mbist_ctrl_i; // bist chain shift control +`endif + +reg reset_mode_q; +reg [5:0] bit_cnt; + +reg [3:0] data_len; +reg [28:0] id; +reg [2:0] bit_stuff_cnt; +reg [2:0] bit_stuff_cnt_tx; +reg tx_point_q; + +reg rx_idle; +reg rx_id1; +reg rx_rtr1; +reg rx_ide; +reg rx_id2; +reg rx_rtr2; +reg rx_r1; +reg rx_r0; +reg rx_dlc; +reg rx_data; +reg rx_crc; +reg rx_crc_lim; +reg rx_ack; +reg rx_ack_lim; +reg rx_eof; +reg rx_inter; +reg go_early_tx_latched; + +reg rtr1; +reg ide; +reg rtr2; +reg [14:0] crc_in; + +reg [7:0] tmp_data; +reg [7:0] tmp_fifo [0:7]; +reg write_data_to_tmp_fifo; +reg [2:0] byte_cnt; +reg bit_stuff_cnt_en; +reg crc_enable; + +reg [2:0] eof_cnt; +reg [2:0] passive_cnt; + +reg transmitting; + +reg error_frame; +reg enable_error_cnt2; +reg [2:0] error_cnt1; +reg [2:0] error_cnt2; +reg [2:0] delayed_dominant_cnt; +reg enable_overload_cnt2; +reg overload_frame; +reg overload_frame_blocked; +reg [1:0] overload_request_cnt; +reg [2:0] overload_cnt1; +reg [2:0] overload_cnt2; +reg tx; +reg crc_err; + +reg arbitration_lost; +reg arbitration_lost_q; +reg arbitration_field_d; +reg [4:0] arbitration_lost_capture; +reg [4:0] arbitration_cnt; +reg arbitration_blocked; +reg tx_q; + +reg need_to_tx; // When the CAN core has something to transmit and a dominant bit is sampled at the third bit +reg [3:0] data_cnt; // Counting the data bytes that are written to FIFO +reg [2:0] header_cnt; // Counting header length +reg wr_fifo; // Write data and header to 64-byte fifo +reg [7:0] data_for_fifo;// Multiplexed data that is stored to 64-byte fifo + +reg [5:0] tx_pointer; +reg tx_bit; +reg tx_state; +reg tx_state_q; +reg transmitter; +reg finish_msg; + +reg [8:0] rx_err_cnt; +reg [8:0] tx_err_cnt; +reg [3:0] bus_free_cnt; +reg bus_free_cnt_en; +reg bus_free; +reg waiting_for_bus_free; + +reg node_error_passive; +reg node_bus_off; +reg node_bus_off_q; +reg ack_err_latched; +reg bit_err_latched; +reg stuff_err_latched; +reg form_err_latched; +reg rule3_exc1_1; +reg rule3_exc1_2; +reg suspend; +reg susp_cnt_en; +reg [2:0] susp_cnt; +reg error_flag_over_latched; + +reg [7:0] error_capture_code; +reg [7:6] error_capture_code_type; +reg error_capture_code_blocked; +reg tx_next; +reg first_compare_bit; + + +wire [4:0] error_capture_code_segment; +wire error_capture_code_direction; + +wire bit_de_stuff; +wire bit_de_stuff_tx; + +wire rule5; + +/* Rx state machine */ +wire go_rx_idle; +wire go_rx_id1; +wire go_rx_rtr1; +wire go_rx_ide; +wire go_rx_id2; +wire go_rx_rtr2; +wire go_rx_r1; +wire go_rx_r0; +wire go_rx_dlc; +wire go_rx_data; +wire go_rx_crc; +wire go_rx_crc_lim; +wire go_rx_ack; +wire go_rx_ack_lim; +wire go_rx_eof; +wire go_rx_inter; + +wire last_bit_of_inter; + +wire go_crc_enable; +wire rst_crc_enable; + +wire bit_de_stuff_set; +wire bit_de_stuff_reset; + +wire go_early_tx; + +wire [14:0] calculated_crc; +wire [15:0] r_calculated_crc; +wire remote_rq; +wire [3:0] limited_data_len; +wire form_err; + +wire error_frame_ended; +wire overload_frame_ended; +wire bit_err; +wire ack_err; +wire stuff_err; + +wire id_ok; // If received ID matches ID set in registers +wire no_byte0; // There is no byte 0 (RTR bit set to 1 or DLC field equal to 0). Signal used for acceptance filter. +wire no_byte1; // There is no byte 1 (RTR bit set to 1 or DLC field equal to 1). Signal used for acceptance filter. + +wire [2:0] header_len; +wire storing_header; +wire [3:0] limited_data_len_minus1; +wire reset_wr_fifo; +wire err; + +wire arbitration_field; + +wire [18:0] basic_chain; +wire [63:0] basic_chain_data; +wire [18:0] extended_chain_std; +wire [38:0] extended_chain_ext; +wire [63:0] extended_chain_data_std; +wire [63:0] extended_chain_data_ext; + +wire rst_tx_pointer; + +wire [7:0] r_tx_data_0; +wire [7:0] r_tx_data_1; +wire [7:0] r_tx_data_2; +wire [7:0] r_tx_data_3; +wire [7:0] r_tx_data_4; +wire [7:0] r_tx_data_5; +wire [7:0] r_tx_data_6; +wire [7:0] r_tx_data_7; +wire [7:0] r_tx_data_8; +wire [7:0] r_tx_data_9; +wire [7:0] r_tx_data_10; +wire [7:0] r_tx_data_11; +wire [7:0] r_tx_data_12; + +wire send_ack; +wire bit_err_exc1; +wire bit_err_exc2; +wire bit_err_exc3; +wire bit_err_exc4; +wire bit_err_exc5; +wire bit_err_exc6; +wire error_flag_over; +wire overload_flag_over; + +wire [5:0] limited_tx_cnt_ext; +wire [5:0] limited_tx_cnt_std; + +assign go_rx_idle = sample_point & sampled_bit & last_bit_of_inter | bus_free & (~node_bus_off); +assign go_rx_id1 = sample_point & (~sampled_bit) & (rx_idle | last_bit_of_inter); +assign go_rx_rtr1 = (~bit_de_stuff) & sample_point & rx_id1 & (bit_cnt[3:0] == 4'd10); +assign go_rx_ide = (~bit_de_stuff) & sample_point & rx_rtr1; +assign go_rx_id2 = (~bit_de_stuff) & sample_point & rx_ide & sampled_bit; +assign go_rx_rtr2 = (~bit_de_stuff) & sample_point & rx_id2 & (bit_cnt[4:0] == 5'd17); +assign go_rx_r1 = (~bit_de_stuff) & sample_point & rx_rtr2; +assign go_rx_r0 = (~bit_de_stuff) & sample_point & (rx_ide & (~sampled_bit) | rx_r1); +assign go_rx_dlc = (~bit_de_stuff) & sample_point & rx_r0; +assign go_rx_data = (~bit_de_stuff) & sample_point & rx_dlc & (bit_cnt[1:0] == 2'd3) & (sampled_bit | (|data_len[2:0])) & (~remote_rq); +assign go_rx_crc = (~bit_de_stuff) & sample_point & (rx_dlc & (bit_cnt[1:0] == 2'd3) & ((~sampled_bit) & (~(|data_len[2:0])) | remote_rq) | + rx_data & (bit_cnt[5:0] == ((limited_data_len<<3) - 1'b1))); // overflow works ok at max value (8<<3 = 64 = 0). 0-1 = 6'h3f +assign go_rx_crc_lim = (~bit_de_stuff) & sample_point & rx_crc & (bit_cnt[3:0] == 4'd14); +assign go_rx_ack = (~bit_de_stuff) & sample_point & rx_crc_lim; +assign go_rx_ack_lim = sample_point & rx_ack; +assign go_rx_eof = sample_point & rx_ack_lim; +assign go_rx_inter = ((sample_point & rx_eof & (eof_cnt == 3'd6)) | error_frame_ended | overload_frame_ended) & (~overload_request); + +assign go_error_frame = (form_err | stuff_err | bit_err | ack_err | (crc_err & go_rx_eof)); +assign error_frame_ended = (error_cnt2 == 3'd7) & tx_point; +assign overload_frame_ended = (overload_cnt2 == 3'd7) & tx_point; + +assign go_overload_frame = ( sample_point & ((~sampled_bit) | overload_request) & (rx_eof & (~transmitter) & (eof_cnt == 3'd6) | error_frame_ended | overload_frame_ended) | + sample_point & (~sampled_bit) & rx_inter & (bit_cnt[1:0] < 2'd2) | + sample_point & (~sampled_bit) & ((error_cnt2 == 3'd7) | (overload_cnt2 == 3'd7)) + ) + & (~overload_frame_blocked) + ; + + +assign go_crc_enable = hard_sync | go_tx; +assign rst_crc_enable = go_rx_crc; + +assign bit_de_stuff_set = go_rx_id1 & (~go_error_frame); +assign bit_de_stuff_reset = go_rx_ack | go_error_frame | go_overload_frame; + +assign remote_rq = ((~ide) & rtr1) | (ide & rtr2); +assign limited_data_len = (data_len < 4'h8)? data_len : 4'h8; + +assign ack_err = rx_ack & sample_point & sampled_bit & tx_state & (~self_test_mode); +assign bit_err = (tx_state | error_frame | overload_frame | rx_ack) & sample_point & (tx != sampled_bit) & (~bit_err_exc1) & (~bit_err_exc2) & (~bit_err_exc3) & (~bit_err_exc4) & (~bit_err_exc5) & (~bit_err_exc6) & (~reset_mode); +assign bit_err_exc1 = tx_state & arbitration_field & tx; +assign bit_err_exc2 = rx_ack & tx; +assign bit_err_exc3 = error_frame & node_error_passive & (error_cnt1 < 3'd7); +assign bit_err_exc4 = (error_frame & (error_cnt1 == 3'd7) & (~enable_error_cnt2)) | (overload_frame & (overload_cnt1 == 3'd7) & (~enable_overload_cnt2)); +assign bit_err_exc5 = (error_frame & (error_cnt2 == 3'd7)) | (overload_frame & (overload_cnt2 == 3'd7)); +assign bit_err_exc6 = (eof_cnt == 3'd6) & rx_eof & (~transmitter); + +assign arbitration_field = rx_id1 | rx_rtr1 | rx_ide | rx_id2 | rx_rtr2; + +assign last_bit_of_inter = rx_inter & (bit_cnt[1:0] == 2'd2); +assign not_first_bit_of_inter = rx_inter & (bit_cnt[1:0] != 2'd0); + + +// Rx idle state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_idle <= 1'b0; + else if (go_rx_id1 | go_error_frame) + rx_idle <=#Tp 1'b0; + else if (go_rx_idle) + rx_idle <=#Tp 1'b1; +end + + +// Rx id1 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_id1 <= 1'b0; + else if (go_rx_rtr1 | go_error_frame) + rx_id1 <=#Tp 1'b0; + else if (go_rx_id1) + rx_id1 <=#Tp 1'b1; +end + + +// Rx rtr1 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_rtr1 <= 1'b0; + else if (go_rx_ide | go_error_frame) + rx_rtr1 <=#Tp 1'b0; + else if (go_rx_rtr1) + rx_rtr1 <=#Tp 1'b1; +end + + +// Rx ide state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_ide <= 1'b0; + else if (go_rx_r0 | go_rx_id2 | go_error_frame) + rx_ide <=#Tp 1'b0; + else if (go_rx_ide) + rx_ide <=#Tp 1'b1; +end + + +// Rx id2 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_id2 <= 1'b0; + else if (go_rx_rtr2 | go_error_frame) + rx_id2 <=#Tp 1'b0; + else if (go_rx_id2) + rx_id2 <=#Tp 1'b1; +end + + +// Rx rtr2 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_rtr2 <= 1'b0; + else if (go_rx_r1 | go_error_frame) + rx_rtr2 <=#Tp 1'b0; + else if (go_rx_rtr2) + rx_rtr2 <=#Tp 1'b1; +end + + +// Rx r0 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_r1 <= 1'b0; + else if (go_rx_r0 | go_error_frame) + rx_r1 <=#Tp 1'b0; + else if (go_rx_r1) + rx_r1 <=#Tp 1'b1; +end + + +// Rx r0 state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_r0 <= 1'b0; + else if (go_rx_dlc | go_error_frame) + rx_r0 <=#Tp 1'b0; + else if (go_rx_r0) + rx_r0 <=#Tp 1'b1; +end + + +// Rx dlc state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_dlc <= 1'b0; + else if (go_rx_data | go_rx_crc | go_error_frame) + rx_dlc <=#Tp 1'b0; + else if (go_rx_dlc) + rx_dlc <=#Tp 1'b1; +end + + +// Rx data state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_data <= 1'b0; + else if (go_rx_crc | go_error_frame) + rx_data <=#Tp 1'b0; + else if (go_rx_data) + rx_data <=#Tp 1'b1; +end + + +// Rx crc state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_crc <= 1'b0; + else if (go_rx_crc_lim | go_error_frame) + rx_crc <=#Tp 1'b0; + else if (go_rx_crc) + rx_crc <=#Tp 1'b1; +end + + +// Rx crc delimiter state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_crc_lim <= 1'b0; + else if (go_rx_ack | go_error_frame) + rx_crc_lim <=#Tp 1'b0; + else if (go_rx_crc_lim) + rx_crc_lim <=#Tp 1'b1; +end + + +// Rx ack state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_ack <= 1'b0; + else if (go_rx_ack_lim | go_error_frame) + rx_ack <=#Tp 1'b0; + else if (go_rx_ack) + rx_ack <=#Tp 1'b1; +end + + +// Rx ack delimiter state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_ack_lim <= 1'b0; + else if (go_rx_eof | go_error_frame) + rx_ack_lim <=#Tp 1'b0; + else if (go_rx_ack_lim) + rx_ack_lim <=#Tp 1'b1; +end + + +// Rx eof state +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_eof <= 1'b0; + else if (go_rx_inter | go_error_frame | go_overload_frame) + rx_eof <=#Tp 1'b0; + else if (go_rx_eof) + rx_eof <=#Tp 1'b1; +end + + + +// Interframe space +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_inter <= 1'b0; + else if (go_rx_idle | go_rx_id1 | go_overload_frame | go_error_frame) + rx_inter <=#Tp 1'b0; + else if (go_rx_inter) + rx_inter <=#Tp 1'b1; +end + + +// ID register +always @ (posedge clk or posedge rst) +begin + if (rst) + id <= 29'h0; + else if (sample_point & (rx_id1 | rx_id2) & (~bit_de_stuff)) + id <=#Tp {id[27:0], sampled_bit}; +end + + +// rtr1 bit +always @ (posedge clk or posedge rst) +begin + if (rst) + rtr1 <= 1'b0; + else if (sample_point & rx_rtr1 & (~bit_de_stuff)) + rtr1 <=#Tp sampled_bit; +end + + +// rtr2 bit +always @ (posedge clk or posedge rst) +begin + if (rst) + rtr2 <= 1'b0; + else if (sample_point & rx_rtr2 & (~bit_de_stuff)) + rtr2 <=#Tp sampled_bit; +end + + +// ide bit +always @ (posedge clk or posedge rst) +begin + if (rst) + ide <= 1'b0; + else if (sample_point & rx_ide & (~bit_de_stuff)) + ide <=#Tp sampled_bit; +end + + +// Data length +always @ (posedge clk or posedge rst) +begin + if (rst) + data_len <= 4'b0; + else if (sample_point & rx_dlc & (~bit_de_stuff)) + data_len <=#Tp {data_len[2:0], sampled_bit}; +end + + +// Data +always @ (posedge clk or posedge rst) +begin + if (rst) + tmp_data <= 8'h0; + else if (sample_point & rx_data & (~bit_de_stuff)) + tmp_data <=#Tp {tmp_data[6:0], sampled_bit}; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + write_data_to_tmp_fifo <= 1'b0; + else if (sample_point & rx_data & (~bit_de_stuff) & (&bit_cnt[2:0])) + write_data_to_tmp_fifo <=#Tp 1'b1; + else + write_data_to_tmp_fifo <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + byte_cnt <= 3'h0; + else if (write_data_to_tmp_fifo) + byte_cnt <=#Tp byte_cnt + 1'b1; + else if (sample_point & go_rx_crc_lim) + byte_cnt <=#Tp 3'h0; +end + + +always @ (posedge clk) +begin + if (write_data_to_tmp_fifo) + tmp_fifo[byte_cnt] <=#Tp tmp_data; +end + + + +// CRC +always @ (posedge clk or posedge rst) +begin + if (rst) + crc_in <= 15'h0; + else if (sample_point & rx_crc & (~bit_de_stuff)) + crc_in <=#Tp {crc_in[13:0], sampled_bit}; +end + + +// bit_cnt +always @ (posedge clk or posedge rst) +begin + if (rst) + bit_cnt <= 6'd0; + else if (go_rx_id1 | go_rx_id2 | go_rx_dlc | go_rx_data | go_rx_crc | + go_rx_ack | go_rx_eof | go_rx_inter | go_error_frame | go_overload_frame) + bit_cnt <=#Tp 6'd0; + else if (sample_point & (~bit_de_stuff)) + bit_cnt <=#Tp bit_cnt + 1'b1; +end + + +// eof_cnt +always @ (posedge clk or posedge rst) +begin + if (rst) + eof_cnt <= 3'd0; + else if (sample_point) + begin + if (go_rx_inter | go_error_frame | go_overload_frame) + eof_cnt <=#Tp 3'd0; + else if (rx_eof) + eof_cnt <=#Tp eof_cnt + 1'b1; + end +end + + +// Enabling bit de-stuffing +always @ (posedge clk or posedge rst) +begin + if (rst) + bit_stuff_cnt_en <= 1'b0; + else if (bit_de_stuff_set) + bit_stuff_cnt_en <=#Tp 1'b1; + else if (bit_de_stuff_reset) + bit_stuff_cnt_en <=#Tp 1'b0; +end + + +// bit_stuff_cnt +always @ (posedge clk or posedge rst) +begin + if (rst) + bit_stuff_cnt <= 3'h1; + else if (bit_de_stuff_reset) + bit_stuff_cnt <=#Tp 3'h1; + else if (sample_point & bit_stuff_cnt_en) + begin + if (bit_stuff_cnt == 3'h5) + bit_stuff_cnt <=#Tp 3'h1; + else if (sampled_bit == sampled_bit_q) + bit_stuff_cnt <=#Tp bit_stuff_cnt + 1'b1; + else + bit_stuff_cnt <=#Tp 3'h1; + end +end + + +// bit_stuff_cnt_tx +always @ (posedge clk or posedge rst) +begin + if (rst) + bit_stuff_cnt_tx <= 3'h1; + else if (reset_mode || bit_de_stuff_reset) + bit_stuff_cnt_tx <=#Tp 3'h1; + else if (tx_point_q & bit_stuff_cnt_en) + begin + if (bit_stuff_cnt_tx == 3'h5) + bit_stuff_cnt_tx <=#Tp 3'h1; + else if (tx == tx_q) + bit_stuff_cnt_tx <=#Tp bit_stuff_cnt_tx + 1'b1; + else + bit_stuff_cnt_tx <=#Tp 3'h1; + end +end + + +assign bit_de_stuff = bit_stuff_cnt == 3'h5; +assign bit_de_stuff_tx = bit_stuff_cnt_tx == 3'h5; + + + +// stuff_err +assign stuff_err = sample_point & bit_stuff_cnt_en & bit_de_stuff & (sampled_bit == sampled_bit_q); + + + +// Generating delayed signals +always @ (posedge clk or posedge rst) +begin + if (rst) + begin + reset_mode_q <=#Tp 1'b0; + node_bus_off_q <=#Tp 1'b0; + end + else + begin + reset_mode_q <=#Tp reset_mode; + node_bus_off_q <=#Tp node_bus_off; + end +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + crc_enable <= 1'b0; + else if (rst_crc_enable) + crc_enable <=#Tp 1'b0; + else if (go_crc_enable) + crc_enable <=#Tp 1'b1; +end + + +// CRC error generation +always @ (posedge clk or posedge rst) +begin + if (rst) + crc_err <= 1'b0; + else if (reset_mode | error_frame_ended) + crc_err <=#Tp 1'b0; + else if (go_rx_ack) + crc_err <=#Tp crc_in != calculated_crc; +end + + +// Conditions for form error +assign form_err = sample_point & ( ((~bit_de_stuff) & rx_crc_lim & (~sampled_bit) ) | + ( rx_ack_lim & (~sampled_bit) ) | + ((eof_cnt < 3'd6)& rx_eof & (~sampled_bit) & (~transmitter) ) | + ( & rx_eof & (~sampled_bit) & transmitter ) + ); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + ack_err_latched <= 1'b0; + else if (reset_mode | error_frame_ended | go_overload_frame) + ack_err_latched <=#Tp 1'b0; + else if (ack_err) + ack_err_latched <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + bit_err_latched <= 1'b0; + else if (reset_mode | error_frame_ended | go_overload_frame) + bit_err_latched <=#Tp 1'b0; + else if (bit_err) + bit_err_latched <=#Tp 1'b1; +end + + + +// Rule 5 (Fault confinement). +assign rule5 = bit_err & ( (~node_error_passive) & error_frame & (error_cnt1 < 3'd7) + | + overload_frame & (overload_cnt1 < 3'd7) + ); + +// Rule 3 exception 1 - first part (Fault confinement). +always @ (posedge clk or posedge rst) +begin + if (rst) + rule3_exc1_1 <= 1'b0; + else if (error_flag_over | rule3_exc1_2) + rule3_exc1_1 <=#Tp 1'b0; + else if (transmitter & node_error_passive & ack_err) + rule3_exc1_1 <=#Tp 1'b1; +end + + +// Rule 3 exception 1 - second part (Fault confinement). +always @ (posedge clk or posedge rst) +begin + if (rst) + rule3_exc1_2 <= 1'b0; + else if (go_error_frame | rule3_exc1_2) + rule3_exc1_2 <=#Tp 1'b0; + else if (rule3_exc1_1 & (error_cnt1 < 3'd7) & sample_point & (~sampled_bit)) + rule3_exc1_2 <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + stuff_err_latched <= 1'b0; + else if (reset_mode | error_frame_ended | go_overload_frame) + stuff_err_latched <=#Tp 1'b0; + else if (stuff_err) + stuff_err_latched <=#Tp 1'b1; +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + form_err_latched <= 1'b0; + else if (reset_mode | error_frame_ended | go_overload_frame) + form_err_latched <=#Tp 1'b0; + else if (form_err) + form_err_latched <=#Tp 1'b1; +end + + + +// Instantiation of the RX CRC module +can_crc i_can_crc_rx +( + .clk(clk), + .data(sampled_bit), + .enable(crc_enable & sample_point & (~bit_de_stuff)), + .initialize(go_crc_enable), + .crc(calculated_crc) +); + + + + +assign no_byte0 = rtr1 | (data_len<4'h1); +assign no_byte1 = rtr1 | (data_len<4'h2); + +can_acf i_can_acf +( + .clk(clk), + .rst(rst), + + .id(id), + + /* Mode register */ + .reset_mode(reset_mode), + .acceptance_filter_mode(acceptance_filter_mode), + + // Clock Divider register + .extended_mode(extended_mode), + + /* This section is for BASIC and EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_0(acceptance_code_0), + + /* Acceptance mask register */ + .acceptance_mask_0(acceptance_mask_0), + /* End: This section is for BASIC and EXTENDED mode */ + + /* This section is for EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_1(acceptance_code_1), + .acceptance_code_2(acceptance_code_2), + .acceptance_code_3(acceptance_code_3), + + /* Acceptance mask register */ + .acceptance_mask_1(acceptance_mask_1), + .acceptance_mask_2(acceptance_mask_2), + .acceptance_mask_3(acceptance_mask_3), + /* End: This section is for EXTENDED mode */ + + .go_rx_crc_lim(go_rx_crc_lim), + .go_rx_inter(go_rx_inter), + .go_error_frame(go_error_frame), + + .data0(tmp_fifo[0]), + .data1(tmp_fifo[1]), + .rtr1(rtr1), + .rtr2(rtr2), + .ide(ide), + .no_byte0(no_byte0), + .no_byte1(no_byte1), + + .id_ok(id_ok) + +); + + + + +assign header_len[2:0] = extended_mode ? (ide? (3'h5) : (3'h3)) : 3'h2; +assign storing_header = header_cnt < header_len; +assign limited_data_len_minus1[3:0] = remote_rq? 4'hf : ((data_len < 4'h8)? (data_len -1'b1) : 4'h7); // - 1 because counter counts from 0 +assign reset_wr_fifo = (data_cnt == (limited_data_len_minus1 + {1'b0, header_len})) || reset_mode; + +assign err = form_err | stuff_err | bit_err | ack_err | form_err_latched | stuff_err_latched | bit_err_latched | ack_err_latched | crc_err; + + + +// Write enable signal for 64-byte rx fifo +always @ (posedge clk or posedge rst) +begin + if (rst) + wr_fifo <= 1'b0; + else if (reset_wr_fifo) + wr_fifo <=#Tp 1'b0; + else if (go_rx_inter & id_ok & (~error_frame_ended) & ((~tx_state) | self_rx_request)) + wr_fifo <=#Tp 1'b1; +end + + +// Header counter. Header length depends on the mode of operation and frame format. +always @ (posedge clk or posedge rst) +begin + if (rst) + header_cnt <= 3'h0; + else if (reset_wr_fifo) + header_cnt <=#Tp 3'h0; + else if (wr_fifo & storing_header) + header_cnt <=#Tp header_cnt + 1'h1; +end + + +// Data counter. Length of the data is limited to 8 bytes. +always @ (posedge clk or posedge rst) +begin + if (rst) + data_cnt <= 4'h0; + else if (reset_wr_fifo) + data_cnt <=#Tp 4'h0; + else if (wr_fifo) + data_cnt <=#Tp data_cnt + 4'h1; +end + + +// Multiplexing data that is stored to 64-byte fifo depends on the mode of operation and frame format +always @ (extended_mode or ide or data_cnt or header_cnt or header_len or + storing_header or id or rtr1 or rtr2 or data_len or + tmp_fifo[0] or tmp_fifo[2] or tmp_fifo[4] or tmp_fifo[6] or + tmp_fifo[1] or tmp_fifo[3] or tmp_fifo[5] or tmp_fifo[7]) +begin + casex ({storing_header, extended_mode, ide, header_cnt}) /* synthesis parallel_case */ + 6'b1_1_1_000 : data_for_fifo = {1'b1, rtr2, 2'h0, data_len}; // extended mode, extended format header + 6'b1_1_1_001 : data_for_fifo = id[28:21]; // extended mode, extended format header + 6'b1_1_1_010 : data_for_fifo = id[20:13]; // extended mode, extended format header + 6'b1_1_1_011 : data_for_fifo = id[12:5]; // extended mode, extended format header + 6'b1_1_1_100 : data_for_fifo = {id[4:0], 3'h0}; // extended mode, extended format header + 6'b1_1_0_000 : data_for_fifo = {1'b0, rtr1, 2'h0, data_len}; // extended mode, standard format header + 6'b1_1_0_001 : data_for_fifo = id[10:3]; // extended mode, standard format header + 6'b1_1_0_010 : data_for_fifo = {id[2:0], rtr1, 4'h0}; // extended mode, standard format header + 6'b1_0_x_000 : data_for_fifo = id[10:3]; // normal mode header + 6'b1_0_x_001 : data_for_fifo = {id[2:0], rtr1, data_len}; // normal mode header + default : data_for_fifo = tmp_fifo[data_cnt - {1'b0, header_len}]; // data + endcase +end + + + + +// Instantiation of the RX fifo module +can_fifo i_can_fifo +( + .clk(clk), + .rst(rst), + + .wr(wr_fifo), + + .data_in(data_for_fifo), + .addr(addr[5:0]), + .data_out(data_out), + .fifo_selected(fifo_selected), + + .reset_mode(reset_mode), + .release_buffer(release_buffer), + .extended_mode(extended_mode), + .overrun(overrun), + .info_empty(info_empty), + .info_cnt(rx_message_counter) + +`ifdef CAN_BIST + , + .mbist_si_i(mbist_si_i), + .mbist_so_o(mbist_so_o), + .mbist_ctrl_i(mbist_ctrl_i) +`endif +); + + +// Transmitting error frame. +always @ (posedge clk or posedge rst) +begin + if (rst) + error_frame <= 1'b0; +// else if (reset_mode || error_frame_ended || go_overload_frame) + else if (set_reset_mode || error_frame_ended || go_overload_frame) + error_frame <=#Tp 1'b0; + else if (go_error_frame) + error_frame <=#Tp 1'b1; +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + error_cnt1 <= 3'd0; + else if (error_frame_ended | go_error_frame | go_overload_frame) + error_cnt1 <=#Tp 3'd0; + else if (error_frame & tx_point & (error_cnt1 < 3'd7)) + error_cnt1 <=#Tp error_cnt1 + 1'b1; +end + + + +assign error_flag_over = ((~node_error_passive) & sample_point & (error_cnt1 == 3'd7) | node_error_passive & sample_point & (passive_cnt == 3'h6)) & (~enable_error_cnt2); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + error_flag_over_latched <= 1'b0; + else if (error_frame_ended | go_error_frame | go_overload_frame) + error_flag_over_latched <=#Tp 1'b0; + else if (error_flag_over) + error_flag_over_latched <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + enable_error_cnt2 <= 1'b0; + else if (error_frame_ended | go_error_frame | go_overload_frame) + enable_error_cnt2 <=#Tp 1'b0; + else if (error_frame & (error_flag_over & sampled_bit)) + enable_error_cnt2 <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + error_cnt2 <= 3'd0; + else if (error_frame_ended | go_error_frame | go_overload_frame) + error_cnt2 <=#Tp 3'd0; + else if (enable_error_cnt2 & tx_point) + error_cnt2 <=#Tp error_cnt2 + 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + delayed_dominant_cnt <= 3'h0; + else if (enable_error_cnt2 | go_error_frame | enable_overload_cnt2 | go_overload_frame) + delayed_dominant_cnt <=#Tp 3'h0; + else if (sample_point & (~sampled_bit) & ((error_cnt1 == 3'd7) | (overload_cnt1 == 3'd7))) + delayed_dominant_cnt <=#Tp delayed_dominant_cnt + 1'b1; +end + + +// passive_cnt +always @ (posedge clk or posedge rst) +begin + if (rst) + passive_cnt <= 3'h1; + else if (error_frame_ended | go_error_frame | go_overload_frame | first_compare_bit) + passive_cnt <=#Tp 3'h1; + else if (sample_point & (passive_cnt < 3'h6)) + begin + if (error_frame & (~enable_error_cnt2) & (sampled_bit == sampled_bit_q)) + passive_cnt <=#Tp passive_cnt + 1'b1; + else + passive_cnt <=#Tp 3'h1; + end +end + + +// When comparing 6 equal bits, first is always equal +always @ (posedge clk or posedge rst) +begin + if (rst) + first_compare_bit <= 1'b0; + else if (go_error_frame) + first_compare_bit <=#Tp 1'b1; + else if (sample_point) + first_compare_bit <= 1'b0; +end + + +// Transmitting overload frame. +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_frame <= 1'b0; + else if (overload_frame_ended | go_error_frame) + overload_frame <=#Tp 1'b0; + else if (go_overload_frame) + overload_frame <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_cnt1 <= 3'd0; + else if (overload_frame_ended | go_error_frame | go_overload_frame) + overload_cnt1 <=#Tp 3'd0; + else if (overload_frame & tx_point & (overload_cnt1 < 3'd7)) + overload_cnt1 <=#Tp overload_cnt1 + 1'b1; +end + + +assign overload_flag_over = sample_point & (overload_cnt1 == 3'd7) & (~enable_overload_cnt2); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + enable_overload_cnt2 <= 1'b0; + else if (overload_frame_ended | go_error_frame | go_overload_frame) + enable_overload_cnt2 <=#Tp 1'b0; + else if (overload_frame & (overload_flag_over & sampled_bit)) + enable_overload_cnt2 <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_cnt2 <= 3'd0; + else if (overload_frame_ended | go_error_frame | go_overload_frame) + overload_cnt2 <=#Tp 3'd0; + else if (enable_overload_cnt2 & tx_point) + overload_cnt2 <=#Tp overload_cnt2 + 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_request_cnt <= 2'b0; + else if (go_error_frame | go_rx_id1) + overload_request_cnt <=#Tp 2'b0; + else if (overload_request & overload_frame) + overload_request_cnt <=#Tp overload_request_cnt + 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_frame_blocked <= 1'b0; + else if (go_error_frame | go_rx_id1) + overload_frame_blocked <=#Tp 1'b0; + else if (overload_request & overload_frame & overload_request_cnt == 2'h2) // This is a second sequential overload_request + overload_frame_blocked <=#Tp 1'b1; +end + + +assign send_ack = (~tx_state) & rx_ack & (~err) & (~listen_only_mode); + + + +always @ (reset_mode or node_bus_off or tx_state or go_tx or bit_de_stuff_tx or tx_bit or tx_q or + send_ack or go_overload_frame or overload_frame or overload_cnt1 or + go_error_frame or error_frame or error_cnt1 or node_error_passive) +begin + if (reset_mode | node_bus_off) // Reset or node_bus_off + tx_next = 1'b1; + else + begin + if (go_error_frame | error_frame) // Transmitting error frame + begin + if (error_cnt1 < 3'd6) + begin + if (node_error_passive) + tx_next = 1'b1; + else + tx_next = 1'b0; + end + else + tx_next = 1'b1; + end + else if (go_overload_frame | overload_frame) // Transmitting overload frame + begin + if (overload_cnt1 < 3'd6) + tx_next = 1'b0; + else + tx_next = 1'b1; + end + else if (go_tx | tx_state) // Transmitting message + tx_next = ((~bit_de_stuff_tx) & tx_bit) | (bit_de_stuff_tx & (~tx_q)); + else if (send_ack) // Acknowledge + tx_next = 1'b0; + else + tx_next = 1'b1; + end +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx <= 1'b1; + else if (reset_mode) + tx <= 1'b1; + else if (tx_point) + tx <=#Tp tx_next; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_q <=#Tp 1'b0; + else if (reset_mode) + tx_q <=#Tp 1'b0; + else if (tx_point) + tx_q <=#Tp tx & (~go_early_tx_latched); +end + + +/* Delayed tx point */ +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_point_q <=#Tp 1'b0; + else if (reset_mode) + tx_point_q <=#Tp 1'b0; + else + tx_point_q <=#Tp tx_point; +end + + +/* Changing bit order from [7:0] to [0:7] */ +can_ibo i_ibo_tx_data_0 (.di(tx_data_0), .do(r_tx_data_0)); +can_ibo i_ibo_tx_data_1 (.di(tx_data_1), .do(r_tx_data_1)); +can_ibo i_ibo_tx_data_2 (.di(tx_data_2), .do(r_tx_data_2)); +can_ibo i_ibo_tx_data_3 (.di(tx_data_3), .do(r_tx_data_3)); +can_ibo i_ibo_tx_data_4 (.di(tx_data_4), .do(r_tx_data_4)); +can_ibo i_ibo_tx_data_5 (.di(tx_data_5), .do(r_tx_data_5)); +can_ibo i_ibo_tx_data_6 (.di(tx_data_6), .do(r_tx_data_6)); +can_ibo i_ibo_tx_data_7 (.di(tx_data_7), .do(r_tx_data_7)); +can_ibo i_ibo_tx_data_8 (.di(tx_data_8), .do(r_tx_data_8)); +can_ibo i_ibo_tx_data_9 (.di(tx_data_9), .do(r_tx_data_9)); +can_ibo i_ibo_tx_data_10 (.di(tx_data_10), .do(r_tx_data_10)); +can_ibo i_ibo_tx_data_11 (.di(tx_data_11), .do(r_tx_data_11)); +can_ibo i_ibo_tx_data_12 (.di(tx_data_12), .do(r_tx_data_12)); + +/* Changing bit order from [14:0] to [0:14] */ +can_ibo i_calculated_crc0 (.di(calculated_crc[14:7]), .do(r_calculated_crc[7:0])); +can_ibo i_calculated_crc1 (.di({calculated_crc[6:0], 1'b0}), .do(r_calculated_crc[15:8])); + + +assign basic_chain = {r_tx_data_1[7:4], 2'h0, r_tx_data_1[3:0], r_tx_data_0[7:0], 1'b0}; +assign basic_chain_data = {r_tx_data_9, r_tx_data_8, r_tx_data_7, r_tx_data_6, r_tx_data_5, r_tx_data_4, r_tx_data_3, r_tx_data_2}; +assign extended_chain_std = {r_tx_data_0[7:4], 2'h0, r_tx_data_0[1], r_tx_data_2[2:0], r_tx_data_1[7:0], 1'b0}; +assign extended_chain_ext = {r_tx_data_0[7:4], 2'h0, r_tx_data_0[1], r_tx_data_4[4:0], r_tx_data_3[7:0], r_tx_data_2[7:3], 1'b1, 1'b1, r_tx_data_2[2:0], r_tx_data_1[7:0], 1'b0}; +assign extended_chain_data_std = {r_tx_data_10, r_tx_data_9, r_tx_data_8, r_tx_data_7, r_tx_data_6, r_tx_data_5, r_tx_data_4, r_tx_data_3}; +assign extended_chain_data_ext = {r_tx_data_12, r_tx_data_11, r_tx_data_10, r_tx_data_9, r_tx_data_8, r_tx_data_7, r_tx_data_6, r_tx_data_5}; + +always @ (extended_mode or rx_data or tx_pointer or extended_chain_data_std or extended_chain_data_ext or rx_crc or r_calculated_crc or + r_tx_data_0 or extended_chain_ext or extended_chain_std or basic_chain_data or basic_chain or + finish_msg) +begin + if (extended_mode) + begin + if (rx_data) // data stage + if (r_tx_data_0[0]) // Extended frame + tx_bit = extended_chain_data_ext[tx_pointer]; + else + tx_bit = extended_chain_data_std[tx_pointer]; + else if (rx_crc) + tx_bit = r_calculated_crc[tx_pointer]; + else if (finish_msg) + tx_bit = 1'b1; + else + begin + if (r_tx_data_0[0]) // Extended frame + tx_bit = extended_chain_ext[tx_pointer]; + else + tx_bit = extended_chain_std[tx_pointer]; + end + end + else // Basic mode + begin + if (rx_data) // data stage + tx_bit = basic_chain_data[tx_pointer]; + else if (rx_crc) + tx_bit = r_calculated_crc[tx_pointer]; + else if (finish_msg) + tx_bit = 1'b1; + else + tx_bit = basic_chain[tx_pointer]; + end +end + + +assign limited_tx_cnt_ext = tx_data_0[3] ? 6'h3f : ((tx_data_0[2:0] <<3) - 1'b1); +assign limited_tx_cnt_std = tx_data_1[3] ? 6'h3f : ((tx_data_1[2:0] <<3) - 1'b1); + +assign rst_tx_pointer = ((~bit_de_stuff_tx) & tx_point & (~rx_data) & extended_mode & r_tx_data_0[0] & tx_pointer == 6'd38 ) | // arbitration + control for extended format + ((~bit_de_stuff_tx) & tx_point & (~rx_data) & extended_mode & (~r_tx_data_0[0]) & tx_pointer == 6'd18 ) | // arbitration + control for extended format + ((~bit_de_stuff_tx) & tx_point & (~rx_data) & (~extended_mode) & tx_pointer == 6'd18 ) | // arbitration + control for standard format + ((~bit_de_stuff_tx) & tx_point & rx_data & extended_mode & tx_pointer == limited_tx_cnt_ext) | // data (overflow is OK here) + ((~bit_de_stuff_tx) & tx_point & rx_data & (~extended_mode) & tx_pointer == limited_tx_cnt_std) | // data (overflow is OK here) + ( tx_point & rx_crc_lim ) | // crc + (go_rx_idle ) | // at the end + (reset_mode ) | + (overload_frame ) | + (error_frame ) ; + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_pointer <= 6'h0; + else if (rst_tx_pointer) + tx_pointer <=#Tp 6'h0; + else if (go_early_tx | (tx_point & (tx_state | go_tx) & (~bit_de_stuff_tx))) + tx_pointer <=#Tp tx_pointer + 1'b1; +end + + +assign tx_successful = transmitter & go_rx_inter & (~go_error_frame) & (~error_frame_ended) & (~overload_frame_ended) & (~arbitration_lost); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + need_to_tx <= 1'b0; + else if (tx_successful | reset_mode | (abort_tx & (~transmitting)) | ((~tx_state) & tx_state_q & single_shot_transmission)) + need_to_tx <=#Tp 1'h0; + else if (tx_request & sample_point) + need_to_tx <=#Tp 1'b1; +end + + + +assign go_early_tx = (~listen_only_mode) & need_to_tx & (~tx_state) & (~suspend | (susp_cnt == 3'h7)) & sample_point & (~sampled_bit) & (rx_idle | last_bit_of_inter); +assign go_tx = (~listen_only_mode) & need_to_tx & (~tx_state) & (~suspend | (sample_point & (susp_cnt == 3'h7))) & (go_early_tx | rx_idle); + +// go_early_tx latched (for proper bit_de_stuff generation) +always @ (posedge clk or posedge rst) +begin + if (rst) + go_early_tx_latched <= 1'b0; + else if (reset_mode || tx_point) + go_early_tx_latched <=#Tp 1'b0; + else if (go_early_tx) + go_early_tx_latched <=#Tp 1'b1; +end + + + +// Tx state +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_state <= 1'b0; + else if (reset_mode | go_rx_inter | error_frame | arbitration_lost) + tx_state <=#Tp 1'b0; + else if (go_tx) + tx_state <=#Tp 1'b1; +end + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_state_q <=#Tp 1'b0; + else if (reset_mode) + tx_state_q <=#Tp 1'b0; + else + tx_state_q <=#Tp tx_state; +end + + + +// Node is a transmitter +always @ (posedge clk or posedge rst) +begin + if (rst) + transmitter <= 1'b0; + else if (go_tx) + transmitter <=#Tp 1'b1; + else if (reset_mode | go_rx_idle | suspend & go_rx_id1) + transmitter <=#Tp 1'b0; +end + + + +// Signal "transmitting" signals that the core is a transmitting (message, error frame or overload frame). No synchronization is done meanwhile. +// Node might be both transmitter or receiver (sending error or overload frame) +always @ (posedge clk or posedge rst) +begin + if (rst) + transmitting <= 1'b0; + else if (go_error_frame | go_overload_frame | go_tx | send_ack) + transmitting <=#Tp 1'b1; + else if (reset_mode | go_rx_idle | (go_rx_id1 & (~tx_state)) | (arbitration_lost & tx_state)) + transmitting <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + suspend <= 1'b0; + else if (reset_mode | (sample_point & (susp_cnt == 3'h7))) + suspend <=#Tp 1'b0; + else if (not_first_bit_of_inter & transmitter & node_error_passive) + suspend <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + susp_cnt_en <= 1'b0; + else if (reset_mode | (sample_point & (susp_cnt == 3'h7))) + susp_cnt_en <=#Tp 1'b0; + else if (suspend & sample_point & last_bit_of_inter) + susp_cnt_en <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + susp_cnt <= 3'h0; + else if (reset_mode | (sample_point & (susp_cnt == 3'h7))) + susp_cnt <=#Tp 3'h0; + else if (susp_cnt_en & sample_point) + susp_cnt <=#Tp susp_cnt + 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + finish_msg <= 1'b0; + else if (go_rx_idle | go_rx_id1 | error_frame | reset_mode) + finish_msg <=#Tp 1'b0; + else if (go_rx_crc_lim) + finish_msg <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_lost <= 1'b0; + else if (go_rx_idle | error_frame_ended) + arbitration_lost <=#Tp 1'b0; + else if (transmitter & sample_point & tx & arbitration_field & ~sampled_bit) + arbitration_lost <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_lost_q <=#Tp 1'b0; + else + arbitration_lost_q <=#Tp arbitration_lost; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_field_d <=#Tp 1'b0; + else if (sample_point) + arbitration_field_d <=#Tp arbitration_field; +end + + +assign set_arbitration_lost_irq = arbitration_lost & (~arbitration_lost_q) & (~arbitration_blocked); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_cnt <= 5'h0; + else if (sample_point && !bit_de_stuff) + if (arbitration_field_d) + arbitration_cnt <=#Tp arbitration_cnt + 1'b1; + else + arbitration_cnt <=#Tp 5'h0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_lost_capture <= 5'h0; + else if (set_arbitration_lost_irq) + arbitration_lost_capture <=#Tp arbitration_cnt; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_blocked <= 1'b0; + else if (read_arbitration_lost_capture_reg) + arbitration_blocked <=#Tp 1'b0; + else if (set_arbitration_lost_irq) + arbitration_blocked <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + rx_err_cnt <= 9'h0; + else if (we_rx_err_cnt & (~node_bus_off)) + rx_err_cnt <=#Tp {1'b0, data_in}; + else if (set_reset_mode) + rx_err_cnt <=#Tp 9'h0; + else + begin + if ((~listen_only_mode) & (~transmitter | arbitration_lost)) + begin + if (go_rx_ack_lim & (~go_error_frame) & (~crc_err) & (rx_err_cnt > 9'h0)) + begin + if (rx_err_cnt > 9'd127) + rx_err_cnt <=#Tp 9'd127; + else + rx_err_cnt <=#Tp rx_err_cnt - 1'b1; + end + else if (rx_err_cnt < 9'd128) + begin + if (go_error_frame & (~rule5)) // 1 (rule 5 is just the opposite then rule 1 exception + rx_err_cnt <=#Tp rx_err_cnt + 1'b1; + else if ( (error_flag_over & (~error_flag_over_latched) & sample_point & (~sampled_bit) & (error_cnt1 == 3'd7) ) | // 2 + (go_error_frame & rule5 ) | // 5 + (sample_point & (~sampled_bit) & (delayed_dominant_cnt == 3'h7) ) // 6 + ) + rx_err_cnt <=#Tp rx_err_cnt + 4'h8; + end + end + end +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_err_cnt <= 9'h0; + else if (we_tx_err_cnt) + tx_err_cnt <=#Tp {1'b0, data_in}; + else + begin + if (set_reset_mode) + tx_err_cnt <=#Tp 9'd128; + else if ((tx_err_cnt > 9'd0) & (tx_successful | bus_free)) + tx_err_cnt <=#Tp tx_err_cnt - 1'h1; + else if (transmitter & (~arbitration_lost)) + begin + if ( (sample_point & (~sampled_bit) & (delayed_dominant_cnt == 3'h7) ) | // 6 + (go_error_frame & rule5 ) | // 4 (rule 5 is the same as rule 4) + (go_error_frame & (~(transmitter & node_error_passive & ack_err)) & (~(transmitter & stuff_err & + arbitration_field & sample_point & tx & (~sampled_bit))) ) | // 3 + (error_frame & rule3_exc1_2 ) // 3 + ) + tx_err_cnt <=#Tp tx_err_cnt + 4'h8; + end + end +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + node_error_passive <= 1'b0; + else if ((rx_err_cnt < 128) & (tx_err_cnt < 9'd128)) + node_error_passive <=#Tp 1'b0; + else if (((rx_err_cnt >= 128) | (tx_err_cnt >= 9'd128)) & (error_frame_ended | go_error_frame | (~reset_mode) & reset_mode_q) & (~node_bus_off)) + node_error_passive <=#Tp 1'b1; +end + + +assign node_error_active = ~(node_error_passive | node_bus_off); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + node_bus_off <= 1'b0; + else if ((rx_err_cnt == 9'h0) & (tx_err_cnt == 9'd0) & (~reset_mode) | (we_tx_err_cnt & (data_in < 8'd255))) + node_bus_off <=#Tp 1'b0; + else if ((tx_err_cnt >= 9'd256) | (we_tx_err_cnt & (data_in == 8'd255))) + node_bus_off <=#Tp 1'b1; +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + bus_free_cnt <= 4'h0; + else if (sample_point) + begin + if (sampled_bit & bus_free_cnt_en & (bus_free_cnt < 4'd10)) + bus_free_cnt <=#Tp bus_free_cnt + 1'b1; + else + bus_free_cnt <=#Tp 4'h0; + end +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + bus_free_cnt_en <= 1'b0; + else if ((~reset_mode) & reset_mode_q | node_bus_off_q & (~reset_mode)) + bus_free_cnt_en <=#Tp 1'b1; + else if (sample_point & sampled_bit & (bus_free_cnt==4'd10) & (~node_bus_off)) + bus_free_cnt_en <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + bus_free <= 1'b0; + else if (sample_point & sampled_bit & (bus_free_cnt==4'd10) && waiting_for_bus_free) + bus_free <=#Tp 1'b1; + else + bus_free <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + waiting_for_bus_free <= 1'b1; + else if (bus_free & (~node_bus_off)) + waiting_for_bus_free <=#Tp 1'b0; + else if (node_bus_off_q & (~reset_mode)) + waiting_for_bus_free <=#Tp 1'b1; +end + + +assign bus_off_on = ~node_bus_off; + +assign set_reset_mode = node_bus_off & (~node_bus_off_q); +assign error_status = extended_mode? ((rx_err_cnt >= error_warning_limit) | (tx_err_cnt >= error_warning_limit)) : + ((rx_err_cnt >= 9'd96) | (tx_err_cnt >= 9'd96)) ; + +assign transmit_status = transmitting || (extended_mode && waiting_for_bus_free); +assign receive_status = extended_mode ? (waiting_for_bus_free || (!rx_idle) && (!transmitting)) : + ((!waiting_for_bus_free) && (!rx_idle) && (!transmitting)); + +/* Error code capture register */ +always @ (posedge clk or posedge rst) +begin + if (rst) + error_capture_code <= 8'h0; + else if (read_error_code_capture_reg) + error_capture_code <=#Tp 8'h0; + else if (set_bus_error_irq) + error_capture_code <=#Tp {error_capture_code_type[7:6], error_capture_code_direction, error_capture_code_segment[4:0]}; +end + + + +assign error_capture_code_segment[0] = rx_idle | rx_ide | (rx_id2 & (bit_cnt<6'd13)) | rx_r1 | rx_r0 | rx_dlc | rx_ack | rx_ack_lim | error_frame & node_error_active; +assign error_capture_code_segment[1] = rx_idle | rx_id1 | rx_id2 | rx_dlc | rx_data | rx_ack_lim | rx_eof | rx_inter | error_frame & node_error_passive; +assign error_capture_code_segment[2] = (rx_id1 & (bit_cnt>6'd7)) | rx_rtr1 | rx_ide | rx_id2 | rx_rtr2 | rx_r1 | error_frame & node_error_passive | overload_frame; +assign error_capture_code_segment[3] = (rx_id2 & (bit_cnt>6'd4)) | rx_rtr2 | rx_r1 | rx_r0 | rx_dlc | rx_data | rx_crc | rx_crc_lim | rx_ack | rx_ack_lim | rx_eof | overload_frame; +assign error_capture_code_segment[4] = rx_crc_lim | rx_ack | rx_ack_lim | rx_eof | rx_inter | error_frame | overload_frame; +assign error_capture_code_direction = ~transmitting; + + +always @ (bit_err or form_err or stuff_err) +begin + if (bit_err) + error_capture_code_type[7:6] = 2'b00; + else if (form_err) + error_capture_code_type[7:6] = 2'b01; + else if (stuff_err) + error_capture_code_type[7:6] = 2'b10; + else + error_capture_code_type[7:6] = 2'b11; +end + + +assign set_bus_error_irq = go_error_frame & (~error_capture_code_blocked); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + error_capture_code_blocked <= 1'b0; + else if (read_error_code_capture_reg) + error_capture_code_blocked <=#Tp 1'b0; + else if (set_bus_error_irq) + error_capture_code_blocked <=#Tp 1'b1; +end + + +endmodule + diff --git a/soc/peripheral/can_btl.v b/soc/peripheral/can_btl.v new file mode 100644 index 0000000..296473b --- /dev/null +++ b/soc/peripheral/can_btl.v @@ -0,0 +1,381 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_btl.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on +`include "can_defines.v" + +module can_btl +( + clk, + rst, + rx, + tx, + + /* Bus Timing 0 register */ + baud_r_presc, + sync_jump_width, + + /* Bus Timing 1 register */ + time_segment1, + time_segment2, + triple_sampling, + + /* Output signals from this module */ + sample_point, + sampled_bit, + sampled_bit_q, + tx_point, + hard_sync, + + /* Output from can_bsp module */ + rx_idle, + rx_inter, + transmitting, + transmitter, + go_rx_inter, + tx_next, + + go_overload_frame, + go_error_frame, + go_tx, + send_ack, + node_error_passive +); + +parameter Tp = 1; + +input clk; +input rst; +input rx; +input tx; + + +/* Bus Timing 0 register */ +input [5:0] baud_r_presc; +input [1:0] sync_jump_width; + +/* Bus Timing 1 register */ +input [3:0] time_segment1; +input [2:0] time_segment2; +input triple_sampling; + +/* Output from can_bsp module */ +input rx_idle; +input rx_inter; +input transmitting; +input transmitter; +input go_rx_inter; +input tx_next; + +input go_overload_frame; +input go_error_frame; +input go_tx; +input send_ack; +input node_error_passive; + +/* Output signals from this module */ +output sample_point; +output sampled_bit; +output sampled_bit_q; +output tx_point; +output hard_sync; + +reg [6:0] clk_cnt; +reg clk_en; +reg clk_en_q; +reg sync_blocked; +reg hard_sync_blocked; +reg sampled_bit; +reg sampled_bit_q; +reg [4:0] quant_cnt; +reg [3:0] delay; +reg sync; +reg seg1; +reg seg2; +reg resync_latched; +reg sample_point; +reg [1:0] sample; +reg tx_point; +reg tx_next_sp; + +wire go_sync; +wire go_seg1; +wire go_seg2; +wire [7:0] preset_cnt; +wire sync_window; +wire resync; + + +assign preset_cnt = (baud_r_presc + 1'b1)<<1; // (BRP+1)*2 +assign hard_sync = (rx_idle | rx_inter) & (~rx) & sampled_bit & (~hard_sync_blocked); // Hard synchronization +assign resync = (~rx_idle) & (~rx_inter) & (~rx) & sampled_bit & (~sync_blocked); // Re-synchronization + + + +/* Generating general enable signal that defines baud rate. */ +always @ (posedge clk or posedge rst) +begin + if (rst) + clk_cnt <= 7'h0; + else if (clk_cnt >= (preset_cnt-1'b1)) + clk_cnt <=#Tp 7'h0; + else + clk_cnt <=#Tp clk_cnt + 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + clk_en <= 1'b0; + else if ({1'b0, clk_cnt} == (preset_cnt-1'b1)) + clk_en <=#Tp 1'b1; + else + clk_en <=#Tp 1'b0; +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + clk_en_q <= 1'b0; + else + clk_en_q <=#Tp clk_en; +end + + + +/* Changing states */ +assign go_sync = clk_en_q & seg2 & (quant_cnt[2:0] == time_segment2) & (~hard_sync) & (~resync); +assign go_seg1 = clk_en_q & (sync | hard_sync | (resync & seg2 & sync_window) | (resync_latched & sync_window)); +assign go_seg2 = clk_en_q & (seg1 & (~hard_sync) & (quant_cnt == (time_segment1 + delay))); + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_point <= 1'b0; + else + tx_point <=#Tp ~tx_point & seg2 & ( clk_en & (quant_cnt[2:0] == time_segment2) + | (clk_en | clk_en_q) & (resync | hard_sync) + ); // When transmitter we should transmit as soon as possible. +end + + + +/* When early edge is detected outside of the SJW field, synchronization request is latched and performed when + SJW is reached */ +always @ (posedge clk or posedge rst) +begin + if (rst) + resync_latched <= 1'b0; + else if (resync & seg2 & (~sync_window)) + resync_latched <=#Tp 1'b1; + else if (go_seg1) + resync_latched <= 1'b0; +end + + + +/* Synchronization stage/segment */ +always @ (posedge clk or posedge rst) +begin + if (rst) + sync <= 1'b0; + else if (clk_en_q) + sync <=#Tp go_sync; +end + + +/* Seg1 stage/segment (together with propagation segment which is 1 quant long) */ +always @ (posedge clk or posedge rst) +begin + if (rst) + seg1 <= 1'b1; + else if (go_seg1) + seg1 <=#Tp 1'b1; + else if (go_seg2) + seg1 <=#Tp 1'b0; +end + + +/* Seg2 stage/segment */ +always @ (posedge clk or posedge rst) +begin + if (rst) + seg2 <= 1'b0; + else if (go_seg2) + seg2 <=#Tp 1'b1; + else if (go_sync | go_seg1) + seg2 <=#Tp 1'b0; +end + + +/* Quant counter */ +always @ (posedge clk or posedge rst) +begin + if (rst) + quant_cnt <= 5'h0; + else if (go_sync | go_seg1 | go_seg2) + quant_cnt <=#Tp 5'h0; + else if (clk_en_q) + quant_cnt <=#Tp quant_cnt + 1'b1; +end + + +/* When late edge is detected (in seg1 stage), stage seg1 is prolonged. */ +always @ (posedge clk or posedge rst) +begin + if (rst) + delay <= 4'h0; + else if (resync & seg1 & (~transmitting | transmitting & (tx_next_sp | (tx & (~rx))))) // when transmitting 0 with positive error delay is set to 0 + delay <=#Tp (quant_cnt > {3'h0, sync_jump_width})? ({2'h0, sync_jump_width} + 1'b1) : (quant_cnt + 1'b1); + else if (go_sync | go_seg1) + delay <=#Tp 4'h0; +end + + +// If early edge appears within this window (in seg2 stage), phase error is fully compensated +assign sync_window = ((time_segment2 - quant_cnt[2:0]) < ( sync_jump_width + 1'b1)); + + +// Sampling data (memorizing two samples all the time). +always @ (posedge clk or posedge rst) +begin + if (rst) + sample <= 2'b11; + else if (clk_en_q) + sample <= {sample[0], rx}; +end + + +// When enabled, tripple sampling is done here. +always @ (posedge clk or posedge rst) +begin + if (rst) + begin + sampled_bit <= 1'b1; + sampled_bit_q <= 1'b1; + sample_point <= 1'b0; + end + else if (go_error_frame) + begin + sampled_bit_q <=#Tp sampled_bit; + sample_point <=#Tp 1'b0; + end + else if (clk_en_q & (~hard_sync)) + begin + if (seg1 & (quant_cnt == (time_segment1 + delay))) + begin + sample_point <=#Tp 1'b1; + sampled_bit_q <=#Tp sampled_bit; + if (triple_sampling) + sampled_bit <=#Tp (sample[0] & sample[1]) | ( sample[0] & rx) | (sample[1] & rx); + else + sampled_bit <=#Tp rx; + end + end + else + sample_point <=#Tp 1'b0; +end + + +// tx_next_sp shows next value that will be driven on the TX. When driving 1 and receiving 0 we +// need to synchronize (even when we are a transmitter) +always @ (posedge clk or posedge rst) +begin + if (rst) + tx_next_sp <= 1'b0; + else if (go_overload_frame | (go_error_frame & (~node_error_passive)) | go_tx | send_ack) + tx_next_sp <=#Tp 1'b0; + else if (go_error_frame & node_error_passive) + tx_next_sp <=#Tp 1'b1; + else if (sample_point) + tx_next_sp <=#Tp tx_next; +end + + + +/* Blocking synchronization (can occur only once in a bit time) */ + +always @ (posedge clk or posedge rst) +begin + if (rst) + sync_blocked <=#Tp 1'b1; + else if (clk_en_q) + begin + if (resync) + sync_blocked <=#Tp 1'b1; + else if (go_seg2) + sync_blocked <=#Tp 1'b0; + end +end + + +/* Blocking hard synchronization when occurs once or when we are transmitting a msg */ +always @ (posedge clk or posedge rst) +begin + if (rst) + hard_sync_blocked <=#Tp 1'b0; + else if (hard_sync & clk_en_q | (transmitting & transmitter | go_tx) & tx_point & (~tx_next)) + hard_sync_blocked <=#Tp 1'b1; + else if (go_rx_inter | (rx_idle | rx_inter) & sample_point & sampled_bit) // When a glitch performed synchronization + hard_sync_blocked <=#Tp 1'b0; +end + + + + + +endmodule + diff --git a/soc/peripheral/can_crc.v b/soc/peripheral/can_crc.v new file mode 100644 index 0000000..31acdfe --- /dev/null +++ b/soc/peripheral/can_crc.v @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_crc.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on + +module can_crc (clk, data, enable, initialize, crc); + + +parameter Tp = 1; + +input clk; +input data; +input enable; +input initialize; + +output [14:0] crc; + +reg [14:0] crc; + +wire crc_next; +wire [14:0] crc_tmp; + + +assign crc_next = data ^ crc[14]; +assign crc_tmp = {crc[13:0], 1'b0}; + +always @ (posedge clk) +begin + if(initialize) + crc <= #Tp 15'h0; + else if (enable) + begin + if (crc_next) + crc <= #Tp crc_tmp ^ 15'h4599; + else + crc <= #Tp crc_tmp; + end +end + + +endmodule diff --git a/soc/peripheral/can_defines.v b/soc/peripheral/can_defines.v new file mode 100755 index 0000000..7b17b5d --- /dev/null +++ b/soc/peripheral/can_defines.v @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_defines.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + + +// Uncomment following line if you want to use WISHBONE interface. Otherwise +// 8051 interface is used. +`define CAN_WISHBONE_IF + +// Uncomment following line if you want to use CAN in Actel APA devices (embedded memory used) +// `define ACTEL_APA_RAM + +// Uncomment following line if you want to use CAN in Altera devices (embedded memory used) +// `define ALTERA_RAM + +// Uncomment following line if you want to use CAN in Xilinx devices (embedded memory used) +// `define XILINX_RAM + +// Uncomment the line for the ram used in ASIC implementation +// `define VIRTUALSILICON_RAM +// `define ARTISAN_RAM + +// Uncomment the following line when RAM BIST is needed (ASIC implementation) +//`define CAN_BIST // Bist (for ASIC implementation) + +/* width of MBIST control bus */ +//`define CAN_MBIST_CTRL_WIDTH 3 diff --git a/soc/peripheral/can_fifo.v b/soc/peripheral/can_fifo.v new file mode 100644 index 0000000..18b4835 --- /dev/null +++ b/soc/peripheral/can_fifo.v @@ -0,0 +1,622 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_fifo.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on +`include "can_defines.v" + +module can_fifo +( + clk, + rst, + + wr, + + data_in, + addr, + data_out, + fifo_selected, + + reset_mode, + release_buffer, + extended_mode, + overrun, + info_empty, + info_cnt + +`ifdef CAN_BIST + , + mbist_si_i, + mbist_so_o, + mbist_ctrl_i +`endif +); + +parameter Tp = 1; + +input clk; +input rst; +input wr; +input [7:0] data_in; +input [5:0] addr; +input reset_mode; +input release_buffer; +input extended_mode; +input fifo_selected; + +output [7:0] data_out; +output overrun; +output info_empty; +output [6:0] info_cnt; + +`ifdef CAN_BIST +input mbist_si_i; +output mbist_so_o; +input [`CAN_MBIST_CTRL_WIDTH - 1:0] mbist_ctrl_i; // bist chain shift control +wire mbist_s_0; +`endif + +`ifdef ALTERA_RAM +`else +`ifdef ACTEL_APA_RAM +`else +`ifdef XILINX_RAM +`else +`ifdef ARTISAN_RAM + reg overrun_info[0:63]; +`else +`ifdef VIRTUALSILICON_RAM + reg overrun_info[0:63]; +`else + reg [7:0] fifo [0:63]; + reg [3:0] length_fifo[0:63]; + reg overrun_info[0:63]; +`endif +`endif +`endif +`endif +`endif + +reg [5:0] rd_pointer; +reg [5:0] wr_pointer; +reg [5:0] read_address; +reg [5:0] wr_info_pointer; +reg [5:0] rd_info_pointer; +reg wr_q; +reg [3:0] len_cnt; +reg [6:0] fifo_cnt; +reg [6:0] info_cnt; +reg latch_overrun; +reg initialize_memories; + +wire [3:0] length_info; +wire write_length_info; +wire fifo_empty; +wire fifo_full; +wire info_full; + +assign write_length_info = (~wr) & wr_q; + +// Delayed write signal +always @ (posedge clk or posedge rst) +begin + if (rst) + wr_q <=#Tp 1'b0; + else if (reset_mode) + wr_q <=#Tp 1'b0; + else + wr_q <=#Tp wr; +end + + +// length counter +always @ (posedge clk or posedge rst) +begin + if (rst) + len_cnt <= 4'h0; + else if (reset_mode | write_length_info) + len_cnt <=#Tp 4'h0; + else if (wr & (~fifo_full)) + len_cnt <=#Tp len_cnt + 1'b1; +end + + +// wr_info_pointer +always @ (posedge clk or posedge rst) +begin + if (rst) + wr_info_pointer <= 6'h0; + else if (write_length_info & (~info_full) | initialize_memories) + wr_info_pointer <=#Tp wr_info_pointer + 1'b1; + else if (reset_mode) + wr_info_pointer <=#Tp rd_info_pointer; +end + + + +// rd_info_pointer +always @ (posedge clk or posedge rst) +begin + if (rst) + rd_info_pointer <= 6'h0; + else if (release_buffer & (~info_full)) + rd_info_pointer <=#Tp rd_info_pointer + 1'b1; +end + + +// rd_pointer +always @ (posedge clk or posedge rst) +begin + if (rst) + rd_pointer <= 5'h0; + else if (release_buffer & (~fifo_empty)) + rd_pointer <=#Tp rd_pointer + {2'h0, length_info}; +end + + +// wr_pointer +always @ (posedge clk or posedge rst) +begin + if (rst) + wr_pointer <= 5'h0; + else if (reset_mode) + wr_pointer <=#Tp rd_pointer; + else if (wr & (~fifo_full)) + wr_pointer <=#Tp wr_pointer + 1'b1; +end + + +// latch_overrun +always @ (posedge clk or posedge rst) +begin + if (rst) + latch_overrun <= 1'b0; + else if (reset_mode | write_length_info) + latch_overrun <=#Tp 1'b0; + else if (wr & fifo_full) + latch_overrun <=#Tp 1'b1; +end + + +// Counting data in fifo +always @ (posedge clk or posedge rst) +begin + if (rst) + fifo_cnt <= 7'h0; + else if (reset_mode) + fifo_cnt <=#Tp 7'h0; + else if (wr & (~release_buffer) & (~fifo_full)) + fifo_cnt <=#Tp fifo_cnt + 1'b1; + else if ((~wr) & release_buffer & (~fifo_empty)) + fifo_cnt <=#Tp fifo_cnt - {3'h0, length_info}; + else if (wr & release_buffer & (~fifo_full) & (~fifo_empty)) + fifo_cnt <=#Tp fifo_cnt - {3'h0, length_info} + 1'b1; +end + +assign fifo_full = fifo_cnt == 7'd64; +assign fifo_empty = fifo_cnt == 7'd0; + + +// Counting data in length_fifo and overrun_info fifo +always @ (posedge clk or posedge rst) +begin + if (rst) + info_cnt <=#Tp 7'h0; + else if (reset_mode) + info_cnt <=#Tp 7'h0; + else if (write_length_info ^ release_buffer) + begin + if (release_buffer & (~info_empty)) + info_cnt <=#Tp info_cnt - 1'b1; + else if (write_length_info & (~info_full)) + info_cnt <=#Tp info_cnt + 1'b1; + end +end + +assign info_full = info_cnt == 7'd64; +assign info_empty = info_cnt == 7'd0; + + +// Selecting which address will be used for reading data from rx fifo +always @ (extended_mode or rd_pointer or addr) +begin + if (extended_mode) // extended mode + read_address = rd_pointer + (addr - 6'd16); + else // normal mode + read_address = rd_pointer + (addr - 6'd20); +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + initialize_memories <= 1'b1; + else if (&wr_info_pointer) + initialize_memories <=#Tp 1'b0; +end + + +`ifdef ALTERA_RAM +// altera_ram_64x8_sync fifo + lpm_ram_dp fifo + ( + .q (data_out), + .rdclock (clk), + .wrclock (clk), + .data (data_in), + .wren (wr & (~fifo_full)), + .rden (fifo_selected), + .wraddress (wr_pointer), + .rdaddress (read_address) + ); + defparam fifo.lpm_width = 8; + defparam fifo.lpm_widthad = 6; + defparam fifo.lpm_numwords = 64; + + +// altera_ram_64x4_sync info_fifo + lpm_ram_dp info_fifo + ( + .q (length_info), + .rdclock (clk), + .wrclock (clk), + .data (len_cnt & {4{~initialize_memories}}), + .wren (write_length_info & (~info_full) | initialize_memories), + .wraddress (wr_info_pointer), + .rdaddress (rd_info_pointer) + ); + defparam info_fifo.lpm_width = 4; + defparam info_fifo.lpm_widthad = 6; + defparam info_fifo.lpm_numwords = 64; + + +// altera_ram_64x1_sync overrun_fifo + lpm_ram_dp overrun_fifo + ( + .q (overrun), + .rdclock (clk), + .wrclock (clk), + .data ((latch_overrun | (wr & fifo_full)) & (~initialize_memories)), + .wren (write_length_info & (~info_full) | initialize_memories), + .wraddress (wr_info_pointer), + .rdaddress (rd_info_pointer) + ); + defparam overrun_fifo.lpm_width = 1; + defparam overrun_fifo.lpm_widthad = 6; + defparam overrun_fifo.lpm_numwords = 64; + +`else +`ifdef ACTEL_APA_RAM + actel_ram_64x8_sync fifo + ( + .DO (data_out), + .RCLOCK (clk), + .WCLOCK (clk), + .DI (data_in), + .PO (), // parity not used + .WRB (~(wr & (~fifo_full))), + .RDB (~fifo_selected), + .WADDR (wr_pointer), + .RADDR (read_address) + ); + + + actel_ram_64x4_sync info_fifo + ( + .DO (length_info), + .RCLOCK (clk), + .WCLOCK (clk), + .DI (len_cnt & {4{~initialize_memories}}), + .PO (), // parity not used + .WRB (~(write_length_info & (~info_full) | initialize_memories)), + .RDB (1'b0), // always enabled + .WADDR (wr_info_pointer), + .RADDR (rd_info_pointer) + ); + + + actel_ram_64x1_sync overrun_fifo + ( + .DO (overrun), + .RCLOCK (clk), + .WCLOCK (clk), + .DI ((latch_overrun | (wr & fifo_full)) & (~initialize_memories)), + .PO (), // parity not used + .WRB (~(write_length_info & (~info_full) | initialize_memories)), + .RDB (1'b0), // always enabled + .WADDR (wr_info_pointer), + .RADDR (rd_info_pointer) + ); +`else +`ifdef XILINX_RAM + + RAMB4_S8_S8 fifo + ( + .DOA(), + .DOB(data_out), + .ADDRA({3'h0, wr_pointer}), + .CLKA(clk), + .DIA(data_in), + .ENA(1'b1), + .RSTA(1'b0), + .WEA(wr & (~fifo_full)), + .ADDRB({3'h0, read_address}), + .CLKB(clk), + .DIB(8'h0), + .ENB(1'b1), + .RSTB(1'b0), + .WEB(1'b0) + ); + + + RAMB4_S4_S4 info_fifo + ( + .DOA(), + .DOB(length_info), + .ADDRA({4'h0, wr_info_pointer}), + .CLKA(clk), + .DIA(len_cnt & {4{~initialize_memories}}), + .ENA(1'b1), + .RSTA(1'b0), + .WEA(write_length_info & (~info_full) | initialize_memories), + .ADDRB({4'h0, rd_info_pointer}), + .CLKB(clk), + .DIB(4'h0), + .ENB(1'b1), + .RSTB(1'b0), + .WEB(1'b0) + ); + + + RAMB4_S1_S1 overrun_fifo + ( + .DOA(), + .DOB(overrun), + .ADDRA({6'h0, wr_info_pointer}), + .CLKA(clk), + .DIA((latch_overrun | (wr & fifo_full)) & (~initialize_memories)), + .ENA(1'b1), + .RSTA(1'b0), + .WEA(write_length_info & (~info_full) | initialize_memories), + .ADDRB({6'h0, rd_info_pointer}), + .CLKB(clk), + .DIB(1'h0), + .ENB(1'b1), + .RSTB(1'b0), + .WEB(1'b0) + ); + + +`else +`ifdef VIRTUALSILICON_RAM + +`ifdef CAN_BIST + vs_hdtp_64x8_bist fifo +`else + vs_hdtp_64x8 fifo +`endif + ( + .RCK (clk), + .WCK (clk), + .RADR (read_address), + .WADR (wr_pointer), + .DI (data_in), + .DOUT (data_out), + .REN (~fifo_selected), + .WEN (~(wr & (~fifo_full))) + `ifdef CAN_BIST + , + // debug chain signals + .mbist_si_i (mbist_si_i), + .mbist_so_o (mbist_s_0), + .mbist_ctrl_i (mbist_ctrl_i) + `endif + ); + +`ifdef CAN_BIST + vs_hdtp_64x4_bist info_fifo +`else + vs_hdtp_64x4 info_fifo +`endif + ( + .RCK (clk), + .WCK (clk), + .RADR (rd_info_pointer), + .WADR (wr_info_pointer), + .DI (len_cnt & {4{~initialize_memories}}), + .DOUT (length_info), + .REN (1'b0), + .WEN (~(write_length_info & (~info_full) | initialize_memories)) + `ifdef CAN_BIST + , + // debug chain signals + .mbist_si_i (mbist_s_0), + .mbist_so_o (mbist_so_o), + .mbist_ctrl_i (mbist_ctrl_i) + `endif + ); + + // overrun_info + always @ (posedge clk) + begin + if (write_length_info & (~info_full) | initialize_memories) + overrun_info[wr_info_pointer] <=#Tp (latch_overrun | (wr & fifo_full)) & (~initialize_memories); + end + + + // reading overrun + assign overrun = overrun_info[rd_info_pointer]; + +`else +`ifdef ARTISAN_RAM + +`ifdef CAN_BIST + art_hstp_64x8_bist fifo + ( + .CLKR (clk), + .CLKW (clk), + .AR (read_address), + .AW (wr_pointer), + .D (data_in), + .Q (data_out), + .REN (~fifo_selected), + .WEN (~(wr & (~fifo_full))), + .mbist_si_i (mbist_si_i), + .mbist_so_o (mbist_s_0), + .mbist_ctrl_i (mbist_ctrl_i) + ); + art_hstp_64x4_bist info_fifo + ( + .CLKR (clk), + .CLKW (clk), + .AR (rd_info_pointer), + .AW (wr_info_pointer), + .D (len_cnt & {4{~initialize_memories}}), + .Q (length_info), + .REN (1'b0), + .WEN (~(write_length_info & (~info_full) | initialize_memories)), + .mbist_si_i (mbist_s_0), + .mbist_so_o (mbist_so_o), + .mbist_ctrl_i (mbist_ctrl_i) + ); +`else + art_hsdp_64x8 fifo + ( + .CENA (1'b0), + .CENB (1'b0), + .CLKA (clk), + .CLKB (clk), + .AA (read_address), + .AB (wr_pointer), + .DA (8'h00), + .DB (data_in), + .QA (data_out), + .QB (), + .OENA (~fifo_selected), + .OENB (1'b1), + .WENA (1'b1), + .WENB (~(wr & (~fifo_full))) + ); + art_hsdp_64x4 info_fifo + ( + .CENA (1'b0), + .CENB (1'b0), + .CLKA (clk), + .CLKB (clk), + .AA (rd_info_pointer), + .AB (wr_info_pointer), + .DA (4'h0), + .DB (len_cnt & {4{~initialize_memories}}), + .QA (length_info), + .QB (), + .OENA (1'b0), + .OENB (1'b1), + .WENA (1'b1), + .WENB (~(write_length_info & (~info_full) | initialize_memories)) + ); +`endif + + // overrun_info + always @ (posedge clk) + begin + if (write_length_info & (~info_full) | initialize_memories) + overrun_info[wr_info_pointer] <=#Tp (latch_overrun | (wr & fifo_full)) & (~initialize_memories); + end + + + // reading overrun + assign overrun = overrun_info[rd_info_pointer]; + +`else + // writing data to fifo + always @ (posedge clk) + begin + if (wr & (~fifo_full)) + fifo[wr_pointer] <=#Tp data_in; + end + + // reading from fifo + assign data_out = fifo[read_address]; + + + // writing length_fifo + always @ (posedge clk) + begin + if (write_length_info & (~info_full) | initialize_memories) + length_fifo[wr_info_pointer] <=#Tp len_cnt & {4{~initialize_memories}}; + end + + + // reading length_fifo + assign length_info = length_fifo[rd_info_pointer]; + + // overrun_info + always @ (posedge clk) + begin + if (write_length_info & (~info_full) | initialize_memories) + overrun_info[wr_info_pointer] <=#Tp (latch_overrun | (wr & fifo_full)) & (~initialize_memories); + end + + + // reading overrun + assign overrun = overrun_info[rd_info_pointer]; + + +`endif +`endif +`endif +`endif +`endif + + + + + +endmodule diff --git a/soc/peripheral/can_ibo.v b/soc/peripheral/can_ibo.v new file mode 100644 index 0000000..e990108 --- /dev/null +++ b/soc/peripheral/can_ibo.v @@ -0,0 +1,69 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_ibo.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// This module only inverts bit order +module can_ibo +( + di, + do +); + +input [7:0] di; +output [7:0] do; + +assign do[0] = di[7]; +assign do[1] = di[6]; +assign do[2] = di[5]; +assign do[3] = di[4]; +assign do[4] = di[3]; +assign do[5] = di[2]; +assign do[6] = di[1]; +assign do[7] = di[0]; + +endmodule diff --git a/soc/peripheral/can_register.v b/soc/peripheral/can_register.v new file mode 100755 index 0000000..b4fe8b4 --- /dev/null +++ b/soc/peripheral/can_register.v @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_register.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on + + +module can_register +( data_in, + data_out, + we, + clk +); + +parameter WIDTH = 8; // default parameter of the register width + +input [WIDTH-1:0] data_in; +input we; +input clk; + +output [WIDTH-1:0] data_out; +reg [WIDTH-1:0] data_out; + + + +always @ (posedge clk) +begin + if (we) // write + data_out<=#1 data_in; +end + + + +endmodule diff --git a/soc/peripheral/can_register_asyn.v b/soc/peripheral/can_register_asyn.v new file mode 100755 index 0000000..738cb8a --- /dev/null +++ b/soc/peripheral/can_register_asyn.v @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_register_asyn.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on + + +module can_register_asyn +( data_in, + data_out, + we, + clk, + rst +); + +parameter WIDTH = 8; // default parameter of the register width +parameter RESET_VALUE = 0; + +input [WIDTH-1:0] data_in; +input we; +input clk; +input rst; + +output [WIDTH-1:0] data_out; +reg [WIDTH-1:0] data_out; + + + +always @ (posedge clk or posedge rst) +begin + if (rst) // asynchronous reset + data_out<=#1 RESET_VALUE; + else if (we) // write + data_out<=#1 data_in; +end + + + +endmodule diff --git a/soc/peripheral/can_register_asyn_syn.v b/soc/peripheral/can_register_asyn_syn.v new file mode 100755 index 0000000..b53f68d --- /dev/null +++ b/soc/peripheral/can_register_asyn_syn.v @@ -0,0 +1,90 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_register_asyn_syn.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on + + +module can_register_asyn_syn +( data_in, + data_out, + we, + clk, + rst, + rst_sync +); + +parameter WIDTH = 8; // default parameter of the register width +parameter RESET_VALUE = 0; + +input [WIDTH-1:0] data_in; +input we; +input clk; +input rst; +input rst_sync; + +output [WIDTH-1:0] data_out; +reg [WIDTH-1:0] data_out; + + + +always @ (posedge clk or posedge rst) +begin + if(rst) + data_out<=#1 RESET_VALUE; + else if (rst_sync) // synchronous reset + data_out<=#1 RESET_VALUE; + else if (we) // write + data_out<=#1 data_in; +end + + + +endmodule diff --git a/soc/peripheral/can_register_syn.v b/soc/peripheral/can_register_syn.v new file mode 100755 index 0000000..24094a0 --- /dev/null +++ b/soc/peripheral/can_register_syn.v @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_register_syn.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on + + +module can_register_syn +( data_in, + data_out, + we, + clk, + rst_sync +); + +parameter WIDTH = 8; // default parameter of the register width +parameter RESET_VALUE = 0; + +input [WIDTH-1:0] data_in; +input we; +input clk; +input rst_sync; + +output [WIDTH-1:0] data_out; +reg [WIDTH-1:0] data_out; + + + +always @ (posedge clk) +begin + if (rst_sync) // synchronous reset + data_out<=#1 RESET_VALUE; + else if (we) // write + data_out<=#1 data_in; +end + + + +endmodule diff --git a/soc/peripheral/can_registers.v b/soc/peripheral/can_registers.v new file mode 100755 index 0000000..c30ea9b --- /dev/null +++ b/soc/peripheral/can_registers.v @@ -0,0 +1,1138 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_registers.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +// `include "timescale.v" +// synopsys translate_on +`include "can_defines.v" + +module can_registers +( + clk, + rst, + cs, + we, + addr, + data_in, + data_out, + irq_n, + + sample_point, + transmitting, + set_reset_mode, + node_bus_off, + error_status, + rx_err_cnt, + tx_err_cnt, + transmit_status, + receive_status, + tx_successful, + need_to_tx, + overrun, + info_empty, + set_bus_error_irq, + set_arbitration_lost_irq, + arbitration_lost_capture, + node_error_passive, + node_error_active, + rx_message_counter, + + + /* Mode register */ + reset_mode, + listen_only_mode, + acceptance_filter_mode, + self_test_mode, + + + /* Command register */ + clear_data_overrun, + release_buffer, + abort_tx, + tx_request, + self_rx_request, + single_shot_transmission, + tx_state, + tx_state_q, + overload_request, + overload_frame, + + /* Arbitration Lost Capture Register */ + read_arbitration_lost_capture_reg, + + /* Error Code Capture Register */ + read_error_code_capture_reg, + error_capture_code, + + /* Bus Timing 0 register */ + baud_r_presc, + sync_jump_width, + + /* Bus Timing 1 register */ + time_segment1, + time_segment2, + triple_sampling, + + /* Error Warning Limit register */ + error_warning_limit, + + /* Rx Error Counter register */ + we_rx_err_cnt, + + /* Tx Error Counter register */ + we_tx_err_cnt, + + /* Clock Divider register */ + extended_mode, + clkout, + + + /* This section is for BASIC and EXTENDED mode */ + /* Acceptance code register */ + acceptance_code_0, + + /* Acceptance mask register */ + acceptance_mask_0, + /* End: This section is for BASIC and EXTENDED mode */ + + /* This section is for EXTENDED mode */ + /* Acceptance code register */ + acceptance_code_1, + acceptance_code_2, + acceptance_code_3, + + /* Acceptance mask register */ + acceptance_mask_1, + acceptance_mask_2, + acceptance_mask_3, + /* End: This section is for EXTENDED mode */ + + /* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ + tx_data_0, + tx_data_1, + tx_data_2, + tx_data_3, + tx_data_4, + tx_data_5, + tx_data_6, + tx_data_7, + tx_data_8, + tx_data_9, + tx_data_10, + tx_data_11, + tx_data_12 + /* End: Tx data registers */ + + + + +); + +parameter Tp = 1; + +input clk; +input rst; +input cs; +input we; +input [7:0] addr; +input [7:0] data_in; + +output [7:0] data_out; +reg [7:0] data_out; + +output irq_n; + +input sample_point; +input transmitting; +input set_reset_mode; +input node_bus_off; +input error_status; +input [7:0] rx_err_cnt; +input [7:0] tx_err_cnt; +input transmit_status; +input receive_status; +input tx_successful; +input need_to_tx; +input overrun; +input info_empty; +input set_bus_error_irq; +input set_arbitration_lost_irq; +input [4:0] arbitration_lost_capture; +input node_error_passive; +input node_error_active; +input [6:0] rx_message_counter; + + + +/* Mode register */ +output reset_mode; +output listen_only_mode; +output acceptance_filter_mode; +output self_test_mode; + +/* Command register */ +output clear_data_overrun; +output release_buffer; +output abort_tx; +output tx_request; +output self_rx_request; +output single_shot_transmission; +input tx_state; +input tx_state_q; +output overload_request; +input overload_frame; + + +/* Arbitration Lost Capture Register */ +output read_arbitration_lost_capture_reg; + +/* Error Code Capture Register */ +output read_error_code_capture_reg; +input [7:0] error_capture_code; + +/* Bus Timing 0 register */ +output [5:0] baud_r_presc; +output [1:0] sync_jump_width; + + +/* Bus Timing 1 register */ +output [3:0] time_segment1; +output [2:0] time_segment2; +output triple_sampling; + +/* Error Warning Limit register */ +output [7:0] error_warning_limit; + +/* Rx Error Counter register */ +output we_rx_err_cnt; + +/* Tx Error Counter register */ +output we_tx_err_cnt; + +/* Clock Divider register */ +output extended_mode; +output clkout; + + +/* This section is for BASIC and EXTENDED mode */ +/* Acceptance code register */ +output [7:0] acceptance_code_0; + +/* Acceptance mask register */ +output [7:0] acceptance_mask_0; + +/* End: This section is for BASIC and EXTENDED mode */ + + +/* This section is for EXTENDED mode */ +/* Acceptance code register */ +output [7:0] acceptance_code_1; +output [7:0] acceptance_code_2; +output [7:0] acceptance_code_3; + +/* Acceptance mask register */ +output [7:0] acceptance_mask_1; +output [7:0] acceptance_mask_2; +output [7:0] acceptance_mask_3; + +/* End: This section is for EXTENDED mode */ + +/* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ +output [7:0] tx_data_0; +output [7:0] tx_data_1; +output [7:0] tx_data_2; +output [7:0] tx_data_3; +output [7:0] tx_data_4; +output [7:0] tx_data_5; +output [7:0] tx_data_6; +output [7:0] tx_data_7; +output [7:0] tx_data_8; +output [7:0] tx_data_9; +output [7:0] tx_data_10; +output [7:0] tx_data_11; +output [7:0] tx_data_12; +/* End: Tx data registers */ + + +reg tx_successful_q; +reg overrun_q; +reg overrun_status; +reg transmission_complete; +reg transmit_buffer_status_q; +reg receive_buffer_status; +reg error_status_q; +reg node_bus_off_q; +reg node_error_passive_q; +reg transmit_buffer_status; +reg single_shot_transmission; +reg self_rx_request; +reg irq_n; + +// Some interrupts exist in basic mode and in extended mode. Since they are in different registers they need to be multiplexed. +wire data_overrun_irq_en; +wire error_warning_irq_en; +wire transmit_irq_en; +wire receive_irq_en; + +wire [7:0] irq_reg; +wire irq; + +wire we_mode = cs & we & (addr == 8'd0); +wire we_command = cs & we & (addr == 8'd1); +wire we_bus_timing_0 = cs & we & (addr == 8'd6) & reset_mode; +wire we_bus_timing_1 = cs & we & (addr == 8'd7) & reset_mode; +wire we_clock_divider_low = cs & we & (addr == 8'd31); +wire we_clock_divider_hi = we_clock_divider_low & reset_mode; + +wire read = cs & (~we); +wire read_irq_reg = read & (addr == 8'd3); +assign read_arbitration_lost_capture_reg = read & extended_mode & (addr == 8'd11); +assign read_error_code_capture_reg = read & extended_mode & (addr == 8'd12); + +/* This section is for BASIC and EXTENDED mode */ +wire we_acceptance_code_0 = cs & we & reset_mode & ((~extended_mode) & (addr == 8'd4) | extended_mode & (addr == 8'd16)); +wire we_acceptance_mask_0 = cs & we & reset_mode & ((~extended_mode) & (addr == 8'd5) | extended_mode & (addr == 8'd20)); +wire we_tx_data_0 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd10) | extended_mode & (addr == 8'd16)) & transmit_buffer_status; +wire we_tx_data_1 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd11) | extended_mode & (addr == 8'd17)) & transmit_buffer_status; +wire we_tx_data_2 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd12) | extended_mode & (addr == 8'd18)) & transmit_buffer_status; +wire we_tx_data_3 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd13) | extended_mode & (addr == 8'd19)) & transmit_buffer_status; +wire we_tx_data_4 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd14) | extended_mode & (addr == 8'd20)) & transmit_buffer_status; +wire we_tx_data_5 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd15) | extended_mode & (addr == 8'd21)) & transmit_buffer_status; +wire we_tx_data_6 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd16) | extended_mode & (addr == 8'd22)) & transmit_buffer_status; +wire we_tx_data_7 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd17) | extended_mode & (addr == 8'd23)) & transmit_buffer_status; +wire we_tx_data_8 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd18) | extended_mode & (addr == 8'd24)) & transmit_buffer_status; +wire we_tx_data_9 = cs & we & (~reset_mode) & ((~extended_mode) & (addr == 8'd19) | extended_mode & (addr == 8'd25)) & transmit_buffer_status; +wire we_tx_data_10 = cs & we & (~reset_mode) & ( extended_mode & (addr == 8'd26)) & transmit_buffer_status; +wire we_tx_data_11 = cs & we & (~reset_mode) & ( extended_mode & (addr == 8'd27)) & transmit_buffer_status; +wire we_tx_data_12 = cs & we & (~reset_mode) & ( extended_mode & (addr == 8'd28)) & transmit_buffer_status; +/* End: This section is for BASIC and EXTENDED mode */ + + +/* This section is for EXTENDED mode */ +wire we_interrupt_enable = cs & we & (addr == 8'd4) & extended_mode; +wire we_error_warning_limit = cs & we & (addr == 8'd13) & reset_mode & extended_mode; +assign we_rx_err_cnt = cs & we & (addr == 8'd14) & reset_mode & extended_mode; +assign we_tx_err_cnt = cs & we & (addr == 8'd15) & reset_mode & extended_mode; +wire we_acceptance_code_1 = cs & we & (addr == 8'd17) & reset_mode & extended_mode; +wire we_acceptance_code_2 = cs & we & (addr == 8'd18) & reset_mode & extended_mode; +wire we_acceptance_code_3 = cs & we & (addr == 8'd19) & reset_mode & extended_mode; +wire we_acceptance_mask_1 = cs & we & (addr == 8'd21) & reset_mode & extended_mode; +wire we_acceptance_mask_2 = cs & we & (addr == 8'd22) & reset_mode & extended_mode; +wire we_acceptance_mask_3 = cs & we & (addr == 8'd23) & reset_mode & extended_mode; +/* End: This section is for EXTENDED mode */ + + + +always @ (posedge clk) +begin + tx_successful_q <=#Tp tx_successful; + overrun_q <=#Tp overrun; + transmit_buffer_status_q <=#Tp transmit_buffer_status; + error_status_q <=#Tp error_status; + node_bus_off_q <=#Tp node_bus_off; + node_error_passive_q <=#Tp node_error_passive; +end + + + +/* Mode register */ +wire [0:0] mode; +wire [4:1] mode_basic; +wire [3:1] mode_ext; +wire receive_irq_en_basic; +wire transmit_irq_en_basic; +wire error_irq_en_basic; +wire overrun_irq_en_basic; + +can_register_asyn_syn #(1, 1'h1) MODE_REG0 +( .data_in(data_in[0]), + .data_out(mode[0]), + .we(we_mode), + .clk(clk), + .rst(rst), + .rst_sync(set_reset_mode) +); + +can_register_asyn #(4, 0) MODE_REG_BASIC +( .data_in(data_in[4:1]), + .data_out(mode_basic[4:1]), + .we(we_mode), + .clk(clk), + .rst(rst) +); + +can_register_asyn #(3, 0) MODE_REG_EXT +( .data_in(data_in[3:1]), + .data_out(mode_ext[3:1]), + .we(we_mode & reset_mode), + .clk(clk), + .rst(rst) +); + +assign reset_mode = mode[0]; +assign listen_only_mode = extended_mode & mode_ext[1]; +assign self_test_mode = extended_mode & mode_ext[2]; +assign acceptance_filter_mode = extended_mode & mode_ext[3]; + +assign receive_irq_en_basic = mode_basic[1]; +assign transmit_irq_en_basic = mode_basic[2]; +assign error_irq_en_basic = mode_basic[3]; +assign overrun_irq_en_basic = mode_basic[4]; +/* End Mode register */ + + +/* Command register */ +wire [4:0] command; +can_register_asyn_syn #(1, 1'h0) COMMAND_REG0 +( .data_in(data_in[0]), + .data_out(command[0]), + .we(we_command), + .clk(clk), + .rst(rst), + .rst_sync(command[0] & sample_point | reset_mode) +); + +can_register_asyn_syn #(1, 1'h0) COMMAND_REG1 +( .data_in(data_in[1]), + .data_out(command[1]), + .we(we_command), + .clk(clk), + .rst(rst), + .rst_sync(sample_point & (tx_request | (abort_tx & ~transmitting)) | reset_mode) +); + +can_register_asyn_syn #(2, 2'h0) COMMAND_REG +( .data_in(data_in[3:2]), + .data_out(command[3:2]), + .we(we_command), + .clk(clk), + .rst(rst), + .rst_sync(|command[3:2] | reset_mode) +); + +can_register_asyn_syn #(1, 1'h0) COMMAND_REG4 +( .data_in(data_in[4]), + .data_out(command[4]), + .we(we_command), + .clk(clk), + .rst(rst), + .rst_sync(command[4] & sample_point | reset_mode) +); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + self_rx_request <= 1'b0; + else if (command[4] & (~command[0])) + self_rx_request <=#Tp 1'b1; + else if ((~tx_state) & tx_state_q) + self_rx_request <=#Tp 1'b0; +end + + +assign clear_data_overrun = command[3]; +assign release_buffer = command[2]; +assign tx_request = command[0] | command[4]; +assign abort_tx = command[1] & (~tx_request); + + +always @ (posedge clk or posedge rst) +begin + if (rst) + single_shot_transmission <= 1'b0; + else if (tx_request & command[1] & sample_point) + single_shot_transmission <=#Tp 1'b1; + else if ((~tx_state) & tx_state_q) + single_shot_transmission <=#Tp 1'b0; +end + + +/* +can_register_asyn_syn #(1, 1'h0) COMMAND_REG_OVERLOAD // Uncomment this to enable overload requests !!! +( .data_in(data_in[5]), + .data_out(overload_request), + .we(we_command), + .clk(clk), + .rst(rst), + .rst_sync(overload_frame & ~overload_frame_q) +); + +reg overload_frame_q; + +always @ (posedge clk or posedge rst) +begin + if (rst) + overload_frame_q <= 1'b0; + else + overload_frame_q <=#Tp overload_frame; +end +*/ +assign overload_request = 0; // Overload requests are not supported, yet !!! + + + + + +/* End Command register */ + + +/* Status register */ + +wire [7:0] status; + +assign status[7] = node_bus_off; +assign status[6] = error_status; +assign status[5] = transmit_status; +assign status[4] = receive_status; +assign status[3] = transmission_complete; +assign status[2] = transmit_buffer_status; +assign status[1] = overrun_status; +assign status[0] = receive_buffer_status; + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + transmission_complete <= 1'b1; + else if (tx_successful & (~tx_successful_q) | abort_tx) + transmission_complete <=#Tp 1'b1; + else if (tx_request) + transmission_complete <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + transmit_buffer_status <= 1'b1; + else if (tx_request) + transmit_buffer_status <=#Tp 1'b0; + else if (reset_mode || !need_to_tx) + transmit_buffer_status <=#Tp 1'b1; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + overrun_status <= 1'b0; + else if (overrun & (~overrun_q)) + overrun_status <=#Tp 1'b1; + else if (reset_mode || clear_data_overrun) + overrun_status <=#Tp 1'b0; +end + + +always @ (posedge clk or posedge rst) +begin + if (rst) + receive_buffer_status <= 1'b0; + else if (reset_mode || release_buffer) + receive_buffer_status <=#Tp 1'b0; + else if (~info_empty) + receive_buffer_status <=#Tp 1'b1; +end + +/* End Status register */ + + +/* Interrupt Enable register (extended mode) */ +wire [7:0] irq_en_ext; +wire bus_error_irq_en; +wire arbitration_lost_irq_en; +wire error_passive_irq_en; +wire data_overrun_irq_en_ext; +wire error_warning_irq_en_ext; +wire transmit_irq_en_ext; +wire receive_irq_en_ext; + +can_register #(8) IRQ_EN_REG +( .data_in(data_in), + .data_out(irq_en_ext), + .we(we_interrupt_enable), + .clk(clk) +); + + +assign bus_error_irq_en = irq_en_ext[7]; +assign arbitration_lost_irq_en = irq_en_ext[6]; +assign error_passive_irq_en = irq_en_ext[5]; +assign data_overrun_irq_en_ext = irq_en_ext[3]; +assign error_warning_irq_en_ext = irq_en_ext[2]; +assign transmit_irq_en_ext = irq_en_ext[1]; +assign receive_irq_en_ext = irq_en_ext[0]; +/* End Bus Timing 0 register */ + + +/* Bus Timing 0 register */ +wire [7:0] bus_timing_0; +can_register #(8) BUS_TIMING_0_REG +( .data_in(data_in), + .data_out(bus_timing_0), + .we(we_bus_timing_0), + .clk(clk) +); + +assign baud_r_presc = bus_timing_0[5:0]; +assign sync_jump_width = bus_timing_0[7:6]; +/* End Bus Timing 0 register */ + + +/* Bus Timing 1 register */ +wire [7:0] bus_timing_1; +can_register #(8) BUS_TIMING_1_REG +( .data_in(data_in), + .data_out(bus_timing_1), + .we(we_bus_timing_1), + .clk(clk) +); + +assign time_segment1 = bus_timing_1[3:0]; +assign time_segment2 = bus_timing_1[6:4]; +assign triple_sampling = bus_timing_1[7]; +/* End Bus Timing 1 register */ + + +/* Error Warning Limit register */ +can_register_asyn #(8, 96) ERROR_WARNING_REG +( .data_in(data_in), + .data_out(error_warning_limit), + .we(we_error_warning_limit), + .clk(clk), + .rst(rst) +); +/* End Error Warning Limit register */ + + + +/* Clock Divider register */ +wire [7:0] clock_divider; +wire clock_off; +wire [2:0] cd; +reg [2:0] clkout_div; +reg [2:0] clkout_cnt; +reg clkout_tmp; + +can_register_asyn #(1, 0) CLOCK_DIVIDER_REG_7 +( .data_in(data_in[7]), + .data_out(clock_divider[7]), + .we(we_clock_divider_hi), + .clk(clk), + .rst(rst) +); + +assign clock_divider[6:4] = 3'h0; + +can_register_asyn #(1, 0) CLOCK_DIVIDER_REG_3 +( .data_in(data_in[3]), + .data_out(clock_divider[3]), + .we(we_clock_divider_hi), + .clk(clk), + .rst(rst) +); + +can_register_asyn #(3, 0) CLOCK_DIVIDER_REG_LOW +( .data_in(data_in[2:0]), + .data_out(clock_divider[2:0]), + .we(we_clock_divider_low), + .clk(clk), + .rst(rst) +); + +assign extended_mode = clock_divider[7]; +assign clock_off = clock_divider[3]; +assign cd[2:0] = clock_divider[2:0]; + + + +always @ (cd) +begin + case (cd) /* synthesis full_case parallel_case */ + 3'b000 : clkout_div = 3'd0; + 3'b001 : clkout_div = 3'd1; + 3'b010 : clkout_div = 3'd2; + 3'b011 : clkout_div = 3'd3; + 3'b100 : clkout_div = 3'd4; + 3'b101 : clkout_div = 3'd5; + 3'b110 : clkout_div = 3'd6; + 3'b111 : clkout_div = 3'd0; + endcase +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + clkout_cnt <= 3'h0; + else if (clkout_cnt == clkout_div) + clkout_cnt <=#Tp 3'h0; + else + clkout_cnt <= clkout_cnt + 1'b1; +end + + + +always @ (posedge clk or posedge rst) +begin + if (rst) + clkout_tmp <= 1'b0; + else if (clkout_cnt == clkout_div) + clkout_tmp <=#Tp ~clkout_tmp; +end + + +assign clkout = clock_off ? 1'b1 : ((&cd)? clk : clkout_tmp); + + + +/* End Clock Divider register */ + + + + +/* This section is for BASIC and EXTENDED mode */ + +/* Acceptance code register */ +can_register #(8) ACCEPTANCE_CODE_REG0 +( .data_in(data_in), + .data_out(acceptance_code_0), + .we(we_acceptance_code_0), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance mask register */ +can_register #(8) ACCEPTANCE_MASK_REG0 +( .data_in(data_in), + .data_out(acceptance_mask_0), + .we(we_acceptance_mask_0), + .clk(clk) +); +/* End: Acceptance mask register */ +/* End: This section is for BASIC and EXTENDED mode */ + + +/* Tx data 0 register. */ +can_register #(8) TX_DATA_REG0 +( .data_in(data_in), + .data_out(tx_data_0), + .we(we_tx_data_0), + .clk(clk) +); +/* End: Tx data 0 register. */ + + +/* Tx data 1 register. */ +can_register #(8) TX_DATA_REG1 +( .data_in(data_in), + .data_out(tx_data_1), + .we(we_tx_data_1), + .clk(clk) +); +/* End: Tx data 1 register. */ + + +/* Tx data 2 register. */ +can_register #(8) TX_DATA_REG2 +( .data_in(data_in), + .data_out(tx_data_2), + .we(we_tx_data_2), + .clk(clk) +); +/* End: Tx data 2 register. */ + + +/* Tx data 3 register. */ +can_register #(8) TX_DATA_REG3 +( .data_in(data_in), + .data_out(tx_data_3), + .we(we_tx_data_3), + .clk(clk) +); +/* End: Tx data 3 register. */ + + +/* Tx data 4 register. */ +can_register #(8) TX_DATA_REG4 +( .data_in(data_in), + .data_out(tx_data_4), + .we(we_tx_data_4), + .clk(clk) +); +/* End: Tx data 4 register. */ + + +/* Tx data 5 register. */ +can_register #(8) TX_DATA_REG5 +( .data_in(data_in), + .data_out(tx_data_5), + .we(we_tx_data_5), + .clk(clk) +); +/* End: Tx data 5 register. */ + + +/* Tx data 6 register. */ +can_register #(8) TX_DATA_REG6 +( .data_in(data_in), + .data_out(tx_data_6), + .we(we_tx_data_6), + .clk(clk) +); +/* End: Tx data 6 register. */ + + +/* Tx data 7 register. */ +can_register #(8) TX_DATA_REG7 +( .data_in(data_in), + .data_out(tx_data_7), + .we(we_tx_data_7), + .clk(clk) +); +/* End: Tx data 7 register. */ + + +/* Tx data 8 register. */ +can_register #(8) TX_DATA_REG8 +( .data_in(data_in), + .data_out(tx_data_8), + .we(we_tx_data_8), + .clk(clk) +); +/* End: Tx data 8 register. */ + + +/* Tx data 9 register. */ +can_register #(8) TX_DATA_REG9 +( .data_in(data_in), + .data_out(tx_data_9), + .we(we_tx_data_9), + .clk(clk) +); +/* End: Tx data 9 register. */ + + +/* Tx data 10 register. */ +can_register #(8) TX_DATA_REG10 +( .data_in(data_in), + .data_out(tx_data_10), + .we(we_tx_data_10), + .clk(clk) +); +/* End: Tx data 10 register. */ + + +/* Tx data 11 register. */ +can_register #(8) TX_DATA_REG11 +( .data_in(data_in), + .data_out(tx_data_11), + .we(we_tx_data_11), + .clk(clk) +); +/* End: Tx data 11 register. */ + + +/* Tx data 12 register. */ +can_register #(8) TX_DATA_REG12 +( .data_in(data_in), + .data_out(tx_data_12), + .we(we_tx_data_12), + .clk(clk) +); +/* End: Tx data 12 register. */ + + + + + +/* This section is for EXTENDED mode */ + +/* Acceptance code register 1 */ +can_register #(8) ACCEPTANCE_CODE_REG1 +( .data_in(data_in), + .data_out(acceptance_code_1), + .we(we_acceptance_code_1), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance code register 2 */ +can_register #(8) ACCEPTANCE_CODE_REG2 +( .data_in(data_in), + .data_out(acceptance_code_2), + .we(we_acceptance_code_2), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance code register 3 */ +can_register #(8) ACCEPTANCE_CODE_REG3 +( .data_in(data_in), + .data_out(acceptance_code_3), + .we(we_acceptance_code_3), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance mask register 1 */ +can_register #(8) ACCEPTANCE_MASK_REG1 +( .data_in(data_in), + .data_out(acceptance_mask_1), + .we(we_acceptance_mask_1), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance mask register 2 */ +can_register #(8) ACCEPTANCE_MASK_REG2 +( .data_in(data_in), + .data_out(acceptance_mask_2), + .we(we_acceptance_mask_2), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* Acceptance mask register 3 */ +can_register #(8) ACCEPTANCE_MASK_REG3 +( .data_in(data_in), + .data_out(acceptance_mask_3), + .we(we_acceptance_mask_3), + .clk(clk) +); +/* End: Acceptance code register */ + + +/* End: This section is for EXTENDED mode */ + + + + +// Reading data from registers +always @ ( addr or extended_mode or mode or bus_timing_0 or bus_timing_1 or clock_divider or + acceptance_code_0 or acceptance_code_1 or acceptance_code_2 or acceptance_code_3 or + acceptance_mask_0 or acceptance_mask_1 or acceptance_mask_2 or acceptance_mask_3 or + reset_mode or tx_data_0 or tx_data_1 or tx_data_2 or tx_data_3 or tx_data_4 or + tx_data_5 or tx_data_6 or tx_data_7 or tx_data_8 or tx_data_9 or status or + error_warning_limit or rx_err_cnt or tx_err_cnt or irq_en_ext or irq_reg or mode_ext or + arbitration_lost_capture or rx_message_counter or mode_basic or error_capture_code + ) +begin + case({extended_mode, addr[4:0]}) /* synthesis parallel_case */ + {1'h1, 5'd00} : data_out = {4'b0000, mode_ext[3:1], mode[0]}; // extended mode + {1'h1, 5'd01} : data_out = 8'h0; // extended mode + {1'h1, 5'd02} : data_out = status; // extended mode + {1'h1, 5'd03} : data_out = irq_reg; // extended mode + {1'h1, 5'd04} : data_out = irq_en_ext; // extended mode + {1'h1, 5'd06} : data_out = bus_timing_0; // extended mode + {1'h1, 5'd07} : data_out = bus_timing_1; // extended mode + {1'h1, 5'd11} : data_out = {3'h0, arbitration_lost_capture[4:0]}; // extended mode + {1'h1, 5'd12} : data_out = error_capture_code; // extended mode + {1'h1, 5'd13} : data_out = error_warning_limit; // extended mode + {1'h1, 5'd14} : data_out = rx_err_cnt; // extended mode + {1'h1, 5'd15} : data_out = tx_err_cnt; // extended mode + {1'h1, 5'd16} : data_out = acceptance_code_0; // extended mode + {1'h1, 5'd17} : data_out = acceptance_code_1; // extended mode + {1'h1, 5'd18} : data_out = acceptance_code_2; // extended mode + {1'h1, 5'd19} : data_out = acceptance_code_3; // extended mode + {1'h1, 5'd20} : data_out = acceptance_mask_0; // extended mode + {1'h1, 5'd21} : data_out = acceptance_mask_1; // extended mode + {1'h1, 5'd22} : data_out = acceptance_mask_2; // extended mode + {1'h1, 5'd23} : data_out = acceptance_mask_3; // extended mode + {1'h1, 5'd24} : data_out = 8'h0; // extended mode + {1'h1, 5'd25} : data_out = 8'h0; // extended mode + {1'h1, 5'd26} : data_out = 8'h0; // extended mode + {1'h1, 5'd27} : data_out = 8'h0; // extended mode + {1'h1, 5'd28} : data_out = 8'h0; // extended mode + {1'h1, 5'd29} : data_out = {1'b0, rx_message_counter}; // extended mode + {1'h1, 5'd31} : data_out = clock_divider; // extended mode + {1'h0, 5'd00} : data_out = {3'b001, mode_basic[4:1], mode[0]}; // basic mode + {1'h0, 5'd01} : data_out = 8'hff; // basic mode + {1'h0, 5'd02} : data_out = status; // basic mode + {1'h0, 5'd03} : data_out = {4'he, irq_reg[3:0]}; // basic mode + {1'h0, 5'd04} : data_out = reset_mode? acceptance_code_0 : 8'hff; // basic mode + {1'h0, 5'd05} : data_out = reset_mode? acceptance_mask_0 : 8'hff; // basic mode + {1'h0, 5'd06} : data_out = reset_mode? bus_timing_0 : 8'hff; // basic mode + {1'h0, 5'd07} : data_out = reset_mode? bus_timing_1 : 8'hff; // basic mode + {1'h0, 5'd10} : data_out = reset_mode? 8'hff : tx_data_0; // basic mode + {1'h0, 5'd11} : data_out = reset_mode? 8'hff : tx_data_1; // basic mode + {1'h0, 5'd12} : data_out = reset_mode? 8'hff : tx_data_2; // basic mode + {1'h0, 5'd13} : data_out = reset_mode? 8'hff : tx_data_3; // basic mode + {1'h0, 5'd14} : data_out = reset_mode? 8'hff : tx_data_4; // basic mode + {1'h0, 5'd15} : data_out = reset_mode? 8'hff : tx_data_5; // basic mode + {1'h0, 5'd16} : data_out = reset_mode? 8'hff : tx_data_6; // basic mode + {1'h0, 5'd17} : data_out = reset_mode? 8'hff : tx_data_7; // basic mode + {1'h0, 5'd18} : data_out = reset_mode? 8'hff : tx_data_8; // basic mode + {1'h0, 5'd19} : data_out = reset_mode? 8'hff : tx_data_9; // basic mode + {1'h0, 5'd31} : data_out = clock_divider; // basic mode + default : data_out = 8'h0; // the rest is read as 0 + endcase +end + + +// Some interrupts exist in basic mode and in extended mode. Since they are in different registers they need to be multiplexed. +assign data_overrun_irq_en = extended_mode ? data_overrun_irq_en_ext : overrun_irq_en_basic; +assign error_warning_irq_en = extended_mode ? error_warning_irq_en_ext : error_irq_en_basic; +assign transmit_irq_en = extended_mode ? transmit_irq_en_ext : transmit_irq_en_basic; +assign receive_irq_en = extended_mode ? receive_irq_en_ext : receive_irq_en_basic; + + +reg data_overrun_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + data_overrun_irq <= 1'b0; + else if (overrun & (~overrun_q) & data_overrun_irq_en) + data_overrun_irq <=#Tp 1'b1; + else if (reset_mode || read_irq_reg) + data_overrun_irq <=#Tp 1'b0; +end + + +reg transmit_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + transmit_irq <= 1'b0; + else if (reset_mode || read_irq_reg) + transmit_irq <=#Tp 1'b0; + else if (transmit_buffer_status & (~transmit_buffer_status_q) & transmit_irq_en) + transmit_irq <=#Tp 1'b1; +end + + +reg receive_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + receive_irq <= 1'b0; + else if ((~info_empty) & (~receive_irq) & receive_irq_en) + receive_irq <=#Tp 1'b1; + else if (reset_mode || release_buffer) + receive_irq <=#Tp 1'b0; +end + + +reg error_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + error_irq <= 1'b0; + else if (((error_status ^ error_status_q) | (node_bus_off ^ node_bus_off_q)) & error_warning_irq_en) + error_irq <=#Tp 1'b1; + else if (read_irq_reg) + error_irq <=#Tp 1'b0; +end + + +reg bus_error_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + bus_error_irq <= 1'b0; + else if (set_bus_error_irq & bus_error_irq_en) + bus_error_irq <=#Tp 1'b1; + else if (reset_mode || read_irq_reg) + bus_error_irq <=#Tp 1'b0; +end + + +reg arbitration_lost_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + arbitration_lost_irq <= 1'b0; + else if (set_arbitration_lost_irq & arbitration_lost_irq_en) + arbitration_lost_irq <=#Tp 1'b1; + else if (reset_mode || read_irq_reg) + arbitration_lost_irq <=#Tp 1'b0; +end + + + +reg error_passive_irq; +always @ (posedge clk or posedge rst) +begin + if (rst) + error_passive_irq <= 1'b0; + else if ((node_error_passive & (~node_error_passive_q) | (~node_error_passive) & node_error_passive_q & node_error_active) & error_passive_irq_en) + error_passive_irq <=#Tp 1'b1; + else if (reset_mode || read_irq_reg) + error_passive_irq <=#Tp 1'b0; +end + + + +assign irq_reg = {bus_error_irq, arbitration_lost_irq, error_passive_irq, 1'b0, data_overrun_irq, error_irq, transmit_irq, receive_irq}; + +assign irq = data_overrun_irq | transmit_irq | receive_irq | error_irq | bus_error_irq | arbitration_lost_irq | error_passive_irq; + + +always @ (posedge clk or posedge rst) +begin + if (rst) + irq_n <= 1'b1; + else if (read_irq_reg || release_buffer) + irq_n <=#Tp 1'b1; + else if (irq) + irq_n <=#Tp 1'b0; +end + + + +endmodule + diff --git a/soc/peripheral/can_top.v b/soc/peripheral/can_top.v new file mode 100644 index 0000000..3dcc55e --- /dev/null +++ b/soc/peripheral/can_top.v @@ -0,0 +1,715 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// can_top.v //// +//// //// +//// //// +//// This file is part of the CAN Protocol Controller //// +//// http://www.opencores.org/projects/can/ //// +//// //// +//// //// +//// Author(s): //// +//// Igor Mohor //// +//// igorm@opencores.org //// +//// //// +//// //// +//// All additional information is available in the README.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002, 2003, 2004 Authors //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +//// The CAN protocol is developed by Robert Bosch GmbH and //// +//// protected by patents. Anybody who wants to implement this //// +//// CAN IP core on silicon has to obtain a CAN protocol license //// +//// from Bosch. //// +//// //// +////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +//`include "timescale.v" //commented this out, see what breaks... -TF +// synopsys translate_on +`include "can_defines.v" + +module can_top +( + `ifdef CAN_WISHBONE_IF + wb_clk_i, + wb_rst_i, + wb_dat_i, + wb_dat_o, + wb_cyc_i, + wb_stb_i, + wb_we_i, + wb_adr_i, + wb_ack_o, + `else + rst_i, + ale_i, + rd_i, + wr_i, + port_0_io, + cs_can_i, + `endif + clk_i, + rx_i, + tx_o, + bus_off_on, + irq_on, + clkout_o + + // Bist +`ifdef CAN_BIST + , + // debug chain signals + mbist_si_i, // bist scan serial in + mbist_so_o, // bist scan serial out + mbist_ctrl_i // bist chain shift control +`endif +); + +parameter Tp = 1; + + +`ifdef CAN_WISHBONE_IF + input wb_clk_i; + input wb_rst_i; + input [7:0] wb_dat_i; + output [7:0] wb_dat_o; + input wb_cyc_i; + input wb_stb_i; + input wb_we_i; + input [7:0] wb_adr_i; + output wb_ack_o; + + reg wb_ack_o; + reg cs_sync1; + reg cs_sync2; + reg cs_sync3; + + reg cs_ack1; + reg cs_ack2; + reg cs_ack3; + reg cs_sync_rst1; + reg cs_sync_rst2; + wire cs_can_i; +`else + input rst_i; + input ale_i; + input rd_i; + input wr_i; + inout [7:0] port_0_io; + input cs_can_i; + + reg [7:0] addr_latched; + reg wr_i_q; + reg rd_i_q; +`endif + +input clk_i; +input rx_i; +output tx_o; +output bus_off_on; +output irq_on; +output clkout_o; + +// Bist +`ifdef CAN_BIST +input mbist_si_i; // bist scan serial in +output mbist_so_o; // bist scan serial out +input [`CAN_MBIST_CTRL_WIDTH - 1:0] mbist_ctrl_i; // bist chain shift control +`endif + +reg data_out_fifo_selected; + + +wire [7:0] data_out_fifo; +wire [7:0] data_out_regs; + + +/* Mode register */ +wire reset_mode; +wire listen_only_mode; +wire acceptance_filter_mode; +wire self_test_mode; + +/* Command register */ +wire release_buffer; +wire tx_request; +wire abort_tx; +wire self_rx_request; +wire single_shot_transmission; +wire tx_state; +wire tx_state_q; +wire overload_request; +wire overload_frame; + + +/* Arbitration Lost Capture Register */ +wire read_arbitration_lost_capture_reg; + +/* Error Code Capture Register */ +wire read_error_code_capture_reg; +wire [7:0] error_capture_code; + +/* Bus Timing 0 register */ +wire [5:0] baud_r_presc; +wire [1:0] sync_jump_width; + +/* Bus Timing 1 register */ +wire [3:0] time_segment1; +wire [2:0] time_segment2; +wire triple_sampling; + +/* Error Warning Limit register */ +wire [7:0] error_warning_limit; + +/* Rx Error Counter register */ +wire we_rx_err_cnt; + +/* Tx Error Counter register */ +wire we_tx_err_cnt; + +/* Clock Divider register */ +wire extended_mode; + +/* This section is for BASIC and EXTENDED mode */ +/* Acceptance code register */ +wire [7:0] acceptance_code_0; + +/* Acceptance mask register */ +wire [7:0] acceptance_mask_0; +/* End: This section is for BASIC and EXTENDED mode */ + + +/* This section is for EXTENDED mode */ +/* Acceptance code register */ +wire [7:0] acceptance_code_1; +wire [7:0] acceptance_code_2; +wire [7:0] acceptance_code_3; + +/* Acceptance mask register */ +wire [7:0] acceptance_mask_1; +wire [7:0] acceptance_mask_2; +wire [7:0] acceptance_mask_3; +/* End: This section is for EXTENDED mode */ + +/* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ +wire [7:0] tx_data_0; +wire [7:0] tx_data_1; +wire [7:0] tx_data_2; +wire [7:0] tx_data_3; +wire [7:0] tx_data_4; +wire [7:0] tx_data_5; +wire [7:0] tx_data_6; +wire [7:0] tx_data_7; +wire [7:0] tx_data_8; +wire [7:0] tx_data_9; +wire [7:0] tx_data_10; +wire [7:0] tx_data_11; +wire [7:0] tx_data_12; +/* End: Tx data registers */ + +wire cs; + +/* Output signals from can_btl module */ +wire sample_point; +wire sampled_bit; +wire sampled_bit_q; +wire tx_point; +wire hard_sync; + +/* output from can_bsp module */ +wire rx_idle; +wire transmitting; +wire transmitter; +wire go_rx_inter; +wire not_first_bit_of_inter; +wire set_reset_mode; +wire node_bus_off; +wire error_status; +wire [7:0] rx_err_cnt; +wire [7:0] tx_err_cnt; +wire rx_err_cnt_dummy; // The MSB is not displayed. It is just used for easier calculation (no counter overflow). +wire tx_err_cnt_dummy; // The MSB is not displayed. It is just used for easier calculation (no counter overflow). +wire transmit_status; +wire receive_status; +wire tx_successful; +wire need_to_tx; +wire overrun; +wire info_empty; +wire set_bus_error_irq; +wire set_arbitration_lost_irq; +wire [4:0] arbitration_lost_capture; +wire node_error_passive; +wire node_error_active; +wire [6:0] rx_message_counter; +wire tx_next; + +wire go_overload_frame; +wire go_error_frame; +wire go_tx; +wire send_ack; + +wire rst; +wire we; +wire [7:0] addr; +wire [7:0] data_in; +reg [7:0] data_out; +reg rx_sync_tmp; +reg rx_sync; + +/* Connecting can_registers module */ +can_registers i_can_registers +( + .clk(clk_i), + .rst(rst), + .cs(cs), + .we(we), + .addr(addr), + .data_in(data_in), + .data_out(data_out_regs), + .irq_n(irq_on), + + .sample_point(sample_point), + .transmitting(transmitting), + .set_reset_mode(set_reset_mode), + .node_bus_off(node_bus_off), + .error_status(error_status), + .rx_err_cnt(rx_err_cnt), + .tx_err_cnt(tx_err_cnt), + .transmit_status(transmit_status), + .receive_status(receive_status), + .tx_successful(tx_successful), + .need_to_tx(need_to_tx), + .overrun(overrun), + .info_empty(info_empty), + .set_bus_error_irq(set_bus_error_irq), + .set_arbitration_lost_irq(set_arbitration_lost_irq), + .arbitration_lost_capture(arbitration_lost_capture), + .node_error_passive(node_error_passive), + .node_error_active(node_error_active), + .rx_message_counter(rx_message_counter), + + + /* Mode register */ + .reset_mode(reset_mode), + .listen_only_mode(listen_only_mode), + .acceptance_filter_mode(acceptance_filter_mode), + .self_test_mode(self_test_mode), + + /* Command register */ + .clear_data_overrun(), + .release_buffer(release_buffer), + .abort_tx(abort_tx), + .tx_request(tx_request), + .self_rx_request(self_rx_request), + .single_shot_transmission(single_shot_transmission), + .tx_state(tx_state), + .tx_state_q(tx_state_q), + .overload_request(overload_request), + .overload_frame(overload_frame), + + /* Arbitration Lost Capture Register */ + .read_arbitration_lost_capture_reg(read_arbitration_lost_capture_reg), + + /* Error Code Capture Register */ + .read_error_code_capture_reg(read_error_code_capture_reg), + .error_capture_code(error_capture_code), + + /* Bus Timing 0 register */ + .baud_r_presc(baud_r_presc), + .sync_jump_width(sync_jump_width), + + /* Bus Timing 1 register */ + .time_segment1(time_segment1), + .time_segment2(time_segment2), + .triple_sampling(triple_sampling), + + /* Error Warning Limit register */ + .error_warning_limit(error_warning_limit), + + /* Rx Error Counter register */ + .we_rx_err_cnt(we_rx_err_cnt), + + /* Tx Error Counter register */ + .we_tx_err_cnt(we_tx_err_cnt), + + /* Clock Divider register */ + .extended_mode(extended_mode), + .clkout(clkout_o), + + /* This section is for BASIC and EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_0(acceptance_code_0), + + /* Acceptance mask register */ + .acceptance_mask_0(acceptance_mask_0), + /* End: This section is for BASIC and EXTENDED mode */ + + /* This section is for EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_1(acceptance_code_1), + .acceptance_code_2(acceptance_code_2), + .acceptance_code_3(acceptance_code_3), + + /* Acceptance mask register */ + .acceptance_mask_1(acceptance_mask_1), + .acceptance_mask_2(acceptance_mask_2), + .acceptance_mask_3(acceptance_mask_3), + /* End: This section is for EXTENDED mode */ + + /* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ + .tx_data_0(tx_data_0), + .tx_data_1(tx_data_1), + .tx_data_2(tx_data_2), + .tx_data_3(tx_data_3), + .tx_data_4(tx_data_4), + .tx_data_5(tx_data_5), + .tx_data_6(tx_data_6), + .tx_data_7(tx_data_7), + .tx_data_8(tx_data_8), + .tx_data_9(tx_data_9), + .tx_data_10(tx_data_10), + .tx_data_11(tx_data_11), + .tx_data_12(tx_data_12) + /* End: Tx data registers */ +); + + + + +/* Connecting can_btl module */ +can_btl i_can_btl +( + .clk(clk_i), + .rst(rst), + .rx(rx_sync), + .tx(tx_o), + + /* Bus Timing 0 register */ + .baud_r_presc(baud_r_presc), + .sync_jump_width(sync_jump_width), + + /* Bus Timing 1 register */ + .time_segment1(time_segment1), + .time_segment2(time_segment2), + .triple_sampling(triple_sampling), + + /* Output signals from this module */ + .sample_point(sample_point), + .sampled_bit(sampled_bit), + .sampled_bit_q(sampled_bit_q), + .tx_point(tx_point), + .hard_sync(hard_sync), + + + /* output from can_bsp module */ + .rx_idle(rx_idle), + .rx_inter(rx_inter), + .transmitting(transmitting), + .transmitter(transmitter), + .go_rx_inter(go_rx_inter), + .tx_next(tx_next), + + .go_overload_frame(go_overload_frame), + .go_error_frame(go_error_frame), + .go_tx(go_tx), + .send_ack(send_ack), + .node_error_passive(node_error_passive) + + + +); + + + +can_bsp i_can_bsp +( + .clk(clk_i), + .rst(rst), + + /* From btl module */ + .sample_point(sample_point), + .sampled_bit(sampled_bit), + .sampled_bit_q(sampled_bit_q), + .tx_point(tx_point), + .hard_sync(hard_sync), + + .addr(addr), + .data_in(data_in), + .data_out(data_out_fifo), + .fifo_selected(data_out_fifo_selected), + + /* Mode register */ + .reset_mode(reset_mode), + .listen_only_mode(listen_only_mode), + .acceptance_filter_mode(acceptance_filter_mode), + .self_test_mode(self_test_mode), + + /* Command register */ + .release_buffer(release_buffer), + .tx_request(tx_request), + .abort_tx(abort_tx), + .self_rx_request(self_rx_request), + .single_shot_transmission(single_shot_transmission), + .tx_state(tx_state), + .tx_state_q(tx_state_q), + .overload_request(overload_request), + .overload_frame(overload_frame), + + /* Arbitration Lost Capture Register */ + .read_arbitration_lost_capture_reg(read_arbitration_lost_capture_reg), + + /* Error Code Capture Register */ + .read_error_code_capture_reg(read_error_code_capture_reg), + .error_capture_code(error_capture_code), + + /* Error Warning Limit register */ + .error_warning_limit(error_warning_limit), + + /* Rx Error Counter register */ + .we_rx_err_cnt(we_rx_err_cnt), + + /* Tx Error Counter register */ + .we_tx_err_cnt(we_tx_err_cnt), + + /* Clock Divider register */ + .extended_mode(extended_mode), + + /* output from can_bsp module */ + .rx_idle(rx_idle), + .transmitting(transmitting), + .transmitter(transmitter), + .go_rx_inter(go_rx_inter), + .not_first_bit_of_inter(not_first_bit_of_inter), + .rx_inter(rx_inter), + .set_reset_mode(set_reset_mode), + .node_bus_off(node_bus_off), + .error_status(error_status), + .rx_err_cnt({rx_err_cnt_dummy, rx_err_cnt[7:0]}), // The MSB is not displayed. It is just used for easier calculation (no counter overflow). + .tx_err_cnt({tx_err_cnt_dummy, tx_err_cnt[7:0]}), // The MSB is not displayed. It is just used for easier calculation (no counter overflow). + .transmit_status(transmit_status), + .receive_status(receive_status), + .tx_successful(tx_successful), + .need_to_tx(need_to_tx), + .overrun(overrun), + .info_empty(info_empty), + .set_bus_error_irq(set_bus_error_irq), + .set_arbitration_lost_irq(set_arbitration_lost_irq), + .arbitration_lost_capture(arbitration_lost_capture), + .node_error_passive(node_error_passive), + .node_error_active(node_error_active), + .rx_message_counter(rx_message_counter), + + /* This section is for BASIC and EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_0(acceptance_code_0), + + /* Acceptance mask register */ + .acceptance_mask_0(acceptance_mask_0), + /* End: This section is for BASIC and EXTENDED mode */ + + /* This section is for EXTENDED mode */ + /* Acceptance code register */ + .acceptance_code_1(acceptance_code_1), + .acceptance_code_2(acceptance_code_2), + .acceptance_code_3(acceptance_code_3), + + /* Acceptance mask register */ + .acceptance_mask_1(acceptance_mask_1), + .acceptance_mask_2(acceptance_mask_2), + .acceptance_mask_3(acceptance_mask_3), + /* End: This section is for EXTENDED mode */ + + /* Tx data registers. Holding identifier (basic mode), tx frame information (extended mode) and data */ + .tx_data_0(tx_data_0), + .tx_data_1(tx_data_1), + .tx_data_2(tx_data_2), + .tx_data_3(tx_data_3), + .tx_data_4(tx_data_4), + .tx_data_5(tx_data_5), + .tx_data_6(tx_data_6), + .tx_data_7(tx_data_7), + .tx_data_8(tx_data_8), + .tx_data_9(tx_data_9), + .tx_data_10(tx_data_10), + .tx_data_11(tx_data_11), + .tx_data_12(tx_data_12), + /* End: Tx data registers */ + + /* Tx signal */ + .tx(tx_o), + .tx_next(tx_next), + .bus_off_on(bus_off_on), + + .go_overload_frame(go_overload_frame), + .go_error_frame(go_error_frame), + .go_tx(go_tx), + .send_ack(send_ack) + + +`ifdef CAN_BIST + , + /* BIST signals */ + .mbist_si_i(mbist_si_i), + .mbist_so_o(mbist_so_o), + .mbist_ctrl_i(mbist_ctrl_i) +`endif +); + + + +// Multiplexing wb_dat_o from registers and rx fifo +always @ (extended_mode or addr or reset_mode) +begin + if (extended_mode & (~reset_mode) & ((addr >= 8'd16) && (addr <= 8'd28)) | (~extended_mode) & ((addr >= 8'd20) && (addr <= 8'd29))) + data_out_fifo_selected = 1'b1; + else + data_out_fifo_selected = 1'b0; +end + + +always @ (posedge clk_i) +begin + if (cs & (~we)) + begin + if (data_out_fifo_selected) + data_out <=#Tp data_out_fifo; + else + data_out <=#Tp data_out_regs; + end +end + + + +always @ (posedge clk_i or posedge rst) +begin + if (rst) + begin + rx_sync_tmp <= 1'b1; + rx_sync <= 1'b1; + end + else + begin + rx_sync_tmp <=#Tp rx_i; + rx_sync <=#Tp rx_sync_tmp; + end +end + + + +`ifdef CAN_WISHBONE_IF + + assign cs_can_i = 1'b1; + + // Combining wb_cyc_i and wb_stb_i signals to cs signal. Than synchronizing to clk_i clock domain. + always @ (posedge clk_i or posedge rst) + begin + if (rst) + begin + cs_sync1 <= 1'b0; + cs_sync2 <= 1'b0; + cs_sync3 <= 1'b0; + cs_sync_rst1 <= 1'b0; + cs_sync_rst2 <= 1'b0; + end + else + begin + cs_sync1 <=#Tp wb_cyc_i & wb_stb_i & (~cs_sync_rst2) & cs_can_i; + cs_sync2 <=#Tp cs_sync1 & (~cs_sync_rst2); + cs_sync3 <=#Tp cs_sync2 & (~cs_sync_rst2); + cs_sync_rst1 <=#Tp cs_ack3; + cs_sync_rst2 <=#Tp cs_sync_rst1; + end + end + + + assign cs = cs_sync2 & (~cs_sync3); + + + always @ (posedge wb_clk_i) + begin + cs_ack1 <=#Tp cs_sync3; + cs_ack2 <=#Tp cs_ack1; + cs_ack3 <=#Tp cs_ack2; + end + + + + // Generating acknowledge signal + always @ (posedge wb_clk_i) + begin + wb_ack_o <=#Tp (cs_ack2 & (~cs_ack3)); + end + + + assign rst = wb_rst_i; + assign we = wb_we_i; + assign addr = wb_adr_i; + assign data_in = wb_dat_i; + assign wb_dat_o = data_out; + + +`else + + // Latching address + always @ (posedge clk_i or posedge rst) + begin + if (rst) + addr_latched <= 8'h0; + else if (ale_i) + addr_latched <=#Tp port_0_io; + end + + + // Generating delayed wr_i and rd_i signals + always @ (posedge clk_i or posedge rst) + begin + if (rst) + begin + wr_i_q <= 1'b0; + rd_i_q <= 1'b0; + end + else + begin + wr_i_q <=#Tp wr_i; + rd_i_q <=#Tp rd_i; + end + end + + + assign cs = ((wr_i & (~wr_i_q)) | (rd_i & (~rd_i_q))) & cs_can_i; + + + assign rst = rst_i; + assign we = wr_i; + assign addr = addr_latched; + assign data_in = port_0_io; + assign port_0_io = (cs_can_i & rd_i)? data_out : 8'hz; + +`endif + + +endmodule diff --git a/soc/peripheral/can_vhdl_top.vhd b/soc/peripheral/can_vhdl_top.vhd new file mode 100644 index 0000000..8fe6a63 --- /dev/null +++ b/soc/peripheral/can_vhdl_top.vhd @@ -0,0 +1,139 @@ +-- +-- can_vhdl_top +-- +-- Wraps the verilog component for the con controller into an VHDL entity +-- The wrapper translates the 8-bit wishbone interface into an 32 bit interface. +-- Still, only 8-bit accesses are allowed. +-- @autor: Thoams Fehmel +-- + + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.all; + +library work; +use work.wishbone.all; +use work.config.all; + +entity can_vhdl_top is +generic( + memaddr : generic_addr_type; + addrmask : generic_mask_type +); +port( + clk : in std_logic; + rstn : in std_logic; + wbs_i : in wb_slv_in_type; + wbs_o : out wb_slv_out_type; + rx_i : in std_logic; + tx_o : out std_logic; + driver_en : out std_logic; + irq_on : out std_logic + +); +end can_vhdl_top; + +architecture Behavioral of can_vhdl_top is + +component can_top is +port( +wb_clk_i : in std_logic; +wb_rst_i : in std_logic; +wb_dat_i : in std_logic_vector(7 downto 0); +wb_dat_o : out std_logic_vector(7 downto 0); +wb_cyc_i : in std_logic; +wb_stb_i : in std_logic; +wb_we_i : in std_logic; +wb_adr_i : in std_logic_vector(7 downto 0); +wb_ack_o : out std_logic; +clk_i : in std_logic; +rx_i : in std_logic; +tx_o : out std_logic; +bus_off_on : out std_logic; +irq_on : out std_logic; +clkout_o : out std_logic +); +end component; + +signal wb_dat_i : std_logic_vector(7 downto 0); +signal wb_dat_o : std_logic_vector(7 downto 0); + +signal wb_addr : std_logic_vector(7 downto 0); + +signal bus_off_on : std_logic; +signal clkout_o : std_logic; + +signal irq_can : std_logic; +signal irq_tmp : std_logic; + +signal tx_int : std_logic; + +begin + +can_mod : can_top +port map( +wb_clk_i=>clk, +wb_rst_i=>rstn, +wb_dat_i=>wb_dat_i, +wb_dat_o=>wb_dat_o, +wb_cyc_i=>wbs_i.cyc, +wb_stb_i=>wbs_i.stb, +wb_we_i=>wbs_i.we, +wb_adr_i=>wb_addr, +wb_ack_o=>wbs_o.ack, +clk_i=>clk, +rx_i=>rx_i, +tx_o=>tx_int, +bus_off_on=>bus_off_on, --goes nowhere +irq_on=>irq_can, +clkout_o=>clkout_o --goes nowhere +); + +wb_dat_i <= + wbs_i.dat(31 downto 24) when wbs_i.sel = "1000" else + wbs_i.dat(23 downto 16) when wbs_i.sel = "0100" else + wbs_i.dat(15 downto 8) when wbs_i.sel = "0010" else + wbs_i.dat( 7 downto 0) when wbs_i.sel = "0001" else + (others=>'0'); + +--assert (wbs_i.stb='0' or ((wbs_i.sel="1000") or (wbs_i.sel="0100") or (wbs_i.sel="0010") or (wbs_i.sel="0001") or (wbs_i.sel="0000"))) report "CAN wishbone itnerface only supports 8-bit accesses" severity ERROR; + +wbs_o.dat(31 downto 24) <= wb_dat_o when wbs_i.sel(3) = '1' else (others=>'0'); +wbs_o.dat(23 downto 16) <= wb_dat_o when wbs_i.sel(2) = '1' else (others=>'0'); +wbs_o.dat(15 downto 8) <= wb_dat_o when wbs_i.sel(1) = '1' else (others=>'0'); +wbs_o.dat( 7 downto 0) <= wb_dat_o when wbs_i.sel(0) = '1' else (others=>'0'); + +--wb_addr <= wbs_i.adr(WB_ADR_BOUND+6 downto WB_ADR_BOUND) & sel2adr(wbs_i.sel); + +addr_adder: if to_unsigned(memaddr, 16)(7 downto 2) /= "000000" generate + wb_addr <= std_logic_vector(unsigned(wbs_i.adr(7 downto 2) & sel2adr(wbs_i.sel)) - to_unsigned(memaddr, 16)(7 downto 0)); +end generate; + +addr_forw: if to_unsigned(memaddr, 16)(7 downto 2) = "000000" generate + wb_addr(7 downto 2) <= wbs_i.adr(7 downto 2); + wb_addr(1 downto 0) <= sel2adr(wbs_i.sel); +end generate; + +--convert irq : active low(can) to activ high(soc) +--interrupt generation: only active for one clk cycle after falling edge of irq_can +irq_gen: process(clk) +begin + if clk = '1' and clk'event then + if irq_tmp = '1' and irq_can = '0' then + irq_on <= '1'; + else + irq_on <= '0'; + end if; + irq_tmp <= irq_can; + end if; +end process; + +--NOTE: address check is skipped udner the assumption that the interconnect handles it. +wbs_o.wbcfg <= wb_membar(memaddr, addrmask); + +-- driver enable +tx_o <= tx_int; +driver_en <= not(tx_int); + +end architecture; \ No newline at end of file diff --git a/soc/peripheral/led.vhd b/soc/peripheral/led.vhd new file mode 100644 index 0000000..ea27027 --- /dev/null +++ b/soc/peripheral/led.vhd @@ -0,0 +1,62 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +entity wb_led is + generic( + memaddr : generic_addr_type; --:= CFG_BADR_LED; + addrmask : generic_mask_type --:= CFG_MADR_LED; + ); + port( + clk : in std_logic; + rst : in std_logic; + led : out std_logic_vector(7 downto 0); + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end wb_led; + +architecture Behavioral of wb_led is + + signal data : std_logic_vector(7 downto 0); + signal ack : std_logic; + +begin + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + ack <= '0'; + data <= x"0F"; + else + if wslvi.stb = '1' and wslvi.cyc = '1' then + if wslvi.we='1' then + data <= dec_wb_dat(wslvi.sel,wslvi.dat)(7 downto 0); + end if; + if ack = '0' then + ack <= '1'; + else + ack <= '0'; + end if; + else + ack <= '0'; + end if; + end if; + end if; + end process; + + wslvo.dat(7 downto 0) <= data; + wslvo.dat(31 downto 8) <= (others=>'0'); + + led <= data; + + wslvo.ack <= ack; + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + +end Behavioral; diff --git a/soc/peripheral/peripherals.vhd b/soc/peripheral/peripherals.vhd new file mode 100644 index 0000000..8bb4d05 --- /dev/null +++ b/soc/peripheral/peripherals.vhd @@ -0,0 +1,36 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; + +library work; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +package lt16soc_peripherals is + + component wb_led is + generic( + memaddr : generic_addr_type;-- := CFG_BADR_LED; + addrmask : generic_mask_type-- := CFG_MADR_LED; + ); + port( + clk : in std_logic; + rst : in std_logic; + led : out std_logic_vector(7 downto 0); + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component; + +end lt16soc_peripherals; + +package body lt16soc_peripherals is + + --insert function bodies + +end lt16soc_peripherals; + diff --git a/soc/testbench/can_tx_sim_tb.vhd b/soc/testbench/can_tx_sim_tb.vhd new file mode 100644 index 0000000..18ba811 --- /dev/null +++ b/soc/testbench/can_tx_sim_tb.vhd @@ -0,0 +1,128 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wishbone.all; +use work.can_tp.all; + +entity can_tx_sim_tb is +end entity can_tx_sim_tb; + +architecture RTL of can_tx_sim_tb is + + + component can_vhdl_top is + generic( + memaddr : generic_addr_type; + addrmask : generic_mask_type; + ); + port( + clk : in std_logic; + rstn : in std_logic; + wbs_i : in wb_slv_in_type; + wbs_o : out wb_slv_out_type; + rx_i : in std_logic; + tx_o : out std_logic; + irq_on : out std_logic + ); + end component can_vhdl_top; + + + component phys_can_sim + generic( + peer_num : integer ); + port( + rst : in std_logic; + rx_vector : out std_logic_vector(peer_num - 1 downto 0); + tx_vector : in std_logic_vector(peer_num - 1 downto 0) ); + end component phys_can_sim; + + + -- management signal + signal clk : std_logic := '0'; + signal rst : std_logic := '1'; + signal test_result: rx_check_result; + signal tx_frame: std_logic_vector(0 to 108); + + -- signals main controller + signal wbs_i : wb_slv_in_type; + signal wbs_o : wb_slv_out_type; + signal irq_on : std_logic; + + + --signals can interconnect + constant peer_num_inst : integer := 2; + signal rx_vector : std_logic_vector(peer_num_inst - 1 downto 0); + signal tx_vector : std_logic_vector(peer_num_inst - 1 downto 0); + +begin + + + can_inst_main : component can_vhdl_top + generic map( + memaddr=>CFG_BADR_MEM, + addrmask=>CFG_MADR_FULL + ) + port map( + clk => clk, + rstn => rst, + wbs_i => wbs_i, + wbs_o => wbs_o, + rx_i => rx_vector(0), + tx_o => tx_vector(0), + irq_on => irq_on); + + can_interconnect : component phys_can_sim + generic map( peer_num => peer_num_inst) + port map( rst => rst, + rx_vector => rx_vector, + tx_vector => tx_vector); + + + + -- stimuli + stimuli: process is + --variable data : std_logic_vector (7 downto 0); + --variable addr : integer; + begin + wait for 10 ns; + rst <= '1'; + wait for 40 ns; + rst <= '0'; + + tx_vector(1) <= '1'; + write_regs_from_file( "./testdata/default_setup.tdf", wbs_i, wbs_o, clk); + wait for 8400 ns; + simulate_can_transmission("10101010111", x"770F0F0F00000000", 1, 300 ns, rx_vector(1), tx_vector(1), test_result); + wait for 2400 ns; + simulate_can_transmission("11100010111", x"770F0F0F00000000", 3, 300 ns, rx_vector(1), tx_vector(1), test_result); + wait for 8400 ns; + simulate_can_transmission("00000000011", x"770F0F0F00000000", 5, 300 ns, rx_vector(1), tx_vector(1), test_result); + wait for 8400 ns; + simulate_can_transmission("10111110011", x"770F0F0F00000000", 8, 300 ns, rx_vector(1), tx_vector(1), test_result); + tx_vector(1) <= '1'; + wait; + + report "end stimuli" severity warning; + + end process stimuli; + + sub_programm_test: process is + + begin + tx_frame <= buildframe("00000000000", x"770F0F0F00000000", 1); + wait; + end process; + + + + -- clock generation + clock : process is + begin + clk <= not clk; + wait for 10 ns / 2; + end process clock; + + + +end architecture RTL; diff --git a/soc/testbench/core2wb_tb.vhd b/soc/testbench/core2wb_tb.vhd new file mode 100644 index 0000000..7472496 --- /dev/null +++ b/soc/testbench/core2wb_tb.vhd @@ -0,0 +1,439 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; + +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.wb_tp.all; + + +entity core2wb_tb is +end core2wb_tb; + +architecture behavior of core2wb_tb is + + component core2wb + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out dmem_core; + out_dmem : in core_dmem; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal out_dmem : core_dmem; + signal wmsti : wb_mst_in_type := wbm_in_none; + + --Outputs + signal in_dmem : dmem_core; + signal wmsto : wb_mst_out_type; + + -- Clock period definitions + constant clk_period : time := 10 ns; + +begin + + -- Instantiate the Unit Under Test (UUT) + uut: core2wb + port map( + clk => clk, + rst => rst, + + in_dmem => in_dmem, + out_dmem => out_dmem, + + wmsti => wmsti, + wmsto => wmsto + + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset_process : process + begin + rst <= '1'; + wait for clk_period*3.5; + rst <= '0'; + wait; + end process; + + -- Stimulus process + stim_proc: process + begin + --gencore2mem_req(out_dmem, req_acc, req_rdadr, req_rdsz, req_wradr, req_wrsz, req_wrdat); + gencore2mem_req(out_dmem, NO_ACC, + --rd + zadr32, "00", + --wr + zadr32, "00", dc32); + --genwb2core(wmsti, req_acc, req_rdsz, wmsto.sel, resp_rddat, READY); + genwb2core(wmsti, NO_ACC, + "00", wmsto.sel, dc32, READY); + wait for clk_period*5; + --//////////////////////////////////////////// + -------------------------------------- + -- Test_case 00: + -------------------------------------- + -- No request i.e. quiet test + -- Expected output wmsto : no response + -- Expected output in_dmem : no response + -- Expected error: No error + -------------------------------------- + -- report ">> TC0 starts <<"; + -------------------------------------- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + NO_ACC, + --rd + zadr32, "00", + --wr + zadr32, "00", dc32); + wait for clk_period; + + -- Handshake-2 (out): + --wait for clk_period; + assert core2wbmo_chk(out_dmem.read_addr, out_dmem.read_size, out_dmem.write_data, + wmsto, NO_ACC) -- put any address and any size + report"E-00: msto.stb or msto.cyc should be inactive as there is no request" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + NO_ACC, "00", wmsto.sel, dc32, NREADY); + wait for clk_period; + + -- Handshake-4 (out): + --wait for clk_period; + assert wbmi2core_chk(in_dmem, + NO_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report "E-01: in_dmem.ready not active!" + severity error; + -------------------------------------- + --report ">> TC0 ends <<"; + -------------------------------------- + -- + --E N D Test_case 00 + -- + -------------------------------------- + -- + -------------------------------------- + -- Test_case 01: + -------------------------------------- + -- Single read request + -- Expected output wmsto : request info from core should be the same as wb request + -- Expected output in_dmem : resp read_data from wb should be the same as incoming resp data to core module + -- Expected error: No error + -------------------------------------- + -- report ">> TC1 starts <<"; + -------------------------------------- + -- + -- test 1A: immediate ack in next clk cycle from request + -- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, + RD_ACC, + --rd + x"A1000003", "00", + --wr + zadr32, "00", dc32); + wait for clk_period; + + + -- Handshake-2 (out): verify rd and wr addr, wr data, request(stb, cyc) + assert core2wbmo_chk(out_dmem.read_addr, out_dmem.read_size, out_dmem.write_data, + wmsto, RD_ACC) + report"E-10: msto.stb, msto.cyc should be active as there is rd request, and msto.we should = 0 (rd)" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, + RD_ACC, "00", wmsto.sel, x"D1AABBCC", READY); + wait for clk_period; + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, + RD_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report "E-11: in_dmem.ready not active or read_data is wrong" + severity error; + -- + -- test 1B: Non-immediate ack in next clk cycle from request + -- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + RD_ACC, + --rd + x"A1000003", "00", + --wr + zadr32, "00", dc32); + wait for clk_period; + + -- Handshake-2 (out): verify rd and wr addr, wr data, request(stb, cyc) + assert core2wbmo_chk(out_dmem.read_addr, out_dmem.read_size, out_dmem.write_data, + wmsto, RD_ACC) + report"E-12: msto.stb, msto.cyc should be active as there is rd request, and msto.we should = 0 (rd)" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + RD_ACC, "00", wmsto.sel, x"D1AABBCC", NREADY); + wait for clk_period; + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, RD_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-13: in_dmem.ready always active or read_data is wrong" + severity error; + -- + -- test 1C: Different read_size (32b) + -- + -- Handshake-1 (in): + --req_rdsz <= "10"; --32b, remark: can't test since read_size has to be the same all the time (fixed in wb_gran) + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + RD_ACC, + --rd + x"A1000003", "10", --test diff siz + --wr + zadr32, "00", dc32); + wait for clk_period; + + + -- Handshake-2 (out): verify rd and wr addr, wr data, request(stb, cyc) + assert core2wbmo_chk(out_dmem.read_addr, out_dmem.read_size, out_dmem.write_data, + wmsto, RD_ACC) + report"E-14: msto.stb, msto.cyc should be active as there is rd request, and msto.we should = 0 (rd)" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + RD_ACC, "10", wmsto.sel, x"D1AABBCC", NREADY); + wait for clk_period; + + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, + RD_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-15: in_dmem.ready always active or read_data is wrong" + severity error; + -------------------------------------- + --report ">> TC1 ends <<"; + -------------------------------------- + -- + --E N D Test_case 01 + -- + -------------------------------------- + -- + -------------------------------------- + -- Test_case 02: + -------------------------------------- + -- Single write request + -- Expected output wmsto : request info from core should be the same as wb request + -- Expected output in_dmem : get ack + -- Expected error: No error + -------------------------------------- + -- report ">> TC2 starts <<"; + -------------------------------------- + -- + -- test 2A: immediate ack in next clk cycle from request + -- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + WR_ACC, + --rd + x"A2000000", "00", + --wr + x"B2000003", "00", x"DB2200AA"); + wait for clk_period; + + -- Handshake-2 (out): + assert core2wbmo_chk(out_dmem.write_addr, out_dmem.write_size, out_dmem.write_data, + wmsto, WR_ACC) + report"E-20: msto.stb, msto.cyc and msto.we should be active as there is wr request" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + WR_ACC, "00", wmsto.sel, x"D2AABBCC", READY); + wait for clk_period; + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, + WR_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-21: in_dmem.ready should be active" + severity error; + -- + -- test 2B: Non-immediate ack in next clk cycle from request + -- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + WR_ACC, + --rd + x"A2000000", "00", + --wr + x"B2000003", "00", x"DB2200AA"); + wait for clk_period; + + + -- Handshake-2 (out): verify rd and wr addr, wr data, request(stb, cyc) + assert core2wbmo_chk(out_dmem.write_addr, out_dmem.write_size, out_dmem.write_data, + wmsto, WR_ACC) + report"E-22: msto.stb, msto.cyc and msto.we should be active as there is wr request" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + WR_ACC, "00", wmsto.sel, x"D2AABBCC", NREADY); + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, + WR_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-23: in_dmem.ready always active or read_data is wrong" + severity error; + -- + -- test 2C: Different write_size (32b) + -- + -- Handshake-1 (in): + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + WR_ACC, + --rd + x"A1000003", "00", + --wr + x"B2000003", "10", x"DB2200AA"); + wait for clk_period; + + -- Handshake-2 (out): verify rd and wr addr, wr data, request(stb, cyc) + assert core2wbmo_chk(out_dmem.write_addr, out_dmem.write_size, out_dmem.write_data, + wmsto, WR_ACC) + report"E-24: msto.stb, msto.cyc and msto.we should be active as there is wr request" + severity error; + + -- Handshake-3 (in): + genwb2core(wmsti, --generated input for wbmi2core_chk + WR_ACC, "00", wmsto.sel, x"D2AABBCC", NREADY); + wait for clk_period; + + -- Handshake-4 (out): + assert wbmi2core_chk(in_dmem, + WR_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-25: in_dmem.ready always active or read_data is wrong" + severity error; + -- + -------------------------------------- + --report ">> TC2 ends <<"; + -------------------------------------- + -- + --E N D Test_case 02 + -- + -------------------------------------- + -- + -------------------------------------- + -- Test_case 03: + -------------------------------------- + -- Simultaneous request i.e. write and read + -- Expected output wmsto : request info from core should be the same as wb request + -- Expected output in_dmem : in_dmem.ready is asserted only when the reading is done but msti.ack should be asserted after both write and read. + -- Expected error: No error + -------------------------------------- + -- report ">> TC3 starts <<"; + -------------------------------------- + -- Handshake-1 (in):sim(wr) + gencore2mem_req(out_dmem, --generated input for core2wbmo_chk + SIM_ACC, + --rd + x"A3000003", "00", + --wr + x"B3000001", "00", x"DB3300AA"); + wait for clk_period; + ------------------------------------------- + -- Handshake-2 (out):wr_req + assert core2wbmo_chk(out_dmem.write_addr, out_dmem.write_size, out_dmem.write_data, + wmsto, WR_ACC) -- For simacc, write first + report"E-30: msto.stb, msto.cyc and msto.we should be active as there is wr request" + severity error; + + --clear request as we want to test only one sim transaction so far + out_dmem.write_en <= '0'; out_dmem.read_en <= '0'; wait for clk_period; + --end tmp clear + + --clear request as we want to test only one sim transaction so far + --out_dmem.write_en <= '0'; out_dmem.read_en <= '0'; + --end tmp clear + --wait for 3*clk_period; + + -- Handshake-3 (in):wr_req + genwb2core(wmsti, --generated input for wbmi2core_chk + WR_ACC, "00", wmsto.sel, dc32, READY); --READY = out_mem2core.ready (wr is done) + + wait for 0.5*clk_period; + + -- Handshake-4 (out):read req is sent once mem_write is done (mem.ready = 1) + --wait until wmsti.ack = '1'; + assert wbmi2core_chk(in_dmem, + SIM_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-31: Sim request (wr)- Wrong ready/ack" + severity error; + + --////////////////// + --once wr_ack is sent, wb_intercon should deassert ack = 0 for read request that is just recently sent after wr_req is done + wmsti.ack <= '0'; + wait for 0.5*clk_period; -- wait for ack to deassert + --////////////////// + + -- Handshake-5 (out):rd_req + assert core2wbmo_chk(out_dmem.read_addr, out_dmem.read_size, out_dmem.write_data, + wmsto, RD_ACC) -- read after write is done + report"E-32: sim request (rd): msto.stb, msto.cyc and msto.we should be (1, 1, 0)" + severity error; + + -- Handshake-6 (out): + genwb2core(wmsti, --generated input for wbmi2core_chk + RD_ACC, "00", wmsto.sel, x"D3AABBCC", READY); + wait for clk_period; + + -- Handshake-7 (out):rd_req + assert wbmi2core_chk(in_dmem, + RD_ACC, wmsto.sel, wmsti.ack, wmsti.dat) + report"E-33: wbmi2core_chk function: Wrong read data" + severity error; + -------------------------------------- + --report ">> TC3 ends <<"; + -------------------------------------- + -- + --E N D Test_case 03 + -- + -------------------------------------- + +--////////////////////////////////////////////////// + assert false + report ">>>> Simulation beendet!" + severity failure; + end process; + +end; diff --git a/soc/testbench/core2wb_wave.wcfg b/soc/testbench/core2wb_wave.wcfg new file mode 100644 index 0000000..67a40bb --- /dev/null +++ b/soc/testbench/core2wb_wave.wcfg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + state + state + + + nstate + nstate + + + out_dmem + out_dmem + + .write_data + out_dmem.write_data + HEXRADIX + + + .write_addr + out_dmem.write_addr + HEXRADIX + + + .write_size + out_dmem.write_size + + + .write_en + out_dmem.write_en + + + .read_addr + out_dmem.read_addr + HEXRADIX + + + .read_size + out_dmem.read_size + + + .read_en + out_dmem.read_en + + + + wmsto + wmsto + + .adr + wmsto.adr + HEXRADIX + + + .dat + wmsto.dat + HEXRADIX + + + .we + wmsto.we + + + .sel + wmsto.sel + + + .stb + wmsto.stb + + + .cyc + wmsto.cyc + + + .wbidx + wmsto.wbidx + + + + wmsti + wmsti + + .dat + wmsti.dat + HEXRADIX + + + .ack + wmsti.ack + + + + in_dmem + in_dmem + + .read_data + in_dmem.read_data + HEXRADIX + + + .ready + in_dmem.ready + + + + req_acc + req_acc + + + req_rdadr[31:0] + req_rdadr[31:0] + HEXRADIX + + + req_rdsz[1:0] + req_rdsz[1:0] + + + resp_rddat[31:0] + resp_rddat[31:0] + HEXRADIX + + + req_wradr[31:0] + req_wradr[31:0] + HEXRADIX + + + req_wrsz[1:0] + req_wrsz[1:0] + + + req_wrdat[31:0] + req_wrdat[31:0] + HEXRADIX + + diff --git a/soc/testbench/coreicnmem_tb.vhd b/soc/testbench/coreicnmem_tb.vhd new file mode 100644 index 0000000..18234eb --- /dev/null +++ b/soc/testbench/coreicnmem_tb.vhd @@ -0,0 +1,343 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + + +ENTITY coreicnmem_tb IS +END coreicnmem_tb; + +ARCHITECTURE behavior OF coreicnmem_tb IS +--////////////////////////////////////////////// +-- component +--////////////////////////////////////////////// +component core + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_dmem : in dmem_core; + out_dmem : out core_dmem; + in_imem : in imem_core; + out_imem : out core_imem; + in_irq : in irq_core; + out_irq : out core_irq; + hardfault : out std_logic); +end component core; + +component memdiv +generic( + filename : in string := "program.ram"; + size : in integer := 256; + imem_latency : in time := 5 ns; + dmem_latency : in time := 5 ns; + dmemsz : integer := DMEMSZ; + imemsz : integer := IMEMSZ +); +port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : in core_dmem; + out_dmem : out dmem_core; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0)); +end component; + +component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); +end component; + +component core2wb + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out dmem_core; + out_dmem : in core_dmem; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); +end component; + +component mem2wb + generic( + memaddr : generic_addr_type := 0; + addrmask : generic_mask_type := 16#3fffff#; + wbidx : integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out core_dmem; + out_dmem : in dmem_core; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end component; + +component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + dat_sz: integer := WB_PORT_SIZE; + adr_sz: integer := WB_ADR_WIDTH; + nib_sz: integer := WB_PORT_GRAN + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); +end component; +--////////////////////////////////////////////// +-- signal +--////////////////////////////////////////////// +-- Clock period definitions + constant clk_period : time := 10 ns; + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1000_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + -- signals between instances + + signal core2dm_sc : core_dmem; + signal core2dm_sm : core_dmem; + signal dm2core_sc : dmem_core; + signal dm2core_sm : dmem_core; + + signal imem_proc_signal : imem_core; + signal proc_imem_signal : core_imem; + + signal irq_proc_signal : irq_core; + signal proc_irq_signal : core_irq; + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0); + + + + signal out_byte: std_logic_vector(7 downto 0); + --signal hardfault: std_logic; + --signal fault: std_logic; + + + ----signal slvi : wb_slv_in_type ;--:= wbs_in_none; + ----signal msti : wb_mst_in_type ;--:= wbm_in_none; + + --signal slvo : wb_slv_out_type := wbs_out_none; + --signal msto : wb_mst_out_type := wbm_out_none; + + signal slvo : wb_slv_out_vector := (others=> wbs_out_none); + signal msto : wb_mst_out_vector := (others=> wbm_out_none); + + signal slvi : wb_slv_in_vector := (others=> wbs_in_none); + signal msti : wb_mst_in_vector := (others=> wbm_in_none); + + +BEGIN +--////////////////////////////////////////////// +-- instantiation +--////////////////////////////////////////////// +---------- +--core +---------- + core_inst : component core + port map( + clk => clk, + rst => rst, + stall => '0', + + in_dmem => dm2core_sc, + out_dmem => core2dm_sc, + + in_imem => imem_proc_signal, + out_imem => proc_imem_signal, + + in_irq => irq_proc_signal, + out_irq => proc_irq_signal, + hardfault => irq_lines(1) + ); +---------- +--memdiv +---------- + mem_inst: memdiv + generic map( + filename => "sample-programs\rawhztest.ram", + size => DMEMSZ + IMEMSZ, + imem_latency => 0 ns, + dmem_latency => 0 ns, + dmemsz => DMEMSZ, + imemsz => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + + in_dmem => core2dm_sm, + out_dmem => dm2core_sm, + + in_imem => proc_imem_signal, + out_imem => imem_proc_signal, + + fault => irq_lines(2), + out_byte => out_byte + ); +---------- +--irq +---------- + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => proc_irq_signal, + out_proc => irq_proc_signal, + irq_lines => irq_lines + ); + +---------- +--core2wb +---------- + core2wb0: core2wb + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_dmem => dm2core_sc, + out_dmem => core2dm_sc, + + wmsti => msti(CFG_LT16), + wmsto => msto(CFG_LT16) + + ); + +---------- +--mem2wb +---------- + mem2wb0: mem2wb + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM + ) + port map( + clk => clk, + rst => rst, + + in_dmem => core2dm_sm, + out_dmem => dm2core_sm, + wslvi => slvi(CFG_MEM), + wslvo => slvo(CFG_MEM) + + + ); +---------- +--wb_intercon +---------- + wbicn_inst: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + -- reset stimuli + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + + -- irq line stimuli + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + -- irq0 is reset + -- irq1 is hardfault + -- irq2 is memfault + + -- wait for 600 ns; + + -- wait until rising_edge(clk); + -- irq_lines(3) <= '1'; + -- irq_lines(4) <= '1'; + -- wait until rising_edge(clk); + -- irq_lines(3) <= '0'; + -- irq_lines(4) <= '0'; + + wait; + + end process irq_stimuli; + + + +-- -- Stimulus process +-- stim_proc: process +-- begin +-- +---- wait for clk_period*10; +-- +---- slvi.adr <= msto.adr; +---- slvi.dat <= msto.dat; +---- slvi.we <= msto.we; +---- slvi.sel <= msto.sel; +---- slvi.stb <= msto.stb; +---- slvi.cyc <= msto.cyc; +---- +-- --- +---- msti.dat <= slvo.dat; +---- msti.ack <= slvo.ack; +-- +-- wait; +-- end process; + +END; diff --git a/soc/testbench/coreicnmem_wave.wcfg b/soc/testbench/coreicnmem_wave.wcfg new file mode 100644 index 0000000..2e561c1 --- /dev/null +++ b/soc/testbench/coreicnmem_wave.wcfg @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + Core 2 dmem + label + + core2dm_sc + core2dm_sc + + .write_data + core2dm_sc.write_data + HEXRADIX + + + .write_addr + core2dm_sc.write_addr + HEXRADIX + + + .write_size + core2dm_sc.write_size + + + .write_en + core2dm_sc.write_en + + + .read_addr + core2dm_sc.read_addr + HEXRADIX + + + .read_size + core2dm_sc.read_size + + + .read_en + core2dm_sc.read_en + + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + + [2] + msto[2] + + + [1] + msto[1] + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + HEXRADIX + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + + + .wbidx + msto[0].wbidx + + + + + slvi[15:0] + slvi[15:0] + + + core2dm_sm + core2dm_sm + + .write_data + core2dm_sm.write_data + UNSIGNEDDECRADIX + + + .write_addr + core2dm_sm.write_addr + HEXRADIX + + + .write_size + core2dm_sm.write_size + + + .write_en + core2dm_sm.write_en + + + .read_addr + core2dm_sm.read_addr + HEXRADIX + + + .read_size + core2dm_sm.read_size + + + .read_en + core2dm_sm.read_en + + + + + dmem 2 core + label + + dm2core_sm + dm2core_sm + + .read_data + dm2core_sm.read_data + HEXRADIX + + + .ready + dm2core_sm.ready + + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + + [14] + slvo[14] + + + [13] + slvo[13] + + + [12] + slvo[12] + + + [11] + slvo[11] + + + [10] + slvo[10] + + + [9] + slvo[9] + + + [8] + slvo[8] + + + [7] + slvo[7] + + + [6] + slvo[6] + + + [5] + slvo[5] + + + [4] + slvo[4] + + + [3] + slvo[3] + + + [2] + slvo[2] + + + [1] + slvo[1] + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + + + .wbidx + slvo[0].wbidx + + + + + msti[3:0] + msti[3:0] + + + dm2core_sc + dm2core_sc + + + + I mem + label + + imem_proc_signal + imem_proc_signal + + .read_data + imem_proc_signal.read_data + HEXRADIX + + + .ready + imem_proc_signal.ready + + + + proc_imem_signal + proc_imem_signal + + .read_addr + proc_imem_signal.read_addr + HEXRADIX + + + .read_en + proc_imem_signal.read_en + + + + + I R Q + label + + irq_proc_signal + irq_proc_signal + + + proc_irq_signal + proc_irq_signal + + + irq_lines[15:0] + irq_lines[15:0] + + + + out_byte[7:0] + out_byte[7:0] + + + ICN + label + 128 128 255 + 230 230 230 + + + ICN + label + + clk + clk + + + rst + rst + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + + [2] + msto[2] + + + [1] + msto[1] + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + + + .wbidx + msto[0].wbidx + + + + + tmpmsto[3:0] + tmpmsto[3:0] + + [3] + tmpmsto[3] + + + [2] + tmpmsto[2] + + + [1] + tmpmsto[1] + + + [0] + tmpmsto[0] + + .adr + tmpmsto[0].adr + HEXRADIX + + + .dat + tmpmsto[0].dat + + + .we + tmpmsto[0].we + + + .sel + tmpmsto[0].sel + + + .stb + tmpmsto[0].stb + + + .cyc + tmpmsto[0].cyc + + + .wbcfg + tmpmsto[0].wbcfg + + + .wbidx + tmpmsto[0].wbidx + + + + + slvi[15:0] + slvi[15:0] + + [15] + slvi[15] + + + [14] + slvi[14] + + + [13] + slvi[13] + + + [12] + slvi[12] + + + [11] + slvi[11] + + + [10] + slvi[10] + + + [9] + slvi[9] + + + [8] + slvi[8] + + + [7] + slvi[7] + + + [6] + slvi[6] + + + [5] + slvi[5] + + + [4] + slvi[4] + + + [3] + slvi[3] + + + [2] + slvi[2] + + + [1] + slvi[1] + + + [0] + slvi[0] + + .adr + slvi[0].adr + HEXRADIX + + + .dat + slvi[0].dat + + + .we + slvi[0].we + + + .sel + slvi[0].sel + + + .stb + slvi[0].stb + + + .cyc + slvi[0].cyc + + + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + + [14] + slvo[14] + + + [13] + slvo[13] + + + [12] + slvo[12] + + + [11] + slvo[11] + + + [10] + slvo[10] + + + [9] + slvo[9] + + + [8] + slvo[8] + + + [7] + slvo[7] + + + [6] + slvo[6] + + + [5] + slvo[5] + + + [4] + slvo[4] + + + [3] + slvo[3] + + + [2] + slvo[2] + + + [1] + slvo[1] + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + HEXRADIX + + + .wbidx + slvo[0].wbidx + + + + + tmpslvo[15:0] + tmpslvo[15:0] + + + msti[3:0] + msti[3:0] + + [3] + msti[3] + + .dat + msti[3].dat + HEXRADIX + + + .ack + msti[3].ack + + + + [2] + msti[2] + + .dat + msti[2].dat + HEXRADIX + + + .ack + msti[2].ack + + + + [1] + msti[1] + + .dat + msti[1].dat + HEXRADIX + + + .ack + msti[1].ack + + + + [0] + msti[0] + + .dat + msti[0].dat + HEXRADIX + + + .ack + msti[0].ack + + + + + mgnt_idx + mgnt_idx + + + mgnt[0:3] + mgnt[0:3] + + + ssel_idx + ssel_idx + + + ssel[0:15] + ssel[0:15] + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + + dat_sz + dat_sz + + + adr_sz + adr_sz + + + nib_sz + nib_sz + + + diff --git a/soc/testbench/corewbmem_tb.vhd b/soc/testbench/corewbmem_tb.vhd new file mode 100644 index 0000000..a310461 --- /dev/null +++ b/soc/testbench/corewbmem_tb.vhd @@ -0,0 +1,314 @@ +-- See the file "LICENSE" for the full license governing this code. -- +--test bench +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + + +ENTITY corewbmem_tb IS +END corewbmem_tb; + +ARCHITECTURE behavior OF corewbmem_tb IS +--////////////////////////////////////////////// +-- component +--////////////////////////////////////////////// +component core + port(clk : in std_logic; + rst : in std_logic; + stall : in std_logic; + in_dmem : in dmem_core; + out_dmem : out core_dmem; + in_imem : in imem_core; + out_imem : out core_imem; + in_irq : in irq_core; + out_irq : out core_irq; + hardfault : out std_logic); +end component core; + +component memdiv +--component memory +generic( + filename : in string := "program.ram"; + size : in integer := 256; + imem_latency : in time := 5 ns; + dmem_latency : in time := 5 ns; + dmemsz : integer := DMEMSZ; + imemsz : integer := IMEMSZ +); +port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : in core_dmem; + out_dmem : out dmem_core; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0)); +end component; + +component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); +end component; + +component core2wb + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out dmem_core; + out_dmem : in core_dmem; + + -- wb master port + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); +end component; + +component mem2wb + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + wbidx : integer := CFG_MEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out core_dmem; + out_dmem : in dmem_core; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end component; + +--////////////////////////////////////////////// +-- signal +--////////////////////////////////////////////// +-- Clock period definitions + constant clk_period : time := 10 ns; + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1000_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + -- signals between instances + + signal core2dm_sc : core_dmem; + signal core2dm_sm : core_dmem; + signal dm2core_sc : dmem_core; + signal dm2core_sm : dmem_core; + + signal imem_proc_signal : imem_core; + signal proc_imem_signal : core_imem; + + signal irq_proc_signal : irq_core; + signal proc_irq_signal : core_irq; + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0); + + --signal slvi : wb_slv_in_type ;--:= wbs_in_none; + --signal msti : wb_mst_in_type ;--:= wbm_in_none; + + signal slvo : wb_slv_out_type := wbs_out_none; + signal msto : wb_mst_out_type := wbm_out_none; + + signal out_byte: std_logic_vector(7 downto 0); + --signal hardfault: std_logic; + --signal fault: std_logic; + +BEGIN + --////////////////////////////////////////////// +-- instantiation +--////////////////////////////////////////////// +---------- +--core +---------- +core_inst : component core + port map( + clk => clk, + rst => rst, + stall => '0', + + in_dmem => dm2core_sc, + out_dmem => core2dm_sc, + + in_imem => imem_proc_signal, + out_imem => proc_imem_signal, + + in_irq => irq_proc_signal, + out_irq => proc_irq_signal, + hardfault => irq_lines(1) +); +---------- +--memdiv +---------- + mem_inst: memdiv + --mem_inst: memory + generic map( + filename => "test_endianess2.ram", + size => DMEMSZ + IMEMSZ, + imem_latency => 0 ns, + dmem_latency => 0 ns, + dmemsz => DMEMSZ, + imemsz => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + + in_dmem => core2dm_sm, + out_dmem => dm2core_sm, + + in_imem => proc_imem_signal, + out_imem => imem_proc_signal, + + fault => irq_lines(2), + out_byte => out_byte + ); +---------- +--irq +---------- + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => proc_irq_signal, + out_proc => irq_proc_signal, + irq_lines => irq_lines + ); + +---------- +--core2wb +---------- + core2wb0: core2wb + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_dmem => dm2core_sc, + out_dmem => core2dm_sc, + + --wmsti => msti, + wmsti.dat => slvo.dat, + wmsti.ack => slvo.ack, + + wmsto => msto + ); + +---------- +--mem2wb +---------- + + +mem2wb0: mem2wb + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM + ) + port map( + clk => clk, + rst => rst, + + in_dmem => core2dm_sm, + out_dmem => dm2core_sm, + + --wslvi => slvi, + wslvi.adr => msto.adr, + wslvi.dat => msto.dat, + wslvi.we => msto.we, + wslvi.sel => msto.sel, + wslvi.stb => msto.stb, + wslvi.cyc => msto.cyc, + -- + wslvo => slvo + ); + + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + -- reset stimuli + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + + -- irq line stimuli + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + -- irq0 is reset + -- irq1 is hardfault + -- irq2 is memfault + + -- wait for 600 ns; + + -- wait until rising_edge(clk); + -- irq_lines(3) <= '1'; + -- irq_lines(4) <= '1'; + -- wait until rising_edge(clk); + -- irq_lines(3) <= '0'; + -- irq_lines(4) <= '0'; + + wait; + + end process irq_stimuli; + + + +-- -- Stimulus process +-- stim_proc: process +-- begin +-- +---- wait for clk_period*10; +-- +---- slvi.adr <= msto.adr; +---- slvi.dat <= msto.dat; +---- slvi.we <= msto.we; +---- slvi.sel <= msto.sel; +---- slvi.stb <= msto.stb; +---- slvi.cyc <= msto.cyc; +---- +-- --- +---- msti.dat <= slvo.dat; +---- msti.ack <= slvo.ack; +-- +-- wait; +-- end process; + +END; diff --git a/soc/testbench/corewrap_tb.vhd b/soc/testbench/corewrap_tb.vhd new file mode 100644 index 0000000..5bc065b --- /dev/null +++ b/soc/testbench/corewrap_tb.vhd @@ -0,0 +1,182 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +ENTITY corewrap_tb IS +END corewrap_tb; + +ARCHITECTURE behavior OF corewrap_tb IS + + component corewrapper + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); + end component; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal in_imem : imem_core; + signal in_proc : irq_core; + signal wmsti : wb_mst_in_type := wbm_in_none; + + --Outputs + signal out_imem : core_imem; + signal out_proc : core_irq; + signal hardfault : std_logic; + signal wmsto : wb_mst_out_type; + + -- Clock period definitions + constant clk_period : time := 10 ns; + + --internal signal + --signal irq2core : irq_core; + --signal core2irq : core_irq; + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0) := (others => '0'); + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: corewrapper + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_imem => in_imem, + out_imem => out_imem, + + in_proc => in_proc, + out_proc => out_proc, + + hardfault => hardfault, + + wmsti => wmsti, + wmsto => wmsto + ); + + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => out_proc, + out_proc => in_proc, + irq_lines => irq_lines + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + --irq_lines(1) <= hardfault; + wait; + end process irq_stimuli; + + -- Stimulus process + stim_proc: process + begin + --init + in_imem.read_data <= (others=>'0'); + in_imem.ready <= '0'; + wmsti <= wbm_in_none; + --end init + + -- hold reset state for 100 ns. + wait for 100 ns; + + wait for clk_period*10; + + -------------------------------------- + -- Test_case 00: + -------------------------------------- + -- No request + -- Expected output all control signal should be inactive + -- Expected error: None + -------------------------------------- + --report ">> TC0 starts <<"; + -------------------------------------- + --data + assert wmsti.ack = '1' + report"E-00: No data request, but msti.ack for dmem should always be active" + severity error; + + --ins + assert in_imem.ready = '1' + report"E-01: No ins request, but in_imem.ready should always be active" + severity error; + -------------------------------------- + --report ">> TC0 ends <<"; + -------------------------------------- + -- + --E N D Test_case 00 + -- + -------------------------------------- + + --///////////////////////////////////////// + assert false + report ">>>> Simulation beendet!" + severity failure; + end process; + +END; diff --git a/soc/testbench/corewrap_wave.wcfg b/soc/testbench/corewrap_wave.wcfg new file mode 100644 index 0000000..17c392d --- /dev/null +++ b/soc/testbench/corewrap_wave.wcfg @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + in_imem + in_imem + + .read_data + in_imem.read_data + HEXRADIX + + + .ready + in_imem.ready + + + + in_proc + in_proc + + + wmsti + wmsti + + .dat + wmsti.dat + HEXRADIX + + + .ack + wmsti.ack + + + + out_imem + out_imem + + .read_addr + out_imem.read_addr + HEXRADIX + + + .read_en + out_imem.read_en + + + + out_proc + out_proc + + + hardfault + hardfault + + + wmsto + wmsto + + + irq_lines[15:0] + irq_lines[15:0] + + + core2wb + label + + clk + clk + + + rst + rst + + + in_dmem + in_dmem + + .read_data + in_dmem.read_data + HEXRADIX + + + .ready + in_dmem.ready + + + + out_dmem + out_dmem + + .write_data + out_dmem.write_data + HEXRADIX + + + .write_addr + out_dmem.write_addr + HEXRADIX + + + .write_size + out_dmem.write_size + + + .write_en + out_dmem.write_en + + + .read_addr + out_dmem.read_addr + HEXRADIX + + + .read_size + out_dmem.read_size + + + .read_en + out_dmem.read_en + + + + wmsti + wmsti + + .dat + wmsti.dat + HEXRADIX + + + .ack + wmsti.ack + + + + wmsto + wmsto + + .adr + wmsto.adr + HEXRADIX + + + .dat + wmsto.dat + HEXRADIX + + + .we + wmsto.we + + + .sel + wmsto.sel + + + .stb + wmsto.stb + + + .cyc + wmsto.cyc + + + .wbcfg + wmsto.wbcfg + + + .wbidx + wmsto.wbidx + + + + msto + msto + + .adr + msto.adr + HEXRADIX + + + .dat + msto.dat + HEXRADIX + + + .we + msto.we + + + .sel + msto.sel + + + .stb + msto.stb + + + .cyc + msto.cyc + + + .wbcfg + msto.wbcfg + + + .wbidx + msto.wbidx + + + + indmem + indmem + + .read_data + indmem.read_data + HEXRADIX + + + .ready + indmem.ready + + + + wbidx + wbidx + + + + Core + label + + clk + clk + + + rst + rst + + + stall + stall + + + in_dmem + in_dmem + + .read_data + in_dmem.read_data + HEXRADIX + + + .ready + in_dmem.ready + + + + out_dmem + out_dmem + + .write_data + out_dmem.write_data + HEXRADIX + + + .write_addr + out_dmem.write_addr + HEXRADIX + + + .write_size + out_dmem.write_size + + + .write_en + out_dmem.write_en + + + .read_addr + out_dmem.read_addr + HEXRADIX + + + .read_size + out_dmem.read_size + + + .read_en + out_dmem.read_en + + + + in_imem + in_imem + + .read_data + in_imem.read_data + HEXRADIX + + + .ready + in_imem.ready + + + + out_imem + out_imem + + .read_addr + out_imem.read_addr + HEXRADIX + + + .read_en + out_imem.read_en + + + + in_irq + in_irq + + + out_irq + out_irq + + + hardfault + hardfault + + + dp_cp_signal + dp_cp_signal + + + dp_dmem_signal + dp_dmem_signal + + + dmem_dp_signal + dmem_dp_signal + + + imem_dec_signal + imem_dec_signal + + + dec_cp_signal + dec_cp_signal + + + dec_imem_signal + dec_imem_signal + + + cp_dp_signal + cp_dp_signal + + + cp_dmem_signal + cp_dmem_signal + + + cp_dec_signal + cp_dec_signal + + + pc_dp_signal + pc_dp_signal + + + dp_pc_signal + dp_pc_signal + + + dec_pc_signal + dec_pc_signal + + + pc_imem_signal + pc_imem_signal + + + cp_pc_signal + cp_pc_signal + + + irq_dec_signal + irq_dec_signal + + + dec_irq_signal + dec_irq_signal + + + dp_dec_signal + dp_dec_signal + + + hardfault_dp + hardfault_dp + + + hardfault_cp + hardfault_cp + + + stall_internal + stall_internal + + + diff --git a/soc/testbench/cwicnmw_tb.vhd b/soc/testbench/cwicnmw_tb.vhd new file mode 100644 index 0000000..fced6b0 --- /dev/null +++ b/soc/testbench/cwicnmw_tb.vhd @@ -0,0 +1,236 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +ENTITY cwicnmw_tb IS +END cwicnmw_tb; + +ARCHITECTURE behavior OF cwicnmw_tb IS +--////////////////////////////////////////////// +-- +-- component +-- +--////////////////////////////////////////////// + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + dat_sz: integer := WB_PORT_SIZE; + adr_sz: integer := WB_ADR_WIDTH; + nib_sz: integer := WB_PORT_GRAN + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + --//////////////////////////////////////////// + component corewrapper + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); + end component; + + component memwrapper + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + wbidx : integer := CFG_MEM; + filename : string := "program.ram"; + dmemsz : integer := DMEMSZ; + imemsz : integer := IMEMSZ + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0); + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component; + +--////////////////////////////////////////////// +-- Signals & constants +--////////////////////////////////////////////// + constant clk_period : time := 10 ns; + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1000_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + --base adr + --constant CFG_BADR_TSTS1 : generic_addr_type := 16#28400000#; -- 30bits (32b = A1000000) + --constant CFG_BADR_TSTS2 : generic_addr_type := 16#28800000#; -- 30bits (32b = A2000000) + + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + --Outputs + --signal led : std_logic_vector(7 downto 0); + signal out_byte: std_logic_vector(7 downto 0); + + -- Internal signals + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0) := (others=>'0'); + + signal slvo : wb_slv_out_vector := (others=> wbs_out_none); + signal msto : wb_mst_out_vector := (others=> wbm_out_none); + + signal slvi : wb_slv_in_vector := (others=> wbs_in_none); + signal msti : wb_mst_in_vector := (others=> wbm_in_none); + + signal core2mem : core_imem; + signal mem2core : imem_core; + + signal irq2core : irq_core; + signal core2irq : core_irq; + + +begin + + wbicn_inst: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + + corewrap_inst: corewrapper + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_imem => mem2core, + out_imem => core2mem, + + in_proc => irq2core, + out_proc => core2irq, + + hardfault => irq_lines(1), + + wmsti => msti(CFG_LT16), + wmsto => msto(CFG_LT16) + ); + + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => core2irq, + out_proc => irq2core, + irq_lines => irq_lines + ); + + memwrap_inst: memwrapper + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM, + --filename => "sample-programs\rawhztest.ram", + filename => "sample-programs\test_endianess2.ram", + dmemsz => DMEMSZ, + imemsz => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + in_imem => core2mem, + out_imem => mem2core, + + fault => irq_lines(2), + out_byte => out_byte, + + wslvi => slvi(CFG_MEM), + wslvo => slvo(CFG_MEM) + ); + +--////////////////////////////////////////////// +-- Process +--////////////////////////////////////////////// + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + wait; + end process irq_stimuli; + + +end; \ No newline at end of file diff --git a/soc/testbench/cwicnmw_wave.wcfg b/soc/testbench/cwicnmw_wave.wcfg new file mode 100644 index 0000000..2f6a262 --- /dev/null +++ b/soc/testbench/cwicnmw_wave.wcfg @@ -0,0 +1,589 @@ + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + out_byte[7:0] + out_byte[7:0] + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + .dat + slvo[15].dat + HEXRADIX + + + .ack + slvo[15].ack + + + .wbcfg + slvo[15].wbcfg + HEXRADIX + + + .wbidx + slvo[15].wbidx + + + + [14] + slvo[14] + + .dat + slvo[14].dat + HEXRADIX + + + .ack + slvo[14].ack + + + .wbcfg + slvo[14].wbcfg + HEXRADIX + + + .wbidx + slvo[14].wbidx + + + + [13] + slvo[13] + + .dat + slvo[13].dat + HEXRADIX + + + .ack + slvo[13].ack + + + .wbcfg + slvo[13].wbcfg + HEXRADIX + + + .wbidx + slvo[13].wbidx + + + + [12] + slvo[12] + + .dat + slvo[12].dat + HEXRADIX + + + .ack + slvo[12].ack + + + .wbcfg + slvo[12].wbcfg + HEXRADIX + + + .wbidx + slvo[12].wbidx + + + + [11] + slvo[11] + + .dat + slvo[11].dat + HEXRADIX + + + .ack + slvo[11].ack + + + .wbcfg + slvo[11].wbcfg + HEXRADIX + + + .wbidx + slvo[11].wbidx + + + + [10] + slvo[10] + + .dat + slvo[10].dat + HEXRADIX + + + .ack + slvo[10].ack + + + .wbcfg + slvo[10].wbcfg + + + .wbidx + slvo[10].wbidx + + + + [9] + slvo[9] + + .dat + slvo[9].dat + HEXRADIX + + + .ack + slvo[9].ack + + + .wbcfg + slvo[9].wbcfg + HEXRADIX + + + .wbidx + slvo[9].wbidx + + + + [8] + slvo[8] + + .dat + slvo[8].dat + HEXRADIX + + + .ack + slvo[8].ack + + + .wbcfg + slvo[8].wbcfg + + + .wbidx + slvo[8].wbidx + + + + [7] + slvo[7] + + .dat + slvo[7].dat + HEXRADIX + + + .ack + slvo[7].ack + + + .wbcfg + slvo[7].wbcfg + HEXRADIX + + + .wbidx + slvo[7].wbidx + + + + [6] + slvo[6] + + .dat + slvo[6].dat + + + .ack + slvo[6].ack + + + .wbcfg + slvo[6].wbcfg + HEXRADIX + + + .wbidx + slvo[6].wbidx + + + + [5] + slvo[5] + + .dat + slvo[5].dat + HEXRADIX + + + .ack + slvo[5].ack + + + .wbcfg + slvo[5].wbcfg + HEXRADIX + + + .wbidx + slvo[5].wbidx + + + + [4] + slvo[4] + + .dat + slvo[4].dat + HEXRADIX + + + .ack + slvo[4].ack + + + .wbcfg + slvo[4].wbcfg + HEXRADIX + + + .wbidx + slvo[4].wbidx + + + + [3] + slvo[3] + + .dat + slvo[3].dat + HEXRADIX + + + .ack + slvo[3].ack + + + .wbcfg + slvo[3].wbcfg + HEXRADIX + + + .wbidx + slvo[3].wbidx + + + + [2] + slvo[2] + + .dat + slvo[2].dat + HEXRADIX + + + .ack + slvo[2].ack + + + .wbcfg + slvo[2].wbcfg + HEXRADIX + + + .wbidx + slvo[2].wbidx + + + + [1] + slvo[1] + + .dat + slvo[1].dat + HEXRADIX + + + .ack + slvo[1].ack + + + .wbcfg + slvo[1].wbcfg + HEXRADIX + + + .wbidx + slvo[1].wbidx + + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + HEXRADIX + + + .wbidx + slvo[0].wbidx + + + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + .adr + msto[3].adr + HEXRADIX + + + .dat + msto[3].dat + HEXRADIX + + + .we + msto[3].we + + + .sel + msto[3].sel + + + .stb + msto[3].stb + + + .cyc + msto[3].cyc + + + .wbcfg + msto[3].wbcfg + HEXRADIX + + + .wbidx + msto[3].wbidx + + + + [2] + msto[2] + + .adr + msto[2].adr + HEXRADIX + + + .dat + msto[2].dat + HEXRADIX + + + .we + msto[2].we + + + .sel + msto[2].sel + + + .stb + msto[2].stb + + + .cyc + msto[2].cyc + + + .wbcfg + msto[2].wbcfg + HEXRADIX + + + .wbidx + msto[2].wbidx + + + + [1] + msto[1] + + .adr + msto[1].adr + HEXRADIX + + + .dat + msto[1].dat + HEXRADIX + + + .we + msto[1].we + + + .sel + msto[1].sel + + + .stb + msto[1].stb + + + .cyc + msto[1].cyc + + + .wbcfg + msto[1].wbcfg + HEXRADIX + + + .wbidx + msto[1].wbidx + + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + HEXRADIX + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + HEXRADIX + + + .wbidx + msto[0].wbidx + + + + + slvi[15:0] + slvi[15:0] + + + msti[3:0] + msti[3:0] + + + core2mem + core2mem + + + mem2core + mem2core + + + IRQ + label + + irq2core + irq2core + + + irq_lines[15:0] + irq_lines[15:0] + + + core2irq + core2irq + + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + diff --git a/soc/testbench/cwmw_tb.vhd b/soc/testbench/cwmw_tb.vhd new file mode 100644 index 0000000..4d6d7f1 --- /dev/null +++ b/soc/testbench/cwmw_tb.vhd @@ -0,0 +1,220 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +ENTITY cwmw_tb IS +END cwmw_tb; + +ARCHITECTURE behavior OF cwmw_tb IS +--////////////////////////////////////////////// +-- +-- component +-- +--////////////////////////////////////////////// + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + dat_sz: integer := WB_PORT_SIZE; + adr_sz: integer := WB_ADR_WIDTH; + nib_sz: integer := WB_PORT_GRAN + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + --//////////////////////////////////////////// + component corewrapper + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); + end component; + + component memwrapper + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + wbidx : integer := CFG_MEM; + filename : string := "program.ram"; + dmemsz : integer := DMEMSZ; + imemsz : integer := IMEMSZ + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0); + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component; + +--////////////////////////////////////////////// +-- Signals & constants +--////////////////////////////////////////////// + constant clk_period : time := 10 ns; + constant filename : string := "rdmem.ram"; + + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1000_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + --Outputs + signal out_byte: std_logic_vector(7 downto 0); + + -- Internal signals + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0) := (others=>'0'); + + signal slvo: wb_slv_out_type := wbs_out_none; + signal msto: wb_mst_out_type := wbm_out_none; + + signal core2mem : core_imem; + signal mem2core : imem_core; + + signal irq2core : irq_core; + signal core2irq : core_irq; + + +begin + + corewrap_inst: corewrapper + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_imem => mem2core, + out_imem => core2mem, + + in_proc => irq2core, + out_proc => core2irq, + + hardfault => irq_lines(1), + + wmsti.dat => slvo.dat, + wmsti.ack => slvo.ack, + wmsto => msto + ); + + + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => core2irq, + out_proc => irq2core, + irq_lines => irq_lines + ); + + memwrap_inst: memwrapper + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM, + filename => filename, + dmemsz => DMEMSZ, + imemsz => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + in_imem => core2mem, + out_imem => mem2core, + + fault => irq_lines(2), + out_byte => out_byte, + wslvi.adr => msto.adr, + wslvi.dat => msto.dat, + wslvi.we => msto.we, + wslvi.sel => msto.sel, + wslvi.stb => msto.stb, + wslvi.cyc => msto.cyc, + wslvo => slvo + ); +--////////////////////////////////////////////// + +--////////////////////////////////////////////// +-- Process +--////////////////////////////////////////////// + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + wait; + end process irq_stimuli; + + +end; \ No newline at end of file diff --git a/soc/testbench/cwmw_wave.wcfg b/soc/testbench/cwmw_wave.wcfg new file mode 100644 index 0000000..155d7ee --- /dev/null +++ b/soc/testbench/cwmw_wave.wcfg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + out_byte[7:0] + out_byte[7:0] + + + slvi + slvi + + .adr + slvi.adr + HEXRADIX + + + .dat + slvi.dat + HEXRADIX + + + .we + slvi.we + + + .sel + slvi.sel + + + .stb + slvi.stb + + + .cyc + slvi.cyc + + + + slvo + slvo + + .dat + slvo.dat + HEXRADIX + + + .ack + slvo.ack + + + .wbcfg + slvo.wbcfg + + + .wbidx + slvo.wbidx + + + + msto + msto + + .adr + msto.adr + HEXRADIX + + + .dat + msto.dat + HEXRADIX + + + .we + msto.we + + + .sel + msto.sel + + + .stb + msto.stb + + + .cyc + msto.cyc + + + .wbcfg + msto.wbcfg + + + .wbidx + msto.wbidx + + + + core2mem + core2mem + + .read_addr + core2mem.read_addr + HEXRADIX + + + .read_en + core2mem.read_en + + + + mem2core + mem2core + + .read_data + mem2core.read_data + HEXRADIX + + + .ready + mem2core.ready + + + + irq_lines[15:0] + irq_lines[15:0] + + + irq2core + irq2core + + + core2irq + core2irq + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + diff --git a/soc/testbench/dmem_sw_tb.vhd b/soc/testbench/dmem_sw_tb.vhd new file mode 100644 index 0000000..8725db3 --- /dev/null +++ b/soc/testbench/dmem_sw_tb.vhd @@ -0,0 +1,57 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY dmem_sw_tb IS +END ENTITY; + +ARCHITECTURE sim OF dmem_sw_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + + signal led : std_logic_vector(7 downto 0); + + COMPONENT lt16soc_top IS + generic( + programfilename : string := "programs/blinky.ram" -- see "Synthesize XST" process properties for actual value ("-generics" in .xst file)! + ); + port( + clk : in std_logic; + rst : in std_logic; + led : out std_logic_vector(7 downto 0) + ); + END COMPONENT; + +BEGIN + + dut: lt16soc_top + generic map( + programfilename=>"programs/dmem_test.ram" + ) + port map( + clk=>clk, + rst=>rst, + led=>led + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '0'; + wait for CLK_PERIOD; + rst <= '1'; + wait for 2000*CLK_PERIOD; + wait; + end process stimuli; + + +END ARCHITECTURE; diff --git a/soc/testbench/dmem_test.vhd b/soc/testbench/dmem_test.vhd new file mode 100644 index 0000000..99b66c6 --- /dev/null +++ b/soc/testbench/dmem_test.vhd @@ -0,0 +1,113 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +library work; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; +use work.wb_tp.all; + +ENTITY dmem_test IS +END dmem_test; + +ARCHITECTURE behavior OF dmem_test IS + + COMPONENT wb_dmem is + generic( + memaddr : generic_addr_type; + addrmask : generic_mask_type := CFG_MADR_DMEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end COMPONENT; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal wslvi : wb_slv_in_type := wbs_in_none; + + --Outputs + signal wslvo : wb_slv_out_type; + + -- Clock period definitions + constant clk_period : time := 10 ns; + + type block_array is array (0 to 63) of std_logic_vector(7 downto 0); + type ram_array is array (0 to 3) of block_array; + constant test_values : ram_array := ( + (x"00", x"04", x"08", others=>x"00"), + (x"01", x"05", x"09", others=>x"00"), + (x"02", x"06", x"0a", others=>x"00"), + (x"03", x"07", x"0b", others=>x"00") + ); + + signal readdata : std_logic_vector(WB_PORT_SIZE -1 downto 0); + signal writedata : std_logic_vector(WB_PORT_SIZE -1 downto 0); + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: wb_dmem + generic map(memaddr=>0) + PORT MAP(clk => clk, rst => rst, wslvi => wslvi, wslvo => wslvo); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + -- Stimulus process + stim_proc: process + begin + rst <= '1'; + wait for 100 ns; + rst <= '0'; + wait until falling_edge(clk); + + for i in 0 to 63 loop + --test 1: write word, read bytes + + -- assume word data is always given in little endian + writedata <= test_values(3)(i) & test_values(2)(i) & test_values(1)(i) & test_values(0)(i); + + wait until falling_edge(clk); + generate_async_wb_slave_writeaccess( + slvi=>wslvi, + slvo=>wslvo, + writedata=>writedata + ); + + wait for clk_period; + + for j in 0 to 3 loop + + generate_async_wb_slave_readaccess( + slvi=>wslvi, + slvo=>wslvo, + readdata=>readdata, + adr_offset=>j, + size=>"00" + ); + --wait for 1 ps; + assert readdata(7 downto 0)=test_values(j)(i) report "Wrong value read!" severity error; + wait until falling_edge(clk); + end loop; + + end loop; + + + wait for clk_period*10; + + assert false report "Simulation Finished!" severity failure; + end process; + +END; diff --git a/soc/testbench/mem2wb_tb.vhd b/soc/testbench/mem2wb_tb.vhd new file mode 100644 index 0000000..6ad8eb9 --- /dev/null +++ b/soc/testbench/mem2wb_tb.vhd @@ -0,0 +1,255 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; + +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.wb_tp.all; + +ENTITY mem2wb_tb IS +END mem2wb_tb; + +ARCHITECTURE behavior OF mem2wb_tb IS + + -- Component Declaration for the Unit Under Test (UUT) + +component mem2wb + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + wbidx : integer := CFG_MEM + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_dmem : out core_dmem; + out_dmem : in dmem_core; + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); +end component; + + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal out_dmem : dmem_core; + signal wslvi : wb_slv_in_type := wbs_in_none; + + --Outputs + signal in_dmem : core_dmem; + signal wslvo : wb_slv_out_type; + + -- Clock period definitions + constant clk_period : time := 10 ns; + + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: mem2wb + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM + ) + port map( + clk => clk, + rst => rst, + + in_dmem => in_dmem, + out_dmem => out_dmem, + + wslvi => wslvi, + wslvo => wslvo + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset_process : process + begin + --report ">> R e s e t"; + rst <= '1'; + wait for clk_period*3.5; + rst <= '0'; + wait; + end process; + + -- Stimulus process + stim_proc: process + variable tmpadr :std_logic_vector(memory_width - 1 downto 0) := (others=>'0'); + begin + --init + out_dmem.read_data <= (others=>'0'); + out_dmem.ready <= '0'; + + --end init + + -- hold reset state for 100 ns. + wait for 100 ns; + + wait for clk_period*10; + -------------------------------------- + -- Test_case 00: + -------------------------------------- + -- No request + -- Expected output all control signal should be inactive + -- Expected error: None + -------------------------------------- + --report ">> TC0 starts <<"; + -------------------------------------- + -- Handshake-1 (in): + tmpadr := x"0000000B"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"49303035"; + wslvi.we <= '0'; + wslvi.sel <= "0001"; + wslvi.stb <= '0'; + wslvi.cyc <= '0'; + wait for clk_period; + + -- Handshake-2 (out): + assert wb2mem_chk(in_dmem, wslvi, NO_ACC) + report"E-00: No request, control signal should be inactive" + severity error; + + -- Handshake-3 (in): + out_dmem.read_data <= x"00000000"; -- mem always returns data at right most + out_dmem.ready <= '0'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.ack = '0' + report"E-01: No request, ack signal should be inactive" + severity error; + -------------------------------------- + --report ">> TC0 ends <<"; + -------------------------------------- + -- + --E N D Test_case 00 + -- + -------------------------------------- + -------------------------------------- + -- Test_case 01: + -------------------------------------- + -- single read request + -- given data at addr[0000_00005] = x"49303031"; (ascii = I001) + -- B0 = x49, B2 = x30, B1 = x30, B0 = x31 + -- Expected output Return correct read data back to wb in correct format + -- Expected error: None + -------------------------------------- + --report ">> TC1 starts <<"; + -------------------------------------- + -- Handshake-1 (in): + tmpadr := x"00000005"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x30 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-2 (out): + assert wb2mem_chk(in_dmem, wslvi, RD_ACC) + report"E-10: wrong conversion from wb to memory" + severity error; + + -- Handshake-3 (in): + out_dmem.read_data <= x"00000030"; -- mem always returns data at right most + out_dmem.ready <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.ack = '1' and wslvo.dat = x"00300000" + report"E-11: wrong conversion from memory data : " & hstr(out_dmem.read_data) & + " slvo.data: " & hstr(wslvo.dat) + severity error; + -------------------------------------- + --report ">> TC1 ends <<"; + -------------------------------------- + -- + --E N D Test_case 01 + -- + -------------------------------------- + -------------------------------------- + -- Test_case 02: + -------------------------------------- + -- single write request + -- given data at addr[0000_0000C] = x"49303035"; (ascii = I005) + -- B0 = x49, B2 = x30, B1 = x30, B0 = x35 + -- Expected output Return ack, written data is converted correctly + -- Expected error: None + -------------------------------------- + --report ">> TC2 starts <<"; + -------------------------------------- + -- Handshake-1 (in): + tmpadr := x"0000000B"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"49303035"; -- feed full data but take written only B2 + wslvi.we <= '1'; -- write + wslvi.sel <= "0001"; -- sel_byte = B3 -> expected writted data portion = x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-2 (out): + assert wb2mem_chk(in_dmem, wslvi, WR_ACC) + report"E-20: wrong conversion from wb to memory" + severity error; + + -- Handshake-3 (in): + out_dmem.read_data <= x"00000000"; -- mem always returns data at right most + out_dmem.ready <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.ack = '1' + report"E-21: wrong conversion from memory data : " & hstr(out_dmem.read_data) & + " slvo.data: " & hstr(wslvo.dat) + severity error; + -------------------------------------- + --report ">> TC2 ends <<"; + -------------------------------------- + -- + --E N D Test_case 02 + -- + -------------------------------------- + --clear data + out_dmem.read_data <= (others=>'0'); + out_dmem.ready <= '0'; + wslvi <= wbs_in_none; + tmpadr := (others=>'0'); + --end clear + + --///////////////////////////////////////// + assert false + report ">>>> Simulation beendet!" + severity failure; + --wait; + end process; + +END; diff --git a/soc/testbench/mem2wb_wave.wcfg b/soc/testbench/mem2wb_wave.wcfg new file mode 100644 index 0000000..66c8251 --- /dev/null +++ b/soc/testbench/mem2wb_wave.wcfg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + To mem + label + + wslvi + wslvi + + .adr + wslvi.adr + HEXRADIX + + + .dat + wslvi.dat + HEXRADIX + + + .we + wslvi.we + + + .sel + wslvi.sel + + + .stb + wslvi.stb + + + .cyc + wslvi.cyc + + + + in_dmem + in_dmem + + .write_data + in_dmem.write_data + HEXRADIX + + + .write_addr + in_dmem.write_addr + HEXRADIX + + + .write_size + in_dmem.write_size + + + .write_en + in_dmem.write_en + + + .read_addr + in_dmem.read_addr + HEXRADIX + + + .read_size + in_dmem.read_size + + + .read_en + in_dmem.read_en + + + + + To wb + label + + out_dmem + out_dmem + + .read_data + out_dmem.read_data + HEXRADIX + + + .ready + out_dmem.ready + + + + wslvo + wslvo + + .dat + wslvo.dat + HEXRADIX + + + .ack + wslvo.ack + + + .wbcfg + wslvo.wbcfg + + + .wbidx + wslvo.wbidx + + + + diff --git a/soc/testbench/memdiv_tb.vhd b/soc/testbench/memdiv_tb.vhd new file mode 100644 index 0000000..970cfa4 --- /dev/null +++ b/soc/testbench/memdiv_tb.vhd @@ -0,0 +1,367 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +ENTITY memdiv_tb IS +END memdiv_tb; + +ARCHITECTURE behavior OF memdiv_tb IS + + + COMPONENT memdiv + generic( + filename : in string := "program.ram"; + size : in integer := 256; + imem_latency : in time := 5 ns; + dmem_latency : in time := 5 ns + ); + PORT( + clk : in std_logic; + rst : in std_logic; + in_dmem : in core_dmem; + out_dmem : out dmem_core; + in_imem : in core_imem; + out_imem : out imem_core; + fault : out std_logic + ); + END COMPONENT; + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal in_dmem : core_dmem; + signal in_imem : core_imem; + + --Outputs + signal out_dmem : dmem_core; + signal out_imem : imem_core; + signal fault : std_logic; + + -- Clock period definitions + constant clk_period : time := 10 ns; + + + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: memdiv + generic map ( + filename => "sample-programs\dummy.ram", + --size => IMEMSZ, + imem_latency => 0 ns, + dmem_latency => 0 ns + ) + PORT MAP ( + clk => clk, + rst => rst, + in_dmem => in_dmem, + out_dmem => out_dmem, + in_imem => in_imem, + out_imem => out_imem, + fault => fault + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + -- reset stimuli + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process; + + -- Stimulus process + stim_proc: process + + begin + --init + in_imem.read_en <= '0'; + in_imem.read_addr <= (others=>'0'); + -- + in_dmem.read_en <= '0'; + in_dmem.read_addr <= (others=>'0'); + in_dmem.read_size <= "00"; + -- + in_dmem.write_en <= '0'; + in_dmem.write_addr<= (others=>'0'); + in_dmem.write_size <= "00"; + in_dmem.write_data<= (others=>'0'); + --end init + + -- hold reset state for 100 ns. + wait for 100 ns; + wait for clk_period*10; + +-- in_imem.read_en <= '1'; + + +-- in_imem.read_addr <= x"00000000"; wait for clk_period; -- wait until out_imem.ready = '1'; +-- assert out_imem.read_data = x"C4050000" +-- report "E-00: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"00000004"; wait for clk_period; +-- assert out_imem.read_data = x"C0000000" +-- report "E-01: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"00000008"; wait for clk_period; +-- assert out_imem.read_data = x"C0000000" +-- report "E-02: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"0000000C"; wait for clk_period; +-- assert out_imem.read_data = x"00000111" +-- report "E-03: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"00000010"; wait for clk_period; +-- assert out_imem.read_data = x"02220333" +-- report "E-04: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"00000014"; wait for clk_period; +-- assert out_imem.read_data = x"04447055" +-- report "E-05: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- +-- in_imem.read_addr <= x"00000018"; wait for clk_period; +-- assert out_imem.read_data = x"0100720A" +-- report "E-06: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- +-- in_imem.read_addr <= x"0000001C"; wait for clk_period; +-- assert out_imem.read_data = x"532F533B" +-- report "E-07: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- in_imem.read_addr <= x"00000020"; wait for clk_period; +-- assert out_imem.read_data = x"A403BA43" +-- report "E-08: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- +-- in_imem.read_addr <= x"00000024"; wait for clk_period; +-- assert out_imem.read_data = x"C4FF0000" +-- report "E-09: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; +-- +-- +-- in_imem.read_addr <= x"00000028"; wait for clk_period; +-- assert out_imem.read_data = x"000003C0" +-- report "E-10: RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) +-- severity error; + +--////////////////////////////////////////////////////////// +------------------------------------------------------- +-- Test case 00: dmem_read only, read byte +-- Read size = 00 (8 bits) +-- Address: 0000_000C +-- wordaddress = 0x03 +-- byteaddress = 00 - 11 +-- word value at address: 0000_0000C = I003 +------------------------------------------------------- + in_dmem.read_en <= '1'; + in_dmem.read_size <= "00"; + -- + in_dmem.write_en <= '0'; + in_dmem.write_addr <= (others=>'0'); + in_dmem.write_size <= "00"; + in_dmem.write_data <= (others=>'0'); + -- + in_dmem.read_addr <= x"0000000C"; wait for clk_period; -- wadr = 0x03, badr = B0 + assert out_dmem.read_data = x"00000049" -- (ascii) val = I + report "E-D00: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000D"; wait for clk_period; -- wadr = 0x03, badr = B1 + assert out_dmem.read_data = x"00000030" -- (ascii) val = 0 + report "E-D01: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000E"; wait for clk_period; -- wadr = 0x03, badr = B2 + assert out_dmem.read_data = x"00000030" -- (ascii) val = 0 + report "E-D02: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000F"; wait for clk_period; -- wadr = 0x03, badr = B3 + assert out_dmem.read_data = x"00000033" -- (ascii) val = 3 + report "E-D03: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + wait for clk_period; +------------------------------------------------------- +-- Test case 01: dmem_write only, write byte +-- write size = 00 (8 bits) +-- Address: 0000_0011 +-- wordaddress = 0x04 +-- byteaddress = 00 - 11 +-- org word value at address: 4930_3034 = I004 +-- new word value at address: 4934_3034 = I404 +------------------------------------------------------- + in_dmem.read_size <= "00"; + -- + in_dmem.write_en <= '1'; + in_dmem.write_size <= "00"; + -- + --Read org value before write + in_dmem.read_en <= '1'; in_dmem.read_addr <= x"00000011"; wait for clk_period; + report "RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity note; + + --write + in_dmem.read_en <= '0'; + in_dmem.write_addr <= x"00000011"; in_dmem.write_data <= x"00000034"; -- (ascii) val = 4 + wait for clk_period; -- wadr = 0x04, badr = B1 + + assert out_dmem.ready = '1' + report "E-D10: WR req addr: " & hstr(in_dmem.write_addr) & ", No Return ack " + severity error; + + --Read writtem value after write + in_dmem.read_en <= '1'; in_dmem.read_addr <= x"00000011"; wait for clk_period; + assert out_dmem.read_data = x"00000034" -- (ascii) val = 4 + report "E-D11: Check written value: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + +------------------------------------------------------- +-- Test case 02: simultaneous read and write with different address +-- read / write size = 00 (8 bits) +-- Read Address: 0000_000C +-- wordaddress = 0x03 +-- byteaddress = 00 - 11 +-- word value at address: 0000_0000C = I003 +-- +-- Write Address: 0000_0015 +-- wordaddress = 0x05 +-- byteaddress = 00 - 11 +-- org word value at address: 4930_3035 = I005 +-- new word value at address: 4935_3035 = I505 +------------------------------------------------------- + in_dmem.read_en <= '1'; + in_dmem.read_size <= "00"; + -- + in_dmem.write_en <= '1'; + in_dmem.write_size <= "00"; + + --Read org value before write + in_dmem.read_addr <= x"00000015"; wait for clk_period; + report "RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity note; + + --start + wait for clk_period; + in_dmem.read_addr <= x"0000000C"; + in_dmem.write_addr <= x"00000015"; in_dmem.write_data <= x"00000035"; -- (ascii) val = 5 + + + wait for clk_period; -- wadr = 0x03, badr = B0 + --assert for read + assert out_dmem.read_data = x"00000049" -- (ascii) val = I + report "E-D20: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + --assert for write_ack + assert out_dmem.ready = '1' + report "E-D20: WR req addr: " & hstr(in_dmem.write_addr) & ", No Return ack " + severity error; + + --asesert for write data + --Read written value after write + in_dmem.read_en <= '1'; in_dmem.read_addr <= x"00000015"; wait for clk_period; + assert out_dmem.read_data = x"00000035" -- (ascii) val = 5 + report "E-D21: Check written value: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000D"; wait for clk_period; -- wadr = 0x03, badr = B1 + assert out_dmem.read_data = x"00000030" -- (ascii) val = 0 + report "E-D22: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000E"; wait for clk_period; -- wadr = 0x03, badr = B2 + assert out_dmem.read_data = x"00000030" -- (ascii) val = 0 + report "E-D23: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + in_dmem.read_addr <= x"0000000F"; wait for clk_period; -- wadr = 0x03, badr = B3 + assert out_dmem.read_data = x"00000033" -- (ascii) val = 3 + report "E-D24: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + +------------------------------------------------------- +-- Test case 03: simultaneous read and write with same address +-- read / write size = 00 (8 bits) +-- Read/Write Address: 0000_001D +-- wordaddress = 0x07 +-- byteaddress = 00 - 11 +-- word value at address: 4930_3037 = I007 +-- +-- org word value at address: 4930_3037 = I007 +-- new word value at address: 4935_3037 = I707 +-- +-- Result: +-- it reads before write i.e. obtaining old value +------------------------------------------------------- + + in_dmem.read_en <= '1'; + in_dmem.read_addr <= x"0000001D"; + in_dmem.read_size <= "00"; + -- + in_dmem.write_en <= '1'; + in_dmem.write_addr <= x"0000001D"; + in_dmem.write_size <= "00"; + in_dmem.write_data <= x"00000037"; -- (ascii) val = 7 + wait for clk_period; + + --Fail if assuming read after write, the new value should be read + assert out_dmem.read_data = x"00000037" -- (ascii) val = 7 + report "E-D30: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + --assert for write ack + assert out_dmem.ready = '1' + report "E-D31: WR req addr: " & hstr(in_dmem.write_addr) & ", No Return ack " + severity error; + + + wait for clk_period; + assert out_dmem.read_data = x"00000037" -- (ascii) val = 7 + report "E-D32: RD req addr: " & hstr(in_dmem.read_addr) & ", Return read_data: " & hstr(out_dmem.read_data) + severity error; + + + --///////////////////////////////////////// + assert false + report ">>>> Simulation beendet!" + severity failure; + --wait; + end process; + +END; diff --git a/soc/testbench/memdiv_tb.wcfg b/soc/testbench/memdiv_tb.wcfg new file mode 100644 index 0000000..538a439 --- /dev/null +++ b/soc/testbench/memdiv_tb.wcfg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + in_dmem + in_dmem + + .write_data + in_dmem.write_data + HEXRADIX + + + .write_addr + in_dmem.write_addr + HEXRADIX + + + .write_size + in_dmem.write_size + + + .write_en + in_dmem.write_en + + + .read_addr + in_dmem.read_addr + HEXRADIX + + + .read_size + in_dmem.read_size + + + .read_en + in_dmem.read_en + + + + in_imem + in_imem + + .read_addr + in_imem.read_addr + HEXRADIX + + + .read_en + in_imem.read_en + + + + out_dmem + out_dmem + + .read_data + out_dmem.read_data + HEXRADIX + + + .ready + out_dmem.ready + + + + out_imem + out_imem + + .read_data + out_imem.read_data + HEXRADIX + + + .ready + out_imem.ready + + + + fault + fault + + + out_byte[7:0] + out_byte[7:0] + + diff --git a/soc/testbench/memwrap_tb.vhd b/soc/testbench/memwrap_tb.vhd new file mode 100644 index 0000000..e1240c6 --- /dev/null +++ b/soc/testbench/memwrap_tb.vhd @@ -0,0 +1,571 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.lt16soc_memories.all; + +ENTITY memwrap_tb IS +END memwrap_tb; + +ARCHITECTURE behavior OF memwrap_tb IS + + -- Component Declaration for the Unit Under Test (UUT) + + -- Clock period definitions + constant clk_period : time := 10 ns; + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal in_imem : core_imem; + signal wslvi : wb_slv_in_type := wbs_in_none; + + --Outputs + signal out_imem : imem_core; + signal fault : std_logic; + signal out_byte : std_logic_vector(7 downto 0); + signal wslvo : wb_slv_out_type; + + + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + memwrap_inst: memwrapper + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM, + filename => "sample-programs\dummy.ram", + size => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + in_imem => in_imem, + out_imem => out_imem, + + fault => fault, --irq_lines(2), + + wslvi => wslvi, + wslvo => wslvo + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + -- Stimulus process + stim_proc: process + variable tmpadr : std_logic_vector(memory_width - 1 downto 0) := (others=>'0'); + begin + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; -- always read + wslvi <= wbs_in_none; + --end init + + -- hold reset state for 100 ns. + wait for 100 ns; + + wait for clk_period*10; + -------------------------------------- + -- Test_case 00: + -------------------------------------- + -- No request + -- Expected output all control signal should be inactive + -- Expected error: None + -------------------------------------- + --report ">> TC0 starts <<"; + -------------------------------------- + assert wslvo.ack = '1' + report"E-00: No request, but slvo.ack for dmem should always be active" + severity error; + + assert out_imem.ready = '1' + report"E-01: No request, but out_imem.ready should always be active" + severity error; + -------------------------------------- + --report ">> TC0 ends <<"; + -------------------------------------- + -- + --E N D Test_case 00 + -- + -------------------------------------- + -------------------------------------- + -- Test_case 01: + -------------------------------------- + -- Single ins read + -- Expected output ins is read correctly + -- Expected error: None + -- 32b_adr = x"00000052", 30b_adr = x"00000014" + -- data at the adr = x49303230 (ascii, I020) + -------------------------------------- + --report ">> TC1 starts <<"; + -------------------------------------- + --data + assert wslvo.ack = '1' + report"E-10: No request, but slvo.ack for dmem should always be active" + severity error; + --ins + in_imem.read_en <= '1'; in_imem.read_addr <= x"00000052"; wait for clk_period; + assert out_imem.read_data = x"49303230" and out_imem.ready = '1'--value in ascii = I020 + report "E-11: ins_RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) + severity error; + -- + -------------------------------------- + --report ">> TC1 ends <<"; + -------------------------------------- + -- + --E N D Test_case 01 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + -------------------------------------- + -- Test_case 02: + -------------------------------------- + -- Single data read + -- Expected output ins is read correctly + -- Expected error: None + -- 32b_adr = x"00000210", 30b_adr = x"00000084" + -- data at the adr = x44303034 (ascii, D004) + -------------------------------------- + --report ">> TC2 starts <<"; + -------------------------------------- + --data + -- Handshake-1 (in): + tmpadr := x"00000210"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "1000"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x30 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-2 (out): + assert wslvo.dat = x"44000000" and wslvo.ack = '1' + report"E-20: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"44000000") + severity error; + + --ins + assert out_imem.ready = '1' + report"E-21: No request, but out_imem should always be active" + severity error; + ---------------- + + -------------------------------------- + --report ">> TC2 ends <<"; + -------------------------------------- + -- + --E N D Test_case 02 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + -------------------------------------- + -- Test_case 03: + -------------------------------------- + -- Single data write, non overlap addr + -- write in address range of data + -- given data at addr[0000_00215] = x"44303035"; (ascii = D005) + -- B0 = x49, B2 = x30, B1 = x30, B0 = x35 + -- Expected output Return ack, written data is converted correctly + -- Expected error: None + -------------------------------------- + --report ">> TC3 starts <<"; + -------------------------------------- + --data + -- Handshake-1 (in): + tmpadr := x"00000215"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"AA35AAAA"; -- feed full data but take written only B2 (feed junk for the rest portion, making sure only sel part is taken) + wslvi.we <= '1'; -- write + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected writted data portion = x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-2 (out): + assert wslvo.ack = '1' + report"E-30: WR request, No ack " + severity error; + + --Read value for checking written value + -- Handshake-3 (in): + --tmpadr := x"0000000B"; + --wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.dat = x"00350000" and wslvo.ack = '1' + report"E-31: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"00350000") + severity error; + + --ins + assert out_imem.ready = '1' + report"E-32: No request, but out_imem should always be active" + severity error; + -------------------------------------- + --report ">> TC3 ends <<"; + -------------------------------------- + -- + --E N D Test_case 03 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + -------------------------------------- + -- Test_case 04: + -------------------------------------- + -- Single data write, overlap addr + -- write in address range of data + -- given data at addr[0000_00015] = x"49303035"; (ascii = I005) + -- B0 = x49, B2 = x30, B1 = x30, B0 = x35 + -- Expected output Return ack, written data is converted correctly + -- Expected error: None + -------------------------------------- + --report ">> TC4 starts <<"; + -------------------------------------- + --data + -- Handshake-1 (in): + tmpadr := x"00000015"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"AA35AAAA"; -- feed full data but take written only B2 (feed junk for the rest portion, making sure only sel part is taken) + wslvi.we <= '1'; -- write + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected writted data portion = x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-2 (out): + assert wslvo.ack = '1' + report"E-40: WR request, No ack " + severity error; + + --Read value for checking written value + -- Handshake-3 (in): + --tmpadr := x"0000000B"; + --wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.dat = x"00350000" and wslvo.ack = '1' + report"E-41: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"00350000") + severity error; + + --ins + assert out_imem.ready = '0' + report"E-42: Read data address is in ins address range, thus imem.ready should be hold to grant to the slv" + severity error; + -------------------------------------- + --report ">> TC4 ends <<"; + -------------------------------------- + -- + --E N D Test_case 04 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + -------------------------------------- + -- Test_case 05: + -------------------------------------- + -- Sim ins/data read, non overlap address + -- Expected output ins/data is read correctly + -- Expected error: None + -- + -- >> data_info + -- 32b_adr = x"00000210", 30b_adr = x"00000084" + -- data at the adr = x44303034 (ascii, D004) + -- + -- >> ins_info + -- 32b_adr = x"00000052", 30b_adr = x"00000014" + -- data at the adr = x49303230 (ascii, I020) + -------------------------------------- + -------------------------------------- + --report ">> TC5 starts <<"; + -------------------------------------- + + -- Handshake-1 (in): + -- data + tmpadr := x"00000210"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "1000"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x30 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + -- ins + in_imem.read_en <= '1'; in_imem.read_addr <= x"00000052"; + wait for clk_period; + + -- Handshake-2 (out): + -- data + assert wslvo.dat = x"44000000" and wslvo.ack = '1' + report"E-50: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"44000000") + severity error; + -- ins + assert out_imem.read_data = x"49303230" and out_imem.ready = '1'--value in ascii = I020 + report "E-51: ins_RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) + severity error; + + -------------------------------------- + --report ">> TC5 ends <<"; + -------------------------------------- + -- + --E N D Test_case 05 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + -------------------------------------- + -- Test_case 06: + -------------------------------------- + -- Sim ins/data read, overlap address range + -- Expected output ins/data is read correctly + -- Expected error: None + -- + -- >> data_info + -- 32b_adr = x"00000056", 30b_adr = x"00000015" + -- data at the adr = x49303231 (ascii, I021) + -- + -- >> ins_info + -- 32b_adr = x"00000052", 30b_adr = x"00000014" + -- data at the adr = x49303230 (ascii, I020) + -------------------------------------- + -------------------------------------- + --report ">> TC6 starts <<"; + -------------------------------------- + + -- Handshake-1 (in): + -- data + tmpadr := x"00000056"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0010"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x30 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + -- ins + in_imem.read_en <= '1'; in_imem.read_addr <= x"00000052"; + wait for clk_period; + + -- Handshake-2 (out): + -- data + assert wslvo.dat = x"00003200" and wslvo.ack = '1' + report"E-60: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"00003200") + severity error; + -- ins + assert out_imem.read_data = x"49303230" and out_imem.ready = '0' -- overlap address range, ready must be inactive + report "E-61: ins_RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) + severity error; + + -------------------------------------- + --report ">> TC6 ends <<"; + -------------------------------------- + -- + --E N D Test_case 06 + -- + -------------------------------------- + --init + in_imem.read_addr <= (others=>'0'); + in_imem.read_en <= '1'; + wslvi <= wbs_in_none; + wait for clk_period; + --end init + ------------------------------------- + -- Test_case 07: + -------------------------------------- + -- Sim ins read and data write, non overlap address range + -- Expected output ins/data is read correctly + -- Expected error: None + -- + -- >> data_info + -- 32b_adr = x"00000215", 30b_adr = x"00000085" + -- data at the adr = x44303035 (ascii, D005) + -- + -- >> ins_info + -- 32b_adr = x"00000052", 30b_adr = x"00000014" + -- data at the adr = x49303230 (ascii, I020) + -------------------------------------- + -------------------------------------- + --report ">> TC7 starts <<"; + -------------------------------------- + -- Handshake-1 (in): + -- data + tmpadr := x"00000215"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"AA35AAAA"; -- feed full data but take written only B2 (feed junk for the rest portion, making sure only sel part is taken) + wslvi.we <= '1'; -- write + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected writted data portion = x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + -- ins + in_imem.read_en <= '1'; in_imem.read_addr <= x"00000052"; + wait for clk_period; + + -- Handshake-2 (out): + -- data + assert wslvo.ack = '1' + report"E-70: WR request, ack should be active " + severity error; + -- ins + assert out_imem.read_data = x"49303230" and out_imem.ready = '1' -- overlap address range, ready must be inactive + report "E-71: imem.ready is inactive or Non-match ins val" & + " ins_RD req addr: " & hstr(in_imem.read_addr) & + ", Return rd ins val: " & hstr(out_imem.read_data) + severity error; + + --Read value for checking written value + -- Handshake-3 (in): + -- tmpadr := x"00000215"; + -- wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.dat = x"00350000" and wslvo.ack = '1' + report"E-72: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"00350000") + severity error; + -------------------------------------- + --report ">> TC7 ends <<"; + -------------------------------------- + -- + --E N D Test_case 07 + -- + -------------------------------------- + -------------------------------------- + -- Test_case 08: + -------------------------------------- + -- Sim ins read and data write, overlap address range + -- Expected output ins/data is read correctly + -- Expected error: None + -- + -- >> data_info + -- 32b_adr = x"00000015", 30b_adr = x"00000005" + -- data at the adr = x49303035 (ascii, I005) + -- + -- >> ins_info + -- 32b_adr = x"00000052", 30b_adr = x"00000014" + -- data at the adr = x49303230 (ascii, I020) + -------------------------------------- + -------------------------------------- + --report ">> TC8 starts <<"; + -------------------------------------- + + -- Handshake-1 (in): + -- data + tmpadr := x"00000015"; + wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= x"AA35AAAA"; -- feed full data but take written only B2 (feed junk for the rest portion, making sure only sel part is taken) + wslvi.we <= '1'; -- write + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected writted data portion = x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + -- ins + in_imem.read_en <= '1'; in_imem.read_addr <= x"00000052"; + wait for clk_period; + + -- Handshake-2 (out): + -- data + assert wslvo.ack = '1' + report"E-80: WR request, No ack " + severity error; + -- ins + assert out_imem.read_data = x"49303230" and out_imem.ready = '0' -- overlap address range, ready must be inactive + report "E-81: ins_RD req addr: " & hstr(in_imem.read_addr) & ", Return read_data: " & hstr(out_imem.read_data) + severity error; + + --Read value for checking written value + -- Handshake-3 (in): + --tmpadr := x"0000000B"; + --wslvi.adr <= tmpadr(31 downto 2); + wslvi.dat <= (others=>'0'); + wslvi.we <= '0'; -- read + wslvi.sel <= "0100"; -- sel_byte = B1 -> expected value return = 0 (ascii) or x35 + wslvi.stb <= '1'; + wslvi.cyc <= '1'; + wait for clk_period; + + -- Handshake-4 (out): + assert wslvo.dat = x"00350000" and wslvo.ack = '1' + report"E-82: wrong data, Return data: " & hstr(wslvo.dat) & " Expected data: " & hstr(x"00350000") + severity error; + -------------------------------------- + --report ">> TC8 ends <<"; + -------------------------------------- + -- + --E N D Test_case 08 + -- + -------------------------------------- + --///////////////////////////////////////// + assert false + report ">>>> Simulation beendet!" + severity failure; + --wait; + end process; + +END; diff --git a/soc/testbench/memwrap_wave.wcfg b/soc/testbench/memwrap_wave.wcfg new file mode 100644 index 0000000..380fc81 --- /dev/null +++ b/soc/testbench/memwrap_wave.wcfg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + in_imem + in_imem + + .read_addr + in_imem.read_addr + HEXRADIX + + + .read_en + in_imem.read_en + + + + wslvi + wslvi + + .adr + wslvi.adr + + + .dat + wslvi.dat + HEXRADIX + + + .we + wslvi.we + + + .sel + wslvi.sel + + + .stb + wslvi.stb + + + .cyc + wslvi.cyc + + + + out_imem + out_imem + + .read_data + out_imem.read_data + HEXRADIX + + + .ready + out_imem.ready + + + + fault + fault + + + out_byte[7:0] + out_byte[7:0] + + + wslvo + wslvo + + .dat + wslvo.dat + HEXRADIX + + + .ack + wslvo.ack + + + .wbcfg + wslvo.wbcfg + + + .wbidx + wslvo.wbidx + + + + mem div + label + 128 128 255 + 230 230 230 + + + memdiv + label + + clk + clk + + + rst + rst + + + in_dmem + in_dmem + + + out_dmem + out_dmem + + + in_imem + in_imem + + .read_addr + in_imem.read_addr + HEXRADIX + + + .read_en + in_imem.read_en + + + + out_imem + out_imem + + .read_data + out_imem.read_data + HEXRADIX + + + .ready + out_imem.ready + + + + fault + fault + + + out_byte[7:0] + out_byte[7:0] + + + memory[0:255] + memory[0:255] + + + imem_data[31:0] + imem_data[31:0] + + + dmem_data[31:0] + dmem_data[31:0] + HEXRADIX + + + dmem_read_fault + dmem_read_fault + + + dmem_write_fault + dmem_write_fault + + + imem_read_fault + imem_read_fault + + + size + size + + + imem_latency + imem_latency + + + dmem_latency + dmem_latency + + + dmemsz + dmemsz + + + imemsz + imemsz + + + width + width + + + in_simulation + in_simulation + + + in_synthesis + in_synthesis + + + filename[1:25] + filename[1:25] + + + + mem2wb + label + 128 128 255 + 230 230 230 + + + mem2wb + label + + clk + clk + + + rst + rst + + + in_dmem + in_dmem + + .write_data + in_dmem.write_data + HEXRADIX + + + .write_addr + in_dmem.write_addr + HEXRADIX + + + .write_size + in_dmem.write_size + + + .write_en + in_dmem.write_en + + + .read_addr + in_dmem.read_addr + + + .read_size + in_dmem.read_size + + + .read_en + in_dmem.read_en + + + + out_dmem + out_dmem + + .read_data + out_dmem.read_data + HEXRADIX + + + .ready + out_dmem.ready + + + + wslvi + wslvi + + .adr + wslvi.adr + HEXRADIX + + + .dat + wslvi.dat + HEXRADIX + + + .we + wslvi.we + + + .sel + wslvi.sel + + + .stb + wslvi.stb + + + .cyc + wslvi.cyc + + + + wslvo + wslvo + + + indmem + indmem + + .write_data + indmem.write_data + HEXRADIX + + + .write_addr + indmem.write_addr + HEXRADIX + + + .write_size + indmem.write_size + + + .write_en + indmem.write_en + + + .read_addr + indmem.read_addr + HEXRADIX + + + .read_size + indmem.read_size + + + .read_en + indmem.read_en + + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + diff --git a/soc/testbench/platform_tb.vhd b/soc/testbench/platform_tb.vhd new file mode 100644 index 0000000..63f6af2 --- /dev/null +++ b/soc/testbench/platform_tb.vhd @@ -0,0 +1,53 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY platform_tb IS +END ENTITY; + +ARCHITECTURE sim OF platform_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + + signal led : std_logic_vector(7 downto 0); + + COMPONENT lt16soc_top IS + generic( + programfilename : string := "programs/test_sync.ram" -- see "Synthesize XST" process properties for actual value ("-generics" in .xst file)! + ); + port( + clk : in std_logic; + rst : in std_logic; + led : out std_logic_vector(7 downto 0) + ); + END COMPONENT; + +BEGIN + + dut: lt16soc_top port map( + clk=>clk, + rst=>rst, + led=>led + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '0'; + wait for CLK_PERIOD; + rst <= '1'; + wait for 2000*CLK_PERIOD; + wait; + end process stimuli; + + +END ARCHITECTURE; diff --git a/soc/testbench/slvtest.vhd b/soc/testbench/slvtest.vhd new file mode 100644 index 0000000..b49f730 --- /dev/null +++ b/soc/testbench/slvtest.vhd @@ -0,0 +1,64 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +LIBRARY work; +USE work.lt16soc_peripherals.ALL; +USE work.wishbone.ALL; +USE work.wb_tp.ALL; +USE work.config.ALL; + +ENTITY slvtest IS +END ENTITY; + +ARCHITECTURE sim OF slvtest IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + signal led : std_logic_vector(7 downto 0); + signal data : std_logic_vector(WB_PORT_SIZE-1 downto 0); + + signal slvi : wb_slv_in_type; + signal slvo : wb_slv_out_type; + +BEGIN + + SIM_SLV: wb_led + generic map( + memaddr => CFG_BADR_LED, + addrmask => CFG_MADR_LED + ) + port map( + clk => clk, + rst => rst, + led => led, + wslvi => slvi, + wslvo => slvo + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '1'; + wait for CLK_PERIOD; + rst <= '0'; + data <= std_logic_vector(to_unsigned(431,32)); + wait for CLK_PERIOD; + + generate_sync_wb_slave_writeaccess(slvi,slvo,clk,data); + wait for 2 ns; + data <= (others => '0'); + generate_sync_wb_slave_readaccess(slvi,slvo,clk,data); + + wait; + end process stimuli; + +END ARCHITECTURE; diff --git a/soc/testbench/top_wave.wcfg b/soc/testbench/top_wave.wcfg new file mode 100644 index 0000000..42110d7 --- /dev/null +++ b/soc/testbench/top_wave.wcfg @@ -0,0 +1,2242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + .dat + slvo[15].dat + HEXRADIX + + + .ack + slvo[15].ack + + + .wbcfg + slvo[15].wbcfg + + + .wbidx + slvo[15].wbidx + + + + [14] + slvo[14] + + .dat + slvo[14].dat + HEXRADIX + + + .ack + slvo[14].ack + + + .wbcfg + slvo[14].wbcfg + + + .wbidx + slvo[14].wbidx + + + + [13] + slvo[13] + + .dat + slvo[13].dat + HEXRADIX + + + .ack + slvo[13].ack + + + .wbcfg + slvo[13].wbcfg + + + .wbidx + slvo[13].wbidx + + + + [12] + slvo[12] + + .dat + slvo[12].dat + HEXRADIX + + + .ack + slvo[12].ack + + + .wbcfg + slvo[12].wbcfg + + + .wbidx + slvo[12].wbidx + + + + [11] + slvo[11] + + .dat + slvo[11].dat + HEXRADIX + + + .ack + slvo[11].ack + + + .wbcfg + slvo[11].wbcfg + + + .wbidx + slvo[11].wbidx + + + + [10] + slvo[10] + + .dat + slvo[10].dat + HEXRADIX + + + .ack + slvo[10].ack + + + .wbcfg + slvo[10].wbcfg + + + .wbidx + slvo[10].wbidx + + + + [9] + slvo[9] + + .dat + slvo[9].dat + HEXRADIX + + + .ack + slvo[9].ack + + + .wbcfg + slvo[9].wbcfg + + + .wbidx + slvo[9].wbidx + + + + [8] + slvo[8] + + .dat + slvo[8].dat + HEXRADIX + + + .ack + slvo[8].ack + + + .wbcfg + slvo[8].wbcfg + + + .wbidx + slvo[8].wbidx + + + + [7] + slvo[7] + + .dat + slvo[7].dat + HEXRADIX + + + .ack + slvo[7].ack + + + .wbcfg + slvo[7].wbcfg + + + .wbidx + slvo[7].wbidx + + + + [6] + slvo[6] + + .dat + slvo[6].dat + HEXRADIX + + + .ack + slvo[6].ack + + + .wbcfg + slvo[6].wbcfg + + + .wbidx + slvo[6].wbidx + + + + [5] + slvo[5] + + .dat + slvo[5].dat + HEXRADIX + + + .ack + slvo[5].ack + + + .wbcfg + slvo[5].wbcfg + + + .wbidx + slvo[5].wbidx + + + + [4] + slvo[4] + + .dat + slvo[4].dat + HEXRADIX + + + .ack + slvo[4].ack + + + .wbcfg + slvo[4].wbcfg + + + .wbidx + slvo[4].wbidx + + + + [3] + slvo[3] + + .dat + slvo[3].dat + HEXRADIX + + + .ack + slvo[3].ack + + + .wbcfg + slvo[3].wbcfg + + + .wbidx + slvo[3].wbidx + + + + [2] + slvo[2] + + .dat + slvo[2].dat + HEXRADIX + + + .ack + slvo[2].ack + + + .wbcfg + slvo[2].wbcfg + + + .wbidx + slvo[2].wbidx + + + + [1] + slvo[1] + + .dat + slvo[1].dat + HEXRADIX + + + .ack + slvo[1].ack + + + .wbcfg + slvo[1].wbcfg + + + .wbidx + slvo[1].wbidx + + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + + + .wbidx + slvo[0].wbidx + + + + + msto[3:0] + msto[3:0] + + + slvi[15:0] + slvi[15:0] + + + msti[3:0] + msti[3:0] + + + core2mem + core2mem + + + mem2core + mem2core + + + test_rddat[31:0] + test_rddat[31:0] + HEXRADIX + + + led[7:0] + led[7:0] + + + out_byte[7:0] + out_byte[7:0] + + + Submodules + label + 128 128 255 + 230 230 230 + + + IRQ + label + + IRQ_module + label + + clk + clk + + + rst + rst + + + in_proc + in_proc + + + out_proc + out_proc + + + irq_lines[15:0] + irq_lines[15:0] + + + num[3:0] + num[3:0] + + + priority[3:0] + priority[3:0] + + + req + req + + + nmi + nmi + + + pending[15:0] + pending[15:0] + + + + irq_lines[15:0] + irq_lines[15:0] + + + irq2core + irq2core + + + core2irq + core2irq + + + + ICN + label + + clk + clk + + + rst + rst + + + msti[3:0] + msti[3:0] + + [3] + msti[3] + + .dat + msti[3].dat + HEXRADIX + + + .ack + msti[3].ack + + + + [2] + msti[2] + + .dat + msti[2].dat + HEXRADIX + + + .ack + msti[2].ack + + + + [1] + msti[1] + + .dat + msti[1].dat + HEXRADIX + + + .ack + msti[1].ack + + + + [0] + msti[0] + + .dat + msti[0].dat + HEXRADIX + + + .ack + msti[0].ack + + + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + .adr + msto[3].adr + HEXRADIX + + + .dat + msto[3].dat + HEXRADIX + + + .we + msto[3].we + + + .sel + msto[3].sel + + + .stb + msto[3].stb + + + .cyc + msto[3].cyc + + + .wbcfg + msto[3].wbcfg + + + .wbidx + msto[3].wbidx + + + + [2] + msto[2] + + .adr + msto[2].adr + HEXRADIX + + + .dat + msto[2].dat + HEXRADIX + + + .we + msto[2].we + + + .sel + msto[2].sel + + + .stb + msto[2].stb + + + .cyc + msto[2].cyc + + + .wbcfg + msto[2].wbcfg + + + .wbidx + msto[2].wbidx + + + + [1] + msto[1] + + .adr + msto[1].adr + HEXRADIX + + + .dat + msto[1].dat + HEXRADIX + + + .we + msto[1].we + + + .sel + msto[1].sel + + + .stb + msto[1].stb + + + .cyc + msto[1].cyc + + + .wbcfg + msto[1].wbcfg + + + .wbidx + msto[1].wbidx + + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + HEXRADIX + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + + + .wbidx + msto[0].wbidx + + + + + slvi[15:0] + slvi[15:0] + + [15] + slvi[15] + + .adr + slvi[15].adr + HEXRADIX + + + .dat + slvi[15].dat + HEXRADIX + + + .we + slvi[15].we + + + .sel + slvi[15].sel + + + .stb + slvi[15].stb + + + .cyc + slvi[15].cyc + + + + [14] + slvi[14] + + .adr + slvi[14].adr + HEXRADIX + + + .dat + slvi[14].dat + HEXRADIX + + + .we + slvi[14].we + + + .sel + slvi[14].sel + + + .stb + slvi[14].stb + + + .cyc + slvi[14].cyc + + + + [13] + slvi[13] + + .adr + slvi[13].adr + HEXRADIX + + + .dat + slvi[13].dat + HEXRADIX + + + .we + slvi[13].we + + + .sel + slvi[13].sel + + + .stb + slvi[13].stb + + + .cyc + slvi[13].cyc + + + + [12] + slvi[12] + + .adr + slvi[12].adr + HEXRADIX + + + .dat + slvi[12].dat + HEXRADIX + + + .we + slvi[12].we + + + .sel + slvi[12].sel + + + .stb + slvi[12].stb + + + .cyc + slvi[12].cyc + + + + [11] + slvi[11] + + .adr + slvi[11].adr + HEXRADIX + + + .dat + slvi[11].dat + HEXRADIX + + + .we + slvi[11].we + + + .sel + slvi[11].sel + + + .stb + slvi[11].stb + + + .cyc + slvi[11].cyc + + + + [10] + slvi[10] + + .adr + slvi[10].adr + HEXRADIX + + + .dat + slvi[10].dat + HEXRADIX + + + .we + slvi[10].we + + + .sel + slvi[10].sel + + + .stb + slvi[10].stb + + + .cyc + slvi[10].cyc + + + + [9] + slvi[9] + + .adr + slvi[9].adr + HEXRADIX + + + .dat + slvi[9].dat + HEXRADIX + + + .we + slvi[9].we + + + .sel + slvi[9].sel + + + .stb + slvi[9].stb + + + .cyc + slvi[9].cyc + + + + [8] + slvi[8] + + .adr + slvi[8].adr + HEXRADIX + + + .dat + slvi[8].dat + HEXRADIX + + + .we + slvi[8].we + + + .sel + slvi[8].sel + + + .stb + slvi[8].stb + + + .cyc + slvi[8].cyc + + + + [7] + slvi[7] + + .adr + slvi[7].adr + HEXRADIX + + + .dat + slvi[7].dat + HEXRADIX + + + .we + slvi[7].we + + + .sel + slvi[7].sel + + + .stb + slvi[7].stb + + + .cyc + slvi[7].cyc + + + + [6] + slvi[6] + + .adr + slvi[6].adr + HEXRADIX + + + .dat + slvi[6].dat + HEXRADIX + + + .we + slvi[6].we + + + .sel + slvi[6].sel + + + .stb + slvi[6].stb + + + .cyc + slvi[6].cyc + + + + [5] + slvi[5] + + .adr + slvi[5].adr + HEXRADIX + + + .dat + slvi[5].dat + HEXRADIX + + + .we + slvi[5].we + + + .sel + slvi[5].sel + + + .stb + slvi[5].stb + + + .cyc + slvi[5].cyc + + + + [4] + slvi[4] + + .adr + slvi[4].adr + HEXRADIX + + + .dat + slvi[4].dat + HEXRADIX + + + .we + slvi[4].we + + + .sel + slvi[4].sel + + + .stb + slvi[4].stb + + + .cyc + slvi[4].cyc + + + + [3] + slvi[3] + + .adr + slvi[3].adr + HEXRADIX + + + .dat + slvi[3].dat + HEXRADIX + + + .we + slvi[3].we + + + .sel + slvi[3].sel + + + .stb + slvi[3].stb + + + .cyc + slvi[3].cyc + + + + [2] + slvi[2] + + .adr + slvi[2].adr + HEXRADIX + + + .dat + slvi[2].dat + HEXRADIX + + + .we + slvi[2].we + + + .sel + slvi[2].sel + + + .stb + slvi[2].stb + + + .cyc + slvi[2].cyc + + + + [1] + slvi[1] + + .adr + slvi[1].adr + HEXRADIX + + + .dat + slvi[1].dat + HEXRADIX + + + .we + slvi[1].we + + + .sel + slvi[1].sel + + + .stb + slvi[1].stb + + + .cyc + slvi[1].cyc + + + + [0] + slvi[0] + + .adr + slvi[0].adr + HEXRADIX + + + .dat + slvi[0].dat + HEXRADIX + + + .we + slvi[0].we + + + .sel + slvi[0].sel + + + .stb + slvi[0].stb + + + .cyc + slvi[0].cyc + + + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + .dat + slvo[15].dat + HEXRADIX + + + .ack + slvo[15].ack + + + .wbcfg + slvo[15].wbcfg + + + .wbidx + slvo[15].wbidx + + + + [14] + slvo[14] + + .dat + slvo[14].dat + HEXRADIX + + + .ack + slvo[14].ack + + + .wbcfg + slvo[14].wbcfg + + + .wbidx + slvo[14].wbidx + + + + [13] + slvo[13] + + .dat + slvo[13].dat + HEXRADIX + + + .ack + slvo[13].ack + + + .wbcfg + slvo[13].wbcfg + + + .wbidx + slvo[13].wbidx + + + + [12] + slvo[12] + + .dat + slvo[12].dat + HEXRADIX + + + .ack + slvo[12].ack + + + .wbcfg + slvo[12].wbcfg + + + .wbidx + slvo[12].wbidx + + + + [11] + slvo[11] + + .dat + slvo[11].dat + HEXRADIX + + + .ack + slvo[11].ack + + + .wbcfg + slvo[11].wbcfg + + + .wbidx + slvo[11].wbidx + + + + [10] + slvo[10] + + .dat + slvo[10].dat + HEXRADIX + + + .ack + slvo[10].ack + + + .wbcfg + slvo[10].wbcfg + + + .wbidx + slvo[10].wbidx + + + + [9] + slvo[9] + + .dat + slvo[9].dat + HEXRADIX + + + .ack + slvo[9].ack + + + .wbcfg + slvo[9].wbcfg + + + .wbidx + slvo[9].wbidx + + + + [8] + slvo[8] + + + [7] + slvo[7] + + .dat + slvo[7].dat + HEXRADIX + + + .ack + slvo[7].ack + + + .wbcfg + slvo[7].wbcfg + + + .wbidx + slvo[7].wbidx + + + + [6] + slvo[6] + + .dat + slvo[6].dat + HEXRADIX + + + .ack + slvo[6].ack + + + .wbcfg + slvo[6].wbcfg + + + .wbidx + slvo[6].wbidx + + + + [5] + slvo[5] + + .dat + slvo[5].dat + HEXRADIX + + + .ack + slvo[5].ack + + + .wbcfg + slvo[5].wbcfg + + + .wbidx + slvo[5].wbidx + + + + [4] + slvo[4] + + .dat + slvo[4].dat + HEXRADIX + + + .ack + slvo[4].ack + + + .wbcfg + slvo[4].wbcfg + + + .wbidx + slvo[4].wbidx + + + + [3] + slvo[3] + + .dat + slvo[3].dat + HEXRADIX + + + .ack + slvo[3].ack + + + .wbcfg + slvo[3].wbcfg + + + .wbidx + slvo[3].wbidx + + + + [2] + slvo[2] + + .dat + slvo[2].dat + HEXRADIX + + + .ack + slvo[2].ack + + + .wbcfg + slvo[2].wbcfg + + + .wbidx + slvo[2].wbidx + + + + [1] + slvo[1] + + .dat + slvo[1].dat + HEXRADIX + + + .ack + slvo[1].ack + + + .wbcfg + slvo[1].wbcfg + + + .wbidx + slvo[1].wbidx + + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + + + .wbidx + slvo[0].wbidx + + + + + tmpslvo[15:0] + tmpslvo[15:0] + + [15] + tmpslvo[15] + + .dat + tmpslvo[15].dat + HEXRADIX + + + .ack + tmpslvo[15].ack + + + .wbcfg + tmpslvo[15].wbcfg + + + .wbidx + tmpslvo[15].wbidx + + + + [14] + tmpslvo[14] + + .dat + tmpslvo[14].dat + HEXRADIX + + + .ack + tmpslvo[14].ack + + + .wbcfg + tmpslvo[14].wbcfg + + + .wbidx + tmpslvo[14].wbidx + + + + [13] + tmpslvo[13] + + .dat + tmpslvo[13].dat + HEXRADIX + + + .ack + tmpslvo[13].ack + + + .wbcfg + tmpslvo[13].wbcfg + + + .wbidx + tmpslvo[13].wbidx + + + + [12] + tmpslvo[12] + + .dat + tmpslvo[12].dat + HEXRADIX + + + .ack + tmpslvo[12].ack + + + .wbcfg + tmpslvo[12].wbcfg + + + .wbidx + tmpslvo[12].wbidx + + + + [11] + tmpslvo[11] + + .dat + tmpslvo[11].dat + HEXRADIX + + + .ack + tmpslvo[11].ack + + + .wbcfg + tmpslvo[11].wbcfg + + + .wbidx + tmpslvo[11].wbidx + + + + [10] + tmpslvo[10] + + .dat + tmpslvo[10].dat + HEXRADIX + + + .ack + tmpslvo[10].ack + + + .wbcfg + tmpslvo[10].wbcfg + + + .wbidx + tmpslvo[10].wbidx + + + + [9] + tmpslvo[9] + + .dat + tmpslvo[9].dat + HEXRADIX + + + .ack + tmpslvo[9].ack + + + .wbcfg + tmpslvo[9].wbcfg + + + .wbidx + tmpslvo[9].wbidx + + + + [8] + tmpslvo[8] + + + [7] + tmpslvo[7] + + .dat + tmpslvo[7].dat + HEXRADIX + + + .ack + tmpslvo[7].ack + + + .wbcfg + tmpslvo[7].wbcfg + + + .wbidx + tmpslvo[7].wbidx + + + + [6] + tmpslvo[6] + + .dat + tmpslvo[6].dat + HEXRADIX + + + .ack + tmpslvo[6].ack + + + .wbcfg + tmpslvo[6].wbcfg + + + .wbidx + tmpslvo[6].wbidx + + + + [5] + tmpslvo[5] + + .dat + tmpslvo[5].dat + HEXRADIX + + + .ack + tmpslvo[5].ack + + + .wbcfg + tmpslvo[5].wbcfg + + + .wbidx + tmpslvo[5].wbidx + + + + [4] + tmpslvo[4] + + .dat + tmpslvo[4].dat + HEXRADIX + + + .ack + tmpslvo[4].ack + + + .wbcfg + tmpslvo[4].wbcfg + + + .wbidx + tmpslvo[4].wbidx + + + + [3] + tmpslvo[3] + + .dat + tmpslvo[3].dat + HEXRADIX + + + .ack + tmpslvo[3].ack + + + .wbcfg + tmpslvo[3].wbcfg + + + .wbidx + tmpslvo[3].wbidx + + + + [2] + tmpslvo[2] + + .dat + tmpslvo[2].dat + HEXRADIX + + + .ack + tmpslvo[2].ack + + + .wbcfg + tmpslvo[2].wbcfg + + + .wbidx + tmpslvo[2].wbidx + + + + [1] + tmpslvo[1] + + .dat + tmpslvo[1].dat + HEXRADIX + + + .ack + tmpslvo[1].ack + + + .wbcfg + tmpslvo[1].wbcfg + + + .wbidx + tmpslvo[1].wbidx + + + + [0] + tmpslvo[0] + + .dat + tmpslvo[0].dat + HEXRADIX + + + .ack + tmpslvo[0].ack + + + .wbcfg + tmpslvo[0].wbcfg + + + .wbidx + tmpslvo[0].wbidx + + + + + tmpmsto[3:0] + tmpmsto[3:0] + + [3] + tmpmsto[3] + + .adr + tmpmsto[3].adr + HEXRADIX + + + .dat + tmpmsto[3].dat + HEXRADIX + + + .we + tmpmsto[3].we + + + .sel + tmpmsto[3].sel + + + .stb + tmpmsto[3].stb + + + .cyc + tmpmsto[3].cyc + + + .wbcfg + tmpmsto[3].wbcfg + + + .wbidx + tmpmsto[3].wbidx + + + + [2] + tmpmsto[2] + + .adr + tmpmsto[2].adr + HEXRADIX + + + .dat + tmpmsto[2].dat + HEXRADIX + + + .we + tmpmsto[2].we + + + .sel + tmpmsto[2].sel + + + .stb + tmpmsto[2].stb + + + .cyc + tmpmsto[2].cyc + + + .wbcfg + tmpmsto[2].wbcfg + + + .wbidx + tmpmsto[2].wbidx + + + + [1] + tmpmsto[1] + + .adr + tmpmsto[1].adr + HEXRADIX + + + .dat + tmpmsto[1].dat + HEXRADIX + + + .we + tmpmsto[1].we + + + .sel + tmpmsto[1].sel + + + .stb + tmpmsto[1].stb + + + .cyc + tmpmsto[1].cyc + + + .wbcfg + tmpmsto[1].wbcfg + + + .wbidx + tmpmsto[1].wbidx + + + + [0] + tmpmsto[0] + + .adr + tmpmsto[0].adr + HEXRADIX + + + .dat + tmpmsto[0].dat + HEXRADIX + + + .we + tmpmsto[0].we + + + .sel + tmpmsto[0].sel + + + .stb + tmpmsto[0].stb + + + .cyc + tmpmsto[0].cyc + + + .wbcfg + tmpmsto[0].wbcfg + + + .wbidx + tmpmsto[0].wbidx + + + + + mgnt_idx + mgnt_idx + + + mgnt[0:3] + mgnt[0:3] + + + ssel_idx + ssel_idx + + + ssel[0:15] + ssel[0:15] + + + + CoreWrap_mst0 + label + + clk + clk + + + rst + rst + + + in_imem + in_imem + + .read_data + in_imem.read_data + HEXRADIX + + + .ready + in_imem.ready + + + + out_imem + out_imem + + .read_addr + out_imem.read_addr + HEXRADIX + + + .read_en + out_imem.read_en + + + + in_proc + in_proc + + + out_proc + out_proc + + + hardfault + hardfault + + + wmsti + wmsti + + + wmsto + wmsto + + + wbmo + wbmo + + + indmem + indmem + + .read_data + indmem.read_data + HEXRADIX + + + .ready + indmem.ready + + + + in_dmem + in_dmem + + + out_dmem + out_dmem + + + wbidx + wbidx + + + + MemWrap_slv0 + label + + clk + clk + + + rst + rst + + + in_imem + in_imem + + + out_imem + out_imem + + + fault + fault + + + out_byte[7:0] + out_byte[7:0] + + + wslvi + wslvi + + + wslvo + wslvo + + + outimem + outimem + + + in_dmem + in_dmem + + + out_dmem + out_dmem + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + dmemsz + dmemsz + + + imemsz + imemsz + + + filename[1:29] + filename[1:29] + + + + Constant + label + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + cfg_badr_tsts2 + cfg_badr_tsts2 + + + cfg_badr_tsts1 + cfg_badr_tsts1 + + + dat_sz + dat_sz + + + adr_sz + adr_sz + + + nib_sz + nib_sz + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + + test_peripheral_slv + label + + testslave1_o + testslave1_o + + .dat + testslave1_o.dat + HEXRADIX + + + .ack + testslave1_o.ack + + + .wbcfg + testslave1_o.wbcfg + + + .wbidx + testslave1_o.wbidx + + + + testslave2_o + testslave2_o + + .dat + testslave2_o.dat + HEXRADIX + + + .ack + testslave2_o.ack + + + .wbcfg + testslave2_o.wbcfg + + + .wbidx + testslave2_o.wbidx + + + + diff --git a/soc/testbench/topmimic_tb.vhd b/soc/testbench/topmimic_tb.vhd new file mode 100644 index 0000000..e09270b --- /dev/null +++ b/soc/testbench/topmimic_tb.vhd @@ -0,0 +1,336 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library ieee; +use ieee.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use ieee.math_real.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.txt_util.all; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; + +ENTITY top_tb IS +END top_tb; + +ARCHITECTURE behavior OF top_tb IS +--////////////////////////////////////////////// +-- +-- component +-- +--////////////////////////////////////////////// +-- COMPONENT lt16soc_top +-- PORT( +-- clk : IN std_logic; +-- rst : IN std_logic; +-- led : OUT std_logic_vector(7 downto 0) +-- ); +-- END COMPONENT; + --//////////////////////////////////////////// + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000"; + dat_sz: integer := WB_PORT_SIZE; + adr_sz: integer := WB_ADR_WIDTH; + nib_sz: integer := WB_PORT_GRAN + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + --//////////////////////////////////////////// + component corewrapper + generic( + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); + end component; + + component memwrapper + generic( + memaddr : generic_addr_type := CFG_BADR_MEM; + addrmask : generic_mask_type := CFG_MADR_MEM; + wbidx : integer := CFG_MEM; + filename : string := "program.ram"; + dmemsz : integer := DMEMSZ; + imemsz : integer := IMEMSZ + ); + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in core_imem; + out_imem : out imem_core; + + fault : out std_logic; + out_byte : out std_logic_vector(7 downto 0); + + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type + ); + end component; + --/////////////////////////////////////////////// + component wb_stestrd + generic( + memaddr : generic_addr_type :=0; + addrmask : generic_mask_type :=CFG_MADR_FULL; + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + test_rddat : in std_logic_vector(31 downto 0) + ); + end component; + + component wb_stestwr + generic( + memaddr : generic_addr_type :=0; + addrmask : generic_mask_type :=CFG_MADR_FULL; + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + led : out std_logic_vector (7 downto 0) + ); + end component; +--////////////////////////////////////////////// +-- Signals & constants +--////////////////////////////////////////////// + constant clk_period : time := 10 ns; + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0000_0000_0000"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + --base adr + constant CFG_BADR_TSTS1 : generic_addr_type := 16#28400000#; -- 30bits (32b = A1000000) + constant CFG_BADR_TSTS2 : generic_addr_type := 16#28800000#; -- 30bits (32b = A2000000) + + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + --Outputs + signal led : std_logic_vector(7 downto 0); + signal out_byte: std_logic_vector(7 downto 0); + + -- Internal signals + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0) := (others=>'0'); + + signal slvo : wb_slv_out_vector := (others=> wbs_out_none); + signal msto : wb_mst_out_vector := (others=> wbm_out_none); + + signal slvi : wb_slv_in_vector := (others=> wbs_in_none); + signal msti : wb_mst_in_vector := (others=> wbm_in_none); + + signal core2mem : core_imem; + signal mem2core : imem_core; + + signal irq2core : irq_core; + signal core2irq : core_irq; + + signal testslave1_o, testslave2_o: wb_slv_out_type := wbs_out_none; + signal test_rddat: std_logic_vector(31 downto 0) := (others=>'0'); + +begin +--////////////////////////////////////////////// +-- Instantiate +--////////////////////////////////////////////// +-- uut: lt16soc_top +-- port map( +-- clk => clk, +-- rst => rst, +-- led => led +-- ); + + wbicn_inst: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + + corewrap_inst: corewrapper + generic map( + wbidx => CFG_LT16 + ) + port map( + clk => clk, + rst => rst, + + in_imem => mem2core, + out_imem => core2mem, + + in_proc => irq2core, + out_proc => core2irq, + + hardfault => irq_lines(1), + + wmsti => msti(CFG_LT16), + wmsto => msto(CFG_LT16) + ); + + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst, + in_proc => core2irq, + out_proc => irq2core, + irq_lines => irq_lines + ); + + memwrap_inst: memwrapper + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + wbidx => CFG_MEM, + filename => "sample-programs\rawhztest.ram", + dmemsz => DMEMSZ, + imemsz => IMEMSZ + ) + port map( + clk => clk, + rst => rst, + in_imem => core2mem, + out_imem => mem2core, + + fault => irq_lines(2), + out_byte => out_byte, + + wslvi => slvi(CFG_MEM), + wslvo => slvo(CFG_MEM) + ); + + srd01: wb_stestrd + generic map( + memaddr => CFG_BADR_TSTS1, + addrmask => CFG_MADR_ZERO, + wbidx => 1 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave1_o, + slvi.adr => slvi(1).adr, + slvi.dat => slvi(1).dat, + slvi.we => slvi(1).we, + slvi.sel => slvi(1).sel, + slvi.stb => slvi(1).stb, + slvi.cyc => slvi(1).cyc, + test_rddat => test_rddat + ); + + swr02: wb_stestwr + generic map( + memaddr => CFG_BADR_TSTS2, + addrmask => CFG_MADR_ZERO, + wbidx => 2 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave2_o, + slvi.adr => slvi(2).adr, + slvi.dat => slvi(2).dat, + slvi.we => slvi(2).we, + slvi.sel => slvi(2).sel, + slvi.stb => slvi(2).stb, + slvi.cyc => slvi(2).cyc, + led => led + ); + +--////////////////////////////////////////////// +-- Process +--////////////////////////////////////////////// + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset : process is + begin + rst <= '1'; + wait for 3.5 * clk_period; + rst <= '0'; + wait; + end process reset; + + irq_stimuli : process is + begin + irq_lines(irq_lines'high downto 3) <= (others => '0'); + irq_lines(0) <= '0'; + wait; + end process irq_stimuli; + +-- -- Stimulus process +-- stim_proc: process +-- begin +-- -- hold reset state for 100 ns. +-- wait for 100 ns; +-- +-- wait for clk_period*10; +-- +-- -- insert stimulus here +-- +-- +-- wait; +-- end process; + + + +end; \ No newline at end of file diff --git a/soc/testbench/warmup1.vhd b/soc/testbench/warmup1.vhd new file mode 100644 index 0000000..78d7d62 --- /dev/null +++ b/soc/testbench/warmup1.vhd @@ -0,0 +1,53 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY warmup1_tb IS +END ENTITY; + +ARCHITECTURE sim OF warmup1_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + + signal led : std_logic_vector(7 downto 0); + + COMPONENT lt16soc_top IS + generic( + programfilename : string := "programs/blinky.ram" + ); + port( + clk : in std_logic; + rst : in std_logic; + led : out std_logic_vector(7 downto 0) + ); + END COMPONENT; + +BEGIN + + dut: lt16soc_top port map( + clk=>clk, + rst=>rst, + led=>led + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '0'; + wait for CLK_PERIOD; + rst <= '1'; + wait for 20000*CLK_PERIOD; + assert false report "Simulation terminated!" severity failure; + end process stimuli; + + +END ARCHITECTURE; diff --git a/soc/testbench/wb_stestrd_tb.vhd b/soc/testbench/wb_stestrd_tb.vhd new file mode 100644 index 0000000..b7785cf --- /dev/null +++ b/soc/testbench/wb_stestrd_tb.vhd @@ -0,0 +1,135 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +library work; +use work.wishbone.all; +use work.config.all; +--use work.wb_tp.all; +use std.textio.all; + + +ENTITY wb_stestrd_tb IS +END wb_stestrd_tb; + +ARCHITECTURE behavior OF wb_stestrd_tb IS + + -- Component Declaration for the Unit Under Test (UUT) + + COMPONENT wb_stestrd + PORT( + clk : IN std_logic; + rst : IN std_logic; + slvi : IN wb_slv_in_type; + slvo : OUT wb_slv_out_type + ); + END COMPONENT; + + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal slvi : wb_slv_in_type := wbs_in_none; + + --Outputs + signal slvo : wb_slv_out_type; + + -- Clock period definitions + constant clk_period : time := 10 ns; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: wb_stestrd + PORT MAP ( + clk => clk, + rst => rst, + slvi => slvi, + slvo => slvo + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset_process : process + begin + report ">>>> R e s e t"; + rst <= '1'; + wait for clk_period*3.5; + rst <= '0'; + wait; + end process; + + + + -- Stimulus process + stim_proc: process + begin + -- hold reset state for 100 ns. + wait for 100 ns; + + wait for clk_period*10; + + -- insert stimulus here +--test 1: no request + slvi <= wbs_in_none ; + + wait for clk_period; + assert (slvo.ack='0') report "err: no mst req, NO slv ack!!" + severity error; +--test 2 + wait for clk_period; + slvi.adr <= b"1010_0001_0000_0000_0000_0000_0000_00"; + slvi.dat <= (others=>'0');--x"B0B0B0B0"; -- wr_data + slvi.we <= '0'; + slvi.sel <= "1000"; -- sel byte 0 (big endian) + slvi.stb <= '1'; + slvi.cyc <= '1'; + + wait for clk_period; + assert (slvo.ack='1') report "err: no Ack to master!!!" + severity error; + +--test 3: no request + wait for 5*clk_period; + slvi <= wbs_in_none; + + wait for clk_period; + assert (slvo.ack='0') report "err: no mst req, NO slv ack!!" + severity error; + +-------/// repeat test +--test 4 + wait for clk_period; + slvi.adr <= b"1010_0001_0000_0000_0000_0000_0000_00"; + slvi.dat <= (others=>'0');--x"B0B0B0B0"; -- wr_data + slvi.we <= '0'; + slvi.sel <= "1111"; -- sel byte 0 (big endian) + slvi.stb <= '1'; + slvi.cyc <= '1'; + + wait for clk_period; + assert (slvo.ack='1') report "err: no Ack to master!!!" + severity error; + +--test 5: no request + wait for 5*clk_period; + slvi <= wbs_in_none; + + wait for clk_period; + assert (slvo.ack='0') report "err: no mst req, NO slv ack!!" + severity error; + + + report ">> F e r t i g: wb_stestrd <<"; + wait; + end process; + +END; diff --git a/soc/top/top.ucf b/soc/top/top.ucf new file mode 100644 index 0000000..596aab2 --- /dev/null +++ b/soc/top/top.ucf @@ -0,0 +1,315 @@ + +NET clk LOC="AG18"; +NET clk TNM_NET = clk; +TIMESPEC TS_clk = PERIOD "clk" 10 ns HIGH 50%; + +#reset button (active low) +NET rst LOC="E7"; +NET rst PULLUP; +NET rst TIG; + +# LED PINS +NET led(0) LOC="AG8"; # | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +NET led(1) LOC="AH8"; # | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +NET led(2) LOC="AH9"; # | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +NET led(3) LOC="AG10"; # | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +NET led(4) LOC="AH10"; # | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +NET led(5) LOC="AG11"; # | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +NET led(6) LOC="AF11"; # | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +NET led(7) LOC="AE11"; # | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors + +# LCD PINS +#NET enableLCD LOC = AA5 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET rsLCD LOC = V7 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET rwLCD LOC = W6 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<7> LOC = AD7 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<6> LOC = AC7 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<5> LOC = AC5 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<4> LOC = AB6 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<3> LOC = AC4 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<2> LOC = AB5 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<1> LOC = AB7 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; +#NET dataLCD<0> LOC = Y8 | IOSTANDARD=LVCMOS33 | TIG | PULLDOWN; + +# onBoard SWITCHES +#NET sw(0) LOC = "J19"; # Bank = 3, Pin name = IO_L3N_GC_3, Sch name = SW0 +#NET sw(1) LOC = "L18"; # Bank = 3, Pin name = IO_L1N_CC_GC_3, Sch name = SW1 +#NET sw(2) LOC = "K18"; # Bank = 3, Pin name = IO_L3P_GC_3, Sch name = SW2 +#NET sw(3) LOC = "H18"; # Bank = 3, Pin name = IO_L0N_CC_GC_3, Sch name = SW3 +#NET sw(4) LOC = "H17"; # Bank = 3, Pin name = IO_L0P_CC_GC_3, Sch name = SW4 +#NET sw(5) LOC = "K17"; # Bank = 3, Pin name = IO_L1P_CC_GC_3, Sch name = SW5 +#NET sw(6) LOC = "G16"; # Bank = 3, Pin name = IO_L2N_GC_VRP_3, Sch name = SW6 +#NET sw(7) LOC = "G15"; # Bank = 3, Pin name = IO_L2P_GC_VRN_3, Sch name = SW7 + +# on Board BUTTONS +#NET "btn<0>" LOC = "G6"; # BTN0 +#NET "btn<1>" LOC = "G7"; # BTN1 +#NET "btn<2>" LOC = "J21"; # BTN3 (joystick button) +#NET "btn<3>" LOC = "E6"; # Joystick "up" +#NET "btn<4>" LOC = "K19"; # Joystick "left" +#NET "btn<5>" LOC = "J17"; # Joystick "right" +#NET "btn<6>" LOC = "H15"; # Joystick "down" + +# Audio +#NET "ac97_bitclk" TNM="bitclk" | IOSTANDARD=LVCMOS33 | LOC = "AH17"; # Bank = 4, Pin name = IO_L7P_GC_VRN_4, Sch name = AUD-BIT-CLK +#NET "ac97_sdi" LOC = "AE18" | IOSTANDARD=LVCMOS33; # Bank = 4, Pin name = IO_L8N_CC_GC_4, Sch name = AUD-SDI +#NET "ac97_sdo" LOC = "AG20" | IOSTANDARD=LVCMOS33; # Bank = 4, Pin name = IO_L4N_GC_VREF_4, Sch name = AUD-SDO +#NET "ac97_sync" LOC = "J9" | IOSTANDARD=LVCMOS33; # Bank = 20, Pin name = IO_L9N_CC_20, Sch name = AUD-SYNC +#NET "ac97_rst" LOC = "E12" | IOSTANDARD=LVCMOS33; # Bank = 20, Pin name = IO_L17P_20, Sch name = AUD-RESET +#TIMESPEC "TS_AC97_BITCLK"=PERIOD "bitclk" 81.4 ns HIGH 50%; + +############################################################################################## +# Anything below is unlikely to be used +############################################################################################## + +#Differential 200MHz CLKs +#NET clk_200_n LOC="H13";# | IOSTANDARD = LVDS_25; # Bank 3, Vcco=2.5V, No DCI +#NET clk_200_p LOC="J14";# | IOSTANDARD = LVDS_25; # Bank 3, Vcco=2.5V, No DCI + +#NET rxd1 LOC="AG15" | IOSTANDARD = LVCMOS33; # Bank 4, Vcco=3.3V, No DCI +#NET txd1 LOC="AF19" | IOSTANDARD = LVCMOS33; # Bank 4, Vcco=3.3V, No DCI +#NET rxd2 LOC="AF18" | IOSTANDARD = LVCMOS33; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET txd2 LOC="AG16" | IOSTANDARD = LVCMOS33; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors + +#NET ps2_keyb_clk LOC="H9" | IOSTANDARD=LVCMOS33 | PULLUP | SLEW = SLOW | DRIVE = 2; +#NET ps2_keyb_data LOC="H10" | IOSTANDARD=LVCMOS33 | PULLUP | SLEW = SLOW | DRIVE = 2; + +#NET dvi_iic_scl LOC="U8"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET dvi_iic_sda LOC="V8"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors + +#NET tft_lcd_data(0) LOC="G10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(1) LOC="G8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(2) LOC="B12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(3) LOC="D12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(4) LOC="C12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(5) LOC="D11"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(6) LOC="F10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(7) LOC="D10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(8) LOC="E9"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(9) LOC="F9"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(10) LOC="E8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET tft_lcd_data(11) LOC="F8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistor +#NET tft_lcd_clk_p LOC="K11"; +#NET tft_lcd_clk_n LOC="J11"; +#NET tft_lcd_hsync LOC="H8"; +#NET tft_lcd_vsync LOC="F13"; +#NET tft_lcd_de LOC="V10"; +#NET tft_lcd_reset_b LOC="V9"; + +#NET ps2_mouse_clk LOC="R27";# | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ps2_mouse_data LOC="U26";# | IOSTANDARD = LVCMOS18; #LVDCI_18; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors + +#NET phy_col LOC="K6";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_crs LOC="L5";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET PHY_INT LOC="T6"; # Bank 3, Vcco=2.5V, No DCI +#NET phy_mii_clk LOC="N5";# | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_mii_data LOC="U10";# | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_rst_n LOC="L4";# | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_rx_clk LOC="L19" | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_dv LOC="N8";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_gtx_clk LOC="J20"| IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_rx_data(0) LOC="N7";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(1) LOC="R6";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(2) LOC="P6";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(3) LOC="P5";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(4) LOC="M7";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(5) LOC="M6";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(6) LOC="M5";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_data(7) LOC="L6";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_rx_er LOC="P7";# | IOSTANDARD = LVCMOS33; # Bank 11, Vcco=2.5V or 3.3V user selectable by J20 +#NET phy_tx_clk LOC="J16" | IOSTANDARD = LVCMOS25; # Bank 3, Vcco=2.5V, No DCI +#NET phy_tx_en LOC="T10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(0) LOC="J5";# | IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(1) LOC="G5";# | IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(2) LOC="F5";# | IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(3) LOC="R7";# | IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(4) LOC="T8" ;#| IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(5) LOC="R11" ;#| IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(6) LOC="T11" ;#| IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_data(7) LOC="U7" ;#| IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET phy_tx_er LOC="R8" ;#| IOSTANDARD = LVDCI_33 | FAST | DRIVE=8; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors + +#DRAM PINS +#NET ddr_ad(0) LOC="L30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(1) LOC="M30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(2) LOC="N29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(3) LOC="P29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(4) LOC="K31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(5) LOC="L31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(6) LOC="P31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(7) LOC="P30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(8) LOC="M31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(9) LOC="R28";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(10) LOC="J31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(11) LOC="R29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(12) LOC="T31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ad(13) LOC="H29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_ba(0) LOC="G31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ba(1) LOC="J30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_ba(2) LOC="R31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_casb LOC="E31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_rasb LOC="H30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_cke(0) LOC="T28";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_cke(1) LOC="U30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_clkb(0) LOC="AJ29";# | IOSTANDARD = SSTL18_I; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_clkb(1) LOC="F28";# | IOSTANDARD = SSTL18_I; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_clk(0) LOC="AK29";# | IOSTANDARD = SSTL18_I; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_clk(1) LOC="E28";# | IOSTANDARD = SSTL18_I; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_csb(0) LOC="L29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_csb(1) LOC="J29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_dq(0) LOC="AF30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(1) LOC="AK31";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(2) LOC="AF31";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(3) LOC="AD30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(4) LOC="AJ30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(5) LOC="AF29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(6) LOC="AD29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(7) LOC="AE29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(8) LOC="AH27";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(9) LOC="AF28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(10) LOC="AH28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(11) LOC="AA28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(12) LOC="AG25";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(13) LOC="AJ26";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(14) LOC="AG28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(15) LOC="AB28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(16) LOC="AC28";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(17) LOC="AB25";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(18) LOC="AC27";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(19) LOC="AA26";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(20) LOC="AB26";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(21) LOC="AA24";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(22) LOC="AB27";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(23) LOC="AA25";# | IOSTANDARD = SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(24) LOC="AC29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(25) LOC="AB30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(26) LOC="W31";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(27) LOC="V30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(28) LOC="AC30";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(29) LOC="W29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(30) LOC="V27";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(31) LOC="W27";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(32) LOC="V29";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(33) LOC="Y27";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(34) LOC="Y26";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(35) LOC="W24";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(36) LOC="V28";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(37) LOC="W25";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(38) LOC="W26";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(39) LOC="V24";# | IOSTANDARD = SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(40) LOC="R24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(41) LOC="P25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(42) LOC="N24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(43) LOC="P26";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(44) LOC="T24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(45) LOC="N25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(46) LOC="P27";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(47) LOC="N28";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(48) LOC="M28";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(49) LOC="L28";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(50) LOC="F25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(51) LOC="H25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(52) LOC="K27";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(53) LOC="K28";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(54) LOC="H24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(55) LOC="G26";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(56) LOC="G25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(57) LOC="M26";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(58) LOC="J24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(59) LOC="L26";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(60) LOC="J27";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(61) LOC="M25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(62) LOC="L25";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dq(63) LOC="L24";# | IOSTANDARD = SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_dm(0) LOC="AJ31";# | IOSTANDARD = SSTL18_I; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(1) LOC="AE28";# | IOSTANDARD = SSTL18_I; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(2) LOC="Y24";# | IOSTANDARD = SSTL18_I; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(3) LOC="Y31";# | IOSTANDARD = SSTL18_I; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(4) LOC="V25";# | IOSTANDARD = SSTL18_I; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(5) LOC="P24";# | IOSTANDARD = SSTL18_I; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(6) LOC="F26";# | IOSTANDARD = SSTL18_I; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dm(7) LOC="J25";# | IOSTANDARD = SSTL18_I; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_dqsn(0) LOC="AA30";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(0) LOC="AA29";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(1) LOC="AK27";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(1) LOC="AK28";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(2) LOC="AJ27";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(2) LOC="AK26";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(3) LOC="AA31";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(3) LOC="AB31";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(4) LOC="Y29";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(4) LOC="Y28";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(5) LOC="E27";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(5) LOC="E26";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(6) LOC="G28";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(6) LOC="H28";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsn(7) LOC="H27";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_dqsp(7) LOC="G27";# | IOSTANDARD = DIFF_SSTL18_II; #DIFF_SSTL18_II; # Bank 19, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_odt(0) LOC="F31";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET ddr_odt(1) LOC="F30";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET DDR2_SCL LOC="E29"; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET DDR2_SDA LOC="F29"; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +# +#NET ddr_web LOC="K29";# | IOSTANDARD = SSTL18_I; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors + +#NET DVI_D0 LOC="G10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D1 LOC="G8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D2 LOC="B12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D3 LOC="D12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D4 LOC="C12"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D5 LOC="D11"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D6 LOC="F10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D7 LOC="D10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D8 LOC="E7"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D9 LOC="F9"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D10 LOC="E8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_D11 LOC="F8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_DE LOC="V10"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +##NET DVI_GPIO1 LOC="N30"; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET DVI_H LOC="H8"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_RESET_B LOC="V9"; # Bank 18, Vcco=3.3V, No DCI +#NET DVI_V LOC="F13"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_XCLK_N LOC="J11"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET DVI_XCLK_P LOC="K11"; # Bank 22, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET FAN_ALERT_B LOC="T30"; # Bank 15, Vcco=1.8V, DCI using 49.9 ohm resistors + +#NET flash_adv_n LOC="AF21"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors (FLASH_ADV_B) +#NET FLASH_AUDIO_RESET_B LOC="AG17"; # Bank 4, Vcco=3.3V, No DCI +#NET flash_ce LOC="AE14"; # Bank 2, Vcco=3.3V +#NET FLASH_CLK LOC="AG21"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET flash_oen LOC="AF14"; # Bank 2, Vcco=3.3V (FLASH_OE_B) +#NET FLASH_WAIT LOC="AH18"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors +#NET FPGA_AVDD LOC="T18"; # Bank 0, Vcco=3.3V +#NET FPGA_CCLK-R LOC="N15"; # Bank 0, Vcco=3.3V +#NET FPGA_CS_B LOC="N22"; # Bank 0, Vcco=3.3V +#NET FPGA_CS0_B LOC="AF21"; # Bank 2, Vcco=3.3V +#NET FPGA_DIFF_CLK_OUT_N LOC="J21"; # Bank 3, Vcco=2.5V, No DCI +#NET FPGA_DIFF_CLK_OUT_P LOC="J20"; # Bank 3, Vcco=2.5V, No DCI +#NET FPGA_DIN LOC="P15"; # Bank 0, Vcco=3.3V +#NET FPGA_DONE LOC="M15"; # Bank 0, Vcco=3.3V +#NET FPGA_DOUT_BUSY LOC="AD15"; # Bank 0, Vcco=3.3V +#NET FPGA_DX_N LOC="W17"; # Bank 0, Vcco=3.3V +#NET FPGA_DX_P LOC="W18"; # Bank 0, Vcco=3.3V +#NET FPGA_EXP_TCK LOC="AB15"; # Bank 0, Vcco=3.3V +#NET FPGA_EXP_TMS LOC="AC14"; # Bank 0, Vcco=3.3V +#NET FPGA_HSWAPEN LOC="M23"; # Bank 0, Vcco=3.3V +#NET FPGA_INIT_B LOC="N14"; # Bank 0, Vcco=3.3V +#NET FPGA_M0 LOC="AD21"; # Bank 0, Vcco=3.3V +#NET FPGA_M1 LOC="AC22"; # Bank 0, Vcco=3.3V +#NET FPGA_M2 LOC="AD22"; # Bank 0, Vcco=3.3V +#NET FPGA_PROG_B LOC="M22"; # Bank 0, Vcco=3.3V +#NET FPGA_RDWR_B LOC="N23"; # Bank 0, Vcco=3.3V +#NET FPGA_ROTARY_INCA LOC="AH30"; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET FPGA_ROTARY_INCB LOC="AG30"; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors +#NET FPGA_ROTARY_PUSH LOC="AH29"; # Bank 17, Vcco=1.8V, DCI using 49.9 ohm resistors diff --git a/soc/top/top.vhd b/soc/top/top.vhd new file mode 100644 index 0000000..a9f15c9 --- /dev/null +++ b/soc/top/top.vhd @@ -0,0 +1,185 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; + +library work; +use work.lt16x32_internal.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; +use work.lt16soc_memories.all; +use work.lt16soc_peripherals.all; + +entity lt16soc_top is +generic( + programfilename : string := "programs/blinky.ram" -- see "Synthesize XST" process properties for actual value ("-generics" in .xst file)! +); +port( + -- clock signal + clk : in std_logic; + -- external reset button + rst : in std_logic; + + led : out std_logic_vector(7 downto 0) +); +end entity lt16soc_top; + + +architecture RTL of lt16soc_top is + --////////////////////////////////////////////////////// + -- constant & signal + --////////////////////////////////////////////////////// + + signal rst_gen : std_logic; + + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0000_0000_0001"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + + signal slvo : wb_slv_out_vector := (others=> wbs_out_none); + signal msto : wb_mst_out_vector := (others=> wbm_out_none); + + signal slvi : wb_slv_in_vector := (others=> wbs_in_none); + signal msti : wb_mst_in_vector := (others=> wbm_in_none); + + signal core2mem : core_imem; + signal mem2core : imem_core; + + signal irq2core : irq_core; + signal core2irq : core_irq; + + signal irq_lines : std_logic_vector((2 ** irq_num_width) - 1 downto 0) := (others=>'0'); + + --////////////////////////////////////////////////////// + -- components + --////////////////////////////////////////////////////// + + component corewrapper + port( + clk : in std_logic; + rst : in std_logic; + + in_imem : in imem_core; + out_imem : out core_imem; + + in_proc : in irq_core; + out_proc : out core_irq; + + hardfault : out std_logic; + + wmsti : in wb_mst_in_type; + wmsto : out wb_mst_out_type + ); + end component; + + component irq_controller + port( + clk : in std_logic; + rst : in std_logic; + + in_proc : in core_irq; + out_proc : out irq_core; + + irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0) + ); + end component; + + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000" + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + +begin + + with RST_ACTIVE_HIGH select rst_gen <= + rst when true, + not rst when others; + + --////////////////////////////////////////////////////// + -- Instantiate + --////////////////////////////////////////////////////// + + corewrap_inst: corewrapper + port map( + clk => clk, + rst => rst_gen, + + in_imem => mem2core, + out_imem => core2mem, + + in_proc => irq2core, + out_proc => core2irq, + + hardfault => irq_lines(1), + wmsti => msti(CFG_LT16), + wmsto => msto(CFG_LT16) + + ); + + irqcontr_inst: irq_controller + port map( + clk => clk, + rst => rst_gen, + in_proc => core2irq, + out_proc => irq2core, + irq_lines => irq_lines + ); + + wbicn_inst: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst_gen, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + + memwrap_inst: memwrapper + generic map( + memaddr => CFG_BADR_MEM, + addrmask => CFG_MADR_MEM, + filename => programfilename, + size => IMEMSZ + ) + port map( + clk => clk, + rst => rst_gen, + in_imem => core2mem, + out_imem => mem2core, + + fault => irq_lines(2), + wslvi => slvi(CFG_MEM), + wslvo => slvo(CFG_MEM) + ); + + dmem : wb_dmem + generic map( + memaddr=>CFG_BADR_DMEM, + addrmask=>CFG_MADR_DMEM) + port map(clk,rst_gen,slvi(CFG_DMEM),slvo(CFG_DMEM)); + + leddev : wb_led + generic map( + CFG_BADR_LED,CFG_MADR_LED + ) + port map( + clk,rst_gen,led,slvi(CFG_LED),slvo(CFG_LED) + ); + +end architecture RTL; diff --git a/soc/top/top_wave.wcfg b/soc/top/top_wave.wcfg new file mode 100644 index 0000000..407a603 --- /dev/null +++ b/soc/top/top_wave.wcfg @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + led[7:0] + led[7:0] + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + .dat + slvo[15].dat + HEXRADIX + + + .ack + slvo[15].ack + + + .wbcfg + slvo[15].wbcfg + + + .wbidx + slvo[15].wbidx + + + + [14] + slvo[14] + + .dat + slvo[14].dat + HEXRADIX + + + .ack + slvo[14].ack + + + .wbcfg + slvo[14].wbcfg + + + .wbidx + slvo[14].wbidx + + + + [13] + slvo[13] + + .dat + slvo[13].dat + HEXRADIX + + + .ack + slvo[13].ack + + + .wbcfg + slvo[13].wbcfg + + + .wbidx + slvo[13].wbidx + + + + [12] + slvo[12] + + .dat + slvo[12].dat + HEXRADIX + + + .ack + slvo[12].ack + + + .wbcfg + slvo[12].wbcfg + + + .wbidx + slvo[12].wbidx + + + + [11] + slvo[11] + + .dat + slvo[11].dat + HEXRADIX + + + .ack + slvo[11].ack + + + .wbcfg + slvo[11].wbcfg + + + .wbidx + slvo[11].wbidx + + + + [10] + slvo[10] + + .dat + slvo[10].dat + HEXRADIX + + + .ack + slvo[10].ack + + + .wbcfg + slvo[10].wbcfg + + + .wbidx + slvo[10].wbidx + + + + [9] + slvo[9] + + .dat + slvo[9].dat + HEXRADIX + + + .ack + slvo[9].ack + + + .wbcfg + slvo[9].wbcfg + + + .wbidx + slvo[9].wbidx + + + + [8] + slvo[8] + + .dat + slvo[8].dat + HEXRADIX + + + .ack + slvo[8].ack + + + .wbcfg + slvo[8].wbcfg + + + .wbidx + slvo[8].wbidx + + + + [7] + slvo[7] + + .dat + slvo[7].dat + HEXRADIX + + + .ack + slvo[7].ack + + + .wbcfg + slvo[7].wbcfg + + + .wbidx + slvo[7].wbidx + + + + [6] + slvo[6] + + .dat + slvo[6].dat + HEXRADIX + + + .ack + slvo[6].ack + + + .wbcfg + slvo[6].wbcfg + + + .wbidx + slvo[6].wbidx + + + + [5] + slvo[5] + + .dat + slvo[5].dat + HEXRADIX + + + .ack + slvo[5].ack + + + .wbcfg + slvo[5].wbcfg + + + .wbidx + slvo[5].wbidx + + + + [4] + slvo[4] + + .dat + slvo[4].dat + HEXRADIX + + + .ack + slvo[4].ack + + + .wbcfg + slvo[4].wbcfg + + + .wbidx + slvo[4].wbidx + + + + [3] + slvo[3] + + .dat + slvo[3].dat + HEXRADIX + + + .ack + slvo[3].ack + + + .wbcfg + slvo[3].wbcfg + + + .wbidx + slvo[3].wbidx + + + + [2] + slvo[2] + + + [1] + slvo[1] + + + [0] + slvo[0] + + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + .adr + msto[3].adr + HEXRADIX + + + .dat + msto[3].dat + HEXRADIX + + + .we + msto[3].we + + + .sel + msto[3].sel + + + .stb + msto[3].stb + + + .cyc + msto[3].cyc + + + .wbcfg + msto[3].wbcfg + + + .wbidx + msto[3].wbidx + + + + [2] + msto[2] + + .adr + msto[2].adr + HEXRADIX + + + .dat + msto[2].dat + HEXRADIX + + + .we + msto[2].we + + + .sel + msto[2].sel + + + .stb + msto[2].stb + + + .cyc + msto[2].cyc + + + .wbcfg + msto[2].wbcfg + + + .wbidx + msto[2].wbidx + + + + [1] + msto[1] + + .adr + msto[1].adr + HEXRADIX + + + .dat + msto[1].dat + HEXRADIX + + + .we + msto[1].we + + + .sel + msto[1].sel + + + .stb + msto[1].stb + + + .cyc + msto[1].cyc + + + .wbcfg + msto[1].wbcfg + + + .wbidx + msto[1].wbidx + + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + HEXRADIX + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + + + .wbidx + msto[0].wbidx + + + + + slvi[15:0] + slvi[15:0] + + + msti[3:0] + msti[3:0] + + + core2mem + core2mem + + .read_addr + core2mem.read_addr + HEXRADIX + + + .read_en + core2mem.read_en + + + + mem2core + mem2core + + .read_data + mem2core.read_data + HEXRADIX + + + .ready + mem2core.ready + + + + IRQ + label + + irq_lines[15:0] + irq_lines[15:0] + + + irq2core + irq2core + + + core2irq + core2irq + + + + testslave1_o + testslave1_o + + .dat + testslave1_o.dat + HEXRADIX + + + .ack + testslave1_o.ack + + + .wbcfg + testslave1_o.wbcfg + + + .wbidx + testslave1_o.wbidx + + + + testslave2_o + testslave2_o + + + test_rddat[31:0] + test_rddat[31:0] + HEXRADIX + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + + cfg_badr_tsts1 + cfg_badr_tsts1 + + + cfg_badr_tsts2 + cfg_badr_tsts2 + + + cfg_madr_zero + cfg_madr_zero + + diff --git a/soc/top/wb_intercon.vhd b/soc/top/wb_intercon.vhd new file mode 100644 index 0000000..6a07e79 --- /dev/null +++ b/soc/top/wb_intercon.vhd @@ -0,0 +1,153 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use IEEE.math_real.all; + +library work; +use work.wishbone.all; +use work.config.all; + +ENTITY wb_intercon IS + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000" + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); +END ENTITY wb_intercon; + +ARCHITECTURE RTL OF wb_intercon IS +--selected slv +signal tmpslvo : wb_slv_out_vector; -- := (others=> wbs_out_none); +--granted mst +signal tmpmsto : wb_mst_out_vector; -- := (others=> wbm_out_none); + +signal mgnt_idx : integer range 0 to NWBMST-1; +signal mgnt : std_logic_vector(0 to NWBMST-1) := (others=>'0'); + +signal ssel_idx : integer range 0 to NWBSLV-1; +signal ssel : std_logic_vector(0 to NWBSLV-1) := (others=>'0'); + + +BEGIN +----------------------------------------------- +-- Master Arbiter: To output which master is granted +----------------------------------------------- + mstarb: for i in 0 to NWBMST-1 generate + onemst: if (i = 0) generate + onemst_exist: if(mst_mask_vector(i)='1') generate + tmpmsto(i) <= msto(i) when (msto(i).cyc='1') else + wbm_out_none; + end generate onemst_exist; + + onemst_dne: if(mst_mask_vector(i)='0') generate + tmpmsto(i) <= wbm_out_none; + end generate onemst_dne; + end generate onemst; + + mulmst: if (i > 0) generate + mulmst_exist: if(mst_mask_vector(i)='1') generate + tmpmsto(i) <= msto(i) when (msto(i).cyc='1') else + tmpmsto(i-1); + end generate mulmst_exist; + + mulmst_dne:if(mst_mask_vector(i)='0') generate + tmpmsto(i) <= tmpmsto(i-1); + end generate mulmst_dne; + end generate mulmst; + + end generate mstarb; + + -- + selslv: process(tmpmsto(NWBMST-1) ,slvo, mgnt_idx) + begin + slvi <= (others=> wbs_in_none); --init slave_input + ssel_idx <= 0; + for i in 0 to NWBSLV-1 loop + if (slv_mask_vector(i)='1') then + --slave active and m_req_adr maps to the slave + if(slvadrmap(slvo(i).wbcfg, tmpmsto(NWBMST-1).adr) and mst_mask_vector(mgnt_idx) = '1') then + ssel <= (others=>'0'); -- clear gnt for previous grant of lower priority master + ssel_idx <= i; + ssel(i) <= '1'; + + slvi(i).dat <= tmpmsto(NWBMST-1).dat; + slvi(i).sel <= tmpmsto(NWBMST-1).sel; + slvi(i).adr <= tmpmsto(NWBMST-1).adr; + slvi(i).cyc <= tmpmsto(NWBMST-1).cyc; + slvi(i).stb <= tmpmsto(NWBMST-1).stb; + slvi(i).we <= tmpmsto(NWBMST-1).we; + slvi(i).cti <= tmpmsto(NWBMST-1).cti; + slvi(i).bte <= tmpmsto(NWBMST-1).bte; + end if; + end if; + end loop; + end process; + +----------------------------------- +--slave decoding: +----------------------------------- + gen_slvmux: for i in 0 to NWBSLV-1 generate + -- One slave exists + oneslv: if (i = 0) generate + oneslv_exist: if(slv_mask_vector(i)='1') generate + tmpslvo(i) <= slvo(i) when slvadrmap(slvo(i).wbcfg, tmpmsto(NWBMST-1).adr) else + wbs_out_none; + end generate oneslv_exist; + + oneslv_dne: if(slv_mask_vector(i)='0') generate + tmpslvo(i)<=wbs_out_none; + end generate oneslv_dne; + end generate oneslv; + + -- Multiple slaves exists + mulslv: if (i > 0) generate + mulslv_exist: if(slv_mask_vector(i)='1') generate + tmpslvo(i) <= slvo(i) when slvadrmap(slvo(i).wbcfg, tmpmsto(NWBMST-1).adr) else + tmpslvo(i-1); + end generate mulslv_exist; + + mulslv_dne: if(slv_mask_vector(i)='0') generate + tmpslvo(i) <= tmpslvo(i-1); + end generate mulslv_dne; + end generate mulslv; + end generate gen_slvmux; + + + gntmst: process(msto) + begin + mgnt <= (others=>'0'); + mgnt_idx <= 0; + for i in 0 to NWBMST-1 loop + if (mst_mask_vector(i)='1') then + if(msto(i).cyc='1') then -- check if master still get the bus + mgnt <= (others=>'0'); -- clear gnt for previous grant of lower priority master + mgnt_idx <= i; + mgnt(i) <= '1'; + end if; + end if; + end loop; + end process; + + process(mgnt_idx,tmpslvo(NWBSLV-1).ack,tmpslvo(NWBSLV-1).dat) + begin + msti <= (others=> wbm_in_none); --init master_input + for i in 0 to NWBMST-1 loop + if mgnt_idx=i then + msti(i).ack <= tmpslvo(NWBSLV-1).ack; + else + msti(i).ack <= '0'; + end if; + msti(i).dat <= tmpslvo(NWBSLV-1).dat; + end loop; + end process; + +END ARCHITECTURE RTL; diff --git a/soc/top/wb_intercon_simple_tb.vhd b/soc/top/wb_intercon_simple_tb.vhd new file mode 100644 index 0000000..73f3c83 --- /dev/null +++ b/soc/top/wb_intercon_simple_tb.vhd @@ -0,0 +1,119 @@ +-- See the file "LICENSE" for the full license governing this code. -- +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use IEEE.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.wb_tp.all; +use work.txt_util.all; +use work.lt16soc_peripherals.all; +use work.lt16soc_memories.all; + +ENTITY wb_intercon_simple_tb IS +END wb_intercon_simple_tb; + +ARCHITECTURE behavior OF wb_intercon_simple_tb IS + + -- component Declaration for the Unit Under Test (UUT) + + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000" + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal msto : wb_mst_out_vector; + signal slvo : wb_slv_out_vector; + + --Outputs + signal msti : wb_mst_in_vector; + signal slvi : wb_slv_in_vector; + signal led : std_logic_vector(7 downto 0); + + signal data : std_logic_vector(31 downto 0); + +--------------------- +-- constant +--------------------- + constant CLK_PERIOD : time := 10 ns; + + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0000_0000_0001"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; + +begin + -- Instantiate the Unit Under Test (UUT) + uut: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + + dmem : wb_dmem + generic map( + memaddr=>CFG_BADR_DMEM, + addrmask=>CFG_MADR_DMEM) + port map(clk,rst,slvi(CFG_DMEM),slvo(CFG_DMEM)); + + leddev : wb_led + generic map( + CFG_BADR_LED,CFG_MADR_LED + ) + port map( + clk,rst,led,slvi(CFG_LED),slvo(CFG_LED) + ); + + clk_gen : process + begin + clk <= '0'; + wait for CLK_PERIOD/2; + clk <= '1'; + wait for CLK_PERIOD/2; + end process; + + stimuli: process + begin + rst <= '1'; + wait for CLK_PERIOD; + rst <= '0'; + + data <= x"EDAB3F5C"; + generate_sync_wb_burst_write(msto(0),slvo(CFG_DMEM),clk,data,4); + data <= not data; +-- generate_sync_wb_single_write(msto(0),slvo(CFG_DMEM),clk,data); + + wait for 2*CLK_PERIOD; + generate_sync_wb_burst_read(msto(0),slvo(CFG_DMEM),clk,data,4); + + wait; + end process stimuli; + +END; diff --git a/soc/top/wb_intercon_tb.vhd b/soc/top/wb_intercon_tb.vhd new file mode 100644 index 0000000..63119e0 --- /dev/null +++ b/soc/top/wb_intercon_tb.vhd @@ -0,0 +1,1272 @@ +-- See the file "LICENSE" for the full license governing this code. -- +-------------------------------------------------------------------------------- +-- Notes: +-- Test case description: +-- 1. Test template is provided at bottommost of this module +-- 2. Test case number descripion: +-- read request: start with test case number 0x +-- write request: start with test case number 5x +-- 3. Error format description: E-xy: (wbicn, fn.) +-- x = main case number +-- y = subcase number +-- 4. The 4-signal handshake sequences of wb_intercon are following +-- Handshake 1 +-- > master request(s) = msto +-- > master module(s) to wb_intercon +-- Handshake 2 +-- > slave obtains the granted master request = slvi +-- > wb_intercon to slave module(s) +-- Handshake 3 +-- > slave responses to the granted master request = slvo +-- > slave module(s) to wb_intercon +-- Handshake 4 +-- > granted master obtains slave response = msti +-- > wb_intercon to master module +-- 5. This test module mainly checks outputs of wb_intercon i.e. msti and slvi +-- > slvi_chk_all function is used for slvi validation +-- > msti_chk_all function is used for msti validation +-- 6. In order to fulfill the request loop as mentioned in (4), +-- This module requires to call test_slave modules for both read and write request +-- a) wb_stestrd +-- > test_slave module for read +-- > This module simply provides read data based on the request address +-- b) wb_stestwr +-- > test_slave module for write +-- > write to LED +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use IEEE.std_logic_textio.all; + +library std; +use std.standard.all; +use std.textio.all; + +library work; +use work.wishbone.all; +use work.config.all; +use work.wb_tp.all; +use work.txt_util.all; + +ENTITY wb_intercon_tb IS +END wb_intercon_tb; + +ARCHITECTURE behavior OF wb_intercon_tb IS + + -- component Declaration for the Unit Under Test (UUT) + + component wb_intercon + generic( + slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"0000_0000_0000_0000"; + mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"0000" + ); + port( + clk : in std_logic; + rst : in std_logic; + msti : out wb_mst_in_vector; + msto : in wb_mst_out_vector; + slvi : out wb_slv_in_vector; + slvo : in wb_slv_out_vector + ); + end component; + + component wb_stestrd + generic( + memaddr : generic_addr_type :=0; + addrmask : generic_mask_type :=16#3fffff#; + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + test_rddat : in std_logic_vector(31 downto 0) + ); + end component; + + component wb_stestwr + generic( + memaddr : generic_addr_type :=0; + addrmask : generic_mask_type :=16#3fffff#; + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + led : out std_logic_vector (7 downto 0) + ); + end component; + + --Inputs + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + signal msto : wb_mst_out_vector; + signal slvo : wb_slv_out_vector; + + --Outputs + signal msti : wb_mst_in_vector; + signal slvi : wb_slv_in_vector; + signal led, led1, led2 : std_logic_vector(7 downto 0); + + --temp + -- read + signal testslave0_o, testslave1_o, testslave3_o, testslave5_o, testslave15_o: wb_slv_out_type := wbs_out_none; + -- write + signal testslave2_o, testslave4_o, testslave14_o: wb_slv_out_type := wbs_out_none; +--------------------- +-- constant +--------------------- + constant clk_period : time := 10 ns; + signal req_mst_idx :integer range 0 to NWBMST-1; + signal test_rddat: std_logic_vector(31 downto 0) := (others=>'0'); + + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1110_0100_0000_0011"; + constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1011"; + --base adr + constant CFG_BADR_TSTS0 : generic_addr_type := 16#2A000000#; -- 30bits (32b = A8000000) + constant CFG_BADR_TSTS1 : generic_addr_type := 16#28400000#; -- 30bits (32b = A1000000) + constant CFG_BADR_TSTS2 : generic_addr_type := 16#28800000#; -- 30bits (32b = A2000000) + constant CFG_BADR_TSTS3 : generic_addr_type := 16#28C00000#; -- 30bits (32b = A3000000) + constant CFG_BADR_TSTS4 : generic_addr_type := 16#29000000#; -- 30bits (32b = A4000000) + constant CFG_BADR_TSTS14 : generic_addr_type := 16#2B800000#; -- 30bits (32b = A2000000) + constant CFG_BADR_TSTS15 : generic_addr_type := 16#2BC44000#; -- 30bits (32b = AF110000) + --mask adr + constant CFG_MADR_TSTS14 : generic_mask_type := 16#3FC000#; + constant CFG_MADR_TSTS15 : generic_mask_type := 16#3FC000#; + constant CFG_MADR_ZERO : generic_mask_type := 0; + constant CFG_MADR_FULL : generic_mask_type := 16#3FFFFF#; + +begin + -- Instantiate the Unit Under Test (UUT) + uut: wb_intercon + generic map( + slv_mask_vector => slv_mask_vector, + mst_mask_vector => mst_mask_vector + ) + port map( + clk => clk, + rst => rst, + msti => msti, + msto => msto, + slvi => slvi, + slvo => slvo + ); + -------------------------------------- + ---- slv- (rd) + -------------------------------------- + srd00: wb_stestrd + generic map( + memaddr => CFG_BADR_TSTS0, + addrmask => CFG_MADR_ZERO, + wbidx => 0 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave0_o, + slvi.adr => slvi(0).adr, + slvi.dat => slvi(0).dat, + slvi.we => slvi(0).we, + slvi.sel => slvi(0).sel, + slvi.stb => slvi(0).stb, + slvi.cyc => slvi(0).cyc, + test_rddat => test_rddat + ); + + srd01: wb_stestrd + generic map( + memaddr => CFG_BADR_TSTS1, + addrmask => CFG_MADR_ZERO, + wbidx => 1 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave1_o, + slvi.adr => slvi(1).adr, + slvi.dat => slvi(1).dat, + slvi.we => slvi(1).we, + slvi.sel => slvi(1).sel, + slvi.stb => slvi(1).stb, + slvi.cyc => slvi(1).cyc, + test_rddat => test_rddat + ); + + srd03: wb_stestrd + generic map( + memaddr => CFG_BADR_TSTS3, + addrmask => CFG_MADR_ZERO, + wbidx => 3 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave3_o, + slvi.adr => slvi(3).adr, + slvi.dat => slvi(3).dat, + slvi.we => slvi(3).we, + slvi.sel => slvi(3).sel, + slvi.stb => slvi(3).stb, + slvi.cyc => slvi(3).cyc, + test_rddat => test_rddat + ); + + srd05: wb_stestrd + generic map( + memaddr => 16#00000000#, --30bits (32b = 00000000) -- test ADDR_base = 0 + addrmask => CFG_MADR_FULL, + wbidx => 5 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave5_o, + slvi.adr => slvi(5).adr, + slvi.dat => slvi(5).dat, + slvi.we => slvi(5).we, + slvi.sel => slvi(5).sel, + slvi.stb => slvi(5).stb, + slvi.cyc => slvi(5).cyc, + test_rddat => test_rddat + ); + + srd15: wb_stestrd + generic map( + memaddr => CFG_BADR_TSTS15, + addrmask => CFG_MADR_TSTS15, + wbidx => 15 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave15_o, + slvi.adr => slvi(15).adr, + slvi.dat => slvi(15).dat, + slvi.we => slvi(15).we, + slvi.sel => slvi(15).sel, + slvi.stb => slvi(15).stb, + slvi.cyc => slvi(15).cyc, + test_rddat => test_rddat + ); + -------------------------------------- + ---- slv- (wr) + -------------------------------------- + swr02: wb_stestwr + generic map( + memaddr => CFG_BADR_TSTS2, + addrmask => CFG_MADR_ZERO, + wbidx => 2 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave2_o, + slvi.adr => slvi(2).adr, + slvi.dat => slvi(2).dat, + slvi.we => slvi(2).we, + slvi.sel => slvi(2).sel, + slvi.stb => slvi(2).stb, + slvi.cyc => slvi(2).cyc, + led => led + ); + + swr04: wb_stestwr + generic map( + memaddr => 16#29000000#, --30bits (32b = A4000000) + addrmask => CFG_MADR_ZERO, + wbidx => 4 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave4_o, + slvi.adr => slvi(4).adr, + slvi.dat => slvi(4).dat, + slvi.we => slvi(4).we, + slvi.sel => slvi(4).sel, + slvi.stb => slvi(4).stb, + slvi.cyc => slvi(4).cyc, + led => led1 + ); + + swr14: wb_stestwr + generic map( + memaddr => CFG_BADR_TSTS14, + addrmask => CFG_MADR_TSTS14, + wbidx => 14 + ) + port map( + clk => clk, + rst => rst, + slvo => testslave14_o, + slvi.adr => slvi(14).adr, + slvi.dat => slvi(14).dat, + slvi.we => slvi(14).we, + slvi.sel => slvi(14).sel, + slvi.stb => slvi(14).stb, + slvi.cyc => slvi(14).cyc, + led => led2 + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + reset_process : process + begin + --report ">> R e s e t"; + rst <= '1'; + wait for clk_period*3.5; + rst <= '0'; + wait; + end process; + + -------------------------------------- + -- Process: gen_slv + -- + -- Directly copy output from testslv module e.g. wb_stestrd, wb_stestwr and input to the wb_intercon + -- Remark: The process is made due to the error that occured + -- from outputting slvo directly from wb_stestrd and wb_stestwr + -------------------------------------- + gen_slv: process( + testslave0_o, + testslave1_o, + testslave2_o, + testslave3_o, + testslave4_o, + testslave5_o, + testslave14_o, + testslave15_o + ) is + begin + slvo <= (others=> wbs_out_none); + -- read + slvo(0) <= testslave0_o; + slvo(1) <= testslave1_o; + slvo(3) <= testslave3_o; + slvo(5) <= testslave5_o; + slvo(15) <= testslave15_o; + -- write + slvo(2) <= testslave2_o; + slvo(4) <= testslave4_o; + slvo(14) <= testslave14_o; + end process; + + -- Stimulus process + stim_proc: process + + begin + --report ">> S t a r t <<"; + + -------------------------------------- + -- Test case 00: + -- + -- No request + -------------------------------------- + --report ">> TC0 starts <<"; + -------------------------------------- + req_mst_idx <= 0; wait for clk_period; + -- Handshake-1: + msto <= (others=> wbm_out_none); + wait for clk_period; + + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-02: (wbicn, fn.slvi_chk_all): No request, all slave input vector should be quiet" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-04: (wbicn, fn.msti_chk_all): No request, all master should be quiet" + severity error; + + -------------------------------------- + --report ">> TC0 ends <<"; + -------------------------------------- + -- + --E N D Test_case 00 + -- + -------------------------------------- + + wait for 10*clk_period; + wait for clk_period/2; + -------------------------------------- + -- Test_case 01: + -------------------------------------- + -- single master read, valid address + -- Expected output, slvi: correct selected slave + -- Expected output, msti: correct response from selected slave + -- Expected error: None + -------------------------------------- + --report ">> TC1 starts <<"; + -------------------------------------- + + -- Handshake-1: master requests (input for intercon) + req_mst_idx <= 3; test_rddat <= x"A00FF00A"; + wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A1000003", (others=>'0'), "1000"); + wait for clk_period; + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + --wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-10: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-12: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC1 ends <<"; + -------------------------------------- + -- + --E N D Test_case 01 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 02: + -- single master read, valid address, different master from Test_case 01 + -- Expected output, slvi: correct selected slave + -- Expected output, msti: correct response from selected slave + -- Expected error: None + -------------------------------------- + wait for 5*clk_period; + --report ">> TC2 starts <<"; + -------------------------------------- + + -- Handshake-1: master requests (input for intercon) + req_mst_idx <= 2; test_rddat <= x"B00FF00B"; + wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A1000000", (others=>'0'), "1000"); + wait for clk_period; + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-20: slvi_chk function" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-22: (wbicn, fn.msti_chk)" + severity error; + + -------------------------------------- + --report ">> TC2 ends <<"; + -------------------------------------- + -- + --E N D Test_case 02 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --////////////////////////////////////////////// + -- + -------------------------------------- + -- Test_case 03: + -- single master read, invalid address + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: no response for all msti + -- Expected error: invalid address map from slvi_chk + -------------------------------------- + wait for 5*clk_period; + --report ">> TC3 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + req_mst_idx <= 3; test_rddat <= x"FFFFFFFF"; + wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"FF000000", (others=>'0'), "1000"); + --! there is no slave at address x"FF000000"? --TF + wait for clk_period; + + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-30: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + --assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-32: (wbicn, fn.msti_chk_all) should return false" + severity error; + -------------------------------------- + --report ">> TC3 ends <<"; + -------------------------------------- + -- + --E N D Test_case 03 + -- + -------------------------------------- + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 04: + -- mult master, same address request + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: response to higher priority master + -- Expected error: no + -------------------------------------- + wait for 5*clk_period; + --report ">> TC4 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + test_rddat <= x"D00FF00D"; + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A1000000", (others=>'0'), "0100"); + wait for clk_period; + + req_mst_idx <= 2; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A1000000", (others=>'0'), "0100"); + wait for clk_period; + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-40: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-42: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC4 ends <<"; + -------------------------------------- + -- + --E N D Test_case 04 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 05: + -- mutl master (highest granted master w/ invalid address) + -- Expected output, slvi: input for valid address + -- Expected output, msti: input for valid request master + -- Expected error: Error, invalid address for higher priority and no grant to lower priority although it's valid + -------------------------------------- + wait for 5*clk_period; + --report ">> TC5 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + test_rddat <= x"D00FF00D"; + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"FF000000", (others=>'0'), "0100"); + wait for clk_period; + + req_mst_idx <= 0; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A1000000", (others=>'0'), "0100"); + wait for clk_period; + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-50: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-52: (wbicn, fn.msti_chk_all): should return false" + severity error; + + -------------------------------------- + --report ">> TC5 ends <<"; + -------------------------------------- + -- + --E N D Test_case 05 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 06: + -------------------------------------- + -- single master read, valid address, inactive slave + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: no request for all msti + -- Expected error: Error, no address map + -------------------------------------- + --report ">> TC6 starts <<"; + -------------------------------------- + + -- Handshake-1: master requests (input for intercon) + req_mst_idx <= 3; test_rddat <= x"FFFFFFFF"; + wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"A3000000", (others=>'0'), "1000"); + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert not slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-60: (wbicn, fn.slvi_chk_all): no address map, it should return false" + severity error; + + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-62: (wbicn, fn.msti_chk_all): no address map, it should return false" + severity error; + -------------------------------------- + --report ">> TC6 ends <<"; + -------------------------------------- + -- + --E N D Test_case 06 + -- + -------------------------------------- + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --////////////////////////////////////////////// + -------------------------------------- + -- Test_case 07: + -- test masking by reusing test case 4 + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: response to higher priority master + -- Expected error: no + -------------------------------------- + wait for 5*clk_period; + --report ">> TC7 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + test_rddat <= x"A770077A"; -- for slave A100_0000 + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"AF110710", (others=>'0'), "0100");-- map to same slv (in range) + wait for clk_period; -- Need for msto assignment + + req_mst_idx <= 2; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"AF110720", (others=>'0'), "0100"); -- map to same slv (in range) + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report "E-70: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-72: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC7 ends <<"; + -------------------------------------- + -- + --E N D Test_case 07 + -- + -------------------------------------- + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --////////////////////////////////////////////// + + + + -------------------------------------- + -- Test_case 08: + -------------------------------------- + -- single master read, valid address + -- *** Test read from slave w/ base address 0 (mockup memory) + -- Expected output, slvi: correct selected slave + -- Expected output, msti: correct response from selected slave + -- Expected error: None + -------------------------------------- + --report ">> TC8 starts <<"; + -------------------------------------- + + -- Handshake-1: master requests (input for intercon) + req_mst_idx <= 3; test_rddat <= x"A008800A"; + wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '0', x"00000000", (others=>'0'), "1000"); + wait for clk_period; + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + --wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-80: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-82: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC8 ends <<"; + -------------------------------------- + -- + --E N D Test_case 08 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 51: + -- single master write + -- Expected output, slvi: address, data from granted master + -- Expected output, msti: ack from written slv + -- Expected error: no error + -------------------------------------- + wait for 5*clk_period; + --report ">> TC51 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + --test_wrdat <= x"332211AA"; + req_mst_idx <= 3; wait for clk_period; + + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A2000000", x"332211AA", "0100"); + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-511: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + -- check led (hardcode check) + wait for clk_period; + assert led = x"22" + report"E-511a: (wbicn) no led out" + severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-512: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC51 ends <<"; + -------------------------------------- + -- + --E N D Test_case 51 + -- + ------------------------------------ + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 52: + -- single master write, valid address, different master from Test_case 51 + -- Expected output, slvi: correct selected slave + -- Expected output, msti: correct response from selected slave + -- Expected error: None + -------------------------------------- + wait for 5*clk_period; + --report ">> TC52 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 2; wait for clk_period; + + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A2000000", x"332211AA", "0010"); + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-521: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + -- check led (hardcode check) + wait for clk_period; + assert led = x"11" + report"E-521a: (wbicn) no led out" + severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-522: (wbicn, fn.msti_chk_all)" + severity error; + + -------------------------------------- + --report ">> TC52 ends <<"; + -------------------------------------- + -- + --E N D Test_case 52 + -- + -------------------------------------- + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + + -------------------------------------- + -- Test_case 53: + -- single master write + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: no response for all msti + -- Expected error: invalid address map from slvi_chk + -------------------------------------- + wait for 5*clk_period; + --report ">> TC53 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 3; wait for clk_period; + + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"FF000000", x"332211AA", "0010"); + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-531: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + -- check led (hardcode check) +-- wait for clk_period; +-- assert led = (others=>'-') -- ERR: internal compiler error. It can't be checked for '-' +-- report"E-531a: (wbicn) led should not be assigned" +-- severity error; +-- + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-532: (wbicn, fn.msti_chk_all): invalid address map, it should return false" + severity error; + -------------------------------------- + --report ">> TC53 ends <<"; + -------------------------------------- + -- + --E N D Test_case 53 + -- + ------------------------------------ + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 54: + -- mult master, same address request + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: response to higher priority master + -- Expected error: no + -------------------------------------- + wait for 5*clk_period; + --report ">> TC54 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A2000000", x"AA3333AA", "0100"); + wait for clk_period; -- Need for msto assignment + + + req_mst_idx <= 2; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A2000000", x"AA2222AA", "0100"); + wait for clk_period; -- Need for msto assignment + + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-541: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + -- check led (hardcode check) + wait for clk_period; + assert led = x"33" -- grant to m3 + report"E-541a: (wbicn) no led out" + severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-542: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC54 ends <<"; + -------------------------------------- + -- + --E N D Test_case 54 + -- + ------------------------------------ + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 55: + -- mutl master (highest granted master w/ invalid address) + -- Expected output, slvi: input for valid address + -- Expected output, msti: input for valid request master + -- Expected error: error invalid address for higher priority and no grant to lower priority although it's valid + -------------------------------------- + wait for 5*clk_period; + --report ">> TC55 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"FF000000", x"AA3333AA", "0100"); + wait for clk_period; -- Need for msto assignment + + + req_mst_idx <= 0; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A2000000", x"AA2222AA", "0100"); + wait for clk_period; -- Need for msto assignment + + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-551: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- +-- -- check led (hardcode check), can't check as led will output as '-' +-- wait for clk_period; +-- assert led = x"22" -- grant to m3 +-- report"E-551a: (wbicn) no led out" +-- severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-552: (wbicn, fn.msti_chk_all): invalid address, it should return false" + severity error; + -------------------------------------- + --report ">> TC55 ends <<"; + -------------------------------------- + -- + --E N D Test_case 55 + -- + ------------------------------------ + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + -------------------------------------- + -- Test_case 56: + -- single master write, valid address, inactive slave + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: no request for all msti + -- Expected error: Error, no address map + -------------------------------------- + wait for 5*clk_period; + --report ">> TC56 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 3; wait for clk_period; + + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"A4000000", x"AA5656AA", "0100"); + wait for clk_period; -- Need for msto assignment + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert not slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-560: (wbicn, fn.slvi_chk_all): inactive slave, it should return false" + severity error; + + -- Handshake-3: + -- +-- -- check led (hardcode check), can't check as led will output as '-' +-- wait for clk_period; +-- assert led1 = x"22" -- grant to m3 +-- report"E-561a: (wbicn) no led out" +-- severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert not msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-562: (wbicn, fn.msti_chk_all): inactive slave, it should return false" + severity error; + -------------------------------------- + --report ">> TC56 ends <<"; + -------------------------------------- + -- + --E N D Test_case 56 + -- + ------------------------------------ + + --/////////////////////////////////////////////////// + -- Quiet all masters + --/////////////////////////////////////////////////// + wait for 5*clk_period; + req_mst_idx <= 0; wait for clk_period; + msto <= (others=> wbm_out_none); + wait for clk_period; + --/////////////////////////////////////////////////// + + -------------------------------------- + -- Test_case 57: + -- mult master, same address request + -- Expected output, slvi: no request for all slvi + -- Expected output, msti: response to higher priority master + -- Expected error: no + -------------------------------------- + wait for 5*clk_period; + --report ">> TC57 starts <<"; + -------------------------------------- + -- Handshake-1: master requests (input for intercon) + wait for clk_period; + req_mst_idx <= 3; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"AE005733", x"AA3333AA", "0100"); + wait for clk_period; -- Need for msto assignment + + + req_mst_idx <= 2; wait for clk_period; + genmst_req(msto(req_mst_idx), req_mst_idx, '1', x"AE005722", x"AA2222AA", "0100"); + wait for clk_period; -- Need for msto assignment + + --------------------- + -- check slave & master + --------------------- + --list_all_mst_req(msto, mst_mask_vector); + + -- Handshake-2: + wait for clk_period; + assert slvi_chk_all(slvo, msto, slvi, mst_mask_vector) + report"E-571: (wbicn, fn.slvi_chk_all)" + severity error; + + -- Handshake-3: + -- + -- check led (hardcode check) + wait for clk_period; + assert led2 = x"33" -- grant to m3 + report"E-571a: (wbicn) no led out" + severity error; + + -- Handshake-4: Evaluate msti, granted master can get the read data from selected slave correctly + wait for clk_period; + assert msti_chk_all(msti, msto, slvo, mst_mask_vector) + report "E-572: (wbicn, fn.msti_chk_all)" + severity error; + -------------------------------------- + --report ">> TC57 ends <<"; + -------------------------------------- + -- + --E N D Test_case 57 + -- + ------------------------------------ + + wait for 5*clk_period; + + assert false report "Simulation End" severity failure; + end process; + +--************************************** +--/////////////////////////////////////////////////// +-- Quiet all masters +--/////////////////////////////////////////////////// +-- wait for 5*clk_period; +-- req_mst_idx <= 0; wait for clk_period; +-- msto <= (others=> wbm_out_none); +-- wait for clk_period; +--/////////////////////////////////////////////////// +-- -------------------------------------- +-- -- Test_case xx: +-- -- [test_case_template, desc] +-- -- Expected output, slvi: +-- -- Expected output, msti: +-- -- Expected error: +-- -------------------------------------- +-- wait for 5*clk_period; +-- --report ">> TCx starts <<"; +-- -------------------------------------- +-- +-- [put test code here] +-- -------------------------------------- +-- --report ">> TCx ends <<"; +-- -------------------------------------- +-- -- +-- --E N D Test_case xx +-- -- +-- -------------------------------------- + +END; diff --git a/soc/top/wb_intercon_wave.wcfg b/soc/top/wb_intercon_wave.wcfg new file mode 100644 index 0000000..25a1e19 --- /dev/null +++ b/soc/top/wb_intercon_wave.wcfg @@ -0,0 +1,1889 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + rst + rst + + + slv_mask_vector[0:15] + slv_mask_vector[0:15] + + + mst_mask_vector[0:3] + mst_mask_vector[0:3] + + + req_mst_idx + req_mst_idx + + + msto[3:0] + msto[3:0] + + [3] + msto[3] + + .adr + msto[3].adr + HEXRADIX + + + .dat + msto[3].dat + HEXRADIX + + + .we + msto[3].we + + + .sel + msto[3].sel + + + .stb + msto[3].stb + + + .cyc + msto[3].cyc + + + .wbcfg + msto[3].wbcfg + HEXRADIX + + + .wbidx + msto[3].wbidx + + + + [2] + msto[2] + + .adr + msto[2].adr + HEXRADIX + + + .dat + msto[2].dat + HEXRADIX + + + .we + msto[2].we + + + .sel + msto[2].sel + + + .stb + msto[2].stb + + + .cyc + msto[2].cyc + + + .wbcfg + msto[2].wbcfg + HEXRADIX + + + .wbidx + msto[2].wbidx + + + + [1] + msto[1] + + .adr + msto[1].adr + HEXRADIX + + + .dat + msto[1].dat + HEXRADIX + + + .we + msto[1].we + + + .sel + msto[1].sel + + + .stb + msto[1].stb + + + .cyc + msto[1].cyc + + + .wbcfg + msto[1].wbcfg + HEXRADIX + + + .wbidx + msto[1].wbidx + + + + [0] + msto[0] + + .adr + msto[0].adr + HEXRADIX + + + .dat + msto[0].dat + HEXRADIX + + + .we + msto[0].we + + + .sel + msto[0].sel + + + .stb + msto[0].stb + + + .cyc + msto[0].cyc + + + .wbcfg + msto[0].wbcfg + HEXRADIX + + + .wbidx + msto[0].wbidx + + + + + slvo[15:0] + slvo[15:0] + + [15] + slvo[15] + + .dat + slvo[15].dat + HEXRADIX + + + .ack + slvo[15].ack + + + .wbcfg + slvo[15].wbcfg + HEXRADIX + + + .wbidx + slvo[15].wbidx + + + + [14] + slvo[14] + + .dat + slvo[14].dat + HEXRADIX + + + .ack + slvo[14].ack + + + .wbcfg + slvo[14].wbcfg + HEXRADIX + + + .wbidx + slvo[14].wbidx + + + + [13] + slvo[13] + + .dat + slvo[13].dat + HEXRADIX + + + .ack + slvo[13].ack + + + .wbcfg + slvo[13].wbcfg + HEXRADIX + + + .wbidx + slvo[13].wbidx + + + + [12] + slvo[12] + + .dat + slvo[12].dat + HEXRADIX + + + .ack + slvo[12].ack + + + .wbcfg + slvo[12].wbcfg + HEXRADIX + + + .wbidx + slvo[12].wbidx + + + + [11] + slvo[11] + + .dat + slvo[11].dat + HEXRADIX + + + .ack + slvo[11].ack + + + .wbcfg + slvo[11].wbcfg + HEXRADIX + + + .wbidx + slvo[11].wbidx + + + + [10] + slvo[10] + + .dat + slvo[10].dat + HEXRADIX + + + .ack + slvo[10].ack + + + .wbcfg + slvo[10].wbcfg + HEXRADIX + + + .wbidx + slvo[10].wbidx + + + + [9] + slvo[9] + + .dat + slvo[9].dat + HEXRADIX + + + .ack + slvo[9].ack + + + .wbcfg + slvo[9].wbcfg + HEXRADIX + + + .wbidx + slvo[9].wbidx + + + + [8] + slvo[8] + + .dat + slvo[8].dat + HEXRADIX + + + .ack + slvo[8].ack + + + .wbcfg + slvo[8].wbcfg + HEXRADIX + + + .wbidx + slvo[8].wbidx + + + + [7] + slvo[7] + + .dat + slvo[7].dat + HEXRADIX + + + .ack + slvo[7].ack + + + .wbcfg + slvo[7].wbcfg + HEXRADIX + + + .wbidx + slvo[7].wbidx + + + + [6] + slvo[6] + + .dat + slvo[6].dat + HEXRADIX + + + .ack + slvo[6].ack + + + .wbcfg + slvo[6].wbcfg + HEXRADIX + + + .wbidx + slvo[6].wbidx + + + + [5] + slvo[5] + + .dat + slvo[5].dat + HEXRADIX + + + .ack + slvo[5].ack + + + .wbcfg + slvo[5].wbcfg + HEXRADIX + + + .wbidx + slvo[5].wbidx + + + + [4] + slvo[4] + + .dat + slvo[4].dat + HEXRADIX + + + .ack + slvo[4].ack + + + .wbcfg + slvo[4].wbcfg + HEXRADIX + + + .wbidx + slvo[4].wbidx + + + + [3] + slvo[3] + + .dat + slvo[3].dat + HEXRADIX + + + .ack + slvo[3].ack + + + .wbcfg + slvo[3].wbcfg + HEXRADIX + + + .wbidx + slvo[3].wbidx + + + + [2] + slvo[2] + + .dat + slvo[2].dat + HEXRADIX + + + .ack + slvo[2].ack + + + .wbcfg + slvo[2].wbcfg + HEXRADIX + + + .wbidx + slvo[2].wbidx + + + + [1] + slvo[1] + + .dat + slvo[1].dat + HEXRADIX + + + .ack + slvo[1].ack + + + .wbcfg + slvo[1].wbcfg + HEXRADIX + + + .wbidx + slvo[1].wbidx + + + + [0] + slvo[0] + + .dat + slvo[0].dat + HEXRADIX + + + .ack + slvo[0].ack + + + .wbcfg + slvo[0].wbcfg + HEXRADIX + + + .wbidx + slvo[0].wbidx + + + + + gmst / ssel + label + 128 128 255 + 230 230 230 + + + tmpmsto[3:0] + tmpmsto[3:0] + + [3] + tmpmsto[3] + + .adr + tmpmsto[3].adr + HEXRADIX + + + .dat + tmpmsto[3].dat + HEXRADIX + + + .we + tmpmsto[3].we + + + .sel + tmpmsto[3].sel + + + .stb + tmpmsto[3].stb + + + .cyc + tmpmsto[3].cyc + + + .wbcfg + tmpmsto[3].wbcfg + + + .wbidx + tmpmsto[3].wbidx + + + + [2] + tmpmsto[2] + + .adr + tmpmsto[2].adr + HEXRADIX + + + .dat + tmpmsto[2].dat + HEXRADIX + + + .we + tmpmsto[2].we + + + .sel + tmpmsto[2].sel + + + .stb + tmpmsto[2].stb + + + .cyc + tmpmsto[2].cyc + + + .wbcfg + tmpmsto[2].wbcfg + + + .wbidx + tmpmsto[2].wbidx + + + + [1] + tmpmsto[1] + + .adr + tmpmsto[1].adr + + + .dat + tmpmsto[1].dat + HEXRADIX + + + .we + tmpmsto[1].we + + + .sel + tmpmsto[1].sel + + + .stb + tmpmsto[1].stb + + + .cyc + tmpmsto[1].cyc + + + .wbcfg + tmpmsto[1].wbcfg + + + .wbidx + tmpmsto[1].wbidx + + + + [0] + tmpmsto[0] + + .adr + tmpmsto[0].adr + HEXRADIX + + + .dat + tmpmsto[0].dat + HEXRADIX + + + .we + tmpmsto[0].we + + + .sel + tmpmsto[0].sel + + + .stb + tmpmsto[0].stb + + + .cyc + tmpmsto[0].cyc + + + .wbcfg + tmpmsto[0].wbcfg + + + .wbidx + tmpmsto[0].wbidx + + + + + tmpslvo[15:0] + tmpslvo[15:0] + + [15] + tmpslvo[15] + + .dat + tmpslvo[15].dat + HEXRADIX + + + .ack + tmpslvo[15].ack + + + .wbcfg + tmpslvo[15].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[15].wbidx + + + + [14] + tmpslvo[14] + + .dat + tmpslvo[14].dat + HEXRADIX + + + .ack + tmpslvo[14].ack + + + .wbcfg + tmpslvo[14].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[14].wbidx + + + + [13] + tmpslvo[13] + + .dat + tmpslvo[13].dat + HEXRADIX + + + .ack + tmpslvo[13].ack + + + .wbcfg + tmpslvo[13].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[13].wbidx + + + + [12] + tmpslvo[12] + + .dat + tmpslvo[12].dat + HEXRADIX + + + .ack + tmpslvo[12].ack + + + .wbcfg + tmpslvo[12].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[12].wbidx + + + + [11] + tmpslvo[11] + + .dat + tmpslvo[11].dat + HEXRADIX + + + .ack + tmpslvo[11].ack + + + .wbcfg + tmpslvo[11].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[11].wbidx + + + + [10] + tmpslvo[10] + + .dat + tmpslvo[10].dat + HEXRADIX + + + .ack + tmpslvo[10].ack + + + .wbcfg + tmpslvo[10].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[10].wbidx + + + + [9] + tmpslvo[9] + + .dat + tmpslvo[9].dat + HEXRADIX + + + .ack + tmpslvo[9].ack + + + .wbcfg + tmpslvo[9].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[9].wbidx + + + + [8] + tmpslvo[8] + + .dat + tmpslvo[8].dat + HEXRADIX + + + .ack + tmpslvo[8].ack + + + .wbcfg + tmpslvo[8].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[8].wbidx + + + + [7] + tmpslvo[7] + + .dat + tmpslvo[7].dat + HEXRADIX + + + .ack + tmpslvo[7].ack + + + .wbcfg + tmpslvo[7].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[7].wbidx + + + + [6] + tmpslvo[6] + + .dat + tmpslvo[6].dat + HEXRADIX + + + .ack + tmpslvo[6].ack + + + .wbcfg + tmpslvo[6].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[6].wbidx + + + + [5] + tmpslvo[5] + + .dat + tmpslvo[5].dat + HEXRADIX + + + .ack + tmpslvo[5].ack + + + .wbcfg + tmpslvo[5].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[5].wbidx + + + + [4] + tmpslvo[4] + + .dat + tmpslvo[4].dat + HEXRADIX + + + .ack + tmpslvo[4].ack + + + .wbcfg + tmpslvo[4].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[4].wbidx + + + + [3] + tmpslvo[3] + + .dat + tmpslvo[3].dat + HEXRADIX + + + .ack + tmpslvo[3].ack + + + .wbcfg + tmpslvo[3].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[3].wbidx + + + + [2] + tmpslvo[2] + + .dat + tmpslvo[2].dat + HEXRADIX + + + .ack + tmpslvo[2].ack + + + .wbcfg + tmpslvo[2].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[2].wbidx + + + + [1] + tmpslvo[1] + + .dat + tmpslvo[1].dat + HEXRADIX + + + .ack + tmpslvo[1].ack + + + .wbcfg + tmpslvo[1].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[1].wbidx + + + + [0] + tmpslvo[0] + + .dat + tmpslvo[0].dat + HEXRADIX + + + .ack + tmpslvo[0].ack + + + .wbcfg + tmpslvo[0].wbcfg + HEXRADIX + + + .wbidx + tmpslvo[0].wbidx + + + + + O u t p u t + label + 128 128 255 + 230 230 230 + + + led1[7:0] + led1[7:0] + + + led[7:0] + led[7:0] + + + msti[3:0] + msti[3:0] + + [3] + msti[3] + + .dat + msti[3].dat + HEXRADIX + + + .ack + msti[3].ack + + + + [2] + msti[2] + + + [1] + msti[1] + + + [0] + msti[0] + + + + slvi[15:0] + slvi[15:0] + + [15] + slvi[15] + + .adr + slvi[15].adr + HEXRADIX + + + .dat + slvi[15].dat + HEXRADIX + + + .we + slvi[15].we + + + .sel + slvi[15].sel + + + .stb + slvi[15].stb + + + .cyc + slvi[15].cyc + + + + [14] + slvi[14] + + .adr + slvi[14].adr + HEXRADIX + + + .dat + slvi[14].dat + HEXRADIX + + + .we + slvi[14].we + + + .sel + slvi[14].sel + + + .stb + slvi[14].stb + + + .cyc + slvi[14].cyc + + + + [13] + slvi[13] + + .adr + slvi[13].adr + HEXRADIX + + + .dat + slvi[13].dat + HEXRADIX + + + .we + slvi[13].we + + + .sel + slvi[13].sel + + + .stb + slvi[13].stb + + + .cyc + slvi[13].cyc + + + + [12] + slvi[12] + + .adr + slvi[12].adr + HEXRADIX + + + .dat + slvi[12].dat + HEXRADIX + + + .we + slvi[12].we + + + .sel + slvi[12].sel + + + .stb + slvi[12].stb + + + .cyc + slvi[12].cyc + + + + [11] + slvi[11] + + .adr + slvi[11].adr + HEXRADIX + + + .dat + slvi[11].dat + HEXRADIX + + + .we + slvi[11].we + + + .sel + slvi[11].sel + + + .stb + slvi[11].stb + + + .cyc + slvi[11].cyc + + + + [10] + slvi[10] + + .adr + slvi[10].adr + HEXRADIX + + + .dat + slvi[10].dat + HEXRADIX + + + .we + slvi[10].we + + + .sel + slvi[10].sel + + + .stb + slvi[10].stb + + + .cyc + slvi[10].cyc + + + + [9] + slvi[9] + + .adr + slvi[9].adr + HEXRADIX + + + .dat + slvi[9].dat + HEXRADIX + + + .we + slvi[9].we + + + .sel + slvi[9].sel + + + .stb + slvi[9].stb + + + .cyc + slvi[9].cyc + + + + [8] + slvi[8] + + .adr + slvi[8].adr + HEXRADIX + + + .dat + slvi[8].dat + HEXRADIX + + + .we + slvi[8].we + + + .sel + slvi[8].sel + + + .stb + slvi[8].stb + + + .cyc + slvi[8].cyc + + + + [7] + slvi[7] + + .adr + slvi[7].adr + HEXRADIX + + + .dat + slvi[7].dat + HEXRADIX + + + .we + slvi[7].we + + + .sel + slvi[7].sel + + + .stb + slvi[7].stb + + + .cyc + slvi[7].cyc + + + + [6] + slvi[6] + + .adr + slvi[6].adr + HEXRADIX + + + .dat + slvi[6].dat + HEXRADIX + + + .we + slvi[6].we + + + .sel + slvi[6].sel + + + .stb + slvi[6].stb + + + .cyc + slvi[6].cyc + + + + [5] + slvi[5] + + .adr + slvi[5].adr + HEXRADIX + + + .dat + slvi[5].dat + HEXRADIX + + + .we + slvi[5].we + + + .sel + slvi[5].sel + + + .stb + slvi[5].stb + + + .cyc + slvi[5].cyc + + + + [4] + slvi[4] + + .adr + slvi[4].adr + HEXRADIX + + + .dat + slvi[4].dat + HEXRADIX + + + .we + slvi[4].we + + + .sel + slvi[4].sel + + + .stb + slvi[4].stb + + + .cyc + slvi[4].cyc + + + + [3] + slvi[3] + + .adr + slvi[3].adr + HEXRADIX + + + .dat + slvi[3].dat + HEXRADIX + + + .we + slvi[3].we + + + .sel + slvi[3].sel + + + .stb + slvi[3].stb + + + .cyc + slvi[3].cyc + + + + [2] + slvi[2] + + .adr + slvi[2].adr + HEXRADIX + + + .dat + slvi[2].dat + HEXRADIX + + + .we + slvi[2].we + + + .sel + slvi[2].sel + + + .stb + slvi[2].stb + + + .cyc + slvi[2].cyc + + + + [1] + slvi[1] + + .adr + slvi[1].adr + HEXRADIX + + + .dat + slvi[1].dat + HEXRADIX + + + .we + slvi[1].we + + + .sel + slvi[1].sel + + + .stb + slvi[1].stb + + + .cyc + slvi[1].cyc + + + + [0] + slvi[0] + + .adr + slvi[0].adr + HEXRADIX + + + .dat + slvi[0].dat + HEXRADIX + + + .we + slvi[0].we + + + .sel + slvi[0].sel + + + .stb + slvi[0].stb + + + .cyc + slvi[0].cyc + + + + + Reg + label + 128 128 255 + 230 230 230 + + + mgnt_idx + mgnt_idx + + + mgnt[0:3] + mgnt[0:3] + + + ssel_idx + ssel_idx + + + ssel[0:15] + ssel[0:15] + + + slv_test_rd + label + 128 128 255 + 230 230 230 + + + s_test_rd_0 + label + + slvi + slvi + + + slvo + slvo + + + test_rddat[31:0] + test_rddat[31:0] + HEXRADIX + + + state + state + + + wbslvo + wbslvo + + .dat + wbslvo.dat + HEXRADIX + + + .ack + wbslvo.ack + + + .wbcfg + wbslvo.wbcfg + HEXRADIX + + + .wbidx + wbslvo.wbidx + + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + + s_test_rd_1 + label + + slvi + slvi + + + slvo + slvo + + + test_rddat[31:0] + test_rddat[31:0] + + + state + state + + + wbslvo + wbslvo + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + + s_test_rd05 + label + + clk + clk + + + rst + rst + + + slvi + slvi + + .adr + slvi.adr + HEXRADIX + + + .dat + slvi.dat + + + .we + slvi.we + + + .sel + slvi.sel + + + .stb + slvi.stb + + + .cyc + slvi.cyc + + + + slvo + slvo + + + test_rddat[31:0] + test_rddat[31:0] + HEXRADIX + + + state + state + + + wbslvo + wbslvo + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + + s_test_rd15 + label + + slvi + slvi + + .adr + slvi.adr + HEXRADIX + + + .dat + slvi.dat + HEXRADIX + + + .we + slvi.we + + + .sel + slvi.sel + + + .stb + slvi.stb + + + .cyc + slvi.cyc + + + + slvo + slvo + + .dat + slvo.dat + HEXRADIX + + + .ack + slvo.ack + + + .wbcfg + slvo.wbcfg + HEXRADIX + + + .wbidx + slvo.wbidx + + + + test_rddat[31:0] + test_rddat[31:0] + HEXRADIX + + + state + state + + + wbslvo + wbslvo + + + memaddr + memaddr + + + addrmask + addrmask + + + wbidx + wbidx + + + + slv_test_wr + label + 128 128 255 + 230 230 230 + + + s_test_wr_0 + label + + + s_test_wr_1 + label + + diff --git a/soc/top/wb_stestrd.vhd b/soc/top/wb_stestrd.vhd new file mode 100644 index 0000000..f8288be --- /dev/null +++ b/soc/top/wb_stestrd.vhd @@ -0,0 +1,80 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use IEEE.math_real.all; +use ieee.std_logic_arith.all; + +library work; +use work.wishbone.all; +use work.config.all; + +entity wb_stestrd is + generic( + memaddr : generic_addr_type := 0; + addrmask : generic_mask_type := 16#3fffff#; + wbidx: integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + test_rddat : in std_logic_vector(31 downto 0) + ); +end entity wb_stestrd; + +architecture RTL of wb_stestrd is + type STATE_TYPE IS (IDLE, RDREQ); + signal state: STATE_TYPE; + signal wbslvo : wb_slv_out_type;-- := wbs_out_none; + +begin + + nxts: process(clk, rst) + begin + if rst = '1' then + state <= IDLE; + elsif(rising_edge(clk)) then + if slvi.cyc='1' and slvi.stb='1' and slvi.we = '0' then -- need to check cyc ? + state <= RDREQ; + else + state <= IDLE; + end if; + end if; + + end process; + --************************************** + ocl: process(state) + begin + --wbslvo.wbcfg <= wb_membar(memaddr, addrmask); + --wbslvo.wbidx <= wbidx; + + ----if (state=RDREQ and slvi.we = '0' and slvi.stb='1') then + if (state=RDREQ) then + wbslvo.dat <= test_rddat; -- test_data + wbslvo.ack <= '1'; + --wbslvo.tagn <= ; + --wbslvo.stall<= ; + --wbslvo.err <= ; + --wbslvo.rty <= ; + --wbslvo.wbcfg <= wb_membar(memaddr, addrmask); + --wbslvo.wbidx <= wbidx; + else + wbslvo <= wbs_out_none; + end if; + end process; + + --slvo <= wbslvo; + + slvo.dat <= wbslvo.dat; + slvo.ack <= wbslvo.ack; +-- slvo.tagn <= wbslvo.tagn; +-- slvo.stall <= wbslvo.stall; +-- slvo.err <= wbslvo.err; +-- slvo.rty <= wbslvo.rty; + +-- wbcfg and wbidx should be assigned directly otw will be delay + slvo.wbcfg <= wb_membar(memaddr, addrmask); + +end architecture RTL; diff --git a/soc/top/wb_stestwr.vhd b/soc/top/wb_stestwr.vhd new file mode 100644 index 0000000..4d5177d --- /dev/null +++ b/soc/top/wb_stestwr.vhd @@ -0,0 +1,84 @@ +-- See the file "LICENSE" for the full license governing this code. -- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use IEEE.math_real.all; +use ieee.std_logic_arith.all; + +library work; +use work.wishbone.all; +use work.config.all; + +entity wb_stestwr is + generic( + memaddr :generic_addr_type :=0; + addrmask :generic_mask_type :=16#3fffff#; + wbidx :integer := 0 + ); + port( + clk : in std_logic; + rst : in std_logic; + slvi : in wb_slv_in_type; + slvo : out wb_slv_out_type; + led : out std_logic_vector (7 downto 0) + ); +end entity wb_stestwr; + +architecture RTL of wb_stestwr is + type STATE_TYPE IS (IDLE, WRREQ); + signal state: STATE_TYPE; + signal wbslvo : wb_slv_out_type;-- := wbs_out_none; + +begin + + nxts: process(clk, rst) + begin + if rst = '1' then + state <= IDLE; + elsif(rising_edge(clk)) then + if slvi.cyc='1' and slvi.stb='1' and slvi.we = '1' then + state <= WRREQ; + else + state <= IDLE; + end if; + end if; + + end process; + --************************************** + ocl: process(state) + begin + ----if (state=WRREQ and slvi.we = '1' and slvi.stb='1') then + if (state=WRREQ) then + wbslvo.dat <= slvi.dat; + wbslvo.ack <= '1'; + --wbslvo.tagn <= ; + --wbslvo.stall<= ; + --wbslvo.err <= ; + --wbslvo.rty <= ; + --wbslvo.wbcfg <= wb_membar(memaddr, addrmask); + --wbslvo.wbidx <= wbidx; + else + wbslvo <= wbs_out_none; + end if; + end process; + + --slvo <= wbslvo; + slvo.dat <= wbslvo.dat; + slvo.ack <= wbslvo.ack; +-- slvo.tagn <= wbslvo.tagn; +-- slvo.stall <= wbslvo.stall; +-- slvo.err <= wbslvo.err; +-- slvo.rty <= wbslvo.rty; + +-- wbcfg and wbidx should be assigned directly otw will be delay + slvo.wbcfg <= wb_membar(memaddr, addrmask); + + --led <= wbslvo.dat( 7 downto 0); + -- big/ little endian ?? (suppose to handle in wb_intercon) !! + led <= wbslvo.dat( 7 downto 0) when slvi.sel(0) = '1' else + wbslvo.dat(15 downto 8) when slvi.sel(1) = '1' else + wbslvo.dat(23 downto 16) when slvi.sel(2) = '1' else + wbslvo.dat(31 downto 24) when slvi.sel(3) = '1' else + wbslvo.dat( 7 downto 0); + +end architecture RTL; diff --git a/soc/util/utils.vhd b/soc/util/utils.vhd new file mode 100644 index 0000000..817b95c --- /dev/null +++ b/soc/util/utils.vhd @@ -0,0 +1,14 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +package lt16soc_utils is + + --insert utility component and function declarations + +end lt16soc_utils; + +package body lt16soc_utils is + + --insert utility function bodies + +end lt16soc_utils; + diff --git a/warmup1.pdf b/warmup1.pdf new file mode 100644 index 0000000..ba0f0d5 Binary files /dev/null and b/warmup1.pdf differ diff --git a/warmup2.pdf b/warmup2.pdf new file mode 100644 index 0000000..8ebc7bc Binary files /dev/null and b/warmup2.pdf differ diff --git a/warmup3.pdf b/warmup3.pdf new file mode 100644 index 0000000..fbfcfba Binary files /dev/null and b/warmup3.pdf differ diff --git a/warmup4.pdf b/warmup4.pdf new file mode 100644 index 0000000..276d319 Binary files /dev/null and b/warmup4.pdf differ