This commit is contained in:
Daniel Torres 2022-07-22 11:16:09 -07:00
commit 0e75142ef4
61 changed files with 3844 additions and 1437 deletions

4
.gitignore vendored
View file

@ -7,12 +7,8 @@ __pycache__/
.vscode/
#External repos
addins
addins/riscv-arch-test/Makefile.include
addins/riscv-tests/target
addins/coremark/work/*
addins/embench/bd_speed/*
addins/embench/bd_size/*
benchmarks/embench/wally*.json
#vsim work files to ignore

1
.gitmodules vendored
View file

@ -17,6 +17,7 @@
[submodule "addins/embench-iot"]
path = addins/embench-iot
url = https://github.com/embench/embench-iot
branch = embench-1.0-branch
[submodule "addins/coremark"]
path = addins/coremark
url = https://github.com/eembc/coremark

View file

@ -1,6 +1,8 @@
# Wally Coremark Makefile
# Daniel Torres & David Harris 28 July 2022
PORT_DIR = $(CURDIR)/riscv64-baremetal
cmbase=../../addins/coremark
# cmbase= ../riscv-coremark/coremark
work_dir= ../../benchmarks/coremark/work
XLEN ?=64
sources=$(cmbase)/core_main.c $(cmbase)/core_list_join.c $(cmbase)/coremark.h \
@ -9,22 +11,12 @@ sources=$(cmbase)/core_main.c $(cmbase)/core_list_join.c $(cmbase)/coremark.h \
$(PORT_DIR)/crt.S $(PORT_DIR)/encoding.h $(PORT_DIR)/util.h $(PORT_DIR)/syscalls.c
ABI := $(if $(findstring "64","$(XLEN)"),lp64,ilp32)
ARCH := rv$(XLEN)im
PORT_CFLAGS = -g -march=rv$(XLEN)im -mabi=$(ABI) -march=$(ARCH) -static -falign-functions=16 \
-mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-3-series -O3 -funroll-all-loops -finline-functions -falign-jumps=4 \
PORT_CFLAGS = -g -mabi=$(ABI) -march=$(ARCH) -static -falign-functions=16 \
-mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-3-series -O3 -finline-functions -falign-jumps=4 \
-fno-delete-null-pointer-checks -fno-rename-registers --param=loop-max-datarefs-for-datadeps=0 \
-funroll-all-loops --param=uninlined-function-insns=8 -fno-tree-vrp -fwrapv -fipa-pta \
-nostdlib -nostartfiles -ffreestanding -mstrict-align \
-DTOTAL_DATA_SIZE=2000 -DMAIN_HAS_NOARGC=1 -DPERFORMANCE_RUN=1 -DXLEN=$(XLEN)
# flags that cause build errors mcmodel=medlow
# -static -mcmodel=medlow -mtune=sifive-7-series \
# -O3 -falign-functions=16 -funroll-all-loops -mbranch-cost=1 -DSKIP_DEFAULT_MEMSET
# -finline-functions -falign-jumps=4 \
# -nostdlib -nostartfiles -ffreestanding -mstrict-align \
# -DTOTAL_DATA_SIZE=2000 -DMAIN_HAS_NOARGC=1 \
# -DPERFORMANCE_RUN=1
# "-march=rv$(XLEN)im -mabi=$(ABI) -mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-7-series -Ofast -funroll-all-loops -fno-delete-null-pointer-checks -fno-rename-registers --param=loop-max-datarefs-for-datadeps=0 -funroll-all-loops --param=uninlined-function-insns=8 -fno-tree-vrp -fwrapv -fipa-pta "
-DTOTAL_DATA_SIZE=2000 -DMAIN_HAS_NOARGC=1 -DPERFORMANCE_RUN=1 -DITERATIONS=10 -DXLEN=$(XLEN)
all: $(work_dir)/coremark.bare.riscv.elf.memfile
@ -38,9 +30,7 @@ $(work_dir)/coremark.bare.riscv.elf.memfile: $(work_dir)/coremark.bare.riscv
extractFunctionRadix.sh $<.elf.objdump
$(work_dir)/coremark.bare.riscv: $(sources) Makefile
# These flags were used by WD on CoreMark
make -C $(cmbase) PORT_DIR=$(PORT_DIR) compile RISCV=$(RISCV)/riscv-gnu-toolchain XCFLAGS="$(PORT_CFLAGS)"
# -fno-toplevel-reorder --param=max-inline-insns-size=128 " # adding this bit caused a compiler error
mkdir -p $(work_dir)
mv $(cmbase)/coremark.bare.riscv $(work_dir)
@ -50,14 +40,3 @@ clean:
rm -f $(work_dir)/*
# # PORT_CFLAGS = -g -march=$(XLEN)im -mabi=$(ABI) -static -mcmodel=medlow -mtune=sifive-3-series \
# # -O3 -falign-functions=16 -funroll-all-loops \
# # -finline-functions -falign-jumps=4 \
# # -nostdlib -nostartfiles -ffreestanding -mstrict-align \
# # -DTOTAL_DATA_SIZE=2000 -DMAIN_HAS_NOARGC=1 \
# # -DPERFORMANCE_RUN=1
# make -C $(cmbase) PORT_DIR=$(PORT_DIR) compile RISCV=$(RISCV)/riscv-gnu-toolchain XCFLAGS="-march=rv$(XLEN)im -mabi=$(ABI) -mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-7-series -Ofast -funroll-all-loops -fno-delete-null-pointer-checks -fno-rename-registers --param=loop-max-datarefs-for-datadeps=0 -funroll-all-loops --param=uninlined-function-insns=8 -fno-tree-vrp -fwrapv -fipa-pta "
# make -C $(cmbase) PORT_DIR=$(PORT_DIR) compile RISCV=/opt/riscv/riscv-gnu-toolchain XCFLAGS="-march=rv64imd -mabi=lp64d -mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-7-series -Ofast -funroll-all-loops -fno-delete-null-pointer-checks -fno-rename-registers --param=loop-max-datarefs-for-datadeps=0 -funroll-all-loops --param=uninlined-function-insns=8 -fno-tree-vrp -fwrapv -fno-toplevel-reorder --param=max-inline-insns-size=128 -fipa-pta"
# make -C $(cmbase) PORT_DIR=$(PORT_DIR) compile RISCV=$(RISCV)/riscv-gnu-toolchain XCFLAGS="-march=rv64imd -mabi=lp64d -mbranch-cost=1 -DSKIP_DEFAULT_MEMSET -mtune=sifive-7-series -Ofast -funroll-all-loops -fno-delete-null-pointer-checks -fno-rename-registers --param=loop-max-datarefs-for-datadeps=0 -funroll-all-loops --param=uninlined-function-insns=8 -fno-tree-vrp -fwrapv -fipa-pta "

View file

@ -114,7 +114,12 @@ void portable_free(void *p) {
#define read_csr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define GETMYTIME(_t) (_t = *(volatile unsigned long long*)0x0200BFF8)
// #if (XLEN==64)
// typedef unsigned long long ee_ptr_int;
// #else
// typedef unsigned long ee_ptr_int;
// #endif
#define GETMYTIME(_t) (_t = *(volatile ee_ptr_int*)0x0200BFF8)
#define MYTIMEDIFF(fin,ini) ((fin)-(ini))
// Changing TIMER_RES_DIVIDER to 1000000 sets EE_TICKS_PER_SEC to 1000 (now counting ticks per ms)
#define TIMER_RES_DIVIDER 10000
@ -196,8 +201,8 @@ void stop_time(void) {
CORE_TICKS get_time(void) {
CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val));
unsigned long instructions = minstretDiff();
long long cm100 = 1000000000 / elapsed; // coremark score * 100
long long cpi100 = elapsed*100/instructions; // CPI * 100
ee_ptr_int cm100 = 1000000000 / elapsed; // coremark score * 100
ee_ptr_int cpi100 = elapsed*100/instructions; // CPI * 100
ee_printf(" WALLY CoreMark Results (from get_time)\n");
ee_printf(" Elapsed MTIME: %u\n", elapsed);
ee_printf(" Elapsed MINSTRET: %lu\n", instructions);

View file

@ -69,14 +69,16 @@ typedef clock_t CORE_TICKS;
// #elif (XLEN==32)
// #include <sys/types.h>
// typedef ee_u32 CORE_TICKS;
#else
/* Configuration: size_t and clock_t
Note these need to match the size of the clock output and the xLen the processor supports
*/
#elif (XLEN==64)
typedef unsigned long int size_t;
typedef unsigned long int clock_t;
typedef clock_t CORE_TICKS;
#else
#include <sys/types.h>
#endif
typedef clock_t CORE_TICKS;
/* Definitions: COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION
Initialize these strings per platform
@ -92,7 +94,7 @@ typedef clock_t CORE_TICKS;
#define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */
#endif
#ifndef MEM_LOCATION
#define MEM_LOCATION "Please put data memory location here\n\t\t\t(e.g. code in flash, data on heap etc)"
#define MEM_LOCATION "Code and Data in external RAM"
#define MEM_LOCATION_UNSPEC 1
#endif

View file

@ -4,7 +4,8 @@
embench_dir = ../../addins/embench-iot
all: build sim size
all: build
run: size sim
allClean: clean all

View file

@ -101,7 +101,7 @@
`define CORRSHIFTSZ ((`DIVRESLEN+`NF) > (3*`NF+8) ? (`DIVRESLEN+`NF) : (3*`NF+6))
// division constants
`define RADIX 32'h2
`define RADIX 32'h4
`define DIVCOPIES 32'h1
`define DIVLEN ((`NF < `XLEN) ? (`XLEN) : (`NF + 3))
`define EXTRAFRACBITS ((`NF<(`XLEN)) ? (`XLEN - `NF) : 3)

View file

@ -1 +1 @@
vsim -c -do "do wally-pipelined-batch.do rv32gc wally32d"
vsim -c -do "do wally-pipelined-batch.do rv32gc wally32periph"

View file

@ -33,7 +33,7 @@ add wave -group {Divide} -group inter0 -noupdate /testbenchfp/divsqrt/srt/intera
# add wave -group {Divide} -group inter0 -noupdate /testbenchfp/divsqrt/srt/interations[0]/divinteration/otfc/otfc2/*
# add wave -group {Divide} -group inter0 -noupdate /testbenchfp/divsqrt/srt/interations[0]/divinteration/qsel/qsel2/*
add wave -group {Divide} -noupdate /testbenchfp/divsqrt/srtpreproc/*
add wave -group {Divide} -noupdate /testbenchfp/divsqrt/srt/expcalc/*
# add wave -group {Divide} -noupdate /testbenchfp/divsqrt/srt/expcalc/*
add wave -group {Divide} -noupdate /testbenchfp/divsqrt/srtfsm/*
add wave -group {Testbench} -noupdate /testbenchfp/*
add wave -group {Testbench} -noupdate /testbenchfp/readvectors/*

View file

@ -60,10 +60,11 @@ module cvtshiftcalc(
// - otherwise:
// | LzcInM | 0's if nessisary |
// change to int shift to the left one
assign CvtShiftIn = ToInt ? {{`XLEN{1'b0}}, Xm[`NF]&~CvtCe[`NE], Xm[`NF-1]|(CvtCe[`NE]&Xm[`NF]), Xm[`NF-2:0], {`CVTLEN-`XLEN{1'b0}}} :
CvtResDenormUf ? {{`NF-1{1'b0}}, Xm, {`CVTLEN-`NF+1{1'b0}}} :
{CvtLzcIn, {`NF+1{1'b0}}};
always_comb
if (ToInt) CvtShiftIn = {{`XLEN{1'b0}}, Xm[`NF]&~CvtCe[`NE], Xm[`NF-1]|(CvtCe[`NE]&Xm[`NF]), Xm[`NF-2:0], {`CVTLEN-`XLEN{1'b0}}};
else if (CvtResDenormUf) CvtShiftIn = {{`NF-1{1'b0}}, Xm, {`CVTLEN-`NF+1{1'b0}}};
else CvtShiftIn = {CvtLzcIn, {`NF+1{1'b0}}};
// choose the negative of the fraction size
if (`FPSIZES == 1) begin

View file

@ -34,20 +34,21 @@ module divsqrt(
input logic clk,
input logic reset,
input logic [`FMTBITS-1:0] FmtE,
input logic [`NF:0] XManE, YManE,
input logic [`NE-1:0] XExpE, YExpE,
input logic [`NF:0] XmE, YmE,
input logic [`NE-1:0] XeE, YeE,
input logic XInfE, YInfE,
input logic XZeroE, YZeroE,
input logic XNaNE, YNaNE,
input logic DivStartE,
input logic StallM,
input logic StallE,
output logic DivStickyM,
input logic StallE,
input logic SqrtE, SqrtM,
output logic DivSM,
output logic DivBusy,
output logic DivDone,
output logic [`NE+1:0] DivCalcExpM,
output logic [`NE+1:0] QeM,
output logic [`DURLEN-1:0] EarlyTermShiftM,
output logic [`QLEN-1-(`RADIX/4):0] QuotM
output logic [`QLEN-1-(`RADIX/4):0] QmM
// output logic [`XLEN-1:0] RemM,
);
@ -55,15 +56,15 @@ module divsqrt(
logic [`DIVLEN+3:0] WS, WC;
logic [`DIVLEN+3:0] StickyWSA;
logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt;
logic [`DIVLEN-1:0] X;
logic [`DIVLEN-1:0] Dpreproc;
logic [`DIVLEN+3:0] X;
logic [`DIVLEN+3:0] Dpreproc;
logic [`DURLEN-1:0] Dur;
logic NegSticky;
srtpreproc srtpreproc(.Xm(XManE), .Dur, .Ym(YManE), .X,.Dpreproc, .XZeroCnt, .YZeroCnt);
srtpreproc srtpreproc(.clk, .DivStart(DivStartE), .Xm(XmE), .QeM, .Xe(XeE), .Fmt(FmtE), .Ye(YeE), .Sqrt(SqrtE), .Dur, .Ym(YmE), .XZero(XZeroE), .X, .Dpreproc, .XZeroCnt, .YZeroCnt);
srtfsm srtfsm(.reset, .NextWSN, .NextWCN, .WS, .WC, .Dur, .DivBusy, .clk, .DivStart(DivStartE),.StallE, .StallM, .DivDone, .XZeroE, .YZeroE, .DivStickyE(DivStickyM), .XNaNE, .YNaNE,
srtfsm srtfsm(.reset, .NextWSN, .NextWCN, .WS, .WC, .Dur, .DivBusy, .clk, .DivStart(DivStartE),.StallE, .StallM, .DivDone, .XZeroE, .YZeroE, .DivSE(DivSM), .XNaNE, .YNaNE,
.StickyWSA, .XInfE, .YInfE, .NegSticky(NegSticky), .EarlyTermShiftE(EarlyTermShiftM));
srt srt(.clk, .FmtE, .X,.Dpreproc, .NegSticky, .XZeroCnt, .YZeroCnt, .FirstWS(WS), .FirstWC(WC), .NextWSN, .NextWCN, .DivStart(DivStartE), .Xe(XExpE), .Ye(YExpE), .XZeroE, .YZeroE,
.StickyWSA, .DivBusy, .Quot(QuotM), .Rem(), .DivCalcExpM);
srt srt(.clk, .Sqrt(SqrtM), .X,.Dpreproc, .NegSticky, .XZeroCnt, .YZeroCnt, .FirstWS(WS), .FirstWC(WC), .NextWSN, .NextWCN, .DivStart(DivStartE), .Xe(XeE), .Ye(YeE), .XZeroE, .YZeroE,
.StickyWSA, .DivBusy, .Qm(QmM), .Rem());
endmodule

View file

@ -29,29 +29,29 @@
`include "wally-config.vh"
module fclassify (
input logic XSgnE, // sign bit
input logic XNaNE, // is NaN
input logic XSNaNE, // is signaling NaN
input logic XDenormE, // is denormal
input logic XZeroE, // is zero
input logic XInfE, // is infinity
output logic [`XLEN-1:0] ClassResE // classify result
);
input logic Xs, // sign bit
input logic XNaN, // is NaN
input logic XSNaN, // is signaling NaN
input logic XDenorm,// is denormal
input logic XZero, // is zero
input logic XInf, // is infinity
output logic [`XLEN-1:0] ClassRes// classify result
);
logic PInf, PZero, PNorm, PDenorm;
logic NInf, NZero, NNorm, NDenorm;
logic XNormE;
logic XNorm;
// determine the sub categories
assign XNormE = ~(XNaNE | XInfE | XDenormE | XZeroE);
assign PInf = ~XSgnE&XInfE;
assign NInf = XSgnE&XInfE;
assign PNorm = ~XSgnE&XNormE;
assign NNorm = XSgnE&XNormE;
assign PDenorm = ~XSgnE&XDenormE;
assign NDenorm = XSgnE&XDenormE;
assign PZero = ~XSgnE&XZeroE;
assign NZero = XSgnE&XZeroE;
assign XNorm= ~(XNaN | XInf| XDenorm| XZero);
assign PInf = ~Xs&XInf;
assign NInf = Xs&XInf;
assign PNorm = ~Xs&XNorm;
assign NNorm = Xs&XNorm;
assign PDenorm = ~Xs&XDenorm;
assign NDenorm = Xs&XDenorm;
assign PZero = ~Xs&XZero;
assign NZero = Xs&XZero;
// determine sub category and combine into the result
// bit 0 - -Inf
@ -64,6 +64,6 @@ module fclassify (
// bit 7 - +Inf
// bit 8 - signaling NaN
// bit 9 - quiet NaN
assign ClassResE = {{`XLEN-10{1'b0}}, XNaNE&~XSNaNE, XSNaNE, PInf, PNorm, PDenorm, PZero, NZero, NDenorm, NNorm, NInf};
assign ClassRes = {{`XLEN-10{1'b0}}, XNaN&~XSNaN, XSNaN, PInf, PNorm, PDenorm, PZero, NZero, NDenorm, NNorm, NInf};
endmodule

View file

@ -27,9 +27,10 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////
`include "wally-config.vh"
// FOpCtrlE values
// OpCtrl values
// 110 min
// 101 max
// 010 equal
@ -37,36 +38,32 @@
// 011 less than or equal
module fcmp (
input logic [`FMTBITS-1:0] FmtE, // precision 1 = double 0 = single
input logic [2:0] FOpCtrlE, // see above table
input logic XSgnE, YSgnE, // input signs
input logic [`NE-1:0] XExpE, YExpE, // input exponents
input logic [`NF:0] XManE, YManE, // input mantissa
input logic XZeroE, YZeroE, // is zero
input logic XNaNE, YNaNE, // is NaN
input logic XSNaNE, YSNaNE, // is signaling NaN
input logic [`FLEN-1:0] FSrcXE, FSrcYE, // original, non-converted to double, inputs
output logic CmpNVE, // invalid flag
output logic [`FLEN-1:0] CmpFpResE, // compare resilt
output logic [`XLEN-1:0] CmpIntResE // compare resilt
input logic [`FMTBITS-1:0] Fmt, // format of fp number
input logic [2:0] OpCtrl, // see above table
input logic Xs, Ys, // input signs
input logic [`NE-1:0] Xe, Ye, // input exponents
input logic [`NF:0] Xm, Ym, // input mantissa
input logic XZero, YZero, // is zero
input logic XNaN, YNaN, // is NaN
input logic XSNaN, YSNaN, // is signaling NaN
input logic [`FLEN-1:0] X, Y, // original inputs (before unpacker)
output logic CmpNV, // invalid flag
output logic [`FLEN-1:0] CmpFpRes, // compare floating-point result
output logic [`XLEN-1:0] CmpIntRes // compare integer result
);
logic LTabs, LT, EQ; // is X < or > or = Y
logic [`FLEN-1:0] NaNRes;
logic BothZero, EitherNaN, EitherSNaN;
logic LTabs, LT, EQ; // is X < or > or = Y
logic [`FLEN-1:0] NaNRes; // NaN result
logic BothZero; // are both inputs zero
logic EitherNaN, EitherSNaN; // are either input a (signaling) NaN
assign LTabs= {1'b0, XExpE, XManE} < {1'b0, YExpE, YManE}; // unsigned comparison, treating FP as integers
assign LT = (XSgnE & ~YSgnE) | (XSgnE & YSgnE & ~LTabs & ~EQ) | (~XSgnE & ~YSgnE & LTabs);
// assign LT = {~XSgnE, XExpE, XManE[`NF-1:0]} < {~YSgnE, YExpE, YManE[`NF-1:0]}; // *** James look at whether we can simplify to this, but it fails regression
assign LTabs= {1'b0, Xe, Xm} < {1'b0, Ye, Ym}; // unsigned comparison, treating FP as integers
assign LT = (Xs & ~Ys) | (Xs & Ys & ~LTabs & ~EQ) | (~Xs & ~Ys & LTabs); // signed comparison
assign EQ = (X == Y);
//assign LT = $signed({XSgnE, XExpE, XManE[`NF-1:0]}) < $signed({YSgnE, YExpE, YManE[`NF-1:0]});
//assign LT = XInt < YInt;
// assign LT = XSgnE^YSgnE ? XSgnE : XExpE==YExpE ? ((XManE<YManE)^XSgnE)&~EQ : (XExpE<YExpE)^XSgnE;
assign EQ = (FSrcXE == FSrcYE);
assign BothZero = XZeroE&YZeroE;
assign EitherNaN = XNaNE|YNaNE;
assign EitherSNaN = XSNaNE|YSNaNE;
assign BothZero = XZero&YZero;
assign EitherNaN = XNaN|YNaN;
assign EitherSNaN = XSNaN|YSNaN;
// flags
@ -74,78 +71,91 @@ module fcmp (
// LT/LE - signaling - sets invalid if NaN input
// EQ - quiet - sets invalid if signaling NaN input
always_comb begin
case (FOpCtrlE[2:0])
3'b110: CmpNVE = EitherSNaN;//min
3'b101: CmpNVE = EitherSNaN;//max
3'b010: CmpNVE = EitherSNaN;//equal
3'b001: CmpNVE = EitherNaN;//less than
3'b011: CmpNVE = EitherNaN;//less than or equal
default: CmpNVE = 1'bx;
case (OpCtrl[2:0])
3'b110: CmpNV = EitherSNaN;//min
3'b101: CmpNV = EitherSNaN;//max
3'b010: CmpNV = EitherSNaN;//equal
3'b001: CmpNV = EitherNaN;//less than
3'b011: CmpNV = EitherNaN;//less than or equal
default: CmpNV = 1'bx;
endcase
end
// Min/Max
// - outputs the min/max of X and Y
// - -0 < 0
// - if both are NaN return quiet X
// - if one is a NaN output the non-NaN
// LT/LE/EQ
// - -0 = 0
// - inf = inf and -inf = -inf
// - return 0 if comparison with NaN (unordered)
// fmin/fmax of two NaNs returns a quiet NaN of the appropriate size
// for IEEE, return the payload of X
// for RISC-V, return the canonical NaN
// select the NaN result
if (`FPSIZES == 1)
if(`IEEE754) assign NaNRes = {XSgnE, {`NE{1'b1}}, 1'b1, XManE[`NF-2:0]};
if(`IEEE754) assign NaNRes = {Xs, {`NE{1'b1}}, 1'b1, Xm[`NF-2:0]};
else assign NaNRes = {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}};
else if (`FPSIZES == 2)
if(`IEEE754) assign NaNRes = FmtE ? {XSgnE, {`NE{1'b1}}, 1'b1, XManE[`NF-2:0]} : {{`FLEN-`LEN1{1'b1}}, XSgnE, {`NE1{1'b1}}, 1'b1, XManE[`NF-2:`NF-`NF1]};
else assign NaNRes = FmtE ? {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}} : {{`FLEN-`LEN1{1'b1}}, 1'b0, {`NE1{1'b1}}, 1'b1, (`NF1-1)'(0)};
if(`IEEE754) assign NaNRes = Fmt ? {Xs, {`NE{1'b1}}, 1'b1, Xm[`NF-2:0]} : {{`FLEN-`LEN1{1'b1}}, Xs, {`NE1{1'b1}}, 1'b1, Xm[`NF-2:`NF-`NF1]};
else assign NaNRes = Fmt ? {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}} : {{`FLEN-`LEN1{1'b1}}, 1'b0, {`NE1{1'b1}}, 1'b1, (`NF1-1)'(0)};
else if (`FPSIZES == 3)
always_comb
case (FmtE)
case (Fmt)
`FMT:
if(`IEEE754) NaNRes = {XSgnE, {`NE{1'b1}}, 1'b1, XManE[`NF-2:0]};
if(`IEEE754) NaNRes = {Xs, {`NE{1'b1}}, 1'b1, Xm[`NF-2:0]};
else NaNRes = {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}};
`FMT1:
if(`IEEE754) NaNRes = {{`FLEN-`LEN1{1'b1}}, XSgnE, {`NE1{1'b1}}, 1'b1, XManE[`NF-2:`NF-`NF1]};
if(`IEEE754) NaNRes = {{`FLEN-`LEN1{1'b1}}, Xs, {`NE1{1'b1}}, 1'b1, Xm[`NF-2:`NF-`NF1]};
else NaNRes = {{`FLEN-`LEN1{1'b1}}, 1'b0, {`NE1{1'b1}}, 1'b1, (`NF1-1)'(0)};
`FMT2:
if(`IEEE754) NaNRes = {{`FLEN-`LEN2{1'b1}}, XSgnE, {`NE2{1'b1}}, 1'b1, XManE[`NF-2:`NF-`NF2]};
if(`IEEE754) NaNRes = {{`FLEN-`LEN2{1'b1}}, Xs, {`NE2{1'b1}}, 1'b1, Xm[`NF-2:`NF-`NF2]};
else NaNRes = {{`FLEN-`LEN2{1'b1}}, 1'b0, {`NE2{1'b1}}, 1'b1, (`NF2-1)'(0)};
default: NaNRes = {`FLEN{1'bx}};
endcase
else if (`FPSIZES == 4)
always_comb
case (FmtE)
case (Fmt)
2'h3:
if(`IEEE754) NaNRes = {XSgnE, {`NE{1'b1}}, 1'b1, XManE[`NF-2:0]};
if(`IEEE754) NaNRes = {Xs, {`NE{1'b1}}, 1'b1, Xm[`NF-2:0]};
else NaNRes = {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}};
2'h1:
if(`IEEE754) NaNRes = {{`FLEN-`D_LEN{1'b1}}, XSgnE, {`D_NE{1'b1}}, 1'b1, XManE[`NF-2:`NF-`D_NF]};
if(`IEEE754) NaNRes = {{`FLEN-`D_LEN{1'b1}}, Xs, {`D_NE{1'b1}}, 1'b1, Xm[`NF-2:`NF-`D_NF]};
else NaNRes = {{`FLEN-`D_LEN{1'b1}}, 1'b0, {`D_NE{1'b1}}, 1'b1, (`D_NF-1)'(0)};
2'h0:
if(`IEEE754) NaNRes = {{`FLEN-`S_LEN{1'b1}}, XSgnE, {`S_NE{1'b1}}, 1'b1, XManE[`NF-2:`NF-`S_NF]};
if(`IEEE754) NaNRes = {{`FLEN-`S_LEN{1'b1}}, Xs, {`S_NE{1'b1}}, 1'b1, Xm[`NF-2:`NF-`S_NF]};
else NaNRes = {{`FLEN-`S_LEN{1'b1}}, 1'b0, {`S_NE{1'b1}}, 1'b1, (`S_NF-1)'(0)};
2'h2:
if(`IEEE754) NaNRes = {{`FLEN-`H_LEN{1'b1}}, XSgnE, {`H_NE{1'b1}}, 1'b1, XManE[`NF-2:`NF-`H_NF]};
if(`IEEE754) NaNRes = {{`FLEN-`H_LEN{1'b1}}, Xs, {`H_NE{1'b1}}, 1'b1, Xm[`NF-2:`NF-`H_NF]};
else NaNRes = {{`FLEN-`H_LEN{1'b1}}, 1'b0, {`H_NE{1'b1}}, 1'b1, (`H_NF-1)'(0)};
endcase
// when one input is a NaN -output the non-NaN
assign CmpFpResE = FOpCtrlE[0] ? XNaNE ? YNaNE ? NaNRes : FSrcYE // Max
: YNaNE ? FSrcXE : LT ? FSrcYE : FSrcXE :
XNaNE ? YNaNE ? NaNRes : FSrcYE // Min
: YNaNE ? FSrcXE : LT ? FSrcXE : FSrcYE;
assign CmpIntResE = {(`XLEN-1)'(0), (((EQ|BothZero)&FOpCtrlE[1])|(LT&FOpCtrlE[0]&~BothZero))&~EitherNaN};
// Min/Max
// - outputs the min/max of X and Y
// - -0 < 0
// - if both are NaN return quiet X
// - if one is a NaN output the non-NaN
always_comb
if(OpCtrl[0]) // MAX
if(XNaN)
if(YNaN) CmpFpRes = NaNRes; // X = NaN Y = NaN
else CmpFpRes = Y; // X = NaN Y != NaN
else
if(YNaN) CmpFpRes = X; // X != NaN Y = NaN
else // X,Y != NaN
if(LT) CmpFpRes = Y; // X < Y
else CmpFpRes = X; // X > Y
else // MIN
if(XNaN)
if(YNaN) CmpFpRes = NaNRes; // X = NaN Y = NaN
else CmpFpRes = Y; // X = NaN Y != NaN
else
if(YNaN) CmpFpRes = X; // X != NaN Y = NaN
else // X,Y != NaN
if(LT) CmpFpRes = X; // X < Y
else CmpFpRes = Y; // X > Y
// LT/LE/EQ
// - -0 = 0
// - inf = inf and -inf = -inf
// - return 0 if comparison with NaN (unordered)
assign CmpIntRes = {(`XLEN-1)'(0), (((EQ|BothZero)&OpCtrl[1])|(LT&OpCtrl[0]&~BothZero))&~EitherNaN};
endmodule

View file

@ -29,25 +29,44 @@
`include "wally-config.vh"
module fctrl (
input logic clk,
input logic reset,
input logic StallE, StallM, StallW, // stall signals
input logic FlushE, FlushM, FlushW, // flush signals
input logic [31:0] InstrD,
input logic [6:0] Funct7D, // bits 31:25 of instruction - may contain percision
input logic [6:0] OpD, // bits 6:0 of instruction
input logic [4:0] Rs2D, // bits 24:20 of instruction
input logic [2:0] Funct3D, // bits 14:12 of instruction - may contain rounding mode
input logic [2:0] FRM_REGW, // rounding mode from CSR
input logic [1:0] STATUS_FS, // is FPU enabled?
output logic IllegalFPUInstrD, // Is the instruction an illegal fpu instruction
output logic FRegWriteD, // FP register write enable
output logic FDivStartD, // Start division or squareroot
output logic [1:0] FResSelD, // select result to be written to fp register
output logic [2:0] FOpCtrlD, // chooses which opperation to do - specifics shown at bottom of module and in each unit
output logic [1:0] PostProcSelD,
output logic [`FMTBITS-1:0] FmtD, // precision - single-0 double-1
output logic [2:0] FrmD, // rounding mode 000 = rount to nearest, ties to even 001 = round twords zero 010 = round down 011 = round up 100 = round to nearest, ties to max magnitude
output logic FWriteIntD // is the result written to the integer register
input logic FDivBusyE, // is the divider busy
output logic IllegalFPUInstrD, IllegalFPUInstrM, // Is the instruction an illegal fpu instruction
output logic FRegWriteM, FRegWriteW, // FP register write enable
output logic [2:0] FrmM, // FP rounding mode
output logic [`FMTBITS-1:0] FmtE, FmtM, // FP format
output logic DivStartE, // Start division or squareroot
output logic XEnE, YEnE, ZEnE,
output logic YEnForwardE, ZEnForwardE,
output logic FWriteIntE, FWriteIntM, // Write to integer register
output logic [2:0] OpCtrlE, OpCtrlM, // Select which opperation to do in each component
output logic [1:0] FResSelE, FResSelM, FResSelW, // Select one of the results that finish in the memory stage
output logic [1:0] PostProcSelE, PostProcSelM, // select result in the post processing unit
output logic [4:0] Adr1E, Adr2E, Adr3E // adresses of each input
);
`define FCTRLW 11
logic [`FCTRLW-1:0] ControlsD;
logic IllegalFPUInstrE;
logic FRegWriteD; // FP register write enable
logic DivStartD; // integer register write enable
logic FWriteIntD; // integer register write enable
logic FRegWriteE; // FP register write enable
logic [2:0] OpCtrlD; // Select which opperation to do in each component
logic [1:0] PostProcSelD; // select result in the post processing unit
logic [1:0] FResSelD; // Select one of the results that finish in the memory stage
logic [2:0] FrmD, FrmE; // FP rounding mode
logic [`FMTBITS-1:0] FmtD; // FP format
//*** will putting x for don't cares reduce area in synthisis???
// FPU Instruction Decoder
always_comb
@ -130,7 +149,7 @@ module fctrl (
endcase
// unswizzle control bits
assign {FRegWriteD, FWriteIntD, FResSelD, PostProcSelD, FOpCtrlD, FDivStartD, IllegalFPUInstrD} = ControlsD;
assign {FRegWriteD, FWriteIntD, FResSelD, PostProcSelD, OpCtrlD, DivStartD, IllegalFPUInstrD} = ControlsD;
// rounding modes:
// 000 - round to nearest, ties to even
@ -155,6 +174,20 @@ module fctrl (
else if (`FPSIZES == 3|`FPSIZES == 4)
assign FmtD = ((Funct7D[6:3] == 4'b0100)&OpD[4]) ? Rs2D[1:0] : Funct7D[1:0];
// enables:
// X - all except int->fp, store, load, mv int->fp
// Y - all except cvt, mv, load, class
// Z - fma ops only
// load/store mv int->fp cvt int->fp
assign XEnE = ~(((FResSelE==2'b10)&~FWriteIntE)|((FResSelE==2'b11)&FRegWriteE)|((FResSelE==2'b01)&(PostProcSelE==2'b00)&OpCtrlE[2]));
// load/class mv cvt
assign YEnE = ~(((FResSelE==2'b10)&(FWriteIntE|FRegWriteE))|(FResSelE==2'b11)|((FResSelE==2'b01)&(PostProcSelE==2'b00)));
assign ZEnE = (PostProcSelE==2'b10)&(FResSelE==2'b01)&(~OpCtrlE[2]|OpCtrlE[1]);
assign YEnForwardE = ~(((FResSelE==2'b10)&(FWriteIntE|FRegWriteE))|(FResSelE==2'b11)|((FResSelE==2'b01)&(PostProcSelE==2'b00)));
assign ZEnForwardE = (PostProcSelE==2'b10)&(FResSelE==2'b01)&~OpCtrlE[2];
// Final Res Sel:
// fp int
// 00 other cmp
@ -168,7 +201,7 @@ module fctrl (
// 10 fma
// Other Sel:
// Ctrl signal = {FOpCtrl[2], &FOpctrl[1:0]}
// Ctrl signal = {OpCtrl[2], &FOpctrl[1:0]}
// 000 - sign 00
// 001 - negate sign 00
// 010 - xor sign 00
@ -186,8 +219,8 @@ module fctrl (
// 110 - add
// 111 - sub
// Div:
// 0 - ???
// 1 - ???
// 0 - div
// 1 - sqrt
// Cvt Int: {Int to Fp?, 64 bit int?, signed int?}
// Cvt Fp: output format
// 10 - to half
@ -205,5 +238,24 @@ module fctrl (
// 01 - negate sign
// 10 - xor sign
// D/E pipleine register
flopenrc #(12+`FMTBITS) DECtrlReg3(clk, reset, FlushE, ~StallE,
{FRegWriteD, PostProcSelD, FResSelD, FrmD, FmtD, OpCtrlD, FWriteIntD},
{FRegWriteE, PostProcSelE, FResSelE, FrmE, FmtE, OpCtrlE, FWriteIntE});
flopenrc #(15) DEAdrReg(clk, reset, FlushE, ~StallE, {InstrD[19:15], InstrD[24:20], InstrD[31:27]},
{Adr1E, Adr2E, Adr3E});
flopenrc #(1) DEDivStartReg(clk, reset, FlushE, ~StallE|FDivBusyE, DivStartD, DivStartE);
if(`FLEN>`XLEN)
flopenrc #(1) DEIllegalReg(clk, reset, FlushE, ~StallE, IllegalFPUInstrD, IllegalFPUInstrE);
// E/M pipleine register
flopenrc #(12+int'(`FMTBITS)) EMCtrlReg (clk, reset, FlushM, ~StallM,
{FRegWriteE, FResSelE, PostProcSelE, FrmE, FmtE, OpCtrlE, FWriteIntE},
{FRegWriteM, FResSelM, PostProcSelM, FrmM, FmtM, OpCtrlM, FWriteIntM});
if(`FLEN>`XLEN)
flopenrc #(1) EMIllegalReg(clk, reset, FlushM, ~StallM, IllegalFPUInstrE, IllegalFPUInstrM);
// M/W pipleine register
flopenrc #(3) MWCtrlReg(clk, reset, FlushW, ~StallW,
{FRegWriteM, FResSelM},
{FRegWriteW, FResSelW});
endmodule

View file

@ -35,7 +35,7 @@ module fcvt (
input logic [`NE-1:0] Xe, // input's exponent
input logic [`NF:0] Xm, // input's fraction
input logic [`XLEN-1:0] Int, // integer input - from IEU
input logic [2:0] FOpCtrl, // choose which opperation (look below for values)
input logic [2:0] OpCtrl, // choose which opperation (look below for values)
input logic ToInt, // is fp->int (since it's writting to the integer register)
input logic XZero, // is the input zero
input logic XDenorm, // is the input denormalized
@ -73,17 +73,17 @@ module fcvt (
// seperate OpCtrl for code readability
assign Signed = FOpCtrl[0];
assign Int64 = FOpCtrl[1];
assign IntToFp = FOpCtrl[2];
assign Signed = OpCtrl[0];
assign Int64 = OpCtrl[1];
assign IntToFp = OpCtrl[2];
// choose the ouptut format depending on the opperation
// - fp -> fp: OpCtrl contains the percision of the output
// - int -> fp: Fmt contains the percision of the output
if (`FPSIZES == 2)
assign OutFmt = IntToFp ? Fmt : (FOpCtrl[1:0] == `FMT);
assign OutFmt = IntToFp ? Fmt : (OpCtrl[1:0] == `FMT);
else if (`FPSIZES == 3 | `FPSIZES == 4)
assign OutFmt = IntToFp ? Fmt : FOpCtrl[1:0];
assign OutFmt = IntToFp ? Fmt : OpCtrl[1:0];
///////////////////////////////////////////////////////////////////////////
@ -103,7 +103,7 @@ module fcvt (
// choose the input to the leading zero counter i.e. priority encoder
// int -> fp : | positive integer | 00000... (if needed) |
// fp -> fp : | fraction | 00000... (if needed) |
assign LzcInFull = IntToFp ? {1'b0, TrimInt, {`CVTLEN-`XLEN{1'b0}}} :
assign LzcInFull = IntToFp ? {TrimInt, {`CVTLEN-`XLEN+1{1'b0}}} :
{Xm, {`CVTLEN-`NF{1'b0}}};
assign LzcIn = LzcInFull[`CVTLEN-1:0];
@ -125,9 +125,10 @@ module fcvt (
// - only shift fp -> fp if the intital value is denormalized
// - this is a problem because the input to the lzc was the fraction rather than the mantissa
// - rather have a few and-gates than an extra bit in the priority encoder??? *** is this true?
assign ShiftAmt = ToInt ? Ce[`LOGCVTLEN-1:0]&{`LOGCVTLEN{~Ce[`NE]}} :
ResDenormUf&~IntToFp ? (`LOGCVTLEN)'(`NF-1)+Ce[`LOGCVTLEN-1:0] :
(LeadingZeros);
always_comb
if(ToInt) ShiftAmt = Ce[`LOGCVTLEN-1:0]&{`LOGCVTLEN{~Ce[`NE]}};
else if (ResDenormUf&~IntToFp) ShiftAmt = (`LOGCVTLEN)'(`NF-1)+Ce[`LOGCVTLEN-1:0];
else ShiftAmt = LeadingZeros;
///////////////////////////////////////////////////////////////////////////
// exp calculations
@ -150,7 +151,9 @@ module fcvt (
assign NewBias = ToInt ? (`NE-1)'(1) : (`NE-1)'(`BIAS);
end else if (`FPSIZES == 2) begin
assign NewBias = ToInt ? (`NE-1)'(1) : OutFmt ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
logic [`NE-2:0] NewBiasToFp;
assign NewBiasToFp = OutFmt ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
assign NewBias = ToInt ? (`NE-1)'(1) : NewBiasToFp;
end else if (`FPSIZES == 3) begin
logic [`NE-2:0] NewBiasToFp;
@ -177,7 +180,7 @@ module fcvt (
// select the old exponent
// int -> fp : largest bias + XLEN
// fp -> ??? : XExp
assign OldExp = IntToFp ? (`NE)'(`BIAS)+(`NE)'(`XLEN) : Xe;
assign OldExp = IntToFp ? (`NE)'(`BIAS)+(`NE)'(`XLEN-1) : Xe;
// calculate CalcExp
// fp -> fp :
@ -222,7 +225,11 @@ module fcvt (
// - if 64-bit : check the msb of the 64-bit integer input and if it's signed
// - if 32-bit : check the msb of the 32-bit integer input and if it's signed
// - otherwise: the floating point input's sign
assign Cs = IntToFp ? Int64 ? Int[`XLEN-1]&Signed : Int[31]&Signed : Xs;
always_comb
if(IntToFp)
if(Int64) Cs = Int[`XLEN-1]&Signed;
else Cs = Int[31]&Signed;
else Cs = Xs;
endmodule

View file

@ -31,49 +31,51 @@
`include "wally-config.vh"
module fhazard(
input logic [4:0] Adr1E, Adr2E, Adr3E, // read data adresses
input logic FRegWriteM, FRegWriteW, // is the fp register being written to
input logic [4:0] RdM, RdW, // the adress being written to
input logic [1:0] FResSelM, // the result being selected
input logic [4:0] Adr1E, Adr2E, Adr3E, // read data adresses
input logic FRegWriteM, FRegWriteW, // is the fp register being written to
input logic [4:0] RdM, RdW, // the adress being written to
input logic [1:0] FResSelM, // the result being selected
input logic XEnE, YEnE, ZEnE,
output logic FStallD, // stall the decode stage
output logic [1:0] FForwardXE, FForwardYE, FForwardZE // select a forwarded value
output logic [1:0] ForwardXE, ForwardYE, ForwardZE // select a forwarded value
);
always_comb begin
// set defaults
FForwardXE = 2'b00; // choose FRD1E
FForwardYE = 2'b00; // choose FRD2E
FForwardZE = 2'b00; // choose FRD3E
ForwardXE = 2'b00; // choose FRD1E
ForwardYE = 2'b00; // choose FRD2E
ForwardZE = 2'b00; // choose FRD3E
FStallD = 0;
//*** this hazard unit is waiting for all three inputs, change so that if an input isnt used then don't wait
// if the needed value is in the memory stage - input 1
if ((Adr1E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) FForwardXE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr1E == RdW) & FRegWriteW) FForwardXE = 2'b01; // choose FPUResult64W
if(XEnE)
if ((Adr1E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) ForwardXE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr1E == RdW) & FRegWriteW) ForwardXE = 2'b01; // choose FPUResult64W
// if the needed value is in the memory stage - input 2
if ((Adr2E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) FForwardYE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr2E == RdW) & FRegWriteW) FForwardYE = 2'b01; // choose FPUResult64W
if(YEnE)
if ((Adr2E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) ForwardYE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr2E == RdW) & FRegWriteW) ForwardYE = 2'b01; // choose FPUResult64W
// if the needed value is in the memory stage - input 3
if ((Adr3E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) FForwardZE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr3E == RdW) & FRegWriteW) FForwardZE = 2'b01; // choose FPUResult64W
if(ZEnE)
if ((Adr3E == RdM) & FRegWriteM)
// if the result will be FResM (can be taken from the memory stage)
if(FResSelM == 2'b00) ForwardZE = 2'b10; // choose FResM
else FStallD = 1; // otherwise stall
// if the needed value is in the writeback stage
else if ((Adr3E == RdW) & FRegWriteW) ForwardZE = 2'b01; // choose FPUResult64W
end

View file

@ -37,7 +37,6 @@ module flags(
input logic NaNIn, // is a NaN input being used
input logic [`FMTBITS-1:0] OutFmt, // output format
input logic XZero, YZero, // inputs are zero
input logic XNaN, YNaN, // inputs are NaN
input logic Sqrt, // Sqrt?
input logic ToInt, // convert to integer
input logic IntToFp, // convert integer to floating point
@ -153,11 +152,11 @@ module flags(
// | | | | or the res rounds up out of bounds
// | | | | and the res didn't underflow
// | | | | |
assign IntInvalid = XNaN|XInf|(ShiftGtIntSz&~FullRe[`NE+1])|((Xs&~Signed)&(~((CvtCe[`NE]|(~|CvtCe))&~Plus1)))|(CvtNegResMsbs[1]^CvtNegResMsbs[0]);
assign IntInvalid = NaNIn|InfIn|(ShiftGtIntSz&~FullRe[`NE+1])|((Xs&~Signed)&(~((CvtCe[`NE]|(~|CvtCe))&~Plus1)))|(CvtNegResMsbs[1]^CvtNegResMsbs[0]);
// |
// or when the positive res rounds up out of range
assign SigNaN = (XSNaN&~(IntToFp&CvtOp)) | (YSNaN&~CvtOp) | (ZSNaN&FmaOp);
assign FmaInvalid = ((XInf | YInf) & ZInf & (FmaPs ^ FmaAs) & ~XNaN & ~YNaN) | (XZero & YInf) | (YZero & XInf);
assign FmaInvalid = ((XInf | YInf) & ZInf & (FmaPs ^ FmaAs) & ~NaNIn) | (XZero & YInf) | (YZero & XInf);
assign DivInvalid = ((XInf & YInf) | (XZero & YZero))&~Sqrt | (Xs&Sqrt);
assign Invalid = SigNaN | (FmaInvalid&FmaOp) | (DivInvalid&DivOp);

View file

@ -34,7 +34,7 @@ module fma(
input logic [`NE-1:0] Xe, Ye, Ze, // input's biased exponents in B(NE.0) format
input logic [`NF:0] Xm, Ym, Zm, // input's significands in U(0.NF) format
input logic XZero, YZero, ZZero, // is the input zero
input logic [2:0] FOpCtrl, // 000 = fmadd (X*Y)+Z, 001 = fmsub (X*Y)-Z, 010 = fnmsub -(X*Y)+Z, 011 = fnmadd -(X*Y)-Z, 100 = fmul (X*Y)
input logic [2:0] OpCtrl, // 000 = fmadd (X*Y)+Z, 001 = fmsub (X*Y)-Z, 010 = fnmsub -(X*Y)+Z, 011 = fnmadd -(X*Y)-Z, 100 = fmul (X*Y)
input logic [`FMTBITS-1:0] Fmt, // format of the result single double half or quad
output logic [`NE+1:0] Pe, // the product's exponent B(NE+2.0) format; adds 2 bits to allow for size of number and negative sign
output logic ZmSticky, // sticky bit that is calculated during alignment
@ -44,7 +44,9 @@ module fma(
output logic InvA, // Was A inverted for effective subtraction (P-A or -P+A)
output logic As, // the aligned addend's sign (modified Z sign for other opperations)
output logic Ps, // the product's sign
output logic [$clog2(3*`NF+7)-1:0] NCnt // normalization shift count
output logic Ss, // the sum's sign
output logic [`NE+1:0] Se,
output logic [$clog2(3*`NF+7)-1:0] SCnt // normalization shift count
);
logic [2*`NF+1:0] Pm; // the product's significand in U(2.2Nf) format
@ -70,7 +72,7 @@ module fma(
// Alignment shifter
///////////////////////////////////////////////////////////////////////////////
// calculate the signs and take the opperation into account
sign sign(.FOpCtrl, .Xs, .Ys, .Zs, .Ps, .As);
sign sign(.OpCtrl, .Xs, .Ys, .Zs, .Ps, .As);
align align(.Ze, .Zm, .XZero, .YZero, .ZZero, .Xe, .Ye,
.Am, .ZmSticky, .KillProd);
@ -81,9 +83,9 @@ module fma(
// // Addition/LZA
// ///////////////////////////////////////////////////////////////////////////////
add add(.Am, .Pm, .Ps, .As, .KillProd, .ZmSticky, .AmInv, .PmKilled, .NegSum, .InvA, .Sm);
add add(.Am, .Pm, .Ze, .Pe, .Ps, .As, .KillProd, .ZmSticky, .AmInv, .PmKilled, .NegSum, .InvA, .Sm, .Se, .Ss);
loa loa(.A(AmInv+{(3*`NF+6)'(0),InvA&~((ZmSticky&~KillProd))}), .P({PmKilled, 1'b0, InvA&Ps&ZmSticky&KillProd}), .NCnt);
loa loa(.A(AmInv+{(3*`NF+6)'(0),InvA&~((ZmSticky&~KillProd))}), .P({PmKilled, 1'b0, InvA&Ps&ZmSticky&KillProd}), .SCnt);
endmodule
@ -118,7 +120,7 @@ endmodule
module sign(
input logic [2:0] FOpCtrl, // opperation contol
input logic [2:0] OpCtrl, // opperation contol
input logic Xs, Ys, Zs, // sign of the inputs
output logic Ps, // the product's sign - takes opperation into account
output logic As // aligned addend sign used in fma - takes opperation into account
@ -128,9 +130,9 @@ module sign(
// Negate product's sign if FNMADD or FNMSUB
// flip is negation opperation
assign Ps = Xs ^ Ys ^ (FOpCtrl[1]&~FOpCtrl[2]);
assign Ps = Xs ^ Ys ^ (OpCtrl[1]&~OpCtrl[2]);
// flip if subtraction
assign As = Zs^FOpCtrl[0];
assign As = Zs^OpCtrl[0];
endmodule
@ -222,10 +224,14 @@ module add(
input logic Ps, As,// the product sign and the alligend addeded's sign (Modified Z sign for other opperations)
input logic KillProd, // should the product be set to 0
input logic ZmSticky,
input logic [`NE-1:0] Ze,
input logic [`NE+1:0] Pe,
output logic [3*`NF+6:0] AmInv, // aligned addend possibly inverted
output logic [2*`NF+1:0] PmKilled, // the product's mantissa possibly killed
output logic NegSum, // was the sum negitive
output logic InvA, // do you invert the aligned addend
output logic Ss,
output logic [`NE+1:0] Se,
output logic [3*`NF+5:0] Sm // the positive sum
);
logic [3*`NF+6:0] PreSum, NegPreSum; // possibly negitive sum
@ -257,13 +263,19 @@ module add(
// Choose the positive sum and accompanying LZA result.
assign Sm = NegSum ? NegPreSum[3*`NF+5:0] : PreSum[3*`NF+5:0];
// is the result negitive
// if p - z is the Sum negitive
// if -p + z is the Sum positive
// if -p - z then the Sum is negitive
assign Ss = NegSum^Ps; //*** move to execute stage
assign Se = KillProd ? {2'b0, Ze} : Pe;
endmodule
module loa( // [Schmookler & Nowka, Leading zero anticipation and detection, IEEE Sym. Computer Arithmetic, 2001]
input logic [3*`NF+6:0] A, // addend
input logic [2*`NF+3:0] P, // product
output logic [$clog2(3*`NF+7)-1:0] NCnt // normalization shift count for the positive result
output logic [$clog2(3*`NF+7)-1:0] SCnt // normalization shift count for the positive result
);
logic [3*`NF+6:0] T;
@ -288,6 +300,6 @@ module loa( // [Schmookler & Nowka, Leading zero anticipation and detection, IEE
lzc #(3*`NF+7) lzc (.num(f), .ZeroCnt(NCnt));
lzc #(3*`NF+7) lzc (.num(f), .ZeroCnt(SCnt));
endmodule

View file

@ -32,17 +32,18 @@ module fmashiftcalc(
input logic [3*`NF+5:0] FmaSm, // the positive sum
input logic [`NE-1:0] Ze, // exponent of Z
input logic [`NE+1:0] FmaPe, // X exponent + Y exponent - bias
input logic [$clog2(3*`NF+7)-1:0] FmaNCnt, // normalization shift count
input logic [$clog2(3*`NF+7)-1:0] FmaSCnt, // normalization shift count
input logic [`FMTBITS-1:0] Fmt, // precision 1 = double 0 = single
input logic FmaKillProd, // is the product set to zero
output logic [`NE+1:0] FmaNe, // exponent of the normalized sum not taking into account denormal or zero results
input logic [`NE+1:0] FmaSe,
output logic [`NE+1:0] NormSumExp, // exponent of the normalized sum not taking into account denormal or zero results
output logic FmaSZero, // is the result denormalized - calculated before LZA corection
output logic FmaPreResultDenorm, // is the result denormalized - calculated before LZA corection
output logic [$clog2(3*`NF+7)-1:0] FmaShiftAmt, // normalization shift count
output logic [3*`NF+8:0] FmaShiftIn // is the sum zero
);
logic [$clog2(3*`NF+7)-1:0] DenormShift; // right shift if the result is denormalized //***change this later
logic [`NE+1:0] NormSumExp; // the exponent of the normalized sum with the `FLEN bias
logic [`NE+1:0] PreNormSumExp; // the exponent of the normalized sum with the `FLEN bias
logic [`NE+1:0] BiasCorr;
///////////////////////////////////////////////////////////////////////////////
// Normalization
@ -50,37 +51,38 @@ module fmashiftcalc(
//*** insert bias-bias simplification in fcvt.sv/phone pictures
// Determine if the sum is zero
assign FmaSZero = ~(|FmaSm);
// calculate the sum's exponent
// ProdExp - NormCnt - 1 + NF+4 = ProdExp + ~NormCnt + 1 - 1 + NF+4 = ProdExp + ~NormCnt + NF+4
assign NormSumExp = (FmaKillProd ? {2'b0, Ze} : FmaPe) + {{`NE+2-$unsigned($clog2(3*`NF+7)){1'b1}}, ~FmaNCnt} + (`NE+2)'(`NF+4);
assign PreNormSumExp = FmaSe + {{`NE+2-$unsigned($clog2(3*`NF+7)){1'b1}}, ~FmaSCnt} + (`NE+2)'(`NF+4);
//convert the sum's exponent into the proper percision
if (`FPSIZES == 1) begin
assign FmaNe = NormSumExp;
assign NormSumExp = PreNormSumExp;
end else if (`FPSIZES == 2) begin
assign FmaNe = Fmt ? NormSumExp : (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`BIAS1))&{`NE+2{|NormSumExp}};
assign BiasCorr = Fmt ? (`NE+2)'(0) : (`NE+2)'(`BIAS1-`BIAS);
assign NormSumExp = PreNormSumExp+BiasCorr;
end else if (`FPSIZES == 3) begin
always_comb begin
case (Fmt)
`FMT: FmaNe = NormSumExp;
`FMT1: FmaNe = (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`BIAS1))&{`NE+2{|NormSumExp}};
`FMT2: FmaNe = (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`BIAS2))&{`NE+2{|NormSumExp}};
default: FmaNe = {`NE+2{1'bx}};
`FMT: BiasCorr = '0;
`FMT1: BiasCorr = (`NE+2)'(`BIAS1-`BIAS);
`FMT2: BiasCorr = (`NE+2)'(`BIAS2-`BIAS);
default: BiasCorr = 'x;
endcase
end
assign NormSumExp = PreNormSumExp+BiasCorr;
end else if (`FPSIZES == 4) begin
always_comb begin
case (Fmt)
2'h3: FmaNe = NormSumExp;
2'h1: FmaNe = (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`D_BIAS))&{`NE+2{|NormSumExp}};
2'h0: FmaNe = (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`S_BIAS))&{`NE+2{|NormSumExp}};
2'h2: FmaNe = (NormSumExp-(`NE+2)'(`BIAS)+(`NE+2)'(`H_BIAS))&{`NE+2{|NormSumExp}};
2'h3: BiasCorr = '0;
2'h1: BiasCorr = (`NE+2)'(`D_BIAS-`Q_BIAS);
2'h0: BiasCorr = (`NE+2)'(`S_BIAS-`Q_BIAS);
2'h2: BiasCorr = (`NE+2)'(`H_BIAS-`Q_BIAS);
endcase
end
assign NormSumExp = PreNormSumExp+BiasCorr;
end
@ -88,26 +90,26 @@ module fmashiftcalc(
if (`FPSIZES == 1) begin
logic Sum0LEZ, Sum0GEFL;
assign Sum0LEZ = NormSumExp[`NE+1] | ~|NormSumExp;
assign Sum0GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF)-(`NE+2)'(2));
assign Sum0LEZ = PreNormSumExp[`NE+1] | ~|PreNormSumExp;
assign Sum0GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF-2));
assign FmaPreResultDenorm = Sum0LEZ & Sum0GEFL & ~FmaSZero;
end else if (`FPSIZES == 2) begin
logic Sum0LEZ, Sum0GEFL, Sum1LEZ, Sum1GEFL;
assign Sum0LEZ = NormSumExp[`NE+1] | ~|NormSumExp;
assign Sum0GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF)-(`NE+2)'(2));
assign Sum1LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`BIAS1));
assign Sum1GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF1+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`BIAS1)) | ~|NormSumExp;
assign Sum0LEZ = PreNormSumExp[`NE+1] | ~|PreNormSumExp;
assign Sum0GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF-2));
assign Sum1LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`BIAS1));
assign Sum1GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF1-2+`BIAS-`BIAS1)) | ~|PreNormSumExp;
assign FmaPreResultDenorm = (Fmt ? Sum0LEZ : Sum1LEZ) & (Fmt ? Sum0GEFL : Sum1GEFL) & ~FmaSZero;
end else if (`FPSIZES == 3) begin
logic Sum0LEZ, Sum0GEFL, Sum1LEZ, Sum1GEFL, Sum2LEZ, Sum2GEFL;
assign Sum0LEZ = NormSumExp[`NE+1] | ~|NormSumExp;
assign Sum0GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF)-(`NE+2)'(2));
assign Sum1LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`BIAS1));
assign Sum1GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF1+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`BIAS1)) | ~|NormSumExp;
assign Sum2LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`BIAS2));
assign Sum2GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF2+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`BIAS2)) | ~|NormSumExp;
assign Sum0LEZ = PreNormSumExp[`NE+1] | ~|PreNormSumExp;
assign Sum0GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF-2));
assign Sum1LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`BIAS1));
assign Sum1GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF1-2+`BIAS-`BIAS1)) | ~|PreNormSumExp;
assign Sum2LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`BIAS2));
assign Sum2GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF2-2+`BIAS-`BIAS2)) | ~|PreNormSumExp;
always_comb begin
case (Fmt)
`FMT: FmaPreResultDenorm = Sum0LEZ & Sum0GEFL & ~FmaSZero;
@ -119,21 +121,21 @@ module fmashiftcalc(
end else if (`FPSIZES == 4) begin
logic Sum0LEZ, Sum0GEFL, Sum1LEZ, Sum1GEFL, Sum2LEZ, Sum2GEFL, Sum3LEZ, Sum3GEFL;
assign Sum0LEZ = NormSumExp[`NE+1] | ~|NormSumExp;
assign Sum0GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`NF )-(`NE+2)'(2));
assign Sum1LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`D_BIAS));
assign Sum1GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`D_NF+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`D_BIAS)) | ~|NormSumExp;
assign Sum2LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`S_BIAS));
assign Sum2GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`S_NF+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`S_BIAS)) | ~|NormSumExp;
assign Sum3LEZ = $signed(NormSumExp) <= $signed( (`NE+2)'(`BIAS)-(`NE+2)'(`H_BIAS));
assign Sum3GEFL = $signed(NormSumExp) >= $signed(-(`NE+2)'(`H_NF+2)+(`NE+2)'(`BIAS)-(`NE+2)'(`H_BIAS)) | ~|NormSumExp;
assign Sum0LEZ = PreNormSumExp[`NE+1] | ~|PreNormSumExp;
assign Sum0GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`NF-2));
assign Sum1LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`D_BIAS));
assign Sum1GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`D_NF-2+`BIAS-`D_BIAS)) | ~|PreNormSumExp;
assign Sum2LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`S_BIAS));
assign Sum2GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`S_NF-2+`BIAS-`S_BIAS)) | ~|PreNormSumExp;
assign Sum3LEZ = $signed(PreNormSumExp) <= $signed((`NE+2)'(`BIAS-`H_BIAS));
assign Sum3GEFL = $signed(PreNormSumExp) >= $signed((`NE+2)'(-`H_NF-2+`BIAS-`H_BIAS)) | ~|PreNormSumExp;
always_comb begin
case (Fmt)
2'h3: FmaPreResultDenorm = Sum0LEZ & Sum0GEFL & ~FmaSZero;
2'h1: FmaPreResultDenorm = Sum1LEZ & Sum1GEFL & ~FmaSZero;
2'h0: FmaPreResultDenorm = Sum2LEZ & Sum2GEFL & ~FmaSZero;
2'h2: FmaPreResultDenorm = Sum3LEZ & Sum3GEFL & ~FmaSZero;
endcase // *** remove checking to see if it's underflowed and only check for less than zero for denorm checking
endcase
end
end
@ -144,13 +146,13 @@ module fmashiftcalc(
// - if kill prod dont add to exp
// Determine if the result is denormal
// assign FmaPreResultDenorm = $signed(FmaNe)<=0 & ($signed(FmaNe)>=$signed(-FracLen)) & ~FmaSZero;
// assign FmaPreResultDenorm = $signed(NormSumExp)<=0 & ($signed(NormSumExp)>=$signed(-FracLen)) & ~FmaSZero;
// Determine the shift needed for denormal results
// - if not denorm add 1 to shift out the leading 1
assign DenormShift = FmaPreResultDenorm ? FmaNe[$clog2(3*`NF+7)-1:0] : 1;
// set and calculate the shift input and amount
// - shift once if killing a product and the result is denormalized
assign FmaShiftIn = {3'b0, FmaSm};
assign FmaShiftAmt = FmaNCnt+DenormShift;
if (`FPSIZES == 1)
assign FmaShiftAmt = FmaPreResultDenorm ? FmaSe[$clog2(3*`NF+7)-1:0]+($clog2(3*`NF+7))'(`NF+3): FmaSCnt+1;
else
assign FmaShiftAmt = FmaPreResultDenorm ? FmaSe[$clog2(3*`NF+7)-1:0]+($clog2(3*`NF+7))'(`NF+3)+BiasCorr[$clog2(3*`NF+7)-1:0]: FmaSCnt+1;
endmodule

View file

@ -30,28 +30,28 @@
`include "wally-config.vh"
module fpu (
input logic clk,
input logic reset,
input logic [2:0] FRM_REGW, // Rounding mode from CSR
input logic [31:0] InstrD, // instruction from IFU
input logic [`FLEN-1:0] ReadDataW,// Read data from memory
input logic [`XLEN-1:0] ForwardedSrcAE, // Integer input being processed (from IEU)
input logic StallE, StallM, StallW, // stall signals from HZU
input logic FlushE, FlushM, FlushW, // flush signals from HZU
input logic [4:0] RdM, RdW, // which FP register to write to (from IEU)
input logic [1:0] STATUS_FS, // Is floating-point enabled?
output logic FRegWriteM, // FP register write enable
output logic FpLoadStoreM, // Fp load instruction?
output logic FStore2,
output logic FStallD, // Stall the decode stage
output logic FWriteIntE, // integer register write enables
output logic [`XLEN-1:0] FWriteDataE, // Data to be written to memory
output logic [`FLEN-1:0] FWriteDataM, // Data to be written to memory
output logic [`XLEN-1:0] FIntResM, // data to be written to integer register
output logic [`XLEN-1:0] FCvtIntResW, // data to be written to integer register
output logic [1:0] FResSelW,
output logic FDivBusyE, // Is the divide/sqrt unit busy (stall execute stage)
output logic IllegalFPUInstrD, // Is the instruction an illegal fpu instruction
input logic clk,
input logic reset,
input logic [2:0] FRM_REGW, // Rounding mode (from CSR)
input logic [31:0] InstrD, // instruction (from IFU)
input logic [`FLEN-1:0] ReadDataW, // Read data (from LSU)
input logic [`XLEN-1:0] ForwardedSrcAE, // Integer input (from IEU)
input logic StallE, StallM, StallW, // stall signals (from HZU)
input logic FlushE, FlushM, FlushW, // flush signals (from HZU)
input logic [4:0] RdM, RdW, // which FP register to write to (from IEU)
input logic [1:0] STATUS_FS, // Is floating-point enabled? (From privileged unit)
output logic FRegWriteM, // FP register write enable (to privileged unit)
output logic FpLoadStoreM, // Fp load instruction? (to LSU)
output logic FStore2, // store two words into memory (to LSU)
output logic FStallD, // Stall the decode stage (To HZU)
output logic FWriteIntE, // integer register write enable (to IEU)
output logic [`XLEN-1:0] FWriteDataE, // Data to be written to memory (to IEU) - only used if `XLEN >`FLEN
output logic [`FLEN-1:0] FWriteDataM, // Data to be written to memory (to IEU) - only used if `XLEN <`FLEN
output logic [`XLEN-1:0] FIntResM, // data to be written to integer register (to IEU)
output logic [`XLEN-1:0] FCvtIntResW, // convert result to to be written to integer register (to IEU)
output logic [1:0] FResSelW, // final result selection (to IEU)
output logic FDivBusyE, // Is the divide/sqrt unit busy (stall execute stage) (to HZU)
output logic IllegalFPUInstrD, // Is the instruction an illegal fpu instruction (to privileged unit)
output logic [4:0] SetFflagsM // FPU flags (to privileged unit)
);
@ -62,97 +62,91 @@ module fpu (
// - sets the underflow after rounding
// control signals
logic FRegWriteD, FRegWriteE, FRegWriteW; // FP register write enable
logic [2:0] FrmD, FrmE, FrmM; // FP rounding mode
logic [`FMTBITS-1:0] FmtD, FmtE, FmtM, FmtW; // FP precision 0-single 1-double
logic FDivStartD, FDivStartE; // Start division or squareroot
logic FWriteIntD; // Write to integer register
logic FWriteIntM; // Write to integer register
logic [1:0] FForwardXE, FForwardYE, FForwardZE; // forwarding mux control signals
logic [2:0] FOpCtrlD, FOpCtrlE, FOpCtrlM; // Select which opperation to do in each component
logic [1:0] FResSelD, FResSelE, FResSelM; // Select one of the results that finish in the memory stage
logic [1:0] PostProcSelD, PostProcSelE, PostProcSelM; // select result in the post processing unit
logic [4:0] Adr1E, Adr2E, Adr3E; // adresses of each input
logic FRegWriteW; // FP register write enable
logic [2:0] FrmM; // FP rounding mode
logic [`FMTBITS-1:0] FmtE, FmtM; // FP precision 0-single 1-double
logic DivStartE; // Start division or squareroot
logic FWriteIntM; // Write to integer register
logic [1:0] ForwardXE, ForwardYE, ForwardZE; // forwarding mux control signals
logic [2:0] OpCtrlE, OpCtrlM; // Select which opperation to do in each component
logic [1:0] FResSelE, FResSelM; // Select one of the results that finish in the memory stage
logic [1:0] PostProcSelE, PostProcSelM; // select result in the post processing unit
logic [4:0] Adr1E, Adr2E, Adr3E; // adresses of each input
logic IllegalFPUInstrM;
logic XEnE, YEnE, ZEnE;
logic YEnForwardE, ZEnForwardE;
// regfile signals
logic [`FLEN-1:0] FRD1D, FRD2D, FRD3D; // Read Data from FP register - decode stage
logic [`FLEN-1:0] FRD1E, FRD2E, FRD3E; // Read Data from FP register - execute stage
logic [`FLEN-1:0] FSrcXE; // Input 1 to the various units (after forwarding)
logic [`XLEN-1:0] IntSrcXE; // Input 1 to the various units (after forwarding)
logic [`FLEN-1:0] FPreSrcYE, FSrcYE; // Input 2 to the various units (after forwarding)
logic [`FLEN-1:0] FPreSrcZE, FSrcZE; // Input 3 to the various units (after forwarding)
logic [`FLEN-1:0] FRD1D, FRD2D, FRD3D; // Read Data from FP register - decode stage
logic [`FLEN-1:0] FRD1E, FRD2E, FRD3E; // Read Data from FP register - execute stage
logic [`FLEN-1:0] XE; // Input 1 to the various units (after forwarding)
logic [`XLEN-1:0] IntSrcXE; // Input 1 to the various units (after forwarding)
logic [`FLEN-1:0] PreYE, YE; // Input 2 to the various units (after forwarding)
logic [`FLEN-1:0] PreZE, ZE; // Input 3 to the various units (after forwarding)
// unpacking signals
logic XSgnE, YSgnE, ZSgnE; // input's sign - execute stage
logic XSgnM, YSgnM; // input's sign - memory stage
logic [`NE-1:0] XExpE, YExpE, ZExpE; // input's exponent - execute stage
logic [`NE-1:0] ZExpM; // input's exponent - memory stage
logic [`NF:0] XManE, YManE, ZManE; // input's fraction - execute stage
logic [`NF:0] XManM, YManM, ZManM; // input's fraction - memory stage
logic XNaNE, YNaNE, ZNaNE; // is the input a NaN - execute stage
logic XNaNM, YNaNM, ZNaNM; // is the input a NaN - memory stage
logic XNaNQ, YNaNQ; // is the input a NaN - divide
logic XSNaNE, YSNaNE, ZSNaNE; // is the input a signaling NaN - execute stage
logic XSNaNM, YSNaNM, ZSNaNM; // is the input a signaling NaN - memory stage
logic XDenormE, ZDenormE, ZDenormM; // is the input denormalized
logic XZeroE, YZeroE, ZZeroE; // is the input zero - execute stage
logic XZeroM, YZeroM, ZZeroM; // is the input zero - memory stage
logic XZeroQ, YZeroQ; // is the input zero - divide
logic XInfE, YInfE, ZInfE; // is the input infinity - execute stage
logic XInfM, YInfM, ZInfM; // is the input infinity - memory stage
logic XInfQ, YInfQ; // is the input infinity - divide
logic XExpMaxE; // is the exponent all ones (max value)
logic FmtQ;
logic FOpCtrlQ;
logic XsE, YsE, ZsE; // input's sign - execute stage
logic XsM, YsM; // input's sign - memory stage
logic [`NE-1:0] XeE, YeE, ZeE; // input's exponent - execute stage
logic [`NE-1:0] ZeM; // input's exponent - memory stage
logic [`NF:0] XmE, YmE, ZmE; // input's fraction - execute stage
logic [`NF:0] XmM, YmM, ZmM; // input's fraction - memory stage
logic XNaNE, YNaNE, ZNaNE; // is the input a NaN - execute stage
logic XNaNM, YNaNM, ZNaNM; // is the input a NaN - memory stage
logic XNaNQ, YNaNQ; // is the input a NaN - divide
logic XSNaNE, YSNaNE, ZSNaNE; // is the input a signaling NaN - execute stage
logic XSNaNM, YSNaNM, ZSNaNM; // is the input a signaling NaN - memory stage
logic XDenormE, ZDenormE, ZDenormM; // is the input denormalized
logic XZeroE, YZeroE, ZZeroE; // is the input zero - execute stage
logic XZeroM, YZeroM, ZZeroM; // is the input zero - memory stage
logic XInfE, YInfE, ZInfE; // is the input infinity - execute stage
logic XInfM, YInfM, ZInfM; // is the input infinity - memory stage
logic XExpMaxE; // is the exponent all ones (max value)
// Fma Signals
logic [3*`NF+5:0] SumE, SumM;
logic [`NE+1:0] ProdExpE, ProdExpM;
logic AddendStickyE, AddendStickyM;
logic KillProdE, KillProdM;
logic InvAE, InvAM;
logic NegSumE, NegSumM;
logic ZSgnEffE, ZSgnEffM;
logic PSgnE, PSgnM;
logic [$clog2(3*`NF+7)-1:0] FmaNormCntE, FmaNormCntM;
logic [3*`NF+5:0] SmE, SmM;
logic [`NE+1:0] PeE, PeM;
logic ZmStickyE, ZmStickyM;
logic [`NE+1:0] SeE,SeM;
logic KillProdE, KillProdM;
logic InvAE, InvAM;
logic NegSumE, NegSumM;
logic AsE, AsM;
logic PsE, PsM;
logic SsE, SsM;
logic [$clog2(3*`NF+7)-1:0] SCntE, SCntM;
// Cvt Signals
logic [`NE:0] CvtCalcExpE, CvtCalcExpM; // the calculated expoent
logic [`LOGCVTLEN-1:0] CvtShiftAmtE, CvtShiftAmtM; // how much to shift by
logic [`NE:0] CeE, CeM; // the calculated expoent
logic [`LOGCVTLEN-1:0] CvtShiftAmtE, CvtShiftAmtM; // how much to shift by
logic CvtResDenormUfE, CvtResDenormUfM;// does the result underflow or is denormalized
logic CvtResSgnE, CvtResSgnM; // the result's sign
logic CsE, CsM; // the result's sign
logic IntZeroE, IntZeroM; // is the integer zero?
logic [`CVTLEN-1:0] CvtLzcInE, CvtLzcInM; // input to the Leading Zero Counter (priority encoder)
logic [`CVTLEN-1:0] CvtLzcInE, CvtLzcInM; // input to the Leading Zero Counter (priority encoder)
//divide signals
logic [`QLEN-1-(`RADIX/4):0] QuotM;
logic [`NE+1:0] DivCalcExpE, DivCalcExpM;
logic DivStickyE, DivStickyM;
logic DivDoneM;
logic [`DURLEN-1:0] EarlyTermShiftM;
logic [`QLEN-1-(`RADIX/4):0] QmM;
logic [`NE+1:0] QeE, QeM;
logic DivSE, DivSM;
logic DivDoneM;
logic [`DURLEN-1:0] EarlyTermShiftM;
// result and flag signals
logic [63:0] FDivResM, FDivResW; // divide/squareroot result
logic [4:0] FDivFlgM; // divide/squareroot flags
logic [`FLEN-1:0] ReadResW; // read result (load instruction)
logic [`XLEN-1:0] ClassResE; // classify result
logic [`XLEN-1:0] FIntResE; // classify result
logic [`FLEN-1:0] FpResM, FpResW; // classify result
logic [`FLEN-1:0] PostProcResM; // classify result
logic [4:0] PostProcFlgM; // classify result
logic [`XLEN-1:0] ClassResE; // classify result
logic [`XLEN-1:0] FIntResE; // classify result
logic [`FLEN-1:0] FpResM, FpResW; // classify result
logic [`FLEN-1:0] PostProcResM; // classify result
logic [4:0] PostProcFlgM; // classify result
logic [`XLEN-1:0] FCvtIntResM;
logic [`FLEN-1:0] CmpFpResE; // compare result
logic [`XLEN-1:0] CmpIntResE; // compare result
logic CmpNVE; // compare invalid flag (Not Valid)
logic [`FLEN-1:0] SgnResE; // sign injection result
logic [`FLEN-1:0] PreFpResE, PreFpResM, PreFpResW; // selected result that is ready in the memory stage
logic PreNVE, PreNVM; // selected flag that is ready in the memory stage
logic [`FLEN-1:0] FPUResultW; // final FP result being written to the FP register
logic [`FLEN-1:0] CmpFpResE; // compare result
logic [`XLEN-1:0] CmpIntResE; // compare result
logic CmpNVE; // compare invalid flag (Not Valid)
logic [`FLEN-1:0] SgnResE; // sign injection result
logic [`FLEN-1:0] PreFpResE, PreFpResM; // selected result that is ready in the memory stage
logic PreNVE, PreNVM; // selected flag that is ready in the memory stage
logic [`FLEN-1:0] FPUResultW; // final FP result being written to the FP register
// other signals
logic FDivSqrtDoneE; // is divide done
logic [63:0] DivInput1E, DivInput2E; // inputs to divide/squareroot unit
logic load_preload; // enable for FF on fpdivsqrt
logic [`FLEN-1:0] AlignedSrcAE; // align SrcA to the floating point format
logic [`FLEN-1:0] AlignedSrcAE; // align SrcA to the floating point format
logic [`FLEN-1:0] BoxedZeroE; // Zero value for Z for multiplication, with NaN boxing if needed
logic [`FLEN-1:0] BoxedOneE; // Zero value for Z for multiplication, with NaN boxing if needed
@ -169,9 +163,11 @@ module fpu (
//////////////////////////////////////////////////////////////////////////////////////////
// calculate FP control signals
fctrl fctrl (.Funct7D(InstrD[31:25]), .OpD(InstrD[6:0]), .Rs2D(InstrD[24:20]), .Funct3D(InstrD[14:12]), .FRM_REGW, .STATUS_FS,
.IllegalFPUInstrD, .FRegWriteD, .FDivStartD, .FResSelD, .FOpCtrlD, .PostProcSelD,
.FmtD, .FrmD, .FWriteIntD);
fctrl fctrl (.Funct7D(InstrD[31:25]), .OpD(InstrD[6:0]), .Rs2D(InstrD[24:20]), .Funct3D(InstrD[14:12]), .InstrD,
.StallE, .StallM, .StallW, .FlushE, .FlushM, .FlushW, .FRM_REGW, .STATUS_FS, .FDivBusyE,
.reset, .clk, .IllegalFPUInstrD, .FRegWriteM, .FRegWriteW, .FrmM, .FmtE, .FmtM, .YEnForwardE, .ZEnForwardE,
.DivStartE, .FWriteIntE, .FWriteIntM, .OpCtrlE, .OpCtrlM, .IllegalFPUInstrM, .XEnE, .YEnE, .ZEnE,
.FResSelE, .FResSelM, .FResSelW, .PostProcSelE, .PostProcSelM, .Adr1E, .Adr2E, .Adr3E);
// FP register file
fregfile fregfile (.clk, .reset, .we4(FRegWriteW),
@ -183,12 +179,6 @@ module fpu (
flopenrc #(`FLEN) DEReg1(clk, reset, FlushE, ~StallE, FRD1D, FRD1E);
flopenrc #(`FLEN) DEReg2(clk, reset, FlushE, ~StallE, FRD2D, FRD2E);
flopenrc #(`FLEN) DEReg3(clk, reset, FlushE, ~StallE, FRD3D, FRD3E);
flopenrc #(15) DEAdrReg(clk, reset, FlushE, ~StallE, {InstrD[19:15], InstrD[24:20], InstrD[31:27]},
{Adr1E, Adr2E, Adr3E});
flopenrc #(12+`FMTBITS) DECtrlReg3(clk, reset, FlushE, ~StallE,
{FRegWriteD, PostProcSelD, FResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD},
{FRegWriteE, PostProcSelE, FResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE});
flopenrc #(1) DEDivStartReg(clk, reset, FlushE, ~StallE|FDivBusyE, FDivStartD, FDivStartE);
// EXECUTION STAGE
@ -205,12 +195,12 @@ module fpu (
// Hazard unit for FPU
// - determines if any forwarding or stalls are needed
fhazard fhazard(.Adr1E, .Adr2E, .Adr3E, .FRegWriteM, .FRegWriteW, .RdM, .RdW, .FResSelM,
.FStallD, .FForwardXE, .FForwardYE, .FForwardZE);
.XEnE, .YEnE(YEnForwardE), .ZEnE(ZEnForwardE), .FStallD, .ForwardXE, .ForwardYE, .ForwardZE);
// forwarding muxs
mux3 #(`FLEN) fxemux (FRD1E, FPUResultW, PreFpResM, FForwardXE, FSrcXE);
mux3 #(`FLEN) fyemux (FRD2E, FPUResultW, PreFpResM, FForwardYE, FPreSrcYE);
mux3 #(`FLEN) fzemux (FRD3E, FPUResultW, PreFpResM, FForwardZE, FPreSrcZE);
mux3 #(`FLEN) fxemux (FRD1E, FPUResultW, PreFpResM, ForwardXE, XE);
mux3 #(`FLEN) fyemux (FRD2E, FPUResultW, PreFpResM, ForwardYE, PreYE);
mux3 #(`FLEN) fzemux (FRD3E, FPUResultW, PreFpResM, ForwardZE, PreZE);
generate
@ -225,7 +215,7 @@ module fpu (
endgenerate
mux2 #(`FLEN) fyaddmux (FPreSrcYE, BoxedOneE, FOpCtrlE[2]&FOpCtrlE[1]&(FResSelE==2'b01)&(PostProcSelE==2'b10), FSrcYE); // Force Z to be 0 for multiply instructions
mux2 #(`FLEN) fyaddmux (PreYE, BoxedOneE, OpCtrlE[2]&OpCtrlE[1]&(FResSelE==2'b01)&(PostProcSelE==2'b10), YE); // Force Z to be 0 for multiply instructions
// Force Z to be 0 for multiply instructions
generate
@ -239,80 +229,76 @@ module fpu (
(`FLEN)'(0), FmtE, BoxedZeroE); // NaN boxing zeroes
endgenerate
mux3 #(`FLEN) fzmulmux (FPreSrcZE, BoxedZeroE, FPreSrcYE, {FOpCtrlE[2]&FOpCtrlE[1], FOpCtrlE[2]&~FOpCtrlE[1]}, FSrcZE);
mux3 #(`FLEN) fzmulmux (PreZE, BoxedZeroE, PreYE, {OpCtrlE[2]&OpCtrlE[1], OpCtrlE[2]&~OpCtrlE[1]}, ZE);
// unpack unit
// - splits FP inputs into their various parts
// - does some classifications (SNaN, NaN, Denorm, Norm, Zero, Infifnity)
unpack unpack (.X(FSrcXE), .Y(FSrcYE), .Z(FSrcZE), .FmtE,
.XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XManE, .YManE, .ZManE,
.XNaNE, .YNaNE, .ZNaNE, .XSNaNE, .YSNaNE, .ZSNaNE, .XDenormE, .ZDenormE,
.XZeroE, .YZeroE, .ZZeroE, .XInfE, .YInfE, .ZInfE, .XExpMaxE);
unpack unpack (.X(XE), .Y(YE), .Z(ZE), .Fmt(FmtE), .Xs(XsE), .Ys(YsE), .Zs(ZsE),
.Xe(XeE), .Ye(YeE), .Ze(ZeE), .Xm(XmE), .Ym(YmE), .Zm(ZmE), .YEn(YEnE),
.XNaN(XNaNE), .YNaN(YNaNE), .ZNaN(ZNaNE), .XSNaN(XSNaNE), .XEn(XEnE),
.YSNaN(YSNaNE), .ZSNaN(ZSNaNE), .XDenorm(XDenormE), .ZDenorm(ZDenormE),
.XZero(XZeroE), .YZero(YZeroE), .ZZero(ZZeroE), .XInf(XInfE), .YInf(YInfE),
.ZEn(ZEnE), .ZInf(ZInfE), .XExpMax(XExpMaxE));
// fma - does multiply, add, and multiply-add instructions
fma fma (.Xs(XSgnE), .Ys(YSgnE), .Zs(ZSgnE),
.Xe(XExpE), .Ye(YExpE), .Ze(ZExpE),
.Xm(XManE), .Ym(YManE), .Zm(ZManE),
// fused multiply add
// - fadd/fsub
// - fmul
// - fmadd/fnmadd/fmsub/fnmsub
fma fma (.Xs(XsE), .Ys(YsE), .Zs(ZsE),
.Xe(XeE), .Ye(YeE), .Ze(ZeE),
.Xm(XmE), .Ym(YmE), .Zm(ZmE),
.XZero(XZeroE), .YZero(YZeroE), .ZZero(ZZeroE),
.FOpCtrl(FOpCtrlE), .Fmt(FmtE),
.As(ZSgnEffE), .Ps(PSgnE),
.Sm(SumE), .Pe(ProdExpE),
.NegSum(NegSumE), .InvA(InvAE), .NCnt(FmaNormCntE),
.ZmSticky(AddendStickyE), .KillProd(KillProdE));
.OpCtrl(OpCtrlE), .Fmt(FmtE),
.As(AsE), .Ps(PsE), .Ss(SsE), .Se(SeE),
.Sm(SmE), .Pe(PeE),
.NegSum(NegSumE), .InvA(InvAE), .SCnt(SCntE),
.ZmSticky(ZmStickyE), .KillProd(KillProdE));
// // fpdivsqrt using Goldschmidt's iteration
// if(`FLEN == 64) begin
// flopenrc #(64) reg_input1 (.d({FSrcXE[63:0]}), .q(DivInput1E),
// .clear(FDivSqrtDoneE), .en(load_preload),
// .reset(reset), .clk(clk));
// flopenrc #(64) reg_input2 (.d({FSrcYE[63:0]}), .q(DivInput2E),
// .clear(FDivSqrtDoneE), .en(load_preload),
// .reset(reset), .clk(clk));
// end
// else if (`FLEN == 32) begin
// flopenrc #(64) reg_input1 (.d({32'b0, FSrcXE[31:0]}), .q(DivInput1E),
// .clear(FDivSqrtDoneE), .en(load_preload),
// .reset(reset), .clk(clk));
// flopenrc #(64) reg_input2 (.d({32'b0, FSrcYE[31:0]}), .q(DivInput2E),
// .clear(FDivSqrtDoneE), .en(load_preload),
// .reset(reset), .clk(clk));
// end
// flopenrc #(8) reg_input3 (.d({XNaNE, YNaNE, XInfE, YInfE, XZeroE, YZeroE, FmtE[0], FOpCtrlE[0]}),
// .q({XNaNQ, YNaNQ, XInfQ, YInfQ, XZeroQ, YZeroQ, FmtQ, FOpCtrlQ}),
// .clear(FDivSqrtDoneE), .en(load_preload),
// .reset(reset), .clk(clk));
// fpdiv_pipe fdivsqrt (.op1(DivInput1E[63:0]), .op2(DivInput2E[63:0]), .rm(FrmE[1:0]), .op_type(FOpCtrlQ),
// .reset, .clk(clk), .start(FDivStartE), .P(~FmtQ), .OvEn(1'b1), .UnEn(1'b1),
// .XNaNQ, .YNaNQ, .XInfQ, .YInfQ, .XZeroQ, .YZeroQ, .load_preload,
// .FDivBusyE, .done(FDivSqrtDoneE), .AS_Result(FDivResM), .Flags(FDivFlgM));
divsqrt divsqrt(.clk, .reset, .FmtE, .XManE, .YManE, .XExpE, .YExpE,
.XInfE, .YInfE, .XZeroE, .YZeroE, .XNaNE, .YNaNE, .DivStartE(FDivStartE),
.StallE, .StallM, .DivStickyM, .DivBusy(FDivBusyE), .DivCalcExpM, //***change divbusyE to M signal
.EarlyTermShiftM, .QuotM, .DivDone(DivDoneM));
// other FP execution units
fcmp fcmp (.FmtE, .FOpCtrlE, .XSgnE, .YSgnE, .XExpE, .YExpE, .XManE, .YManE,
.XZeroE, .YZeroE, .XNaNE, .YNaNE, .XSNaNE, .YSNaNE, .FSrcXE, .FSrcYE, .CmpNVE, .CmpFpResE, .CmpIntResE);
fsgninj fsgninj(.SgnOpCodeE(FOpCtrlE[1:0]), .XSgnE, .YSgnE, .FSrcXE, .FmtE, .SgnResE);
fclassify fclassify (.XSgnE, .XDenormE, .XZeroE, .XNaNE, .XInfE, .XSNaNE, .ClassResE);
// divide and squareroot
// - fdiv
// - fsqrt
// *** add other opperations
divsqrt divsqrt(.clk, .reset, .FmtE, .XmE, .YmE, .XeE, .YeE, .SqrtE(OpCtrlE[0]), .SqrtM(OpCtrlM[0]),
.XInfE, .YInfE, .XZeroE, .YZeroE, .XNaNE, .YNaNE, .DivStartE(DivStartE),
.StallE, .StallM, .DivSM, .DivBusy(FDivBusyE), .QeM, //***change divbusyE to M signal
.EarlyTermShiftM, .QmM, .DivDone(DivDoneM));
// compare
// - fmin/fmax
// - flt/fle/feq
fcmp fcmp (.Fmt(FmtE), .OpCtrl(OpCtrlE), .Xs(XsE), .Ys(YsE), .Xe(XeE), .Ye(YeE),
.Xm(XmE), .Ym(YmE), .XZero(XZeroE), .YZero(YZeroE), .XNaN(XNaNE), .YNaN(YNaNE),
.XSNaN(XSNaNE), .YSNaN(YSNaNE), .X(XE), .Y(YE), .CmpNV(CmpNVE),
.CmpFpRes(CmpFpResE), .CmpIntRes(CmpIntResE));
// sign injection
// - fsgnj/fsgnjx/fsgnjn
fsgninj fsgninj(.OpCtrl(OpCtrlE[1:0]), .Xs(XsE), .Ys(YsE), .X(XE), .Fmt(FmtE), .SgnRes(SgnResE));
fcvt fcvt (.Xs(XSgnE), .Xe(XExpE), .Xm(XManE), .Int(ForwardedSrcAE), .FOpCtrl(FOpCtrlE),
.ToInt(FWriteIntE), .XZero(XZeroE), .XDenorm(XDenormE), .Fmt(FmtE), .Ce(CvtCalcExpE),
.ShiftAmt(CvtShiftAmtE), .ResDenormUf(CvtResDenormUfE), .Cs(CvtResSgnE), .IntZero(IntZeroE),
// classify
// - fclass
fclassify fclassify (.Xs(XsE), .XDenorm(XDenormE), .XZero(XZeroE), .XNaN(XNaNE),
.XInf(XInfE), .XSNaN(XSNaNE), .ClassRes(ClassResE));
// convert
// - fcvt.*.*
fcvt fcvt (.Xs(XsE), .Xe(XeE), .Xm(XmE), .Int(ForwardedSrcAE), .OpCtrl(OpCtrlE),
.ToInt(FWriteIntE), .XZero(XZeroE), .XDenorm(XDenormE), .Fmt(FmtE), .Ce(CeE),
.ShiftAmt(CvtShiftAmtE), .ResDenormUf(CvtResDenormUfE), .Cs(CsE), .IntZero(IntZeroE),
.LzcIn(CvtLzcInE));
// data to be stored in memory - to IEU
// - FP uses NaN-blocking format
// - if there are any unsused bits the most significant bits are filled with 1s
if (`LLEN==`XLEN) begin
assign FWriteDataE = FSrcYE[`XLEN-1:0];
assign FWriteDataE = YE[`XLEN-1:0];
end else begin
logic [`FLEN-1:0] FWriteDataE;
if(`FMTBITS == 2) assign FStore2 = FmtM == `FMT;
else assign FStore2 = FmtM;
if(`FMTBITS == 2) assign FStore2 = (FmtM == `FMT)&~IllegalFPUInstrM;
else assign FStore2 = FmtM&~IllegalFPUInstrM;
if (`FPSIZES==1) assign FWriteDataE = FSrcYE;
else if (`FPSIZES==2) assign FWriteDataE = FmtE ? FSrcYE : {2{FSrcYE[`LEN1-1:0]}};
else assign FWriteDataE = FmtE == `FMT ? FSrcYE : {2{FSrcYE[`LEN1-1:0]}};
if (`FPSIZES==1) assign FWriteDataE = YE;
else if (`FPSIZES==2) assign FWriteDataE = FmtE ? YE : {2{YE[`LEN1-1:0]}};
else assign FWriteDataE = FmtE == `FMT ? YE : {2{YE[`LEN1-1:0]}};
flopenrc #(`FLEN) EMWriteDataReg (clk, reset, FlushM, ~StallM, FWriteDataE, FWriteDataM);
end
@ -329,14 +315,14 @@ module fpu (
{{`FLEN-`XLEN{1'b1}}, ForwardedSrcAE}, FmtE, AlignedSrcAE); // NaN boxing zeroes
endgenerate
// select a result that may be written to the FP register
mux3 #(`FLEN) FResMux(SgnResE, AlignedSrcAE, CmpFpResE, {FOpCtrlE[2], &FOpCtrlE[1:0]}, PreFpResE);
assign PreNVE = CmpNVE&(FOpCtrlE[2]|FWriteIntE);
mux3 #(`FLEN) FResMux(SgnResE, AlignedSrcAE, CmpFpResE, {OpCtrlE[2], &OpCtrlE[1:0]}, PreFpResE);
assign PreNVE = CmpNVE&(OpCtrlE[2]|FWriteIntE);
// select the result that may be written to the integer register - to IEU
if (`FLEN>`XLEN)
assign IntSrcXE = FSrcXE[`XLEN-1:0];
assign IntSrcXE = XE[`XLEN-1:0];
else
assign IntSrcXE = {{`XLEN-`FLEN{FSrcXE[`FLEN-1:0]}}, FSrcXE};
assign IntSrcXE = {{`XLEN-`FLEN{XE[`FLEN-1:0]}}, XE};
mux3 #(`XLEN) IntResMux (ClassResE, IntSrcXE, CmpIntResE, {~FResSelE[1], FResSelE[0]}, FIntResE);
// *** DH 5/25/22: CvtRes will move to mem stage. Premux in execute to save area, then make sure stalls are ok
@ -344,27 +330,24 @@ module fpu (
// E/M pipe registers
// flopenrc #(64) EMFpReg1(clk, reset, FlushM, ~StallM, FSrcXE, FSrcXM);
flopenrc #(`NF+2) EMFpReg2 (clk, reset, FlushM, ~StallM, {XSgnE,XManE}, {XSgnM,XManM});
flopenrc #(`NF+2) EMFpReg3 (clk, reset, FlushM, ~StallM, {YSgnE,YManE}, {YSgnM,YManM});
flopenrc #(`FLEN) EMFpReg4 (clk, reset, FlushM, ~StallM, {ZExpE,ZManE}, {ZExpM,ZManM});
// flopenrc #(64) EMFpReg1(clk, reset, FlushM, ~StallM, XE, FSrcXM);
flopenrc #(`NF+2) EMFpReg2 (clk, reset, FlushM, ~StallM, {XsE,XmE}, {XsM,XmM});
flopenrc #(`NF+2) EMFpReg3 (clk, reset, FlushM, ~StallM, {YsE,YmE}, {YsM,YmM});
flopenrc #(`FLEN) EMFpReg4 (clk, reset, FlushM, ~StallM, {ZeE,ZmE}, {ZeM,ZmM});
flopenrc #(`XLEN) EMFpReg6 (clk, reset, FlushM, ~StallM, FIntResE, FIntResM);
flopenrc #(`FLEN) EMFpReg7 (clk, reset, FlushM, ~StallM, PreFpResE, PreFpResM);
flopenrc #(13) EMFpReg5 (clk, reset, FlushM, ~StallM,
{XZeroE, YZeroE, ZZeroE, XInfE, YInfE, ZInfE, XNaNE, YNaNE, ZNaNE, XSNaNE, YSNaNE, ZSNaNE, ZDenormE},
{XZeroM, YZeroM, ZZeroM, XInfM, YInfM, ZInfM, XNaNM, YNaNM, ZNaNM, XSNaNM, YSNaNM, ZSNaNM, ZDenormM});
flopenrc #(1) EMRegCmpFlg (clk, reset, FlushM, ~StallM, PreNVE, PreNVM);
flopenrc #(12+int'(`FMTBITS)) EMCtrlReg (clk, reset, FlushM, ~StallM,
{FRegWriteE, FResSelE, PostProcSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE},
{FRegWriteM, FResSelM, PostProcSelM, FrmM, FmtM, FOpCtrlM, FWriteIntM});
flopenrc #(3*`NF+6) EMRegFma2(clk, reset, FlushM, ~StallM, SumE, SumM);
flopenrc #(`NE+2) EMRegFma3(clk, reset, FlushM, ~StallM, ProdExpE, ProdExpM);
flopenrc #($clog2(3*`NF+7)+6) EMRegFma4(clk, reset, FlushM, ~StallM,
{AddendStickyE, KillProdE, InvAE, FmaNormCntE, NegSumE, ZSgnEffE, PSgnE},
{AddendStickyM, KillProdM, InvAM, FmaNormCntM, NegSumM, ZSgnEffM, PSgnM});
flopenrc #(3*`NF+6) EMRegFma2(clk, reset, FlushM, ~StallM, SmE, SmM);
flopenrc #(`NE+2) EMRegFma3(clk, reset, FlushM, ~StallM, PeE, PeM);
flopenrc #($clog2(3*`NF+7)+9+`NE) EMRegFma4(clk, reset, FlushM, ~StallM,
{ZmStickyE, KillProdE, InvAE, SCntE, NegSumE, AsE, PsE, SsE, SeE},
{ZmStickyM, KillProdM, InvAM, SCntM, NegSumM, AsM, PsM, SsM, SeM});
flopenrc #(`NE+`LOGCVTLEN+`CVTLEN+4) EMRegCvt(clk, reset, FlushM, ~StallM,
{CvtCalcExpE, CvtShiftAmtE, CvtResDenormUfE, CvtResSgnE, IntZeroE, CvtLzcInE},
{CvtCalcExpM, CvtShiftAmtM, CvtResDenormUfM, CvtResSgnM, IntZeroM, CvtLzcInM});
{CeE, CvtShiftAmtE, CvtResDenormUfE, CsE, IntZeroE, CvtLzcInE},
{CeM, CvtShiftAmtM, CvtResDenormUfM, CsM, IntZeroM, CvtLzcInM});
// BEGIN MEMORY STAGE
@ -380,11 +363,11 @@ module fpu (
assign FpLoadStoreM = FResSelM[1];
postprocess postprocess(.Xs(XSgnM), .Ys(YSgnM), .Ze(ZExpM), .Xm(XManM), .Ym(YManM), .Zm(ZManM), .Frm(FrmM), .Fmt(FmtM), .FmaPe(ProdExpM), .DivEarlyTermShift(EarlyTermShiftM),
.FmaZmS(AddendStickyM), .FmaKillProd(KillProdM), .XZero(XZeroM), .YZero(YZeroM), .ZZero(ZZeroM), .XInf(XInfM), .YInf(YInfM), .DivQm(QuotM),
.ZInf(ZInfM), .XNaN(XNaNM), .YNaN(YNaNM), .ZNaN(ZNaNM), .XSNaN(XSNaNM), .YSNaN(YSNaNM), .ZSNaN(ZSNaNM), .FmaSm(SumM), .DivQe(DivCalcExpM), .DivDone(DivDoneM),
.FmaNegSum(NegSumM), .FmaInvA(InvAM), .ZDenorm(ZDenormM), .FmaAs(ZSgnEffM), .FmaPs(PSgnM), .FOpCtrl(FOpCtrlM), .FmaNCnt(FmaNormCntM),
.CvtCe(CvtCalcExpM), .CvtResDenormUf(CvtResDenormUfM),.CvtShiftAmt(CvtShiftAmtM), .CvtCs(CvtResSgnM), .ToInt(FWriteIntM), .DivS(DivStickyM),
postprocess postprocess(.Xs(XsM), .Ys(YsM), .Ze(ZeM), .Xm(XmM), .Ym(YmM), .Zm(ZmM), .Frm(FrmM), .Fmt(FmtM), .FmaPe(PeM), .DivEarlyTermShift(EarlyTermShiftM),
.FmaZmS(ZmStickyM), .FmaKillProd(KillProdM), .XZero(XZeroM), .YZero(YZeroM), .ZZero(ZZeroM), .XInf(XInfM), .YInf(YInfM), .DivQm(QmM), .FmaSs(SsM),
.ZInf(ZInfM), .XNaN(XNaNM), .YNaN(YNaNM), .ZNaN(ZNaNM), .XSNaN(XSNaNM), .YSNaN(YSNaNM), .ZSNaN(ZSNaNM), .FmaSm(SmM), .DivQe(QeM), .DivDone(DivDoneM),
.FmaNegSum(NegSumM), .FmaInvA(InvAM), .ZDenorm(ZDenormM), .FmaAs(AsM), .FmaPs(PsM), .OpCtrl(OpCtrlM), .FmaSCnt(SCntM), .FmaSe(SeM),
.CvtCe(CeM), .CvtResDenormUf(CvtResDenormUfM),.CvtShiftAmt(CvtShiftAmtM), .CvtCs(CsM), .ToInt(FWriteIntM), .DivS(DivSM),
.CvtLzcIn(CvtLzcInM), .IntZero(IntZeroM), .PostProcSel(PostProcSelM), .PostProcRes(PostProcResM), .PostProcFlg(PostProcFlgM), .FCvtIntRes(FCvtIntResM));
// FPU flag selection - to privileged
@ -394,9 +377,6 @@ module fpu (
// M/W pipe registers
flopenrc #(`FLEN) MWRegFp(clk, reset, FlushW, ~StallW, FpResM, FpResW);
flopenrc #(`XLEN) MWRegInt(clk, reset, FlushW, ~StallW, FCvtIntResM, FCvtIntResW);
flopenrc #(4+int'(`FMTBITS-1)) MWCtrlReg(clk, reset, FlushW, ~StallW,
{FRegWriteM, FResSelM, FmtM},
{FRegWriteW, FResSelW, FmtW});
// BEGIN WRITEBACK STAGE

View file

@ -26,60 +26,59 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////
`include "wally-config.vh"
module fsgninj (
input logic XSgnE, YSgnE, // X and Y sign bits
input logic [`FLEN-1:0] FSrcXE, // X
input logic [`FMTBITS-1:0] FmtE, // precision 1 = double 0 = single
input logic [1:0] SgnOpCodeE, // operation control
output logic [`FLEN-1:0] SgnResE // result
input logic Xs, Ys, // X and Y sign bits
input logic [`FLEN-1:0] X, // X
input logic [`FMTBITS-1:0] Fmt, // format
input logic [1:0] OpCtrl, // operation control
output logic [`FLEN-1:0] SgnRes // result
);
logic ResSgn;
//op code designation:
//
//00 - fsgnj - directly copy over sign value of FSrcYE
//01 - fsgnjn - negate sign value of FSrcYE
//10 - fsgnjx - XOR sign values of FSrcXE & FSrcYE
//
// OpCtrl:
// 00 - fsgnj - directly copy over sign value of Y
// 01 - fsgnjn - negate sign value of Y
// 10 - fsgnjx - XOR sign values of X and Y
// calculate the result's sign
assign ResSgn = (SgnOpCodeE[1] ? XSgnE : SgnOpCodeE[0]) ^ YSgnE;
assign ResSgn = (OpCtrl[1] ? Xs : OpCtrl[0]) ^ Ys;
// format final result based on precision
// - uses NaN-blocking format
// - if there are any unsused bits the most significant bits are filled with 1s
if (`FPSIZES == 1)
assign SgnResE = {ResSgn, FSrcXE[`FLEN-2:0]};
assign SgnRes = {ResSgn, X[`FLEN-2:0]};
else if (`FPSIZES == 2)
assign SgnResE = {~FmtE|ResSgn, FSrcXE[`FLEN-2:`LEN1], FmtE ? FSrcXE[`LEN1-1] : ResSgn, FSrcXE[`LEN1-2:0]};
assign SgnRes = {~Fmt|ResSgn, X[`FLEN-2:`LEN1], Fmt ? X[`LEN1-1] : ResSgn, X[`LEN1-2:0]};
else if (`FPSIZES == 3) begin
logic [2:0] SgnBits;
always_comb
case (FmtE)
`FMT: SgnBits = {ResSgn, FSrcXE[`LEN1-1], FSrcXE[`LEN2-1]};
`FMT1: SgnBits = {1'b1, ResSgn, FSrcXE[`LEN2-1]};
case (Fmt)
`FMT: SgnBits = {ResSgn, X[`LEN1-1], X[`LEN2-1]};
`FMT1: SgnBits = {1'b1, ResSgn, X[`LEN2-1]};
`FMT2: SgnBits = {2'b11, ResSgn};
default: SgnBits = {3{1'bx}};
endcase
assign SgnResE = {SgnBits[2], FSrcXE[`FLEN-2:`LEN1], SgnBits[1], FSrcXE[`LEN1-2:`LEN2], SgnBits[0], FSrcXE[`LEN2-2:0]};
assign SgnRes = {SgnBits[2], X[`FLEN-2:`LEN1], SgnBits[1], X[`LEN1-2:`LEN2], SgnBits[0], X[`LEN2-2:0]};
end else if (`FPSIZES == 4) begin
logic [3:0] SgnBits;
always_comb
case (FmtE)
`Q_FMT: SgnBits = {ResSgn, FSrcXE[`D_LEN-1], FSrcXE[`S_LEN-1], FSrcXE[`H_LEN-1]};
`D_FMT: SgnBits = {1'b1, ResSgn, FSrcXE[`S_LEN-1], FSrcXE[`H_LEN-1]};
`S_FMT: SgnBits = {2'b11, ResSgn, FSrcXE[`H_LEN-1]};
case (Fmt)
`Q_FMT: SgnBits = {ResSgn, X[`D_LEN-1], X[`S_LEN-1], X[`H_LEN-1]};
`D_FMT: SgnBits = {1'b1, ResSgn, X[`S_LEN-1], X[`H_LEN-1]};
`S_FMT: SgnBits = {2'b11, ResSgn, X[`H_LEN-1]};
`H_FMT: SgnBits = {3'b111, ResSgn};
endcase
assign SgnResE = {SgnBits[3], FSrcXE[`Q_LEN-2:`D_LEN], SgnBits[2], FSrcXE[`D_LEN-2:`S_LEN], SgnBits[1], FSrcXE[`S_LEN-2:`H_LEN], SgnBits[0], FSrcXE[`H_LEN-2:0]};
assign SgnRes = {SgnBits[3], X[`Q_LEN-2:`D_LEN], SgnBits[2], X[`D_LEN-2:`S_LEN], SgnBits[1], X[`S_LEN-2:`H_LEN], SgnBits[0], X[`H_LEN-2:0]};
end
endmodule

View file

@ -42,7 +42,12 @@ module negateintres(
// round and negate the positive res if needed
assign CvtNegRes = Xs ? -({2'b0, Shifted[`NORMSHIFTSZ-1:`NORMSHIFTSZ-`XLEN]}+{{`XLEN+1{1'b0}}, Plus1}) : {2'b0, Shifted[`NORMSHIFTSZ-1:`NORMSHIFTSZ-`XLEN]}+{{`XLEN+1{1'b0}}, Plus1};
assign CvtNegResMsbs = Signed ? Int64 ? CvtNegRes[`XLEN:`XLEN-1] : CvtNegRes[32:31] :
Int64 ? CvtNegRes[`XLEN+1:`XLEN] : CvtNegRes[33:32];
always_comb
if(Signed)
if(Int64) CvtNegResMsbs = CvtNegRes[`XLEN:`XLEN-1];
else CvtNegResMsbs = CvtNegRes[32:31];
else
if(Int64) CvtNegResMsbs = CvtNegRes[`XLEN+1:`XLEN];
else CvtNegResMsbs = CvtNegRes[33:32];
endmodule

View file

@ -58,6 +58,41 @@ module otfc2 (
endmodule
///////////////////////////////
// Square Root OTFC, Radix 2 //
///////////////////////////////
module sotfc2(
input logic clk,
input logic Start,
input logic sp, sn,
input logic Sqrt,
input logic [`DIVLEN+3:0] C,
output logic [`DIVLEN-2:0] Sq,
output logic [`DIVLEN+3:0] S, SM
);
// The on-the-fly converter transfers the square root
// bits to the quotient as they come.
// Use this otfc for division and square root.
logic [`DIVLEN+3:0] SNext, SMNext, SMux;
flopr #(`DIVLEN+4) SMreg(clk, Start, SMNext, SM);
mux2 #(`DIVLEN+4) Smux(SNext, {3'b000, Sqrt, {(`DIVLEN){1'b0}}}, Start, SMux);
flop #(`DIVLEN+4) Sreg(clk, SMux, S);
always_comb begin
if (sp) begin
SNext = S | (C & ~(C << 1));
SMNext = S;
end else if (sn) begin
SNext = SM | (C & ~(C << 1));
SMNext = SM;
end else begin // If sp and sn are not true, then sz is
SNext = S;
SMNext = SM | (C & ~(C << 1));
end
end
assign Sq = S[`DIVLEN] ? S[`DIVLEN-1:1] : S[`DIVLEN-2:0];
endmodule
module otfc4 (
input logic [3:0] q,
@ -107,6 +142,41 @@ module otfc4 (
QMNext = {QMR, 2'b11};
end
end
// Final Quoteint is in the range [.5, 2)
// Final Qmeint is in the range [.5, 2)
endmodule
///////////////////////////////
// Square Root OTFC, Radix 4 //
///////////////////////////////
module sotfc4(
input logic [3:0] s,
input logic Sqrt,
input logic [`DIVLEN+3:0] S, SM,
input logic [`DIVLEN+3:0] C,
output logic [`DIVLEN+3:0] SNext, SMNext
);
// The on-the-fly converter transfers the square root
// bits to the quotient as they come.
// Use this otfc for division and square root.
always_comb begin
if (s[3]) begin
SNext = S | ((C << 1)&~(C << 2));
SMNext = S | (C&~(C << 1));
end else if (s[2]) begin
SNext = S | (C&~(C << 1));
SMNext = S;
end else if (s[1]) begin
SNext = SM | (C&~(C << 2));
SMNext = SM | ((C << 1)&~(C << 2));
end else if (s[0]) begin
SNext = SM | ((C << 1)&~(C << 2));
SMNext = SM | (C&~(C << 1));
end else begin // If sp and sn are not true, then sz is
SNext = S;
SMNext = SM | (C & ~(C << 2));
end
end
endmodule

View file

@ -36,7 +36,7 @@ module postprocess (
input logic [`NF:0] Xm, Ym, Zm, // input mantissas
input logic [2:0] Frm, // rounding mode 000 = rount to nearest, ties to even 001 = round twords zero 010 = round down 011 = round up 100 = round to nearest, ties to max magnitude
input logic [`FMTBITS-1:0] Fmt, // precision 1 = double 0 = single
input logic [2:0] FOpCtrl, // choose which opperation (look below for values)
input logic [2:0] OpCtrl, // choose which opperation (look below for values)
input logic XZero, YZero, ZZero, // inputs are zero
input logic XInf, YInf, ZInf, // inputs are infinity
input logic XNaN, YNaN, ZNaN, // inputs are NaN
@ -46,13 +46,15 @@ module postprocess (
//fma signals
input logic FmaAs, // the modified Z sign - depends on instruction
input logic FmaPs, // the product's sign
input logic [`NE+1:0] FmaSe,
input logic [`NE+1:0] FmaPe, // Product exponent
input logic [3*`NF+5:0] FmaSm, // the positive sum
input logic FmaZmS, // sticky bit that is calculated during alignment
input logic FmaKillProd, // set the product to zero before addition if the product is too small to matter
input logic FmaNegSum, // was the sum negitive
input logic FmaInvA, // do you invert Z
input logic [$clog2(3*`NF+7)-1:0] FmaNCnt, // the normalization shift count
input logic FmaSs,
input logic [$clog2(3*`NF+7)-1:0] FmaSCnt, // the normalization shift count
//divide signals
input logic [`DURLEN-1:0] DivEarlyTermShift,
input logic DivS,
@ -92,10 +94,10 @@ module postprocess (
logic UfL;
logic [`FMTBITS-1:0] OutFmt;
// fma signals
logic [`NE+1:0] FmaSe; // exponent of the normalized sum
logic [`NE+1:0] FmaMe; // exponent of the normalized sum
logic FmaSZero; // is the sum zero
logic [3*`NF+8:0] FmaShiftIn; // shift input
logic [`NE+1:0] FmaNe; // exponent of the normalized sum not taking into account denormal or zero results
logic [`NE+1:0] NormSumExp; // exponent of the normalized sum not taking into account denormal or zero results
logic FmaPreResultDenorm; // is the result denormalized - calculated before LZA corection
logic [$clog2(3*`NF+7)-1:0] FmaShiftAmt; // normalization shift count
// division singals
@ -123,26 +125,26 @@ module postprocess (
logic Sqrt;
// signals to help readability
assign Signed = FOpCtrl[0];
assign Int64 = FOpCtrl[1];
assign IntToFp = FOpCtrl[2];
assign Mult = FOpCtrl[2]&~FOpCtrl[1]&~FOpCtrl[0];
assign Signed = OpCtrl[0];
assign Int64 = OpCtrl[1];
assign IntToFp = OpCtrl[2];
assign Mult = OpCtrl[2]&~OpCtrl[1]&~OpCtrl[0];
assign CvtOp = (PostProcSel == 2'b00);
assign FmaOp = (PostProcSel == 2'b10);
assign DivOp = (PostProcSel == 2'b01)&DivDone;
assign Sqrt = FOpCtrl[0];
assign Sqrt = OpCtrl[0];
// is there an input of infinity or NaN being used
assign InfIn = (XInf&~(IntToFp&CvtOp))|(YInf&~CvtOp)|(ZInf&FmaOp);
assign NaNIn = (XNaN&~(IntToFp&CvtOp))|(YNaN&~CvtOp)|(ZNaN&FmaOp);
assign InfIn = XInf|YInf|ZInf;
assign NaNIn = XNaN|YNaN|ZNaN;
// choose the ouptut format depending on the opperation
// - fp -> fp: OpCtrl contains the percision of the output
// - otherwise: Fmt contains the percision of the output
if (`FPSIZES == 2)
assign OutFmt = IntToFp|~CvtOp ? Fmt : (FOpCtrl[1:0] == `FMT);
assign OutFmt = IntToFp|~CvtOp ? Fmt : (OpCtrl[1:0] == `FMT);
else if (`FPSIZES == 3 | `FPSIZES == 4)
assign OutFmt = IntToFp|~CvtOp ? Fmt : FOpCtrl[1:0];
assign OutFmt = IntToFp|~CvtOp ? Fmt : OpCtrl[1:0];
///////////////////////////////////////////////////////////////////////////////
// Normalization
@ -150,7 +152,7 @@ module postprocess (
cvtshiftcalc cvtshiftcalc(.ToInt, .CvtCe, .CvtResDenormUf, .Xm, .CvtLzcIn,
.XZero, .IntToFp, .OutFmt, .CvtResUf, .CvtShiftIn);
fmashiftcalc fmashiftcalc(.FmaSm, .Ze, .FmaPe, .FmaNCnt, .Fmt, .FmaKillProd, .FmaNe,
fmashiftcalc fmashiftcalc(.FmaSm, .Ze, .FmaPe, .FmaSCnt, .Fmt, .FmaKillProd, .NormSumExp, .FmaSe,
.FmaSZero, .FmaPreResultDenorm, .FmaShiftAmt, .FmaShiftIn);
divshiftcalc divshiftcalc(.Fmt, .DivQe, .DivQm, .DivEarlyTermShift, .DivResDenorm, .DivDenormShift, .DivShiftAmt, .DivShiftIn);
@ -181,9 +183,9 @@ module postprocess (
normshift normshift (.ShiftIn, .ShiftAmt, .Shifted);
shiftcorrection shiftcorrection(.FmaOp, .FmaPreResultDenorm, .FmaNe,
shiftcorrection shiftcorrection(.FmaOp, .FmaPreResultDenorm, .NormSumExp,
.DivResDenorm, .DivDenormShift, .DivOp, .DivQe,
.Qe, .FmaSZero, .Shifted, .FmaSe, .Mf);
.Qe, .FmaSZero, .Shifted, .FmaMe, .Mf);
///////////////////////////////////////////////////////////////////////////////
// Rounding
@ -197,10 +199,10 @@ module postprocess (
roundsign roundsign(.FmaPs, .FmaAs, .FmaInvA, .FmaOp, .DivOp, .CvtOp, .FmaNegSum,
.Xs, .Ys, .CvtCs, .Ms);
.FmaSs, .Xs, .Ys, .CvtCs, .Ms);
round round(.OutFmt, .Frm, .S, .FmaZmS, .Plus1, .PostProcSel, .CvtCe, .Qe,
.Ms, .FmaSe, .FmaOp, .CvtOp, .CvtResDenormUf, .Mf, .ToInt, .CvtResUf,
.Ms, .FmaMe, .FmaOp, .CvtOp, .CvtResDenormUf, .Mf, .ToInt, .CvtResUf,
.DivS, .DivDone,
.DivOp, .UfPlus1, .FullRe, .Rf, .Re, .R, .UfL, .Me);
@ -208,7 +210,7 @@ module postprocess (
// Sign calculation
///////////////////////////////////////////////////////////////////////////////
resultsign resultsign(.Frm, .FmaPs, .FmaAs, .FmaSe, .R, .S,
resultsign resultsign(.Frm, .FmaPs, .FmaAs, .FmaMe, .R, .S,
.FmaOp, .ZInf, .InfIn, .FmaSZero, .Mult, .Ms, .Ws);
///////////////////////////////////////////////////////////////////////////////
@ -217,7 +219,7 @@ module postprocess (
flags flags(.XSNaN, .YSNaN, .ZSNaN, .XInf, .YInf, .ZInf, .InfIn, .XZero, .YZero,
.Xs, .Sqrt, .ToInt, .IntToFp, .Int64, .Signed, .OutFmt, .CvtCe,
.XNaN, .YNaN, .NaNIn, .FmaAs, .FmaPs, .R, .IntInvalid, .DivByZero,
.NaNIn, .FmaAs, .FmaPs, .R, .IntInvalid, .DivByZero,
.UfL, .S, .UfPlus1, .CvtOp, .DivOp, .FmaOp, .FullRe, .Plus1,
.Me, .CvtNegResMsbs, .Invalid, .Overflow, .PostProcFlg);

View file

@ -42,7 +42,7 @@ module qsel2 ( // *** eventually just change to 4 bits
// for efficiency. You can probably optimize your logic to
// select the proper divisor with less delay.
// Quotient equations from EE371 lecture notes 13-20
// Qmient equations from EE371 lecture notes 13-20
assign p = ps ^ pc;
assign g = ps & pc;
@ -62,9 +62,36 @@ module qsel2 ( // *** eventually just change to 4 bits
// assign #1 qn = magnitude & sign;
endmodule
////////////////////////////////////
// Adder Input Generation, Radix 2 //
////////////////////////////////////
module fgen2 (
input logic sp, sn,
input logic [`DIVLEN+3:0] C, S, SM,
output logic [`DIVLEN+3:0] F
);
logic [`DIVLEN+3:0] FP, FN, FZ;
// Generate for both positive and negative bits
assign FP = ~(S << 1) & C;
assign FN = (SM << 1) | (C & (~C << 2));
assign FZ = '0;
// Choose which adder input will be used
always_comb
if (sp) F = FP;
else if (sn) F = FN;
else F = FZ;
// assign F = sp ? FP : (sn ? FN : FZ);
endmodule
module qsel4 (
input logic [`DIVLEN+3:0] D,
input logic [`DIVLEN+3:0] WS, WC,
input logic Sqrt,
output logic [3:0] q
);
logic [6:0] Wmsbs;
@ -91,45 +118,77 @@ module qsel4 (
else if(w2>=4) QSel4[i] = 4'b0100;
else if(w2>=-4) QSel4[i] = 4'b0000;
else if(w2>=-13) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else QSel4[i] = 4'b0001;
1: if(w2>=14) QSel4[i] = 4'b1000;
else if(w2>=4) QSel4[i] = 4'b0100;
else if(w2>=-6) QSel4[i] = 4'b0000;
else if(w2>=-15) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else if(w2>=-5) QSel4[i] = 4'b0000; // was -6
else if(~Sqrt&(w2>=-15)) QSel4[i] = 4'b0010; // divide case
else if( Sqrt&(w2>=-14)) QSel4[i] = 4'b0010; // sqrt case
else QSel4[i] = 4'b0001;
2: if(w2>=15) QSel4[i] = 4'b1000;
else if(w2>=4) QSel4[i] = 4'b0100;
else if(w2>=-6) QSel4[i] = 4'b0000;
else if(w2>=-16) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else QSel4[i] = 4'b0001;
3: if(w2>=16) QSel4[i] = 4'b1000;
else if(w2>=4) QSel4[i] = 4'b0100;
else if(w2>=-6) QSel4[i] = 4'b0000;
else if(w2>=-18) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else if(w2>=-17) QSel4[i] = 4'b0010; // was -18
else QSel4[i] = 4'b0001;
4: if(w2>=18) QSel4[i] = 4'b1000;
else if(w2>=6) QSel4[i] = 4'b0100;
else if(w2>=-8) QSel4[i] = 4'b0000;
else if(w2>=-20) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else if(w2>=-6) QSel4[i] = 4'b0000; // was -8
else if(~Sqrt&(w2>=-20)) QSel4[i] = 4'b0010; // divide case
else if( Sqrt&(w2>=-18)) QSel4[i] = 4'b0010; // sqrt case
else QSel4[i] = 4'b0001;
5: if(w2>=20) QSel4[i] = 4'b1000;
else if(w2>=6) QSel4[i] = 4'b0100;
else if(w2>=-8) QSel4[i] = 4'b0000;
else if(w2>=-20) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else QSel4[i] = 4'b0001;
6: if(w2>=20) QSel4[i] = 4'b1000;
else if(w2>=8) QSel4[i] = 4'b0100;
else if(w2>=-8) QSel4[i] = 4'b0000;
else if(w2>=-22) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
7: if(w2>=24) QSel4[i] = 4'b1000;
else QSel4[i] = 4'b0001;
7: if(w2>=22) QSel4[i] = 4'b1000; // was 24
else if(w2>=8) QSel4[i] = 4'b0100;
else if(w2>=-8) QSel4[i] = 4'b0000;
else if(w2>=-24) QSel4[i] = 4'b0010;
else QSel4[i] = 4'b0001;
else if(w2>=-23) QSel4[i] = 4'b0010; // was -24
else QSel4[i] = 4'b0001;
endcase
end
end
assign q = QSel4[{Dmsbs,Wmsbs}];
endmodule
////////////////////////////////////
// Adder Input Generation, Radix 4 //
////////////////////////////////////
module fgen4 (
input logic [3:0] s,
input logic [`DIVLEN+3:0] C, S, SM,
output logic [`DIVLEN+3:0] F
);
logic [`DIVLEN+3:0] F2, F1, F0, FN1, FN2;
// Generate for both positive and negative bits
assign F2 = (~S << 2) & (C << 2);
assign F1 = ~(S << 1) & C;
assign F0 = '0;
assign FN1 = (SM << 1) | (C & ~(C << 2));
assign FN2 = (SM << 2) | ((C << 2)&~(C <<4));
// Choose which adder input will be used
always_comb
if (s[3]) F = F2;
else if (s[2]) F = F1;
else if (s[1]) F = FN1;
else if (s[0]) F = FN2;
else F = F0;
// assign F = sp ? FP : (sn ? FN : FZ);
endmodule

View file

@ -34,7 +34,7 @@ module resultsign(
input logic ZInf,
input logic InfIn,
input logic FmaOp,
input logic [`NE+1:0] FmaSe,
input logic [`NE+1:0] FmaMe,
input logic FmaSZero,
input logic Mult,
input logic R,
@ -46,11 +46,21 @@ module resultsign(
logic Zeros;
logic Infs;
// Determine the sign if the sum is zero
// if cancelation then 0 unless round to -infinity
// if multiply then Psgn
// otherwise psign
assign Zeros = (FmaPs^FmaAs)&~(FmaSe[`NE+1] | ((FmaSe == 0) & (R|S)))&~Mult ? Frm[1:0] == 2'b10 : FmaPs;
// The IEEE754-2019 standard specifies:
// - the sign of an exact zero sum (with operands of diffrent signs) should be positive unless rounding toward negitive infinity
// - when the exact result of an FMA opperation is non-zero, but is zero due to rounding, use the sign of the exact result
// - if x = +0 or -0 then x+x=x and x-(-x)=x
// - the sign of a product is the exclisive or or the opperand's signs
// Zero sign will only be selected if:
// - P=Z and a cancelation occurs - exact zero
// - Z is zero and P is zero - exact zero
// - P is killed and Z is zero - Psgn
// - Z is killed and P is zero - impossible
// Zero sign calculation:
// - if a multiply opperation is done, then use the products sign(Ps)
// - if the zero sum is not exactly zero i.e. R|S use the sign of the exact result (which is the product's sign)
// - if an effective addition occurs (P+A or -P+-A or P--A) then use the product's sign
assign Zeros = (FmaPs^FmaAs)&~(R|S)&~Mult ? Frm[1:0] == 2'b10 : FmaPs;
// is the result negitive
@ -58,6 +68,9 @@ module resultsign(
// if -p + z is the Sum positive
// if -p - z then the Sum is negitive
assign Infs = ZInf ? FmaAs : FmaPs;
assign Ws = InfIn&FmaOp ? Infs : FmaSZero&FmaOp ? Zeros : Ms;
always_comb
if(InfIn&FmaOp) Ws = Infs;
else if(FmaSZero&FmaOp) Ws = Zeros;
else Ws = Ms;
endmodule

View file

@ -48,7 +48,7 @@ module round(
input logic CvtResUf,
input logic [`CORRSHIFTSZ-1:0] Mf,
input logic FmaZmS, // addend's sticky bit
input logic [`NE+1:0] FmaSe, // exponent of the normalized sum
input logic [`NE+1:0] FmaMe, // exponent of the normalized sum
input logic Ms, // the result's sign
input logic [`NE:0] CvtCe, // the calculated expoent
input logic [`NE+1:0] Qe, // the calculated expoent
@ -176,7 +176,7 @@ module round(
// only add the Addend sticky if doing an FMA opperation
// - the shifter shifts too far left when there's an underflow (shifting out all possible sticky bits)
assign UfS = FmaZmS&FmaOp | NormS | CvtResUf&CvtOp | FmaSe[`NE+1]&FmaOp | DivS&DivOp;
assign UfS = FmaZmS&FmaOp | NormS | CvtResUf&CvtOp | FmaMe[`NE+1]&FmaOp | DivS&DivOp;
// determine round and LSB of the rounded value
// - underflow round bit is used to determint the underflow flag
@ -299,7 +299,7 @@ module round(
always_comb
case(PostProcSel)
2'b10: Me = FmaSe; // fma
2'b10: Me = FmaMe; // fma
2'b00: Me = {CvtCe[`NE], CvtCe}&{`NE+2{~CvtResDenormUf|CvtResUf}}; // cvt
2'b01: Me = DivDone ? Qe : '0; // divide
default: Me = '0;

View file

@ -38,23 +38,15 @@ module roundsign(
input logic DivOp,
input logic CvtOp,
input logic CvtCs,
input logic FmaSs,
output logic Ms
);
logic FmaResSgnTmp;
logic Qs;
// is the result negitive
// if p - z is the Sum negitive
// if -p + z is the Sum positive
// if -p - z then the Sum is negitive
assign FmaResSgnTmp = FmaNegSum^FmaPs; //*** move to execute stage
// assign FmaResSgnTmp = FmaInvA&(FmaAs)&FmaNegSum | FmaInvA&FmaPs&~FmaNegSum | (FmaAs&FmaPs);
assign Qs = Xs^Ys;
// Sign for rounding calulation
assign Ms = (FmaResSgnTmp&FmaOp) | (CvtCs&CvtOp) | (Qs&DivOp);
assign Ms = (FmaSs&FmaOp) | (CvtCs&CvtOp) | (Qs&DivOp);
endmodule

View file

@ -35,15 +35,15 @@ module shiftcorrection(
input logic DivResDenorm,
input logic [`NE+1:0] DivQe,
input logic [`NE+1:0] DivDenormShift,
input logic [`NE+1:0] FmaNe, // exponent of the normalized sum not taking into account denormal or zero results
input logic [`NE+1:0] NormSumExp, // exponent of the normalized sum not taking into account denormal or zero results
input logic FmaPreResultDenorm, // is the result denormalized - calculated before LZA corection
input logic FmaSZero,
output logic [`CORRSHIFTSZ-1:0] Mf, // the shifted sum before LZA correction
output logic [`NE+1:0] Qe,
output logic [`NE+1:0] FmaSe // exponent of the normalized sum
output logic [`NE+1:0] FmaMe // exponent of the normalized sum
);
logic [3*`NF+5:0] CorrSumShifted; // the shifted sum after LZA correction
logic [`CORRSHIFTSZ-1:0] CorrQuotShifted;
logic [`CORRSHIFTSZ-1:0] CorrQmShifted;
logic ResDenorm; // is the result denormalized
logic LZAPlus1, LZAPlus2; // add one or two to the sum's exponent due to LZA correction
@ -53,12 +53,15 @@ module shiftcorrection(
// the only possible mantissa for a plus two is all zeroes - a one has to propigate all the way through a sum. so we can leave the bottom statement alone
assign CorrSumShifted = LZAPlus1 ? Shifted[`NORMSHIFTSZ-3:1] : Shifted[`NORMSHIFTSZ-4:0];
// if the msb is 1 or the exponent was one, but the shifted quotent was < 1 (Denorm)
assign CorrQuotShifted = (LZAPlus2|(DivQe==1&~LZAPlus2)) ? Shifted[`NORMSHIFTSZ-2:`NORMSHIFTSZ-`CORRSHIFTSZ-1] : Shifted[`NORMSHIFTSZ-3:`NORMSHIFTSZ-`CORRSHIFTSZ-2];
assign CorrQmShifted = (LZAPlus2|(DivQe==1&~LZAPlus2)) ? Shifted[`NORMSHIFTSZ-2:`NORMSHIFTSZ-`CORRSHIFTSZ-1] : Shifted[`NORMSHIFTSZ-3:`NORMSHIFTSZ-`CORRSHIFTSZ-2];
// if the result of the divider was calculated to be denormalized, then the result was correctly normalized, so select the top shifted bits
assign Mf = FmaOp ? {CorrSumShifted, {`CORRSHIFTSZ-(3*`NF+6){1'b0}}} : DivOp&~DivResDenorm ? CorrQuotShifted : Shifted[`NORMSHIFTSZ-1:`NORMSHIFTSZ-`CORRSHIFTSZ];
always_comb
if(FmaOp) Mf = {CorrSumShifted, {`CORRSHIFTSZ-(3*`NF+6){1'b0}}};
else if (DivOp&~DivResDenorm) Mf = CorrQmShifted;
else Mf = Shifted[`NORMSHIFTSZ-1:`NORMSHIFTSZ-`CORRSHIFTSZ];
// Determine sum's exponent
// if plus1 If plus2 if said denorm but norm plus 1 if said denorm but norm plus 2
assign FmaSe = (FmaNe+{{`NE+1{1'b0}}, LZAPlus1}+{{`NE{1'b0}}, LZAPlus2, 1'b0}+{{`NE+1{1'b0}}, ~ResDenorm&FmaPreResultDenorm}+{{`NE+1{1'b0}}, &FmaNe&Shifted[3*`NF+6]}) & {`NE+2{~(FmaSZero|ResDenorm)}};
assign FmaMe = (NormSumExp+{{`NE+1{1'b0}}, LZAPlus1}+{{`NE{1'b0}}, LZAPlus2, 1'b0}+{{`NE+1{1'b0}}, ~ResDenorm&FmaPreResultDenorm}+{{`NE+1{1'b0}}, &NormSumExp&Shifted[3*`NF+6]}) & {`NE+2{~(FmaSZero|ResDenorm)}};
// recalculate if the result is denormalized
assign ResDenorm = FmaPreResultDenorm&~Shifted[`NORMSHIFTSZ-3]&~Shifted[`NORMSHIFTSZ-2];

View file

@ -95,9 +95,14 @@ module specialcase(
end else begin
assign InvalidRes = OutFmt ? {1'b0, {`NE{1'b1}}, 1'b1, {`NF-1{1'b0}}} : {{`FLEN-`LEN1{1'b1}}, 1'b0, {`NE1{1'b1}}, 1'b1, (`NF1-1)'(0)};
end
assign OfRes = OutFmt ? OfResMax ? {Ws, {`NE-1{1'b1}}, 1'b0, {`NF{1'b1}}} : {Ws, {`NE{1'b1}}, {`NF{1'b0}}} :
OfResMax ? {{`FLEN-`LEN1{1'b1}}, Ws, {`NE1-1{1'b1}}, 1'b0, {`NF1{1'b1}}} : {{`FLEN-`LEN1{1'b1}}, Ws, {`NE1{1'b1}}, (`NF1)'(0)};
always_comb
if(OutFmt)
if(OfResMax) OfRes = {Ws, {`NE-1{1'b1}}, 1'b0, {`NF{1'b1}}};
else OfRes = {Ws, {`NE{1'b1}}, {`NF{1'b0}}};
else
if(OfResMax) OfRes = {{`FLEN-`LEN1{1'b1}}, Ws, {`NE1-1{1'b1}}, 1'b0, {`NF1{1'b1}}};
else OfRes = {{`FLEN-`LEN1{1'b1}}, Ws, {`NE1{1'b1}}, (`NF1)'(0)};
assign UfRes = OutFmt ? {Ws, (`FLEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)} : {{`FLEN-`LEN1{1'b1}}, Ws, (`LEN1-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
assign NormRes = OutFmt ? {Ws, Re, Rf} : {{`FLEN-`LEN1{1'b1}}, Ws, Re[`NE1-1:0], Rf[`NF-1:`NF-`NF1]};
@ -234,20 +239,21 @@ module specialcase(
assign KillRes = CvtOp ? (CvtResUf|(XZero&~IntToFp)|(IntZero&IntToFp)) : FullRe[`NE+1] | (((YInf&~XInf)|XZero)&DivOp);//Underflow & ~ResDenorm & (Re!=1);
assign SelOfRes = Overflow|DivByZero|(InfIn&~(YInf&DivOp));
// output infinity with result sign if divide by zero
if(`IEEE754) begin
assign PostProcRes = XNaN&~(IntToFp&CvtOp) ? XNaNRes :
YNaN&~CvtOp ? YNaNRes :
ZNaN&FmaOp ? ZNaNRes :
Invalid ? InvalidRes :
SelOfRes ? OfRes :
KillRes ? UfRes :
NormRes;
end else begin
assign PostProcRes = NaNIn|Invalid ? InvalidRes :
SelOfRes ? OfRes :
KillRes ? UfRes :
NormRes;
end
if(`IEEE754)
always_comb
if(XNaN&~(IntToFp&CvtOp)) PostProcRes = XNaNRes;
else if(YNaN&~CvtOp) PostProcRes = YNaNRes;
else if(ZNaN&FmaOp) PostProcRes = ZNaNRes;
else if(Invalid) PostProcRes = InvalidRes;
else if(SelOfRes) PostProcRes = OfRes;
else if(KillRes) PostProcRes = UfRes;
else PostProcRes = NormRes;
else
always_comb
if(NaNIn|Invalid) PostProcRes = InvalidRes;
else if(SelOfRes) PostProcRes = OfRes;
else if(KillRes) PostProcRes = UfRes;
else PostProcRes = NormRes;
///////////////////////////////////////////////////////////////////////////////////////
//
@ -272,10 +278,17 @@ module specialcase(
// unsigned | 2^32-1 | 2^64-1 |
//
// other: 32 bit unsinged res should be sign extended as if it were a signed number
assign OfIntRes = Signed ? Xs&~XNaN ? Int64 ? {1'b1, {`XLEN-1{1'b0}}} : {{`XLEN-32{1'b1}}, 1'b1, {31{1'b0}}} : // signed negitive
Int64 ? {1'b0, {`XLEN-1{1'b1}}} : {{`XLEN-32{1'b0}}, 1'b0, {31{1'b1}}} : // signed positive
Xs&~XNaN ? {`XLEN{1'b0}} : // unsigned negitive
{`XLEN{1'b1}};// unsigned positive
always_comb
if(Signed)
if(Xs&~NaNIn) // signed negitive
if(Int64) OfIntRes = {1'b1, {`XLEN-1{1'b0}}};
else OfIntRes = {{`XLEN-32{1'b1}}, 1'b1, {31{1'b0}}};
else // signed positive
if(Int64) OfIntRes = {1'b0, {`XLEN-1{1'b1}}};
else OfIntRes = {{`XLEN-32{1'b0}}, 1'b0, {31{1'b1}}};
else
if(Xs&~NaNIn) OfIntRes = {`XLEN{1'b0}}; // unsigned negitive
else OfIntRes = {`XLEN{1'b1}}; // unsigned positive
// select the integer output
@ -284,7 +297,11 @@ module specialcase(
// - if rounding and signed opperation and negitive input, output -1
// - otherwise output a rounded 0
// - otherwise output the normal res (trmined and sign extended if nessisary)
assign FCvtIntRes = IntInvalid ? OfIntRes :
CvtCe[`NE] ? Xs&Signed&Plus1 ? {{`XLEN{1'b1}}} : {{`XLEN-1{1'b0}}, Plus1} : //CalcExp has to come after invalid ***swap to actual mux at some point??
Int64 ? CvtNegRes[`XLEN-1:0] : {{`XLEN-32{CvtNegRes[31]}}, CvtNegRes[31:0]};
always_comb
if(IntInvalid) FCvtIntRes = OfIntRes;
else if(CvtCe[`NE])
if(Xs&Signed&Plus1) FCvtIntRes = {{`XLEN{1'b1}}};
else FCvtIntRes = {{`XLEN-1{1'b0}}, Plus1};
else if(Int64) FCvtIntRes = CvtNegRes[`XLEN-1:0];
else FCvtIntRes = {{`XLEN-32{CvtNegRes[31]}}, CvtNegRes[31:0]};
endmodule

View file

@ -34,18 +34,17 @@ module srt(
input logic clk,
input logic DivStart,
input logic DivBusy,
input logic [`FMTBITS-1:0] FmtE,
input logic [`NE-1:0] Xe, Ye,
input logic XZeroE, YZeroE,
input logic [`DIVLEN-1:0] X,
input logic [`DIVLEN-1:0] Dpreproc,
input logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt,
input logic NegSticky,
output logic [`QLEN-1-(`RADIX/4):0] Quot,
input logic Sqrt,
input logic [`DIVLEN+3:0] X,
input logic [`DIVLEN+3:0] Dpreproc,
input logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt,
input logic NegSticky,
output logic [`QLEN-1-(`RADIX/4):0] Qm,
output logic [`DIVLEN+3:0] NextWSN, NextWCN,
output logic [`DIVLEN+3:0] StickyWSA,
output logic [`DIVLEN+3:0] FirstWS, FirstWC,
output logic [`NE+1:0] DivCalcExpM,
output logic [`XLEN-1:0] Rem
);
@ -59,13 +58,19 @@ module srt(
logic [`QLEN-1:0] QM[`DIVCOPIES-1:0];
logic [`QLEN-1:0] QNext[`DIVCOPIES-1:0];
logic [`QLEN-1:0] QMNext[`DIVCOPIES-1:0];
logic [`DIVLEN+3:0] S[`DIVCOPIES-1:0]; //***change to QLEN???
logic [`DIVLEN+3:0] SM[`DIVCOPIES-1:0];
logic [`DIVLEN+3:0] SNext[`DIVCOPIES-1:0];
logic [`DIVLEN+3:0] SMNext[`DIVCOPIES-1:0];
logic [`DIVLEN+3:0] C[`DIVCOPIES-1:0];
/* verilator lint_on UNOPTFLAT */
logic [`DIVLEN+3:0] WSN, WCN;
logic [`DIVLEN+3:0] D, DBar, D2, DBar2;
logic [`NE+1:0] DivCalcExp;
logic [$clog2(`XLEN+1)-1:0] intExp;
logic intSign;
logic [`QLEN-1:0] QMMux;
logic [`DIVLEN+3:0] CMux;
logic [`DIVLEN+3:0] SMux;
// Top Muxes and Registers
// When start is asserted, the inputs are loaded into the divider.
@ -83,13 +88,13 @@ module srt(
assign NextWCN = {WCA[`DIVCOPIES-1][`DIVLEN+1:0], 2'b0};
end
mux2 #(`DIVLEN+4) wsmux(NextWSN, {3'b000, ~XZeroE, X}, DivStart, WSN);
mux2 #(`DIVLEN+4) wsmux(NextWSN, X, DivStart, WSN);
flopen #(`DIVLEN+4) wsflop(clk, DivStart|DivBusy, WSN, WS[0]);
mux2 #(`DIVLEN+4) wcmux(NextWCN, {`DIVLEN+4{1'b0}}, DivStart, WCN);
flopen #(`DIVLEN+4) wcflop(clk, DivStart|DivBusy, WCN, WC[0]);
flopen #(`DIVLEN+4) dflop(clk, DivStart, {4'b0001, Dpreproc}, D);
flopen #(`NE+2) expflop(clk, DivStart, DivCalcExp, DivCalcExpM);
flopen #(`DIVLEN+4) dflop(clk, DivStart, Dpreproc, D);
mux2 #(`DIVLEN+4) Cmux({2'b11, C[`DIVCOPIES-1][`DIVLEN+3:2]}, {5'b11111, Sqrt, {(`DIVLEN-2){1'b0}}}, DivStart, CMux);
flop #(`DIVLEN+4) cflop(clk, CMux, C[0]);
// Divisor Selections
// - choose the negitive version of what's being selected
@ -102,8 +107,9 @@ module srt(
genvar i;
generate
for(i=0; $unsigned(i)<`DIVCOPIES; i++) begin : interations
divinteration divinteration(.D, .DBar, .D2, .DBar2,
.WS(WS[i]), .WC(WC[i]), .WSA(WSA[i]), .WCA(WCA[i]), .Q(Q[i]), .QM(QM[i]), .QNext(QNext[i]), .QMNext(QMNext[i]));
divinteration divinteration(.D, .DBar, .D2, .DBar2, .Sqrt,
.WS(WS[i]), .WC(WC[i]), .WSA(WSA[i]), .WCA(WCA[i]), .Q(Q[i]), .QM(QM[i]), .QNext(QNext[i]), .QMNext(QMNext[i]),
.C(C[i]), .S(S[i]), .SM(SM[i]), .SNext(SNext[i]), .SMNext(SMNext[i]));
if(i<(`DIVCOPIES-1)) begin
if (`RADIX==2)begin
assign WS[i+1] = {WSA[i][`DIVLEN+1:0], 1'b0};
@ -111,9 +117,12 @@ module srt(
end else begin
assign WS[i+1] = {WSA[i][`DIVLEN+1:0], 2'b0};
assign WC[i+1] = {WCA[i][`DIVLEN+1:0], 2'b0};
assign C[i+1] = {2'b11, C[i][`DIVLEN+3:2]};
end
assign Q[i+1] = QNext[i];
assign QM[i+1] = QMNext[i];
assign S[i+1] = SNext[i];
assign SM[i+1] = SMNext[i];
end
end
endgenerate
@ -123,16 +132,27 @@ module srt(
flopenr #(`QLEN) Qreg(clk, DivStart, DivBusy, QNext[`DIVCOPIES-1], Q[0]);
flopen #(`QLEN) QMreg(clk, DivBusy, QMMux, QM[0]);
assign Quot = NegSticky ? QM[0][`QLEN-1-(`RADIX/4):0] : Q[0][`QLEN-1-(`RADIX/4):0];
flopr #(`DIVLEN+4) SMreg(clk, DivStart, SMNext[`DIVCOPIES-1], SM[0]);
mux2 #(`DIVLEN+4) Smux(SNext[`DIVCOPIES-1], {3'b000, Sqrt, {(`DIVLEN){1'b0}}}, DivStart, SMux);
flop #(`DIVLEN+4) Sreg(clk, SMux, S[0]);
always_comb
if(Sqrt)
if(NegSticky) Qm = SM[0][`QLEN-1-(`RADIX/4):0];
else Qm = S[0][`QLEN-1-(`RADIX/4):0];
else
if(NegSticky) Qm = QM[0][`QLEN-1-(`RADIX/4):0];
else Qm = Q[0][`QLEN-1-(`RADIX/4):0];
assign FirstWS = WS[0];
assign FirstWC = WC[0];
if(`RADIX==2)
if (`DIVCOPIES == 1)
assign StickyWSA = {WSA[0][`DIVLEN+2:0], 1'b0};
else
assign StickyWSA = {WSA[1][`DIVLEN+2:0], 1'b0};
expcalc expcalc(.FmtE, .Xe, .Ye, .XZeroE, .XZeroCnt, .YZeroCnt, .DivCalcExp);
endmodule
@ -145,8 +165,12 @@ module divinteration (
input logic [`DIVLEN+3:0] D,
input logic [`DIVLEN+3:0] DBar, D2, DBar2,
input logic [`QLEN-1:0] Q, QM,
input logic [`DIVLEN+3:0] S, SM,
input logic [`DIVLEN+3:0] WS, WC,
input logic [`DIVLEN+3:0] C,
input logic Sqrt,
output logic [`QLEN-1:0] QNext, QMNext,
output logic [`DIVLEN+3:0] SNext, SMNext,
output logic [`DIVLEN+3:0] WSA, WCA
);
/* verilator lint_on UNOPTFLAT */
@ -154,8 +178,10 @@ module divinteration (
logic [`DIVLEN+3:0] Dsel;
logic [3:0] q;
logic qp, qz;//, qn;
logic [`DIVLEN+3:0] F;
logic [`DIVLEN+3:0] AddIn;
// Quotient Selection logic
// Qmient Selection logic
// Given partial remainder, select quotient of +1, 0, or -1 (qp, qz, pm)
// q encoding:
// 1000 = +2
@ -166,7 +192,8 @@ module divinteration (
if(`RADIX == 2) begin : qsel
qsel2 qsel2(WS[`DIVLEN+3:`DIVLEN], WC[`DIVLEN+3:`DIVLEN], qp, qz);//, qn);
end else begin
qsel4 qsel4(.D, .WS, .WC, .q);
qsel4 qsel4(.D, .WS, .WC, .Sqrt, .q);
fgen4 fgen4(.s(q), .C, .S, .SM, .F);
end
if(`RADIX == 2) begin : dsel
@ -184,16 +211,18 @@ module divinteration (
end
// Partial Product Generation
// WSA, WCA = WS + WC - qD
assign AddIn = Sqrt ? F : Dsel;
if (`RADIX == 2) begin : csa
csa #(`DIVLEN+4) csa(WS, WC, Dsel, qp, WSA, WCA);
csa #(`DIVLEN+4) csa(WS, WC, AddIn, qp, WSA, WCA);
end else begin
csa #(`DIVLEN+4) csa(WS, WC, Dsel, |q[3:2], WSA, WCA);
csa #(`DIVLEN+4) csa(WS, WC, AddIn, |q[3:2], WSA, WCA);
end
if (`RADIX == 2) begin : otfc
otfc2 otfc2(.qp, .qz, .Q, .QM, .QNext, .QMNext);
end else begin
otfc4 otfc4(.q, .Q, .QM, .QNext, .QMNext);
sotfc4 sotfc4(.s(q), .Sqrt, .C, .S, .SM, .SNext, .SMNext);
end
endmodule
@ -220,40 +249,3 @@ module csa #(parameter N=69) (
assign out2 = {in1[N-2:0] & (in2[N-2:0] | in3[N-2:0]) |
(in2[N-2:0] & in3[N-2:0]), cin};
endmodule
module expcalc(
input logic [`FMTBITS-1:0] FmtE,
input logic [`NE-1:0] Xe, Ye,
input logic XZeroE,
input logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt,
output logic [`NE+1:0] DivCalcExp
);
logic [`NE-2:0] Bias;
if (`FPSIZES == 1) begin
assign Bias = (`NE-1)'(`BIAS);
end else if (`FPSIZES == 2) begin
assign Bias = FmtE ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
end else if (`FPSIZES == 3) begin
always_comb
case (FmtE)
`FMT: Bias = (`NE-1)'(`BIAS);
`FMT1: Bias = (`NE-1)'(`BIAS1);
`FMT2: Bias = (`NE-1)'(`BIAS2);
default: Bias = 'x;
endcase
end else if (`FPSIZES == 4) begin
always_comb
case (FmtE)
2'h3: Bias = (`NE-1)'(`Q_BIAS);
2'h1: Bias = (`NE-1)'(`D_BIAS);
2'h0: Bias = (`NE-1)'(`S_BIAS);
2'h2: Bias = (`NE-1)'(`H_BIAS);
endcase
end
// correct exponent for denormalized input's normalization shifts
assign DivCalcExp = ({2'b0, Xe} - {{`NE+1-$unsigned($clog2(`NF+2)){1'b0}}, XZeroCnt} - {2'b0, Ye} + {{`NE+1-$unsigned($clog2(`NF+2)){1'b0}}, YZeroCnt} + {3'b0, Bias})&{`NE+2{~XZeroE}};
endmodule

View file

@ -43,7 +43,7 @@ module srtfsm(
input logic [`DIVLEN+3:0] StickyWSA,
input logic [`DURLEN-1:0] Dur,
output logic [`DURLEN-1:0] EarlyTermShiftE,
output logic DivStickyE,
output logic DivSE,
output logic DivDone,
output logic NegSticky,
output logic DivBusy
@ -65,9 +65,9 @@ module srtfsm(
// this is only a problem on radix 2 (and pssibly maximally redundant 4) since minimally redundant
// radix-4 division can't create a QM that continually adds 0's
if (`RADIX == 2)
assign DivStickyE = |W&~(StickyWSA == WS);
assign DivSE = |W&~(StickyWSA == WS);
else
assign DivStickyE = |W;
assign DivSE = |W;
assign DivDone = (state == DONE);
assign W = WC+WS;
assign NegSticky = W[`DIVLEN+3]; //*** is there a better way to do this???

View file

@ -31,16 +31,25 @@
`include "wally-config.vh"
module srtpreproc (
input logic clk,
input logic DivStart,
input logic [`NF:0] Xm, Ym,
output logic [`DIVLEN-1:0] X,
output logic [`DIVLEN-1:0] Dpreproc,
input logic [`NE-1:0] Xe, Ye,
input logic [`FMTBITS-1:0] Fmt,
input logic Sqrt,
input logic XZero,
output logic [`NE+1:0] QeM,
output logic [`DIVLEN+3:0] X,
output logic [`DIVLEN+3:0] Dpreproc,
output logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt,
output logic [`DURLEN-1:0] Dur
);
// logic [`XLEN-1:0] PosA, PosB;
// logic [`DIVLEN-1:0] ExtraA, ExtraB, PreprocA, PreprocB, PreprocX, PreprocY;
logic [`DIVLEN-1:0] PreprocA, PreprocX;
logic [`DIVLEN-1:0] PreprocB, PreprocY;
logic [`NF-1:0] PreprocA, PreprocX;
logic [`NF-1:0] PreprocB, PreprocY;
logic [`NF+3:0] SqrtX;
logic [`NE+1:0] Qe;
// assign PosA = (Signed & SrcA[`XLEN - 1]) ? -SrcA : SrcA;
// assign PosB = (Signed & SrcB[`XLEN - 1]) ? -SrcB : SrcB;
@ -49,23 +58,22 @@ module srtpreproc (
// ***can probably merge X LZC with conversion
// cout the number of leading zeros
lzc #(`NF+1) lzcA (Xm, XZeroCnt);
lzc #(`NF+1) lzcB (Ym, YZeroCnt);
lzc #(`NF+1) lzcX (Xm, XZeroCnt);
lzc #(`NF+1) lzcY (Ym, YZeroCnt);
// assign ExtraA = {PosA, {`DIVLEN-`XLEN{1'b0}}};
// assign ExtraB = {PosB, {`DIVLEN-`XLEN{1'b0}}};
// assign PreprocA = ExtraA << zeroCntA;
// assign PreprocB = ExtraB << (zeroCntB + 1);
assign PreprocX = {Xm[`NF-1:0]<<XZeroCnt, {`DIVLEN-`NF{1'b0}}};
assign PreprocY = {Ym[`NF-1:0]<<YZeroCnt, {`DIVLEN-`NF{1'b0}}};
assign PreprocX = Xm[`NF-1:0]<<XZeroCnt;
assign PreprocY = Ym[`NF-1:0]<<YZeroCnt;
assign X = PreprocX;
assign Dpreproc = PreprocY;
assign SqrtX = Xe[0] ? {3'b110, ~XZero, PreprocX} : {2'b11, ~XZero, PreprocX, 1'b0};
assign X = Sqrt ? {SqrtX, {`DIVLEN-`NF{1'b0}}} : {3'b000, ~XZero, PreprocX, {`DIVLEN-`NF{1'b0}}};
assign Dpreproc = {4'b0001, /*Int ? PreprocB : */PreprocY, {`DIVLEN-`NF{1'b0}}};
assign Dur = (`DURLEN)'(`FPDUR);
// assign intExp = zeroCntB - zeroCntA + 1;
// assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
// radix 2 radix 4
// 1 copies DIVLEN+2 DIVLEN+2/2
@ -76,6 +84,52 @@ module srtpreproc (
// DIVRESLEN = DIVLEN or DIVLEN+2
// r = 1 or 2
// DIVRESLEN/(r*`DIVCOPIES)
flopen #(`NE+2) expflop(clk, DivStart, Qe, QeM);
expcalc expcalc(.Fmt, .Xe, .Ye, .Sqrt, .XZero, .XZeroCnt, .YZeroCnt, .Qe);
endmodule
module expcalc(
input logic [`FMTBITS-1:0] Fmt,
input logic [`NE-1:0] Xe, Ye,
input logic Sqrt,
input logic XZero,
input logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt,
output logic [`NE+1:0] Qe
);
logic [`NE-2:0] Bias;
logic [`NE-1:0] SExp, SXExp;
logic [`NE+1:0] DExp;
if (`FPSIZES == 1) begin
assign Bias = (`NE-1)'(`BIAS);
end else if (`FPSIZES == 2) begin
assign Bias = Fmt ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
end else if (`FPSIZES == 3) begin
always_comb
case (Fmt)
`FMT: Bias = (`NE-1)'(`BIAS);
`FMT1: Bias = (`NE-1)'(`BIAS1);
`FMT2: Bias = (`NE-1)'(`BIAS2);
default: Bias = 'x;
endcase
end else if (`FPSIZES == 4) begin
always_comb
case (Fmt)
2'h3: Bias = (`NE-1)'(`Q_BIAS);
2'h1: Bias = (`NE-1)'(`D_BIAS);
2'h0: Bias = (`NE-1)'(`S_BIAS);
2'h2: Bias = (`NE-1)'(`H_BIAS);
endcase
end
assign SXExp = Xe - (`NE)'(`BIAS);
assign SExp = {1'b0, SXExp[`NE-1:1]} + Bias;
// correct exponent for denormalized input's normalization shifts
assign DExp = ({2'b0, Xe} - {{`NE+1-$unsigned($clog2(`NF+2)){1'b0}}, XZeroCnt} - {2'b0, Ye} + {{`NE+1-$unsigned($clog2(`NF+2)){1'b0}}, YZeroCnt} + {3'b0, Bias})&{`NE+2{~XZero}};
assign Qe = Sqrt ? {2'b0, SExp} : DExp;
endmodule

View file

@ -30,35 +30,35 @@
module unpack (
input logic [`FLEN-1:0] X, Y, Z, // inputs from register file
input logic [`FMTBITS-1:0] FmtE, // format signal 00 - single 01 - double 11 - quad 10 - half
output logic XSgnE, YSgnE, ZSgnE, // sign bits of XYZ
output logic [`NE-1:0] XExpE, YExpE, ZExpE, // exponents of XYZ (converted to largest supported precision)
output logic [`NF:0] XManE, YManE, ZManE, // mantissas of XYZ (converted to largest supported precision)
output logic XNaNE, YNaNE, ZNaNE, // is XYZ a NaN
output logic XSNaNE, YSNaNE, ZSNaNE, // is XYZ a signaling NaN
output logic XDenormE, ZDenormE, // is XYZ denormalized
output logic XZeroE, YZeroE, ZZeroE, // is XYZ zero
output logic XInfE, YInfE, ZInfE, // is XYZ infinity
output logic XExpMaxE // does X have the maximum exponent (NaN or Inf)
input logic [`FMTBITS-1:0] Fmt, // format signal 00 - single 01 - double 11 - quad 10 - half
input logic XEn, YEn, ZEn,
output logic Xs, Ys, Zs, // sign bits of XYZ
output logic [`NE-1:0] Xe, Ye, Ze, // exponents of XYZ (converted to largest supported precision)
output logic [`NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision)
output logic XNaN, YNaN, ZNaN, // is XYZ a NaN
output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN
output logic XDenorm, ZDenorm, // is XYZ denormalized
output logic XZero, YZero, ZZero, // is XYZ zero
output logic XInf, YInf, ZInf, // is XYZ infinity
output logic XExpMax // does X have the maximum exponent (NaN or Inf)
);
logic [`NF-1:0] XFracE, YFracE, ZFracE; //Fraction of XYZ
logic XExpNonZero, YExpNonZero, ZExpNonZero; // is the exponent of XYZ non-zero
logic XFracZero, YFracZero, ZFracZero; // is the fraction zero
logic YExpMaxE, ZExpMaxE; // is the exponent all 1s
logic YExpMax, ZExpMax; // is the exponent all 1s
unpackinput unpackinputX (.In(X), .FmtE, .Sgn(XSgnE), .Exp(XExpE), .Man(XManE),
.NaN(XNaNE), .SNaN(XSNaNE), .ExpNonZero(XExpNonZero),
.Zero(XZeroE), .Inf(XInfE), .ExpMax(XExpMaxE), .FracZero(XFracZero));
unpackinput unpackinputX (.In(X), .Fmt, .Sgn(Xs), .Exp(Xe), .Man(Xm), .En(XEn),
.NaN(XNaN), .SNaN(XSNaN), .ExpNonZero(XExpNonZero),
.Zero(XZero), .Inf(XInf), .ExpMax(XExpMax), .FracZero(XFracZero));
unpackinput unpackinputY (.In(Y), .FmtE, .Sgn(YSgnE), .Exp(YExpE), .Man(YManE),
.NaN(YNaNE), .SNaN(YSNaNE), .ExpNonZero(YExpNonZero),
.Zero(YZeroE), .Inf(YInfE), .ExpMax(YExpMaxE), .FracZero(YFracZero));
unpackinput unpackinputY (.In(Y), .Fmt, .Sgn(Ys), .Exp(Ye), .Man(Ym), .En(YEn),
.NaN(YNaN), .SNaN(YSNaN), .ExpNonZero(YExpNonZero),
.Zero(YZero), .Inf(YInf), .ExpMax(YExpMax), .FracZero(YFracZero));
unpackinput unpackinputZ (.In(Z), .FmtE, .Sgn(ZSgnE), .Exp(ZExpE), .Man(ZManE),
.NaN(ZNaNE), .SNaN(ZSNaNE), .ExpNonZero(ZExpNonZero),
.Zero(ZZeroE), .Inf(ZInfE), .ExpMax(ZExpMaxE), .FracZero(ZFracZero));
unpackinput unpackinputZ (.In(Z), .Fmt, .Sgn(Zs), .Exp(Ze), .Man(Zm), .En(ZEn),
.NaN(ZNaN), .SNaN(ZSNaN), .ExpNonZero(ZExpNonZero),
.Zero(ZZero), .Inf(ZInf), .ExpMax(ZExpMax), .FracZero(ZFracZero));
// is the input denormalized
assign XDenormE = ~XExpNonZero & ~XFracZero;
assign ZDenormE = ~ZExpNonZero & ~ZFracZero;
assign XDenorm = ~XExpNonZero & ~XFracZero;
assign ZDenorm = ~ZExpNonZero & ~ZFracZero;
endmodule

View file

@ -30,7 +30,8 @@
module unpackinput (
input logic [`FLEN-1:0] In, // inputs from register file
input logic [`FMTBITS-1:0] FmtE, // format signal 00 - single 01 - double 11 - quad 10 - half
input logic En, // enable the input
input logic [`FMTBITS-1:0] Fmt, // format signal 00 - single 01 - double 11 - quad 10 - half
output logic Sgn, // sign bits of XYZ
output logic [`NE-1:0] Exp, // exponents of XYZ (converted to largest supported precision)
output logic [`NF:0] Man, // mantissas of XYZ (converted to largest supported precision)
@ -74,16 +75,16 @@ module unpackinput (
// quad and half
// double and half
assign BadNaNBox = ~(FmtE|(&In[`FLEN-1:`LEN1])); // Check NaN boxing
assign BadNaNBox = ~(Fmt|(&In[`FLEN-1:`LEN1])); // Check NaN boxing
// choose sign bit depending on format - 1=larger precsion 0=smaller precision
assign Sgn = FmtE ? In[`FLEN-1] : In[`LEN1-1];
assign Sgn = Fmt ? In[`FLEN-1] : In[`LEN1-1];
// extract the fraction, add trailing zeroes to the mantissa if nessisary
assign Frac = FmtE ? In[`NF-1:0] : {In[`NF1-1:0], (`NF-`NF1)'(0)};
assign Frac = Fmt ? In[`NF-1:0] : {In[`NF1-1:0], (`NF-`NF1)'(0)};
// is the exponent non-zero
assign ExpNonZero = FmtE ? |In[`FLEN-2:`NF] : |In[`LEN1-2:`NF1];
assign ExpNonZero = Fmt ? |In[`FLEN-2:`NF] : |In[`LEN1-2:`NF1];
// example double to single conversion:
// 1023 = 0011 1111 1111
@ -95,10 +96,10 @@ module unpackinput (
// extract the exponent, converting the smaller exponent into the larger precision if nessisary
// - if the original precision had a denormal number convert the exponent value 1
assign Exp = FmtE ? {In[`FLEN-2:`NF+1], In[`NF]|~ExpNonZero} : {In[`LEN1-2], {`NE-`NE1{~In[`LEN1-2]}}, In[`LEN1-3:`NF1+1], In[`NF1]|~ExpNonZero};
assign Exp = Fmt ? {In[`FLEN-2:`NF+1], In[`NF]|~ExpNonZero} : {In[`LEN1-2], {`NE-`NE1{~In[`LEN1-2]}}, In[`LEN1-3:`NF1+1], In[`NF1]|~ExpNonZero};
// is the exponent all 1's
assign ExpMax = FmtE ? &In[`FLEN-2:`NF] : &In[`LEN1-2:`NF1];
assign ExpMax = Fmt ? &In[`FLEN-2:`NF] : &In[`LEN1-2:`NF1];
end else if (`FPSIZES == 3) begin // three floating point precsions supported
@ -122,7 +123,7 @@ module unpackinput (
// Check NaN boxing
always_comb
case (FmtE)
case (Fmt)
`FMT: BadNaNBox = 0;
`FMT1: BadNaNBox = ~&In[`FLEN-1:`LEN1];
`FMT2: BadNaNBox = ~&In[`FLEN-1:`LEN2];
@ -131,7 +132,7 @@ module unpackinput (
// extract the sign bit
always_comb
case (FmtE)
case (Fmt)
`FMT: Sgn = In[`FLEN-1];
`FMT1: Sgn = In[`LEN1-1];
`FMT2: Sgn = In[`LEN2-1];
@ -140,7 +141,7 @@ module unpackinput (
// extract the fraction
always_comb
case (FmtE)
case (Fmt)
`FMT: Frac = In[`NF-1:0];
`FMT1: Frac = {In[`NF1-1:0], (`NF-`NF1)'(0)};
`FMT2: Frac = {In[`NF2-1:0], (`NF-`NF2)'(0)};
@ -149,7 +150,7 @@ module unpackinput (
// is the exponent non-zero
always_comb
case (FmtE)
case (Fmt)
`FMT: ExpNonZero = |In[`FLEN-2:`NF]; // if input is largest precision (`FLEN - ie quad or double)
`FMT1: ExpNonZero = |In[`LEN1-2:`NF1]; // if input is larger precsion (`LEN1 - double or single)
`FMT2: ExpNonZero = |In[`LEN2-2:`NF2]; // if input is smallest precsion (`LEN2 - single or half)
@ -166,7 +167,7 @@ module unpackinput (
// convert the larger precision's exponent to use the largest precision's bias
always_comb
case (FmtE)
case (Fmt)
`FMT: Exp = {In[`FLEN-2:`NF+1], In[`NF]|~ExpNonZero};
`FMT1: Exp = {In[`LEN1-2], {`NE-`NE1{~In[`LEN1-2]}}, In[`LEN1-3:`NF1+1], In[`NF1]|~ExpNonZero};
`FMT2: Exp = {In[`LEN2-2], {`NE-`NE2{~In[`LEN2-2]}}, In[`LEN2-3:`NF2+1], In[`NF2]|~ExpNonZero};
@ -175,7 +176,7 @@ module unpackinput (
// is the exponent all 1's
always_comb
case (FmtE)
case (Fmt)
`FMT: ExpMax = &In[`FLEN-2:`NF];
`FMT1: ExpMax = &In[`LEN1-2:`NF1];
`FMT2: ExpMax = &In[`LEN2-2:`NF2];
@ -194,7 +195,7 @@ module unpackinput (
// Check NaN boxing
always_comb
case (FmtE)
case (Fmt)
2'b11: BadNaNBox = 0;
2'b01: BadNaNBox = ~&In[`Q_LEN-1:`D_LEN];
2'b00: BadNaNBox = ~&In[`Q_LEN-1:`S_LEN];
@ -203,7 +204,7 @@ module unpackinput (
// extract sign bit
always_comb
case (FmtE)
case (Fmt)
2'b11: Sgn = In[`Q_LEN-1];
2'b01: Sgn = In[`D_LEN-1];
2'b00: Sgn = In[`S_LEN-1];
@ -213,7 +214,7 @@ module unpackinput (
// extract the fraction
always_comb
case (FmtE)
case (Fmt)
2'b11: Frac = In[`Q_NF-1:0];
2'b01: Frac = {In[`D_NF-1:0], (`Q_NF-`D_NF)'(0)};
2'b00: Frac = {In[`S_NF-1:0], (`Q_NF-`S_NF)'(0)};
@ -222,7 +223,7 @@ module unpackinput (
// is the exponent non-zero
always_comb
case (FmtE)
case (Fmt)
2'b11: ExpNonZero = |In[`Q_LEN-2:`Q_NF];
2'b01: ExpNonZero = |In[`D_LEN-2:`D_NF];
2'b00: ExpNonZero = |In[`S_LEN-2:`S_NF];
@ -240,7 +241,7 @@ module unpackinput (
// convert the double precsion exponent into quad precsion
always_comb
case (FmtE)
case (Fmt)
2'b11: Exp = {In[`Q_LEN-2:`Q_NF+1], In[`Q_NF]|~ExpNonZero};
2'b01: Exp = {In[`D_LEN-2], {`Q_NE-`D_NE{~In[`D_LEN-2]}}, In[`D_LEN-3:`D_NF+1], In[`D_NF]|~ExpNonZero};
2'b00: Exp = {In[`S_LEN-2], {`Q_NE-`S_NE{~In[`S_LEN-2]}}, In[`S_LEN-3:`S_NF+1], In[`S_NF]|~ExpNonZero};
@ -250,7 +251,7 @@ module unpackinput (
// is the exponent all 1's
always_comb
case (FmtE)
case (Fmt)
2'b11: ExpMax = &In[`Q_LEN-2:`Q_NF];
2'b01: ExpMax = &In[`D_LEN-2:`D_NF];
2'b00: ExpMax = &In[`S_LEN-2:`S_NF];
@ -262,8 +263,8 @@ module unpackinput (
// Output logic
assign FracZero = ~|Frac; // is the fraction zero?
assign Man = {ExpNonZero, Frac}; // add the assumed one (or zero if denormal or zero) to create the significand
assign NaN = (ExpMax & ~FracZero)|BadNaNBox; // is the input a NaN?
assign NaN = ((ExpMax & ~FracZero)|BadNaNBox)&En; // is the input a NaN?
assign SNaN = NaN&~Frac[`NF-1]&~BadNaNBox; // is the input a singnaling NaN?
assign Inf = ExpMax & FracZero; // is the input infinity?
assign Inf = ExpMax & FracZero &En; // is the input infinity?
assign Zero = ~ExpNonZero & FracZero; // is the input zero?
endmodule

View file

@ -165,6 +165,7 @@ module uartPC16550D(
SCR <= #1 8'b0; // not strictly necessary to reset
end else begin
if (~MEMWb) begin
/* verilator lint_off CASEINCOMPLETE */
case (A)
/* -----\/----- EXCLUDED -----\/-----
3'b000: if (DLAB) DLL <= #1 Din; // else TXHR <= #1 Din; // TX handled in TX register/FIFO section
@ -177,34 +178,42 @@ module uartPC16550D(
// freq /baud / 16 = div
//3'b000: if (DLAB) DLL <= #1 8'd38; //else TXHR <= #1 Din; // TX handled in TX register/FIFO section
//3'b000: if (DLAB) DLL <= #1 8'd11; //else TXHR <= #1 Din; // TX handled in
3'b000: if (DLAB) DLL <= #1 8'd8; //else TXHR <= #1 Din; // TX handled in
3'b000: if (DLAB) DLL <= #1 8'd8; //else TXHR <= #1 Din; // TX handled in
3'b001: if (DLAB) DLM <= #1 8'b0; else IER <= #1 Din[3:0];
3'b010: FCR <= #1 {Din[7:6], 2'b0, Din[3], 2'b0, Din[0]}; // Write only FIFO Control Register; 4:5 reserved and 2:1 self-clearing
3'b011: LCR <= #1 Din;
3'b100: MCR <= #1 Din[4:0];
3'b101: LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3
3'b110: MSR <= #1 Din[3:0];
3'b111: SCR <= #1 Din;
endcase
/* verilator lint_on CASEINCOMPLETE */
end
// Line Status Register (8.6.3)
// Ben 6/9/21 I don't like how this is a register. A lot of the individual bits have clocked components, so this just adds unecessary delay.
LSR[0] <= #1 rxdataready; // Data ready
LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
LSR[5] <= #1 THRE; // THRE
LSR[6] <= #1 ~txsrfull & THRE; // TEMT
if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error
// Ben 6/9/21 I don't like how this is a register. A lot of the individual bits have clocked components, so this just adds unecessary delay.
if (~MEMWb & (A == 3'b101))
LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3
else begin
LSR[0] <= #1 rxdataready; // Data ready
LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
LSR[5] <= #1 THRE; // THRE
LSR[6] <= #1 ~txsrfull & THRE; // TEMT
if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error
end
// Modem Status Register (8.6.8)
MSR[0] <= #1 MSR[0] | CTSb2 ^ CTSbsync; // Delta Clear to Send
MSR[1] <= #1 MSR[1] | DSRb2 ^ DSRbsync; // Delta Data Set Ready
MSR[2] <= #1 MSR[2] | (~RIb2 & RIbsync); // Trailing Edge of Ring Indicator
MSR[3] <= #1 MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect
if (~MEMWb & (A == 3'b110))
MSR <= #1 Din[3:0];
else if (~MEMRb & (A == 3'b110))
MSR <= #1 4'b0; // Reading MSR clears the flags in MSR bits 3:0
else begin
MSR[0] <= #1 MSR[0] | CTSb2 ^ CTSbsync; // Delta Clear to Send
MSR[1] <= #1 MSR[1] | DSRb2 ^ DSRbsync; // Delta Data Set Ready
MSR[2] <= #1 MSR[2] | (~RIb2 & RIbsync); // Trailing Edge of Ring Indicator
MSR[3] <= #1 MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect
end
end
always_comb
if (~MEMRb)
@ -215,7 +224,8 @@ module uartPC16550D(
3'b011: Dout = LCR;
3'b100: Dout = {3'b000, MCR};
3'b101: Dout = LSR;
3'b110: Dout = {~CTSbsync, ~DSRbsync, ~RIbsync, ~DCDbsync, MSR[3:0]};
// 3'b110: Dout = {~CTSbsync, ~DSRbsync, ~RIbsync, ~DCDbsync, MSR[3:0]};
3'b110: Dout = {~DCDbsync, ~RIbsync, ~DSRbsync, ~CTSbsync, MSR[3:0]};
3'b111: Dout = SCR;
endcase
else Dout = 8'b0;
@ -304,7 +314,7 @@ module uartPC16550D(
// ERROR CONDITIONS
assign rxparity = ^rxdata;
assign rxparityerr = rxparity ^ rxparitybit ^ ~evenparitysel; // Check even/odd parity (*** check if LCR needs to be inverted)
assign rxparityerr = (rxparity ^ rxparitybit ^ ~evenparitysel) & LCR[3]; // Check even/odd parity (*** check if LCR needs to be inverted)
assign rxoverrunerr = fifoenabled ? (rxfifoentries == 15) : rxdataready; // overrun if FIFO or receive buffer register full
assign rxframingerr = ~rxstopbit; // framing error if no stop bit
assign rxbreak = rxframingerr & (rxdata9 == 9'b0); // break when 0 for start + data + parity + stop time
@ -405,7 +415,7 @@ module uartPC16550D(
txstate <= #1 UART_IDLE;
end
assign txbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1 + {3'b000, LCR[2]} - 4'd1; // start bit + data bits + (parity bit) + stop bit(s)
assign txbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1 + {3'b000, LCR[2]} - 4'd1; // start bit + data bits + (parity bit) + stop bit(s) - 1
// *** explain; is this necessary?
if (`QEMU) assign txnextbit = txbaudpulse & (txoversampledcnt[1:0] == 2'b00); // implies txstate = UART_ACTIVE
else assign txnextbit = txbaudpulse & (txoversampledcnt == 4'b0000); // implies txstate = UART_ACTIVE

View file

@ -1,4 +1,4 @@
all: exptestgen testgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen
all: exptestgen testgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen modtestgen
sqrttestgen: sqrttestgen.c
gcc sqrttestgen.c -o sqrttestgen -lm
@ -28,6 +28,10 @@ inttestgen: inttestgen.c
gcc -lm -o inttestgen inttestgen.c
./inttestgen
modtestgen: modtestgen.c
gcc -lm -o modtestgen modtestgen.c
./modtestgen
clean:
rm -f testgen exptestgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen
rm -f testgen exptestgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen modtestgen

View file

@ -96,10 +96,6 @@ void output(FILE *fptr, int aSign, int aExp, double aFrac, int bSign, int bExp,
// Print r in standard double format
fprintf(fptr, "%03x", rExp|(rSign<<11));
printhex(fptr, rFrac);
fprintf(fptr, "_");
// Spacing for testbench, value doesn't matter
fprintf(fptr, "%016x", 0);
fprintf(fptr, "\n");
}

Binary file not shown.

View file

@ -1,9 +1,8 @@
/* testgen.c */
/* Written 10/31/96 by David Harris
/* Written 7/21/2022 by Cedar Turek
This program creates test vectors for mantissa component
of an IEEE floating point divider.
This program creates test vectors for integer divide.
*/
/* #includes */
@ -19,7 +18,7 @@
/* Prototypes */
void output(FILE *fptr, long a, long b, long r, long rem);
void output(FILE *fptr, long a, long b, long r);
void printhex(FILE *fptr, long x);
double random_input(void);
@ -28,7 +27,7 @@ double random_input(void);
void main(void)
{
FILE *fptr;
long a, b, r, rem;
long a, b, r;
long list[ENTRIES] = {1, 3, 5, 18, 25, 33, 42, 65, 103, 255};
int i, j;
@ -42,32 +41,22 @@ void main(void)
for (j=0; j<ENTRIES; j++) {
a = list[j];
r = a/b;
rem = a%b;
output(fptr, a, b, r, rem);
output(fptr, a, b, r);
}
}
// for (i = 0; i< RANDOM_VECS; i++) {
// a = random_input();
// b = random_input();
// r = a/b;
// output(fptr, a, b, r);
// }
fclose(fptr);
}
/* Functions */
void output(FILE *fptr, long a, long b, long r, long rem)
void output(FILE *fptr, long a, long b, long r)
{
printhex(fptr, a);
fprintf(fptr, "_");
printhex(fptr, b);
fprintf(fptr, "_");
printhex(fptr, r);
fprintf(fptr, "_");
printhex(fptr, rem);
fprintf(fptr, "\n");
}

BIN
pipelined/srt/modtestgen Executable file

Binary file not shown.

View file

@ -0,0 +1,73 @@
/* testgen.c */
/* Written 7/21/2022 by Cedar Turek
This program creates test vectors for modulo
calculation from integer divide.
*/
/* #includes */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* Constants */
#define ENTRIES 10
#define RANDOM_VECS 500
/* Prototypes */
void output(FILE *fptr, long a, long b, long rem);
void printhex(FILE *fptr, long x);
double random_input(void);
/* Main */
void main(void)
{
FILE *fptr;
long a, b, rem;
long list[ENTRIES] = {1, 3, 5, 18, 25, 33, 42, 65, 103, 255};
int i, j;
if ((fptr = fopen("modtestvectors","w")) == NULL) {
fprintf(stderr, "Couldn't write testvectors file\n");
exit(1);
}
for (i=0; i<ENTRIES; i++) {
b = list[i];
for (j=0; j<ENTRIES; j++) {
a = list[j];
rem = a%b;
output(fptr, a, b, rem);
}
}
fclose(fptr);
}
/* Functions */
void output(FILE *fptr, long a, long b, long rem)
{
printhex(fptr, a);
fprintf(fptr, "_");
printhex(fptr, b);
fprintf(fptr, "_");
printhex(fptr, rem);
fprintf(fptr, "\n");
}
void printhex(FILE *fptr, long m)
{
fprintf(fptr, "%016llx", m);
}
double random_input(void)
{
return 1.0 + rand()/32767.0;
}

Binary file not shown.

View file

@ -1,6 +1,6 @@
/* sqrttestgen.c */
/* Written 19 October 2021 David_Harris@hmc.edu
/* Written 7/22/2022 by Cedar Turek
This program creates test vectors for mantissa component
of an IEEE floating point square root.
@ -15,6 +15,7 @@
/* Constants */
#define ENTRIES 17
#define BIGENT 1000
#define RANDOM_VECS 500
/* Prototypes */
@ -34,6 +35,9 @@ void main(void)
1.75, 1.875, 1.99999,
1.1, 1.5, 1.01, 1.001, 1.0001,
2/1.1, 2/1.5, 2/1.25, 2/1.125};
double bigtest[BIGENT];
double exps[ENTRIES] = {0, 0, 2, 3, 4, 5, 6, 7, 8, 1, 10,
11, 12, 13, 14, 15, 16};
int i;
@ -44,13 +48,14 @@ void main(void)
exit(1);
}
for (i=0; i<ENTRIES; i++) {
aFrac = mans[i];
aExp = exps[i] + bias;
rFrac = sqrt(aFrac * pow(2, exps[i]));
rExp = (int) (log(rFrac)/log(2) + bias);
output(fptr, aExp, aFrac, rExp, rFrac);
}
// Small Test
// for (i=0; i<ENTRIES; i++) {
// aFrac = mans[i];
// aExp = exps[i] + bias;
// rFrac = sqrt(aFrac * pow(2, exps[i]));
// rExp = (int) (log(rFrac)/log(2) + bias);
// output(fptr, aExp, aFrac, rExp, rFrac);
// }
// WS
// Test 1: sqrt(1) = 1 0000 0000 0000 00
@ -67,6 +72,16 @@ void main(void)
// output(fptr, a, r);
// }
// Big Test
for (i=0; i<BIGENT; i++) {
bigtest[i] = random_input();
aFrac = bigtest[i];
aExp = (i - BIGENT/2) + bias;
rFrac = sqrt(aFrac * pow(2, (i - BIGENT/2)));
rExp = (int) (log(rFrac)/log(2) + bias);
output(fptr, aExp, aFrac, rExp, rFrac);
}
fclose(fptr);
}
@ -86,10 +101,6 @@ void output(FILE *fptr, int aExp, double aFrac, int rExp, double rFrac)
// Print r in standard double format
fprintf(fptr, "%03x", rExp);
printhex(fptr, rFrac);
fprintf(fptr, "_");
// Spacing for testbench, value doesn't matter
fprintf(fptr, "%016x", 0);
fprintf(fptr, "\n");
}
@ -109,6 +120,6 @@ void printhex(FILE *fptr, double m)
double random_input(void)
{
return 1.0 + rand()/32767.0;
return 1.0 + ((rand() % 32768)/32767.0);
}

View file

@ -2,4 +2,6 @@ add wave -noupdate /testbench/*
add wave -noupdate /testbench/srt/*
add wave -noupdate /testbench/srt/sotfc2/*
add wave -noupdate /testbench/srt/preproc/*
add wave -noupdate /testbench/srt/postproc/*
add wave -noupdate /testbench/srt/expcalc/*
add wave -noupdate /testbench/srt/divcounter/*

View file

@ -2,7 +2,7 @@
// srt.sv
//
// Written: David_Harris@hmc.edu 13 January 2022
// Modified: cturek@hmc.edu June 2022
// Modified: cturek@hmc.edu July 2022
//
// Purpose: Combined Divide and Square Root Floating Point and Integer Unit
//
@ -35,33 +35,36 @@ module srt (
input logic Start,
input logic Stall, // *** multiple pipe stages
input logic Flush, // *** multiple pipe stages
// Floating Point Inputs
// later add exponents, signs, special cases
// Floating Point
input logic XSign, YSign,
input logic [`NE-1:0] XExp, YExp,
input logic [`NF-1:0] SrcXFrac, SrcYFrac,
// Integer
input logic [`XLEN-1:0] SrcA, SrcB,
// Customization
input logic [1:0] Fmt, // Floats: 00 = 16 bit, 01 = 32 bit, 10 = 64 bit, 11 = 128 bit
input logic W64, // 32-bit ints on XLEN=64
// Selection
input logic Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs
input logic Mod, // perform remainder calculation (modulo) instead of divide
input logic Sqrt, // perform square root, not divide
output logic rsign, done,
output logic [`DIVLEN-2:0] Rem, Quot, // *** later handle integers
output logic [`DIVLEN-1:0] Result,
output logic [`NE-1:0] rExp,
output logic [3:0] Flags
);
logic qp, qz, qn; // quotient is +1, 0, or -1
logic qp, qz, qn; // result bits are +1, 0, or -1
logic [`NE-1:0] calcExp;
logic calcSign;
logic [`DIVLEN+3:0] X, Dpreproc, C, F, AddIn;
logic [`DIVLEN+3:0] X, Dpreproc, C, F, S, SM, AddIn;
logic [`DIVLEN+3:0] WS, WSA, WSN, WC, WCA, WCN, D, Db, Dsel;
logic [$clog2(`XLEN+1)-1:0] intExp, dur, calcDur;
logic [$clog2(`XLEN+1)-1:0] zeroCntD, intExp, dur, calcDur;
logic intSign;
logic cin;
srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, XExp, Fmt, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, calcDur, intSign);
srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, XExp, Fmt, W64, Signed, Int, Mod, Sqrt, X, Dpreproc, zeroCntD, intExp, calcDur, intSign);
// Top Muxes and Registers
// When start is asserted, the inputs are loaded into the divider.
@ -75,7 +78,7 @@ module srt (
// Quotient Selection logic
// Given partial remainder, select quotient of +1, 0, or -1 (qp, qz, pm)
qsel2 qsel2(WS[`DIVLEN+3:`DIVLEN-1], WC[`DIVLEN+3:`DIVLEN-1], Sqrt, qp, qz, qn);
qsel2 qsel2(WS[`DIVLEN+3:`DIVLEN], WC[`DIVLEN+3:`DIVLEN], Sqrt, qp, qz, qn);
flopen #(`NE) expflop(clk, Start, calcExp, rExp);
flopen #(1) signflop(clk, Start, calcSign, rsign);
@ -90,8 +93,9 @@ module srt (
// If only implementing division, use divide otfc
// otfc2 #(`DIVLEN) otfc2(clk, Start, qp, qz, qn, Quot);
// otherwise use sotfc
creg sotfcC(clk, Start, C);
sotfc2 sotfc2(clk, Start, qp, qn, C, Quot, F);
creg sotfcC(clk, Start, Sqrt, C);
sotfc2 sotfc2(clk, Start, qp, qn, Sqrt, C, S, SM);
fsel2 fsel(qp, qn, C, S, SM, F);
// Adder input selection
assign AddIn = Sqrt ? F : Dsel;
@ -102,7 +106,7 @@ module srt (
expcalc expcalc(.XExp, .YExp, .calcExp, .Sqrt);
signcalc signcalc(.XSign, .YSign, .calcSign);
srtpostproc postproc(.WS, .WC, .X, .D, .S, .SM, .dur, .zeroCntD, .XSign, .YSign, .Signed, .Int, .Mod, .Result, .calcSign);
endmodule
////////////////
@ -120,13 +124,14 @@ module srtpreproc (
input logic W64, // 32-bit ints on XLEN=64
input logic Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs
input logic Mod, // perform remainder calculation (modulo) instead of divide
input logic Sqrt, // perform square root, not divide
output logic [`DIVLEN+3:0] X, D,
output logic [$clog2(`XLEN+1)-1:0] intExp, dur, // Quotient integer exponent
output logic [$clog2(`XLEN+1)-1:0] zeroCntB, intExp, dur, // Quotient integer exponent
output logic intSign // Quotient integer sign
);
logic [$clog2(`XLEN+1)-1:0] zeroCntA, zeroCntB;
logic [$clog2(`XLEN+1)-1:0] zeroCntA;
logic [`XLEN-1:0] PosA, PosB;
logic [`DIVLEN-1:0] ExtraA, ExtraB, PreprocA, PreprocB, PreprocX, PreprocY, DivX;
logic [`NF+4:0] SqrtX;
@ -153,12 +158,12 @@ module srtpreproc (
// Selecting correct divider inputs
assign DivX = Int ? PreprocA : PreprocX;
assign SqrtX = XExp[0] ? {4'b0000, SrcXFrac, 1'b0} : {5'b11111, SrcXFrac};
assign SqrtX = XExp[0] ? {5'b11101, SrcXFrac} : {4'b1111, SrcXFrac, 1'b0};
assign X = Sqrt ? {SqrtX, {(`EXTRAFRACBITS-1){1'b0}}} : {4'b0001, DivX};
assign D = {4'b0001, Int ? PreprocB : PreprocY};
// Integer exponent and sign calculations
assign intExp = zeroCntB - zeroCntA + 1;
assign intExp = zeroCntB - zeroCntA - Mod + (PreprocA >= PreprocB);
assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
// Number of cycles of divider
@ -168,13 +173,13 @@ endmodule
/////////////////////////////////
// Quotient Selection, Radix 2 //
/////////////////////////////////
module qsel2 ( // *** eventually just change to 4 bits
input logic [`DIVLEN+3:`DIVLEN-1] ps, pc,
module qsel2 (
input logic [`DIVLEN+3:`DIVLEN] ps, pc,
input logic Sqrt,
output logic qp, qz, qn
);
logic [`DIVLEN+3:`DIVLEN-1] p, g;
logic [`DIVLEN+3:`DIVLEN] p, g;
logic magnitude, sign, cout;
// The quotient selection logic is presented for simplicity, not
@ -185,8 +190,8 @@ module qsel2 ( // *** eventually just change to 4 bits
assign p = ps ^ pc;
assign g = ps & pc;
assign #1 magnitude = ~(&p[`DIVLEN+2:`DIVLEN-1]);
assign #1 cout = g[`DIVLEN+2] | (p[`DIVLEN+2] & (g[`DIVLEN+1] | p[`DIVLEN+1] & (g[`DIVLEN] | (Sqrt & (p[`DIVLEN] & g[`DIVLEN-1])))));
assign #1 magnitude = ~(&p[`DIVLEN+2:`DIVLEN]);
assign #1 cout = g[`DIVLEN+2] | (p[`DIVLEN+2] & (g[`DIVLEN+1] | p[`DIVLEN+1] & (g[`DIVLEN])));
assign #1 sign = p[`DIVLEN+3] ^ cout;
/* assign #1 magnitude = ~((ps[54]^pc[54]) & (ps[53]^pc[53]) &
(ps[52]^pc[52]));
@ -212,13 +217,18 @@ module fsel2 (
logic [`DIVLEN+3:0] FP, FN, FZ;
// Generate for both positive and negative bits
assign FP = ~S & C;
assign FN = SM | (C & (~C << 2));
assign FZ = {(`DIVLEN+4){1'b0}};
assign FP = ~(S << 1) & C;
assign FN = (SM << 1) | (C & (~C << 2));
assign FZ = '0;
// Choose which adder input will be used
assign F = sp ? FP : (sn ? FN : FZ);
always_comb
if (sp) F = FP;
else if (sn) F = FN;
else F = FZ;
// assign F = sp ? FP : (sn ? FN : FZ);
endmodule
@ -229,7 +239,7 @@ module otfc2 #(parameter N=66) (
input logic clk,
input logic Start,
input logic qp, qz, qn,
output logic [N-3:0] r
output logic [N-3:0] Result
);
// The on-the-fly converter transfers the quotient
// bits to the quotient as they come.
@ -255,7 +265,7 @@ module otfc2 #(parameter N=66) (
QMNext = {QMR, 1'b0};
end
end
assign r = Q[N] ? Q[N-1:2] : Q[N-2:1];
assign Result = Q[N] ? Q[N-1:2] : Q[N-2:1];
endmodule
@ -266,35 +276,31 @@ module sotfc2(
input logic clk,
input logic Start,
input logic sp, sn,
input logic Sqrt,
input logic [`DIVLEN+3:0] C,
output logic [`DIVLEN-2:0] Sq,
output logic [`DIVLEN+3:0] F
output logic [`DIVLEN+3:0] S, SM
);
// The on-the-fly converter transfers the square root
// bits to the quotient as they come.
// Use this otfc for division and square root.
logic [`DIVLEN+3:0] S, SM, SNext, SMNext, SMux;
logic [`DIVLEN+3:0] SNext, SMNext, SMux;
flopr #(`DIVLEN+4) SMreg(clk, Start, SMNext, SM);
mux2 #(`DIVLEN+4) Smux(SNext, {4'b0001, {(`DIVLEN){1'b0}}}, Start, SMux);
mux2 #(`DIVLEN+4) Smux(SNext, {3'b000, Sqrt, {(`DIVLEN){1'b0}}}, Start, SMux);
flop #(`DIVLEN+4) Sreg(clk, SMux, S);
always_comb begin
if (sp) begin
SNext = S | ((C << 1) & ~(C << 2));
SNext = S | (C & ~(C << 1));
SMNext = S;
end else if (sn) begin
SNext = SM | ((C << 1) & ~(C << 2));
SNext = SM | (C & ~(C << 1));
SMNext = SM;
end else begin // If sp and sn are not true, then sz is
SNext = S;
SMNext = SM | ((C << 1) & ~(C << 2));
SMNext = SM | (C & ~(C << 1));
end
end
assign Sq = S[`DIVLEN] ? S[`DIVLEN-1:1] : S[`DIVLEN-2:0];
fsel2 fsel(sp, sn, C, S, SM, F);
endmodule
//////////////////////////
@ -302,11 +308,12 @@ endmodule
//////////////////////////
module creg(input logic clk,
input logic Start,
input logic Sqrt,
output logic [`DIVLEN+3:0] C
);
logic [`DIVLEN+3:0] CMux;
mux2 #(`DIVLEN+4) Cmux({1'b1, C[`DIVLEN+3:1]}, {6'b111111, {(`DIVLEN-2){1'b0}}}, Start, CMux);
mux2 #(`DIVLEN+4) Cmux({1'b1, C[`DIVLEN+3:1]}, {4'b1111, Sqrt, {(`DIVLEN-1){1'b0}}}, Start, CMux);
flop #(`DIVLEN+4) cflop(clk, CMux, C);
endmodule
@ -382,22 +389,86 @@ module expcalc(
input logic Sqrt,
output logic [`NE-1:0] calcExp
);
logic [`NE-1:0] SExp, DExp, SXExp;
assign SXExp = XExp - (`NE)'(`BIAS);
assign SExp = {1'b0, SXExp[`NE-1:1]} + (`NE)'(`BIAS);
assign DExp = XExp - YExp + (`NE)'(`BIAS);
assign calcExp = Sqrt ? SExp : DExp;
logic [`NE+1:0] SExp, DExp, SXExp;
assign SXExp = {2'b00, XExp} - (`NE+2)'(`BIAS);
assign SExp = (SXExp >> 1) + (`NE+2)'(`BIAS);
assign DExp = {2'b00, XExp} - {2'b00, YExp} + (`NE+2)'(`BIAS);
assign calcExp = Sqrt ? SExp[`NE-1:0] : DExp[`NE-1:0];
endmodule
//////////////
// signcalc //
//////////////
module signcalc(
input logic XSign, YSign,
module srtpostproc(
input logic [`DIVLEN+3:0] WS, WC, X, D, S, SM,
input logic [$clog2(`XLEN+1)-1:0] dur, zeroCntD,
input logic XSign, YSign, Signed, Int, Mod,
output logic [`DIVLEN-1:0] Result,
output logic calcSign
);
logic [`DIVLEN+3:0] W, shiftRem, intRem, intS;
logic [`DIVLEN-1:0] floatRes, intRes;
logic WSign;
assign W = WS + WC;
assign WSign = W[`DIVLEN+3];
// Remainder handling
always_comb begin
if (zeroCntD == ($clog2(`XLEN+1))'(`XLEN)) begin
intRem = X;
intS = -1;
end
else if (~Signed) begin
if (WSign) begin
intRem = W + D;
intS = SM;
end else begin
intRem = W;
intS = S;
end
end
else case ({YSign, XSign, WSign})
3'b000: begin
intRem = W;
intS = S;
end
3'b001: begin
intRem = W + D;
intS = SM;
end
3'b010: begin
intRem = W - D;
intS = ~S;
end
3'b011: begin
intRem = W;
intS = ~SM;
end
3'b100: begin
intRem = W;
intS = ~SM;
end
3'b101: begin
intRem = W + D;
intS = ~SM + 1;
end
3'b110: begin
intRem = W - D;
intS = S + 1;
end
3'b111: begin
intRem = W;
intS = S;
end
endcase
end
assign floatRes = S[`DIVLEN] ? S[`DIVLEN:1] : S[`DIVLEN-1:0];
assign intRes = intS[`DIVLEN] ? intS[`DIVLEN:1] : intS[`DIVLEN-1:0];
assign shiftRem = (intRem >> (zeroCntD));
always_comb begin
if (Int) begin
if (Mod) Result = shiftRem[`DIVLEN-1:0];
else Result = intRes >> (`DIVLEN - dur);
end else Result = floatRes;
end
assign calcSign = XSign ^ YSign;
endmodule
endmodule

View file

@ -42,24 +42,23 @@ module testbench;
logic clk;
logic req;
logic done;
logic Int;
logic Int, Sqrt, Mod;
logic [`XLEN-1:0] a, b;
logic [`NF-1:0] afrac, bfrac;
logic [`NE-1:0] aExp, bExp;
logic asign, bsign;
logic [`NF-1:0] r;
logic [`XLEN-1:0] rInt;
logic [`DIVLEN-2:0] Quot;
logic [`DIVLEN-1:0] Quot;
// Test parameters
parameter MEM_SIZE = 40000;
parameter MEM_WIDTH = 64+64+64+64;
parameter MEM_WIDTH = 64+64+64;
// Test sizes
`define memrem 63:0
`define memr 127:64
`define memb 191:128
`define mema 255:192
`define memr 63:0
`define memb 127:64
`define mema 191:128
// Test logicisters
logic [MEM_WIDTH-1:0] Tests [0:MEM_SIZE]; // Space for input file
@ -70,8 +69,9 @@ module testbench;
logic rsign;
integer testnum, errors;
// Equip Int test or Sqrt test
assign Int = 1'b0;
// Equip Int, Sqrt, or IntMod test
assign Int = 1'b0;
assign Mod = 1'b0;
assign Sqrt = 1'b1;
// Divider
@ -81,8 +81,8 @@ module testbench;
.XSign(asign), .YSign(bsign), .rsign,
.SrcXFrac(afrac), .SrcYFrac(bfrac),
.SrcA(a), .SrcB(b), .Fmt(2'b00),
.W64(1'b1), .Signed(1'b0), .Int, .Sqrt,
.Quot, .Rem(), .Flags(), .done);
.W64(1'b1), .Signed(1'b0), .Int, .Mod, .Sqrt,
.Result(Quot), .Flags(), .done);
// Counter
// counter counter(clk, req, done);
@ -109,7 +109,7 @@ module testbench;
{bsign, bExp, bfrac} = b;
nextr = Vec[`memr];
r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
rInt = {1'b1, Quot};
rInt = Quot;
req <= #5 1;
end
@ -117,9 +117,9 @@ module testbench;
always @(posedge clk) begin
r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
rInt = {1'b1, Quot};
rInt = Quot;
if (done) begin
if (~Int & ~Sqrt) begin
if (~Int & ~Sqrt) begin // This test case checks floating point division
req <= #5 1;
diffp = correctr[51:0] - r;
diffn = r - correctr[51:0];
@ -135,23 +135,21 @@ module testbench;
$display("%d Tests completed successfully", testnum);
$stop;
end
end else if (~Sqrt) begin
end else if (~Sqrt) begin // This test case works for both integer divide and integer modulo
req <= #5 1;
diffp = correctr[63:0] - rInt;
diffn = rInt - correctr[63:0];
if (($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp
if (($signed(diffp) != 0) | (diffp === 64'bx)) // check if accurate to 1 ulp
begin
errors = errors+1;
$display("result was %h, should be %h %h %h\n", rInt, correctr, diffn, diffp);
$display("result was %h, should be %h %h\n", rInt, correctr, diffp);
$display("failed\n");
$stop;
end
if (afrac === 52'hxxxxxxxxxxxxx)
begin
$display("%d Tests completed successfully", testnum);
$display("%d Tests completed successfully", testnum - errors);
$stop;
end
end else begin
end else begin // This test case verifies square root
req <= #5 1;
diffp = correctr[51:0] - r;
diffn = r - correctr[51:0];

View file

@ -66,9 +66,9 @@ module testbenchfp;
logic [`XLEN-1:0] IntRes, CmpRes; // Results from each unit
logic [4:0] FmaFlg, CvtFlg, DivFlg, CmpFlg; // Outputed flags
logic AnsNaN, ResNaN, NaNGood;
logic XSgn, YSgn, ZSgn; // sign of the inputs
logic [`NE-1:0] XExp, YExp, ZExp; // exponent of the inputs
logic [`NF:0] XMan, YMan, ZMan; // mantissas of the inputs
logic Xs, Ys, Zs; // sign of the inputs
logic [`NE-1:0] Xe, Ye, Ze; // exponent of the inputs
logic [`NF:0] Xm, Ym, Zm; // mantissas of the inputs
logic XNaN, YNaN, ZNaN; // is the input NaN
logic XSNaN, YSNaN, ZSNaN; // is the input a signaling NaN
logic XDenorm, ZDenorm; // is the input denormalized
@ -94,10 +94,12 @@ module testbenchfp;
// in-between FMA signals
logic Mult;
logic Ss;
logic [`NE+1:0] Pe;
logic [`NE+1:0] Se;
logic ZmSticky;
logic KillProd;
logic [$clog2(3*`NF+7)-1:0] NCnt;
logic [$clog2(3*`NF+7)-1:0] SCnt;
logic [3*`NF+5:0] Sm;
logic InvA;
logic NegSum;
@ -648,14 +650,14 @@ module testbenchfp;
// extract the inputs (X, Y, Z, SrcA) and the output (Ans, AnsFlg) from the current test vector
readvectors readvectors (.clk, .Fmt(FmtVal), .ModFmt, .TestVector(TestVectors[VectorNum]), .VectorNum, .Ans(Ans), .AnsFlg(AnsFlg), .SrcA,
.XSgnE(XSgn), .YSgnE(YSgn), .ZSgnE(ZSgn), .Unit (UnitVal),
.XExpE(XExp), .YExpE(YExp), .ZExpE(ZExp), .TestNum, .OpCtrl(OpCtrlVal),
.XManE(XMan), .YManE(YMan), .ZManE(ZMan), .DivStart,
.XNaNE(XNaN), .YNaNE(YNaN), .ZNaNE(ZNaN),
.XSNaNE(XSNaN), .YSNaNE(YSNaN), .ZSNaNE(ZSNaN),
.XDenormE(XDenorm), .ZDenormE(ZDenorm),
.XZeroE(XZero), .YZeroE(YZero), .ZZeroE(ZZero),
.XInfE(XInf), .YInfE(YInf), .ZInfE(ZInf), .XExpMaxE(XExpMax),
.Xs, .Ys, .Zs, .Unit(UnitVal),
.Xe, .Ye, .Ze, .TestNum, .OpCtrl(OpCtrlVal),
.Xm, .Ym, .Zm, .DivStart,
.XNaN, .YNaN, .ZNaN,
.XSNaN, .YSNaN, .ZSNaN,
.XDenorm, .ZDenorm,
.XZero, .YZero, .ZZero,
.XInf, .YInf, .ZInf, .XExpMax,
.X, .Y, .Z);
@ -671,34 +673,34 @@ module testbenchfp;
///////////////////////////////////////////////////////////////////////////////////////////////
// instantiate devices under test
fma fma(.Xs(XSgn), .Ys(YSgn), .Zs(ZSgn),
.Xe(XExp), .Ye(YExp), .Ze(ZExp),
.Xm(XMan), .Ym(YMan), .Zm(ZMan),
.XZero, .YZero, .ZZero,
.FOpCtrl(OpCtrlVal), .Fmt(ModFmt), .Sm, .NegSum, .InvA, .NCnt, .As, .Ps,
fma fma(.Xs(Xs), .Ys(Ys), .Zs(Zs),
.Xe(Xe), .Ye(Ye), .Ze(Ze),
.Xm(Xm), .Ym(Ym), .Zm(Zm),
.XZero, .YZero, .ZZero, .Ss, .Se,
.OpCtrl(OpCtrlVal), .Fmt(ModFmt), .Sm, .NegSum, .InvA, .SCnt, .As, .Ps,
.Pe, .ZmSticky, .KillProd);
postprocess postprocess(.Xs(XSgn), .Ys(YSgn), .PostProcSel(UnitVal[1:0]),
.Ze(ZExp), .ZDenorm(ZDenorm), .FOpCtrl(OpCtrlVal), .DivQm(Quot), .DivQe(DivCalcExp),
.Xm(XMan), .Ym(YMan), .Zm(ZMan), .CvtCe(CvtCalcExpE), .DivS(DivSticky),
postprocess postprocess(.Xs(Xs), .Ys(Ys), .PostProcSel(UnitVal[1:0]),
.Ze(Ze), .ZDenorm(ZDenorm), .OpCtrl(OpCtrlVal), .DivQm(Quot), .DivQe(DivCalcExp),
.Xm(Xm), .Ym(Ym), .Zm(Zm), .CvtCe(CvtCalcExpE), .DivS(DivSticky), .FmaSs(Ss),
.XNaN(XNaN), .YNaN(YNaN), .ZNaN(ZNaN), .CvtResDenormUf(CvtResDenormUfE),
.XZero(XZero), .YZero(YZero), .ZZero(ZZero), .CvtShiftAmt(CvtShiftAmtE),
.XInf(XInf), .YInf(YInf), .ZInf(ZInf), .CvtCs(CvtResSgnE), .ToInt(WriteIntVal),
.XSNaN(XSNaN), .YSNaN(YSNaN), .ZSNaN(ZSNaN), .CvtLzcIn(CvtLzcInE), .IntZero,
.FmaKillProd(KillProd), .FmaZmS(ZmSticky), .FmaPe(Pe), .DivDone,
.FmaSm(Sm), .FmaNegSum(NegSum), .FmaInvA(InvA), .FmaNCnt(NCnt), .DivEarlyTermShift(EarlyTermShift), .FmaAs(As), .FmaPs(Ps), .Fmt(ModFmt), .Frm(FrmVal),
.FmaKillProd(KillProd), .FmaZmS(ZmSticky), .FmaPe(Pe), .DivDone, .FmaSe(Se),
.FmaSm(Sm), .FmaNegSum(NegSum), .FmaInvA(InvA), .FmaSCnt(SCnt), .DivEarlyTermShift(EarlyTermShift), .FmaAs(As), .FmaPs(Ps), .Fmt(ModFmt), .Frm(FrmVal),
.PostProcFlg(Flg), .PostProcRes(FpRes), .FCvtIntRes(IntRes));
fcvt fcvt (.Xs(XSgn), .Xe(XExp), .Xm(XMan), .Int(SrcA), .ToInt(WriteIntVal),
.XZero(XZero), .XDenorm(XDenorm), .FOpCtrl(OpCtrlVal), .IntZero,
fcvt fcvt (.Xs(Xs), .Xe(Xe), .Xm(Xm), .Int(SrcA), .ToInt(WriteIntVal),
.XZero(XZero), .XDenorm(XDenorm), .OpCtrl(OpCtrlVal), .IntZero,
.Fmt(ModFmt), .Ce(CvtCalcExpE), .ShiftAmt(CvtShiftAmtE), .ResDenormUf(CvtResDenormUfE), .Cs(CvtResSgnE), .LzcIn(CvtLzcInE));
fcmp fcmp (.FmtE(ModFmt), .FOpCtrlE(OpCtrlVal), .XSgnE(XSgn), .YSgnE(YSgn), .XExpE(XExp), .YExpE(YExp),
.XManE(XMan), .YManE(YMan), .XZeroE(XZero), .YZeroE(YZero), .CmpIntResE(CmpRes),
.XNaNE(XNaN), .YNaNE(YNaN), .XSNaNE(XSNaN), .YSNaNE(YSNaN), .FSrcXE(X), .FSrcYE(Y), .CmpNVE(CmpFlg[4]), .CmpFpResE(FpCmpRes));
divsqrt divsqrt(.clk, .reset, .FmtE(ModFmt), .XManE(XMan), .YManE(YMan), .XExpE(XExp), .YExpE(YExp),
fcmp fcmp (.Fmt(ModFmt), .OpCtrl(OpCtrlVal), .Xs, .Ys, .Xe, .Ye,
.Xm, .Ym, .XZero, .YZero, .CmpIntRes(CmpRes),
.XNaN, .YNaN, .XSNaN, .YSNaN, .X, .Y, .CmpNV(CmpFlg[4]), .CmpFpRes(FpCmpRes));
divsqrt divsqrt(.clk, .reset, .FmtE(ModFmt), .XmE(Xm), .YmE(Ym), .XeE(Xe), .YeE(Ye), .SqrtE(1'b0), .SqrtM(1'b0),
.XInfE(XInf), .YInfE(YInf), .XZeroE(XZero), .YZeroE(YZero), .XNaNE(XNaN), .YNaNE(YNaN), .DivStartE(DivStart),
.StallE(1'b0), .StallM(1'b0), .DivStickyM(DivSticky), .DivBusy, .DivCalcExpM(DivCalcExp),
.EarlyTermShiftM(EarlyTermShift), .QuotM(Quot), .DivDone);
.StallE(1'b0), .StallM(1'b0), .DivSM(DivSticky), .DivBusy, .QeM(DivCalcExp),
.EarlyTermShiftM(EarlyTermShift), .QmM(Quot), .DivDone);
assign CmpFlg[3:0] = 0;
@ -866,10 +868,10 @@ end
// Testfloat outputs 800... for both the largest integer values for both positive and negitive numbers but
// the riscv spec specifies 2^31-1 for positive values out of range and NaNs ie 7fff...
else if ((UnitVal === `CVTINTUNIT) & ~(((WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&XSgn&(Res[`XLEN-1:0] === (`XLEN)'(0))) |
(WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~XSgn|XNaN)&OpCtrlVal[1]&(Res[`XLEN-1:0] === {1'b0, {`XLEN-1{1'b1}}})) |
(WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~XSgn|XNaN)&~OpCtrlVal[1]&(Res[`XLEN-1:0] === {{`XLEN-32{1'b0}}, 1'b0, {31{1'b1}}})) |
(~(WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&XSgn&~XNaN)&(Res === Ans | NaNGood | NaNGood === 1'bx))) & (ResFlg === AnsFlg | AnsFlg === 5'bx))) begin
else if ((UnitVal === `CVTINTUNIT) & ~(((WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&Xs&(Res[`XLEN-1:0] === (`XLEN)'(0))) |
(WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~Xs|XNaN)&OpCtrlVal[1]&(Res[`XLEN-1:0] === {1'b0, {`XLEN-1{1'b1}}})) |
(WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~Xs|XNaN)&~OpCtrlVal[1]&(Res[`XLEN-1:0] === {{`XLEN-32{1'b0}}, 1'b0, {31{1'b1}}})) |
(~(WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&Xs&~XNaN)&(Res === Ans | NaNGood | NaNGood === 1'bx))) & (ResFlg === AnsFlg | AnsFlg === 5'bx))) begin
errors += 1;
$display("There is an error in %s", Tests[TestNum]);
$display("inputs: %h %h %h\nSrcA: %h\n Res: %h %h\n Ans: %h %h", X, Y, Z, SrcA, Res, ResFlg, Ans, AnsFlg);
@ -922,18 +924,19 @@ module readvectors (
output logic [`FLEN-1:0] Ans,
output logic [`XLEN-1:0] SrcA,
output logic [4:0] AnsFlg,
output logic XSgnE, YSgnE, ZSgnE, // sign bits of XYZ
output logic [`NE-1:0] XExpE, YExpE, ZExpE, // exponents of XYZ (converted to largest supported precision)
output logic [`NF:0] XManE, YManE, ZManE, // mantissas of XYZ (converted to largest supported precision)
output logic XNaNE, YNaNE, ZNaNE, // is XYZ a NaN
output logic XSNaNE, YSNaNE, ZSNaNE, // is XYZ a signaling NaN
output logic XDenormE, ZDenormE, // is XYZ denormalized
output logic XZeroE, YZeroE, ZZeroE, // is XYZ zero
output logic XInfE, YInfE, ZInfE, // is XYZ infinity
output logic XExpMaxE,
output logic Xs, Ys, Zs, // sign bits of XYZ
output logic [`NE-1:0] Xe, Ye, Ze, // exponents of XYZ (converted to largest supported precision)
output logic [`NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision)
output logic XNaN, YNaN, ZNaN, // is XYZ a NaN
output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN
output logic XDenorm, ZDenorm, // is XYZ denormalized
output logic XZero, YZero, ZZero, // is XYZ zero
output logic XInf, YInf, ZInf, // is XYZ infinity
output logic XExpMax,
output logic DivStart,
output logic [`FLEN-1:0] X, Y, Z
);
logic XEn, YEn, ZEn;
// apply test vectors on rising edge of clk
// Format of vectors Inputs(1/2/3)_AnsFlg
@ -1255,8 +1258,12 @@ module readvectors (
endcase
end
unpack unpack(.X, .Y, .Z, .FmtE(ModFmt), .XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE,
.XManE, .YManE, .ZManE, .XNaNE, .YNaNE, .ZNaNE, .XSNaNE, .YSNaNE, .ZSNaNE,
.XDenormE, .ZDenormE, .XZeroE, .YZeroE, .ZZeroE, .XInfE, .YInfE, .ZInfE,
.XExpMaxE);
assign XEn = ~((Unit == `CVTINTUNIT)&OpCtrl[2]);
assign YEn = ~((Unit == `CVTINTUNIT)|(Unit == `CVTFPUNIT));
assign ZEn = (Unit == `FMAUNIT);
unpack unpack(.X, .Y, .Z, .Fmt(ModFmt), .Xs, .Ys, .Zs, .Xe, .Ye, .Ze,
.Xm, .Ym, .Zm, .XNaN, .YNaN, .ZNaN, .XSNaN, .YSNaN, .ZSNaN,
.XDenorm, .ZDenorm, .XZero, .YZero, .ZZero, .XInf, .YInf, .ZInf,
.XEn, .YEn, .ZEn, .XExpMax);
endmodule

File diff suppressed because it is too large Load diff

View file

@ -17,13 +17,20 @@ root:
mkdir -p $(wally_workdir)
sed 's,{0},$(current_dir),g;s,{1},$(XLEN)$(if $(findstring 64,$(XLEN)),gc,imc),g' config.ini > config$(XLEN).ini
build_arch:
fsd_fld_tempfix:
# this is a temporary fix, there's a typo on the rv64i_m/D/src/d_fsd-align-01.S and rv64i_m/D/src/d_fld-align-01.S tests
# https://github.com/riscv-non-isa/riscv-arch-test/issues/266
find ../../addins/riscv-arch-test/riscv-test-suite -type f -name "*d_fld-align*.S" | xargs -I{} sed -i 's,regex(\.\*32\.\*),regex(\.\*64\.\*),g' {}
find ../../addins/riscv-arch-test/riscv-test-suite -type f -name "*d_fsd-align*.S" | xargs -I{} sed -i 's,regex(\.\*32\.\*),regex(\.\*64\.\*),g' {}
build_arch: fsd_fld_tempfix
riscof run --work-dir=$(work_dir) --config=config$(XLEN).ini --suite=$(arch_dir)/riscv-test-suite/ --env=$(arch_dir)/riscv-test-suite/env --no-browser
rm -rf $(arch_workdir)/rv$(XLEN)i_m
mv -f $(work_dir)/rv$(XLEN)i_m $(arch_workdir)/
rsync -a $(work_dir)/rv32i_m/ $(arch_workdir)/rv$(XLEN)i_m/ || echo "error suppressed"
rsync -a $(work_dir)/rv64i_m/ $(arch_workdir)/rv$(XLEN)i_m/ || echo "error suppressed"
build_wally:
riscof --verbose debug run --work-dir=$(work_dir) --config=config$(XLEN).ini --suite=$(wally_dir)/riscv-test-suite/ --env=$(wally_dir)/riscv-test-suite/env --no-browser --no-dut-run
riscof --verbose debug run --work-dir=$(work_dir) --config=config$(XLEN).ini --suite=$(wally_dir)/riscv-test-suite/ --env=$(wally_dir)/riscv-test-suite/env --no-browser --no-dut-run 2>&1 | tee log.txt
rm -rf $(wally_workdir)/rv$(XLEN)i_m
mv -f $(work_dir)/rv$(XLEN)i_m $(wally_workdir)/

View file

@ -94,7 +94,7 @@ class sail_cSim(pluginTemplate):
execute = "@cd "+testentry['work_dir']+";"
cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen) + ' ' + test + ' -o ' + elf
cmd = self.compile_cmd.format(testentry['isa'].lower().replace('zicsr', ' ', 1), self.xlen) + ' ' + test + ' -o ' + elf
compile_cmd = cmd + ' -D' + " -D".join(testentry['macros'])
execute+=compile_cmd+";"

View file

@ -151,7 +151,7 @@ class spike(pluginTemplate):
# substitute all variables in the compile command that we created in the initialize
# function
cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen, test, elf, compile_macros)
cmd = self.compile_cmd.format(testentry['isa'].lower().replace('zicsr', ' ', 2), self.xlen, test, elf, compile_macros)
# if the user wants to disable running the tests and only compile the tests, then
# the "else" clause is executed below assigning the sim command to simple no action

View file

@ -55,6 +55,8 @@ target_tests_nosim = \
WALLY-status-tw-01 \
WALLY-gpio-01 \
WALLY-clint-01 \
WALLY-plic-01 \
WALLY-uart-01 \
rv32i_tests = $(addsuffix .elf, $(rv32i_sc_tests))

View file

@ -0,0 +1,249 @@
00000000 # read empty MIP (1.0.0)
00000008 # check GPIO interrupt pending on intPending0
00000000 # Claim gives no interrupt due to zero priority
00000008 # interrupt still pending due to no claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.0.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000000 # read empty MIP (1.0.2)
00000000 # check GPIO interrupt pending on intPending0
00000000 # claim gives no interrupt due to no intPending
00000000 # no interrupts pending after clear
00000000 # still no interrupts after clear
00000000 # read empty MIP (1.1.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # interrupt still pending due to no claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.1.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.2.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.2.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.3.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.3.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.4.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.4.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.5.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.5.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.6.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set due to PLIC priority (1.6.1)
00000008 # check GPIO interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000000 # read empty MIP (1.7.0)
00000008 # check GPIO interrupt pending on intPending0
00000003 # Claim gives 3 for ID of GPIO
00000000 # check no interrupts pending after claim
00000000 # check no interrupts pending
00000800 # MEIP set (2.0)
00000408 # gpio and uart pending
00000003 # claim gpio
00000400 # gpio no longer pending
00000000 # no interrupts pending
00000800 # MEIP set (2.1)
00000408 # gpio and uart pending
00000003 # claim gpio
00000400 # gpio no longer pending
00000000 # no interrupts pending
00000800 # MEIP set (2.2)
00000408 # gpio and uart pending
0000000A # claim uart
00000008 # uart no longer pending
00000000 # no interrupts pending
00000800 # MEIP set (2.3)
00000408 # gpio and uart pending
0000000A # claim uart
00000008 # uart no longer pending
00000000 # no interrupts pending
00000000 # MEIP empty (2.4)
00000408 # gpio and uart pending
0000000A # claim none
00000008 # gpio and uart still pending
00000000 # no interrupts pending
00000A00 # MEIP and SEIP set (3.0)
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000200 # SEIP set (3.1)
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000200 # SEIP set (3.2)
00000408 # check GPIO and UART interrupt pending on intPending0
0000000A # claim UART
00000008 # GPIO interrupt pending after UART claimcomp
00000000 # check no interrupts pending
00000000 # read empty MIP (3.3)
00000408 # check GPIO and UART interrupt pending on intPending0
0000000A # claim UART
00000008 # check UART interrupt pending cleared after claim
00000000 # check no interrupts pending
00000A00 # MEIP and SEIP set (4.0)
00000400 # UART interrupt pending
0000000A # claim UART
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000200 # SEIP set (4.1)
00000400 # UART interrupt pending
00000000 # nothing in claim register
00000400 # UART interrupt pending
00000000 # check no interrupts pending
00000A00 # MEIP and SEIP set (4.2)
00000400 # UART interrupt pending
0000000A # claim UART
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000800 # MEIP set (4.3)
00000400 # UART interrupt pending
0000000A # claim UART
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000800 # MEIP set (4.4)
00000400 # UART interrupt pending
0000000A # claim UART
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000200 # SEIP set (4.5)
00000400 # UART interrupt pending
00000000 # nothing in claim register
00000400 # UART interrupt pending
00000000 # check no interrupts pending
00000000 # All disabled (4.6)
00000400 # UART interrupt pending
00000000 # nothing in claim register
00000400 # UART interrupt pending
00000000 # check no interrupts pending
00000200 # SEIP set (5.0)
00000008 # GPIO interrupt pending
00000000 # nothing in claim register
00000008 # GPIO interrupt pending
00000000 # check no interrupts pending
00000A00 # MEIP and SEIP set (5.1)
00000008 # GPIO interrupt pending
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000800 # MEIP set (5.2)
00000008 # GPIO interrupt pending
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000A00 # MEIP and SEIP set (5.3)
00000008 # GPIO interrupt pending
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000800 # MEIP set (5.4)
00000008 # GPIO interrupt pending
00000003 # claim gives 3 for ID of GPIO
00000000 # check no interrupts pending
00000000 # check no interrupts pending
00000200 # SEIP set (5.5)
00000008 # GPIO interrupt pending
00000000 # nothing in claim register
00000008 # GPIO interrupt pending
00000000 # check no interrupts pending
00000000 # read empty MIP (5.6)
00000008 # GPIO interrupt pending
00000000 # nothing in claim register
00000008 # GPIO interrupt pending
00000000 # check no interrupts pending
0000000b # written due to goto_s_mode
00000200 # read sip (7.0)
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000200 # read sip (7.1)
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000200 # read sip (7.2)
00000408 # check GPIO and UART interrupt pending on intPending0
0000000A # claim UART
00000008 # GPIO interrupt pending after UART claimcomp
00000000 # check no interrupts pending
00000200 # read sip (7.3)
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000000 # read sip
00000408 # check GPIO and UART interrupt pending on intPending0
00000000 # nothing in claim register
00000408 # check GPIO and UART interrupt pending on intPending0
00000000 # check no interrupts pending
00000200 # read sip
00000408 # check GPIO and UART interrupt pending on intPending0
00000003 # claim gives 3 for ID of GPIO
00000400 # check GPIO interrupt pending cleared after claim
00000000 # check no interrupts pending
00000000 # read sip
00000408 # check GPIO and UART interrupt pending on intPending0
00000000 # nothing in claim register
00000408 # check GPIO and UART interrupt pending on intPending0
00000000 # check no interrupts pending
00000009 # output from ecall in supervisor mode
00000800 # MEIP set
00000408 # check GPIO and UART interrupt pending on intPending0
0000000A # claim UART
00000008 # GPIO interrupt pending after UART claimcomp
00000003 # claim gives 3 for ID of GPIO
00000000 # read empty MIP # no interrupts, meip is low
00000000 # check no interrupts pending
00000800 # MEIP set
00000008 # GPIO interrupt pending after complete
00000003 # claim gives 3 for ID of GPIO
00000000 # read empty MIP # meip is zeroed
00000000 # check no interrupts pending
00000800 # MEIP set
00000400 # check GPIO interrupt pending cleared after claim
00000800 # MEIP set
00000408 # check GPIO and UART interrupt pending on intPending0
0000000A # claim UART

View file

@ -0,0 +1,33 @@
00000000 # Reset tests
00000001 # 00000000 *** commented because LCR should reset to zero but resets to 3 due to the FPGA
00000000
00000060
00000000
00000060 # read-write test
00000020 # transmitter register empty but shift register not
00000101 # transmitter is not empty when done transmitting 5 bits
00000000
00000060
00000101 # Multi-bit transmission: 5 bits
00000015
00000101 # Transmit 6 bits
0000002A
00000101 # Transmit 7 bits
0000007F
00000101 # Transmit 8 bits
00000080
00000002 # Transmission interrupt tests
00000401 # Interrupt generated by finished transmission
00000004
00000006 # IIR return LSR intr and LSR has an overflow error
00000063
00000004
00000001
00000001 # MODEM interrupt tests
00000000
00000011
00000001
0000000b # ecall from test termination

View file

@ -965,6 +965,17 @@ read08_test:
// address to read in t3, expected 8 bit value in t4 (unused, but there for your perusal).
li t2, 0xBAD // bad value that will be overwritten on good reads.
lb t2, 0(t3)
andi t2, t2, 0xFF // mask to lower 8 bits
sw t2, 0(t1)
addi t1, t1, 4
addi a6, a6, 4
j test_loop // go to next test case
read04_test:
// address to read in t3, expected 8 bit value in t4 (unused, but there for your perusal).
li t2, 0xBAD // bad value that will be overwritten on good reads.
lb t2, 0(t3)
andi t2, t2, 15 // mask lower 4 bits
sw t2, 0(t1)
addi t1, t1, 4
addi a6, a6, 4
@ -984,6 +995,103 @@ readsip_test: // read the MIP into the signature
addi a6, a6, 4
j test_loop // go to next test case
claim_m_plic_interrupts: // clears one non-pending PLIC interrupt
li t2, 0x0C00000C // GPIO priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C000028 // UART priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C002000
li t3, 0x0C200004
li t4, 0xFFF
lw t6, 0(t2) // save current enable status
sw t4, 0(t2) // enable all relevant interrupts on PLIC
lw t5, 0(t3) // make PLIC claim
sw t5, 0(t3) // complete claim made
sw t6, 0(t2) // restore saved enable status
li t2, 0x0C00000C // GPIO priority
li t3, 0x0C000028 // UART priority
lw t4, 4(sp) // load stored GPIO and UART priority
lw t5, 0(sp)
addi sp, sp, 8 // restore stack pointer
sw t4, 0(t2)
sw t5, 0(t3)
j test_loop
claim_s_plic_interrupts: // clears one non-pending PLIC interrupt
li t2, 0x0C00000C // GPIO priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C000028 // UART priority
li t3, 7
lw t4, 0(t2)
sw t3, 0(t2)
sw t4, -4(sp)
addi sp, sp, -4
li t2, 0x0C002080
li t3, 0x0C201004
li t4, 0xFFF
lw t6, 0(t2) // save current enable status
sw t4, 0(t2) // enable all relevant interrupts on PLIC
lw t5, 0(t3) // make PLIC claim
sw t5, 0(t3) // complete claim made
sw t6, 0(t2) // restore saved enable status
li t2, 0x0C00000C // GPIO priority
li t3, 0x0C000028 // UART priority
lw t4, 4(sp) // load stored GPIO and UART priority
lw t5, 0(sp)
addi sp, sp, 8 // restore stack pointer
sw t4, 0(t2)
sw t5, 0(t3)
j test_loop
uart_lsr_intr_wait: // waits for interrupts to be ready
li t2, 0x10000002 // IIR
li t4, 0x6
uart_lsr_intr_loop:
lb t3, 0(t2)
andi t3, t3, 0x7
bne t3, t4, uart_lsr_intr_loop
sw t3, 0(t1)
addi t1, t1, 4
addi a6, a6, 4
j test_loop
uart_data_wait:
li t2, 0x10000005 // LSR
li t3, 0x10000002 // IIR
li a4, 0x61
uart_read_LSR_IIR:
lb t4, 0(t3) // save IIR before potential clear
lb t5, 0(t2)
andi t6, t5, 0x61 // only care if all transmissions are done
bne a4, t6, uart_read_LSR_IIR
uart_data_ready:
li t2, 0
sw t2, 0(t1) // clear entry deadbeef from memory
andi t5, t5, 0x9F // mask THRE and TEMT from signature
sb t4, 1(t1) // IIR
sb t5, 0(t1) // LSR
addi t1, t1, 4
addi a6, a6, 4
j test_loop
uart_clearmodemintr:
li t2, 0x10000006
lb t2, 0(t2)
j test_loop
goto_s_mode:
// return to address in t3,
li a0, 3 // Trap handler behavior (go to supervisor mode)

View file

@ -143,18 +143,22 @@ SETUP_PLIC
.4byte high_ie, 0x00020000, write32_test # enable high interrupt on bit 17, which is pending
.4byte 0x0, 0x00000800, readmip_test # MEIP should be raised
.4byte high_ie, 0x00000000, write32_test # disable high interrupt on bit 17
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear PLIC pending interrupts
.4byte 0x0, 0x00000000, readmip_test # MEIP should be released
.4byte low_ie, 0x00010000, write32_test # enable low interrupt on bit 16, which is pending
.4byte 0x0, 0x00000800, readmip_test # MEIP should be raised
.4byte low_ie, 0x00000000, write32_test # disable low interrupt on bit 16
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear PLIC pending interrupts
.4byte 0x0, 0x00000000, readmip_test # MEIP should be released
.4byte rise_ie, 0x00200000, write32_test # enable rise interrupt on bit 21, which is pending
.4byte 0x0, 0x00000800, readmip_test # MEIP should be raised
.4byte rise_ie, 0x00000000, write32_test # disable rise interrupt on bit 21, which is pending
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear PLIC pending interrupts
.4byte 0x0, 0x00000000, readmip_test # MEIP should be released
.4byte fall_ie, 0x01000000, write32_test # enable high interrupt on bit 24, which is pending
.4byte 0x0, 0x00000800, readmip_test # MEIP should be raised
.4byte fall_ie, 0x00000000, write32_test # disable high interrupt on bit 24, which is pending
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear PLIC pending interrupts
.4byte 0x0, 0x00000000, readmip_test # MEIP should be released
.4byte 0x0, 0x0, terminate_test # terminate tests

View file

@ -0,0 +1,951 @@
///////////////////////////////////////////
//
// WALLY-plic
//
// Author: David_Harris@hmc.edu and Nicholas Lucio <nlucio@hmc.edu>
//
// Created 2022-06-16
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
#include "WALLY-TEST-LIB-32.h"
INIT_TESTS
TRAP_HANDLER m
j run_test_loop // begin test loop/table tests instead of executing inline code.
INIT_TEST_TABLE
END_TESTS
TEST_STACK_AND_DATA
.align 2
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.4byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.4byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# =========== Define PLIC registers ===========
.equ PLIC, 0x0C000000
.equ PLIC_INTPRI_GPIO, (PLIC+0x00000C) # GPIO is interrupt 3
.equ PLIC_INTPRI_UART, (PLIC+0x000028) # UART is interrupt 10
.equ PLIC_INTPENDING0, (PLIC+0x001000) # intPending0 register
.equ PLIC_INTEN00, (PLIC+0x002000) # interrupt enables for context 0 (machine mode) sources 31:1
.equ PLIC_INTEN10, (PLIC+0x002080) # interrupt enables for context 1 (supervisor mode) sources 31:1
.equ PLIC_THRESH0, (PLIC+0x200000) # Priority threshold for context 0 (machine mode)
.equ PLIC_CLAIM0, (PLIC+0x200004) # Claim/Complete register for context 0
.equ PLIC_THRESH1, (PLIC+0x201000) # Priority threshold for context 1 (supervisor mode)
.equ PLIC_CLAIM1, (PLIC+0x201004) # Claim/Complete register for context 1
# =========== Define GPIO registers ===========
.equ GPIO, 0x10060000
.equ input_val, (GPIO+0x00)
.equ input_en, (GPIO+0x04)
.equ output_en, (GPIO+0x08)
.equ output_val, (GPIO+0x0C)
.equ rise_ie, (GPIO+0x18)
.equ rise_ip, (GPIO+0x1C)
.equ fall_ie, (GPIO+0x20)
.equ fall_ip, (GPIO+0x24)
.equ high_ie, (GPIO+0x28)
.equ high_ip, (GPIO+0x2C)
.equ low_ie, (GPIO+0x30)
.equ low_ip, (GPIO+0x34)
.equ iof_en, (GPIO+0x38)
.equ iof_sel, (GPIO+0x3C)
.equ out_xor, (GPIO+0x40)
# =========== Define UART registers ===========
.equ UART, 0x10000000
.equ UART_IER, (UART+0x01)
.equ UART_MCR, (UART+0x04)
.equ UART_MSR, (UART+0x06)
# =========== Initialize UART and GPIO ===========
# GPIO Initialization
.4byte input_en, 0x00000001, write32_test # enable bit 0 of input_en
.4byte output_en, 0x00000001, write32_test # enable bit 0 of output_en
.4byte output_val, 0x00000000, write32_test # make sure output_val is 0
.4byte rise_ie, 0x00000001, write32_test # enable rise interrupts
# =========== Initialize relevant PLIC registers ===========
.4byte PLIC_INTPRI_GPIO, 0x00000000, write32_test # set GPIO priority to zero
.4byte PLIC_INTPRI_UART, 0x00000000, write32_test # set UART priority to zero
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000007, write32_test # set s-mode threshold to max
# =========== Machine-Mode Priority Testing (1.T.X) ===========
# Test 1.0.0: GPIO int lacks priority (0 = 0)
.4byte PLIC_THRESH0, 0x00000000, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.0.1: GPIO int has priority (1 > 0)
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.0.2: meip and c/c clear without interrupt pending
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.1.0: GPIO lacks priority (1 = 1)
.4byte PLIC_THRESH0, 0x00000001, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.1.1: GPIO int has priority (2 > 1)
.4byte PLIC_INTPRI_GPIO, 0x00000002, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.2.0: GPIO int lacks priority (2 = 2)
.4byte PLIC_THRESH0, 0x00000002, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.2.1: GPIO int has priority (3 > 2)
.4byte PLIC_INTPRI_GPIO, 0x00000003, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.3.0: GPIO int lacks priority (3 = 3)
.4byte PLIC_THRESH0, 0x00000003, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.3.1: GPIO int has priority (4 > 3)
.4byte PLIC_INTPRI_GPIO, 0x00000004, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.4.0: GPIO int lacks priority (4 = 4)
.4byte PLIC_THRESH0, 0x00000004, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.4.1: GPIO int has priority (5 > 4)
.4byte PLIC_INTPRI_GPIO, 0x00000005, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.5.0: GPIO int lacks priority (5 = 5)
.4byte PLIC_THRESH0, 0x00000005, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.5.1: GPIO int has priority (6 > 5)
.4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.6.0: GPIO int lacks priority (6 = 6)
.4byte PLIC_THRESH0, 0x00000006, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.6.1: GPIO int has priority (7 > 6)
.4byte PLIC_INTPRI_GPIO, 0x00000007, write32_test # let GPIO cause interrupts
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# Test 1.7.0: GPIO int lacks priority (7 = 7)
.4byte PLIC_THRESH0, 0x00000007, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim from earlier
.4byte 0x0, 0x00000000, claim_m_plic_interrupts # clear interrupt one
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# =========== UART vs GPIO priority (2.X) ===========
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000007, write32_test # set s-mode threshold to max
# UART Initialization
.4byte UART_IER, 0x08, write08_test # enable modem status interrupts from CTS
.4byte UART_MCR, 0x10, write08_test # enable loopback mode, RTS = 0
.4byte UART_MSR, 0x00, write08_test # disable UART interrupt
# Test 2.0: GPIO Priority = UART Priority
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIOPriority = 1
.4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UARTPriority = 1
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 2.1: GPIO Priority > UART Priority
.4byte PLIC_INTPRI_GPIO, 0x00000003, write32_test # GPIOPriority = 3
.4byte PLIC_INTPRI_UART, 0x00000002, write32_test # UARTPriority = 2
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 2.2: GPIO Priority < UART Priority
.4byte PLIC_INTPRI_GPIO, 0x00000004, write32_test # GPIOPriority = 4
.4byte PLIC_INTPRI_UART, 0x00000005, write32_test # UARTPriority = 5
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for UART
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 2.3: GPIO Priority < UART Priority
.4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # GPIOPriority = 6
.4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UARTPriority = 7
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for UART
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 2.4: Interrupts don't have enough priority
.4byte PLIC_INTPRI_GPIO, 0x00000004, write32_test # GPIOPriority = 4
.4byte PLIC_INTPRI_UART, 0x00000005, write32_test # UARTPriority = 5
.4byte PLIC_THRESH0, 0x00000006, write32_test # set m-mode threshold to 6
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# =========== SEIP tests (3.X) ===========
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
# Test 3.0: Cause machine and supervisor interrupts
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIOPriority = 1
.4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UARTPriority = 1
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000A00, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 3.1: Suppress machine mode interrupts
.4byte PLIC_INTPRI_GPIO, 0x00000003, write32_test # GPIOPriority = 3
.4byte PLIC_INTPRI_UART, 0x00000002, write32_test # UARTPriority = 2
.4byte PLIC_THRESH0, 0x00000007, write32_test # set m-mode threshold to 7
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 3.2: Cause SEIP with UART first
.4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # GPIOPriority = 6
.4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UARTPriority = 7
.4byte PLIC_THRESH0, 0x00000007, write32_test # set m-mode threshold to 7
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 3.3: Low SEIP due to insufficient priority
.4byte PLIC_INTPRI_GPIO, 0x00000002, write32_test # GPIOPriority = 2
.4byte PLIC_INTPRI_UART, 0x00000003, write32_test # UARTPriority = 3
.4byte PLIC_THRESH0, 0x00000004, write32_test # set m-mode threshold to 4
.4byte PLIC_THRESH1, 0x00000005, write32_test # set s-mode threshold to 5
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# =========== UART interrupt enable tests (4.X) ===========
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIO Priority = 1
.4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UART Priority = 1
# Test 4.0: GPIO m-mode disabled
.4byte PLIC_INTEN00, 0x00000400, write32_test # disable GPIO m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000A00, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.1: UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000008, write32_test # disable UART m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.2: GPIO s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000400, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000A00, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.3: UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000008, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.4: GPIO and UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.5: GPIO and UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 4.6: GPIO and UART fully disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# =========== GPIO interrupt enable tests (5.X) ===========
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIO Priority = 1
.4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UART Priority = 1
# Test 5.0: GPIO m-mode disabled
.4byte PLIC_INTEN00, 0x00000400, write32_test # disable GPIO m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.1: UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000008, write32_test # disable UART m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000A00, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.2: GPIO s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000400, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.3: UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000008, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000A00, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.4: GPIO and UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.5: GPIO and UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000200, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 5.6: GPIO and UART fully disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM0, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending for GPIO and UART
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte PLIC_CLAIM0, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_m_plic_interrupts # clear interrupt two
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x0, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# =========== S-mode enable tests (7.X) ===========
.4byte 0x0, 0x0, goto_s_mode # go to s-mode. 0xb written to output
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIO Priority = 1
.4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UART Priority = 1
# Test 7.0: GPIO m-mode disabled
.4byte PLIC_INTEN00, 0x00000400, write32_test # disable GPIO m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.1: UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000008, write32_test # disable UART m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.2: GPIO s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000400, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x0000000A, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x0000000A, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.3: UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000008, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.4: GPIO and UART s-mode disabled
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000000, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.5: GPIO and UART m-mode disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000200, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000003, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000003, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# Test 7.6: GPIO and UART fully disabled
.4byte PLIC_INTEN00, 0x00000000, write32_test # disable GPIO interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000000, readsip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
.4byte PLIC_CLAIM1, 0x00000000, read32_test # read claim register
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending cleared for GPIO
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000001, write32_test # clear GPIO interrupt
.4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
.4byte PLIC_CLAIM1, 0x00000000, write32_test # complete claim made earlier
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt one
.4byte 0x0, 0x00000000, claim_s_plic_interrupts # clear interrupt two
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupts pending
# =========== Special claim tests (8) ===========
.4byte 0x0, 0x0, goto_m_mode # write 0x9 to output
.4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # GPIO Priority = 6
.4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UART Priority = 7
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable all m-mode interrupts
.4byte PLIC_INTEN10, 0x00000000, write32_test # enable all s-mode interrupts
.4byte PLIC_THRESH0, 0x00000005, write32_test # set m-mode threshold to 5
# Test 8
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte UART_MSR, 0x0F, write08_test # cause UART interrupt
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # read interrupt pending
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # claim UART
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # UART interrupt cleared
.4byte PLIC_CLAIM0, 0x00000003, read32_test # claim GPIO
.4byte 0x0, 0x00000000, readmip_test # no interrupts, meip is low
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # both interrupts claimed
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete GPIO
.4byte 0x0, 0x00000800, readmip_test # GPIO interrupt sets MEIP
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # GPIO bit is set
.4byte PLIC_CLAIM0, 0x00000003, read32_test # claim GPIO again
.4byte 0x0, 0x00000000, readmip_test # meip is zeroed
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # both interrupts claimed
.4byte PLIC_CLAIM0, 0x0000000A, write32_test # complete UART claim
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000400, read32_test # UART pending
.4byte PLIC_CLAIM0, 0x00000003, write32_test # complete GPIO claim
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000408, read32_test # GPIO and UART pending
.4byte PLIC_CLAIM0, 0x0000000A, read32_test # claim UART
.4byte 0x0, 0x0, terminate_test # terminate tests

View file

@ -0,0 +1,493 @@
///////////////////////////////////////////
//
// WALLY-gpio
//
// Author: David_Harris@hmc.edu and Nicholas Lucio <nlucio@hmc.edu>
//
// Created 2022-06-16
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
#include "WALLY-TEST-LIB-32.h"
INIT_TESTS
TRAP_HANDLER m
j run_test_loop // begin test loop/table tests instead of executing inline code.
INIT_TEST_TABLE
END_TESTS
TEST_STACK_AND_DATA
.align 2
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.4byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.4byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# =========== Define PLIC registers ===========
.equ PLIC, 0x0C000000
.equ PLIC_INTPRI_GPIO, (PLIC+0x00000C) # GPIO is interrupt 3
.equ PLIC_INTPRI_UART, (PLIC+0x000028) # UART is interrupt 10
.equ PLIC_INTPENDING0, (PLIC+0x001000) # intPending0 register
.equ PLIC_INTEN00, (PLIC+0x002000) # interrupt enables for context 0 (machine mode) sources 31:1
.equ PLIC_INTEN10, (PLIC+0x002080) # interrupt enables for context 1 (supervisor mode) sources 31:1
.equ PLIC_THRESH0, (PLIC+0x200000) # Priority threshold for context 0 (machine mode)
.equ PLIC_CLAIM0, (PLIC+0x200004) # Claim/Complete register for context 0
.equ PLIC_THRESH1, (PLIC+0x201000) # Priority threshold for context 1 (supervisor mode)
.equ PLIC_CLAIM1, (PLIC+0x201004) # Claim/Complete register for context 1
# =========== Define GPIO registers ===========
.equ GPIO, 0x10060000
.equ input_val, (GPIO+0x00)
.equ input_en, (GPIO+0x04)
.equ output_en, (GPIO+0x08)
.equ output_val, (GPIO+0x0C)
.equ rise_ie, (GPIO+0x18)
.equ rise_ip, (GPIO+0x1C)
.equ fall_ie, (GPIO+0x20)
.equ fall_ip, (GPIO+0x24)
.equ high_ie, (GPIO+0x28)
.equ high_ip, (GPIO+0x2C)
.equ low_ie, (GPIO+0x30)
.equ low_ip, (GPIO+0x34)
.equ iof_en, (GPIO+0x38)
.equ iof_sel, (GPIO+0x3C)
.equ out_xor, (GPIO+0x40)
# =========== Define UART registers ===========
.equ UART, 0x10000000
.equ UART_IER, (UART+0x01)
.equ UART_MCR, (UART+0x04)
.equ UART_MSR, (UART+0x06)
# =========== Initialize UART and GPIO ===========
# GPIO Initialization
.4byte input_en, 0x00000001, write32_test # enable bit 0 of input_en
.4byte output_en, 0x00000001, write32_test # enable bit 0 of output_en
.4byte output_val, 0x00000000, write32_test # make sure output_val is 0
.4byte rise_ie, 0x00000001, write32_test # enable rise interrupts
# UART Initialization
.4byte UART_IER, 0x08, write08_test # enable modem status interrupts from CTS
.4byte UART_MCR, 0x10, write08_test # enable loopback mode, RTS = 0
.4byte UART_MSR, 0x00, write08_test # disable UART interrupt
# =========== Initialize relevant PLIC registers ===========
.4byte PLIC_INTPRI_GPIO, 0x00000000, write32_test # set GPIO priority to zero
.4byte PLIC_INTPRI_UART, 0x00000000, write32_test # set UART priority to zero
.4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
.4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
.4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
.4byte PLIC_THRESH1, 0x00000007, write32_test # set s-mode threshold to max
# =========== Machine-Mode Priority Testing (1.T.X) ===========
# Test 1.0.0: GPIO int lacks priority (0 = 0)
.4byte PLIC_THRESH0, 0x00000000, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect no interrupt pending *** pending bug?????
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.0.1: GPIO int has priority (1 > 0)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.0.2: meip and c/c clear without interrupt pending
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
# Test 1.1.0: GPIO lacks priority (1 = 1)
.4byte PLIC_THRESH0, 0x00000001, write32_test # change threshold
.4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.1.1: GPIO int has priority (2 > 1)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000002, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.2.0: GPIO int lacks priority (2 = 2)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000002, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.2.1: GPIO int has priority (3 > 2)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000003, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.3.0: GPIO int lacks priority (3 = 3)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000003, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.3.1: GPIO int has priority (4 > 3)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000004, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.4.0: GPIO int lacks priority (4 = 4)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000004, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.4.1: GPIO int has priority (5 > 4)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000005, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.5.0: GPIO int lacks priority (5 = 5)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000005, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.5.1: GPIO int has priority (6 > 5)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.6.0: GPIO int lacks priority (6 = 6)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000006, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.6.1: GPIO int has priority (7 > 6)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_INTPRI_GPIO, 0x00000007, write32_test # let GPIO cause interrupts
.4byte 0x0, 0x00000800, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000008, read32_test # expect interrupt pending on bit 3
.4byte 0x0, 0x00000003, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# Test 1.7.0: GPIO int lacks priority (7 = 7)
.4byte output_val, 0x00000001, write32_test # set GPIO rise_ip high
.4byte PLIC_THRESH0, 0x00000007, write32_test # change threshold
.4byte 0x0, 0x00000000, readmip_test # read mip
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # expect no interrupt pending
.4byte 0x0, 0x00000000, readmclaimcomplete_test # read and clear claimcomplete
.4byte PLIC_INTPENDING0, 0x00000000, read32_test # interrupt pending was cleared
.4byte output_val, 0x00000000, write32_test # clear output_val
.4byte rise_ip, 0x00000000, write32_test # clear interrupt
# # =========== UART vs GPIO priority (2.X) =========== ***
# .4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
# .4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
# .4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
# .4byte PLIC_THRESH1, 0x00000007, write32_test # set s-mode threshold to max
# # Test 2.0: GPIO Priority = UART Priority
# .4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIOPriority = 1
# .4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UARTPriority = 1
# .4byte 0x0, 0x00000800, readmip_test # read mip
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # GPIO claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000200, read32_test # GPIO interrupt was cleared
# .4byte 0x0, 0x00000800, readmip_test # expect mip to remain high
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # UART claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # UART interrupt pending was cleared
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 2.1: GPIO Priority < UART Priority
# .4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000002, write32_test # GPIO Priority = 2
# .4byte PLIC_INTPRI_UART, 0x00000003, write32_test # UART Priority = 3
# .4byte 0x0, 0x00000800, readmip_test # read mip
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for UART and GPIO
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # UART claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000008, read32_test # UART interrupt was cleared
# .4byte 0x0, 0x00000800, readmip_test # expect mip to remain high
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # GPIO claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # GPIO interrupt pending was cleared
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 2.2: GPIO Priority > UART Priority
# .4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000005, write32_test # GPIO Priority = 5
# .4byte PLIC_INTPRI_UART, 0x00000004, write32_test # UART Priority = 4
# .4byte 0x0, 0x00000800, readmip_test # read mip
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # GPIO claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000200, read32_test # GPIO interrupt was cleared
# .4byte 0x0, 0x00000800, readmip_test # expect mip to remain high
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # UART claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # UART interrupt pending was cleared
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 2.3: GPIO Priority < UART Priority (2)
# .4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # GPIO Priority = 6
# .4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UART Priority = 7
# .4byte 0x0, 0x00000800, readmip_test # read mip
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for UART and GPIO
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # UART claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000008, read32_test # UART interrupt was cleared
# .4byte 0x0, 0x00000800, readmip_test # expect mip to remain high
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # GPIO claim/complete process
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # GPIO interrupt pending was cleared
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 2.4: Interrupts disabled (Thresh0 = 7)
# .4byte output_val, 0x00000001, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_THRESH0, 0x00000007, write32_test # Disable m-mode interrupts
# .4byte PLIC_INTPRI_GPIO, 0x00000007, write32_test # GPIO Priority = 7
# .4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UART Priority = 7
# .4byte 0x0, 0x00000000, readmip_test, # read mip
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# .4byte 0x0, 0x00000000, readmclaimcomplete_test # no interrupt pending
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # =========== SEIP tests (3.X) ===========
# .4byte PLIC_INTEN00, 0x00000408, write32_test # enable m-mode interrupts
# .4byte PLIC_INTEN10, 0x00000408, write32_test # enable s-mode interrupts
# .4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
# .4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
# # Test 3.0: Cause machine and supervisor interrupts
# .4byte output_val, 0x00000000, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIO Priority = 1
# .4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UART Priority = 1
# .4byte 0x0, 0x00000A00, readmip_test # Expect high on MEIP and SEIP
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # Expect GPIO on claim/complete
# .4byte 0x0, 0x00000A00, readmip_test # Still expect high on MEIP and SEIP
# .4byte PLIC_INTPENDING0, 0x00000200, read32_test # GPIO interrupt was cleared
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # Expect UART on claim/complete
# .4byte 0x0, 0x00000000, readmip_test # all interrupts were cleared
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # Pending should also be clear
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 3.1: Suppress machine mode interrupts
# .4byte output_val, 0x00000000, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000003, write32_test # GPIO Priority = 3
# .4byte PLIC_INTPRI_UART, 0x00000002, write32_test # UART Priority = 2
# .4byte PLIC_THRESH0, 0x00000007, write32_test # set m-mode threshold to 7
# .4byte 0x0, 0x00000200, readmip_test # Expect high on SEIP only
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # Expect GPIO on claim/complete
# .4byte 0x0, 0x00000200, readmip_test # Expect high on SEIP only
# .4byte PLIC_INTPENDING0, 0x00000200, read32_test # GPIO interrupt was cleared
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # Expect UART on claim/complete
# .4byte 0x0, 0x00000000, readmip_test # all interrupts were cleared
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # Pending should also be clear
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 3.2: Cause SEIP with UART first
# .4byte output_val, 0x00000000, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000006, write32_test # GPIO Priority = 6
# .4byte PLIC_INTPRI_UART, 0x00000007, write32_test # UART Priority = 7
# .4byte 0x0, 0x00000200, readmip_test # Expect high on SEIP only
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # Expect UART on claim/complete
# .4byte 0x0, 0x00000200, readmip_test # Expect high on SEIP only
# .4byte PLIC_INTPENDING0, 0x00000008, read32_test # UART interrupt was cleared
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # Expect GPIO on claim/complete
# .4byte 0x0, 0x00000000, readmip_test # all interrupts were cleared
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # Pending should also be clear
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # Test 3.3: Low SEIP due to insufficient priority
# .4byte output_val, 0x00000000, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTPRI_GPIO, 0x00000002, write32_test # GPIO Priority = 2
# .4byte PLIC_INTPRI_UART, 0x00000003, write32_test # UART Priority = 3
# .4byte PLIC_THRESH0, 0x00000004, write32_test # set m-mode threshold to 7
# .4byte PLIC_THRESH1, 0x00000005, write32_test # set s-mode threshold to 7
# .4byte 0x0, 0x00000000, readmip_test # no interrupt pending
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # no interrupt pending
# .4byte 0x0, 0x00000000, readmclaimcomplete_test # Expect nothing on claim/complete
# .4byte output_val, 0x00000000, write32_test # clear output_val
# .4byte rise_ip, 0x00000000, write32_test # clear GPIO interrupt
# .4byte UART_MSR, 0x00000000, write08_test # clear UART interrupt
# # =========== UART interrupt enable tests (4.X) ===========
# .4byte PLIC_THRESH0, 0x00000000, write32_test # set m-mode threshold to 0
# .4byte PLIC_THRESH1, 0x00000000, write32_test # set s-mode threshold to 0
# .4byte PLIC_INTPRI_GPIO, 0x00000001, write32_test # GPIO Priority = 1
# .4byte PLIC_INTPRI_UART, 0x00000001, write32_test # UART Priority = 1
# # Test 4.0: GPIO m-mode disabled
# .4byte output_val, 0x00000000, write32_test # cause rise_ip to go high
# .4byte UART_MSR, 0x00000010, write08_test # step 1 of UART interrupt
# .4byte UART_MSR, 0x00000012, write08_test # step 2 of UART interrupt
# .4byte PLIC_INTEN00, 0x000000200, write32_test # GPIO m-mode interrupt disabled
# .4byte PLIC_INTEN00, 0x000000208, write32_test # No s-mode interrupt disabled
# .4byte 0x0, 0x00000A00, readmip_test # Expect high on MEIP from UART and SEIP from GPIO
# .4byte PLIC_INTPENDING0, 0x00000408, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x00000003, readmclaimcomplete_test # Expect GPIO on claim/complete
# .4byte 0x0, 0x00000200, readmip_test # Expect high on MEIP and SEIP from UART
# .4byte PLIC_INTPENDING0, 0x00000200, read32_test # interrupt pending for GPIO and UART
# .4byte 0x0, 0x0000000A, readmclaimcomplete_test # Expect UART on claim/complete
# .4byte 0x0, 0x00000000, readmip_test # all interrupts were cleared
# .4byte PLIC_INTPENDING0, 0x00000000, read32_test # Pending should also be clear
# Test 4.1: UART m-mode disabled
# Test 4.2: GPIO s-mode disabled
# Test 4.3: UART s-mode disabled
# Test 4.4: GPIO and UART s-mode disabled
# Test 4.5: GPIO and UART m-mode disabled
# Test 4.6: GPIO and UART fully disabled
.4byte 0x0, 0x0, terminate_test # terminate tests

View file

@ -0,0 +1,140 @@
///////////////////////////////////////////
//
// WALLY-uart
//
// Author: David_Harris@hmc.edu and Nicholas Lucio <nlucio@hmc.edu>
//
// Created 2022-06-16
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
#include "WALLY-TEST-LIB-32.h"
INIT_TESTS
TRAP_HANDLER m
j run_test_loop // begin test loop/table tests instead of executing inline code.
INIT_TEST_TABLE
END_TESTS
TEST_STACK_AND_DATA
.align 2
.equ UART, 0x10000000
.equ UART_RBR, (UART)
.equ UART_THR, (UART)
.equ UART_IER, (UART+0x01)
.equ UART_IIR, (UART+0x02)
.equ UART_FCR, (UART+0x02)
.equ UART_LCR, (UART+0x03)
.equ UART_MCR, (UART+0x04)
.equ UART_LSR, (UART+0x05)
.equ UART_MSR, (UART+0x06)
.equ UART_Scr, (UART+0x07)
test_cases:
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.4byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.4byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# =========== UART resets to correct values on master reset ===========
.4byte UART_IER, 0x00, read08_test
.4byte UART_IIR, 0x01, read08_test # IIR resets to 1
# .4byte UART_LCR, 0x00, read08_test *** commented out because LCR should reset to zero but resets to 3
.4byte UART_MCR, 0x00, read08_test
.4byte UART_LSR, 0x60, read08_test # LSR resets with transmit status bits set
.4byte UART_MSR, 0x00, read04_test
# =========== Basic read-write ===========
.4byte UART_LCR, 0x00, write08_test # set LCR to reset value *** remove if UART resets to correct value
.4byte UART_MCR, 0x10, write08_test # put UART into loopback for MSR test
.4byte UART_LSR, 0x60, read08_test
.4byte UART_THR, 0x00, write08_test # write value to UART
.4byte UART_LSR, 0x00, read08_test # data not ready and transmitter is not empty
.4byte 0x0, 0x0101, uart_data_wait # wait for data to become ready then output IIR and LSR
.4byte UART_RBR, 0x00, read08_test # read written value
.4byte UART_LSR, 0x60, read08_test # read LSR
# =========== Different size read-write ===========
# Transmit 5 bits
.4byte UART_LCR, 0x00, write08_test # set LCR to transmit 5 bits
.4byte UART_THR, 0x55, write08_test # write value to UART
.4byte 0x0, 0x0101, uart_data_wait # wait for data to become ready then output IIR and then LSR
.4byte UART_RBR, 0x15, read08_test # read written value without bits 5-7
# Transmit 6 bits
.4byte UART_LCR, 0x01, write08_test # set LCR to transmit six bits
.4byte UART_THR, 0xAA, write08_test # write value to UART
.4byte 0x0, 0x0101, uart_data_wait # wait for data to become ready then output IIR and then LSR
.4byte UART_RBR, 0x2A, read08_test # read written value without bits 6 & 7
# Transmit 7 bits
.4byte UART_LCR, 0x02, write08_test # set LCR to transmit seven bits
.4byte UART_THR, 0xFF, write08_test # write value to UART
.4byte 0x0, 0x0101, uart_data_wait # wait for data to become ready then output IIR and then LSR
.4byte UART_RBR, 0x7F, read08_test # read written value without bit 7
# Transmit 8 bits
.4byte UART_LCR, 0x03, write08_test # set LCR to transmit seven bits
.4byte UART_THR, 0x80, write08_test # write value to UART
.4byte 0x0, 0x0101, uart_data_wait # wait for data to become ready then output IIR and then LSR
.4byte UART_RBR, 0x80, read08_test # read full written value + sign extension
# =========== Transmit-related interrupts ===========
.4byte UART_IER, 0x07, write08_test # enable data available, buffer empty, and line status interrupts
.4byte UART_IIR, 0x02, read08_test # buffer should be empty, causing interrupt
.4byte UART_THR, 0x00, write08_test # write zeroes to transmitter
.4byte 0x0, 0x0401, uart_data_wait # IIR should have data ready interrupt
.4byte UART_THR, 0x01, write08_test # write 1 to transmitter buffer
.4byte UART_IIR, 0x04, read08_test # data interrupt should still be high
.4byte 0x0, 0x06, uart_lsr_intr_wait # wait for transmission to complete, IIR should throw error due to overrun error.
.4byte UART_LSR, 0x63, read08_test # read overrun error from LSR
.4byte UART_IIR, 0x04, read08_test # check that LSR interrupt was cleared
.4byte UART_RBR, 0x01, read08_test # read previous value from UART
# =========== MODEM interrupts ===========
.4byte UART_MSR, 0x00, write08_test # clear MSR
.4byte UART_IER, 0x08, write08_test # enable MODEM Status interrupts
.4byte UART_IIR, 0x01, read08_test # no interrupts pending
.4byte UART_MCR, 0x02, write08_test # Cause DCTS interrupt
.4byte UART_IIR, 0x00, read08_test # MODEM interrupt
.4byte UART_MSR, 0x11, read08_test # Read MSR to clear interrupt
.4byte UART_IIR, 0x01, read08_test # interrupt cleared by reading MSR
.4byte 0x0, 0x0, terminate_test