2022-07-07 23:01:33 +00:00
|
|
|
///////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Written: me@KatherineParry.com
|
|
|
|
// Modified: 7/5/2022
|
|
|
|
//
|
|
|
|
// Purpose: control unit
|
|
|
|
//
|
|
|
|
// A component of the Wally configurable RISC-V project.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
|
|
|
//
|
|
|
|
// MIT LICENSE
|
|
|
|
// 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.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
2022-06-01 23:34:29 +00:00
|
|
|
`include "wally-config.vh"
|
2021-04-04 18:09:13 +00:00
|
|
|
|
|
|
|
module fctrl (
|
2022-07-20 02:27:39 +00:00
|
|
|
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,
|
2021-07-24 18:59:57 +00:00
|
|
|
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
|
2022-05-03 11:56:31 +00:00
|
|
|
input logic [1:0] STATUS_FS, // is FPU enabled?
|
2022-07-20 02:27:39 +00:00
|
|
|
input logic FDivBusyE, // is the divider busy
|
2022-07-20 21:57:23 +00:00
|
|
|
output logic IllegalFPUInstrD, IllegalFPUInstrM, // Is the instruction an illegal fpu instruction
|
2022-07-20 02:27:39 +00:00
|
|
|
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
|
2022-07-21 01:20:06 +00:00
|
|
|
output logic XEnE, YEnE, ZEnE,
|
|
|
|
output logic YEnForwardE, ZEnForwardE,
|
2022-07-20 02:27:39 +00:00
|
|
|
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
|
2021-07-24 18:59:57 +00:00
|
|
|
);
|
2021-04-04 18:09:13 +00:00
|
|
|
|
2022-06-13 22:47:51 +00:00
|
|
|
`define FCTRLW 11
|
2021-06-28 22:53:58 +00:00
|
|
|
logic [`FCTRLW-1:0] ControlsD;
|
2022-07-20 21:57:23 +00:00
|
|
|
logic IllegalFPUInstrE;
|
2022-07-20 02:27:39 +00:00
|
|
|
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
|
2022-06-13 22:47:51 +00:00
|
|
|
//*** will putting x for don't cares reduce area in synthisis???
|
2021-06-28 22:53:58 +00:00
|
|
|
// FPU Instruction Decoder
|
|
|
|
always_comb
|
2022-05-03 11:56:31 +00:00
|
|
|
if (STATUS_FS == 2'b00) // FPU instructions are illegal when FPU is disabled
|
2022-06-14 23:58:39 +00:00
|
|
|
ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1;
|
2022-05-03 11:56:31 +00:00
|
|
|
else case(OpD)
|
2022-06-13 22:47:51 +00:00
|
|
|
// FRegWrite_FWriteInt_FResSel_PostProcSel_FOpCtrl_FDivStart_IllegalFPUInstr
|
2021-06-28 22:53:58 +00:00
|
|
|
7'b0000111: case(Funct3D)
|
2022-06-14 23:58:39 +00:00
|
|
|
3'b010: ControlsD = `FCTRLW'b1_0_10_xx_0xx_0_0; // flw
|
|
|
|
3'b011: ControlsD = `FCTRLW'b1_0_10_xx_0xx_0_0; // fld
|
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
|
|
|
7'b0100111: case(Funct3D)
|
2022-06-28 21:33:31 +00:00
|
|
|
3'b010: ControlsD = `FCTRLW'b0_0_10_xx_0xx_0_0; // fsw
|
|
|
|
3'b011: ControlsD = `FCTRLW'b0_0_10_xx_0xx_0_0; // fsd
|
2022-06-14 23:58:39 +00:00
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2022-06-13 22:47:51 +00:00
|
|
|
7'b1000011: ControlsD = `FCTRLW'b1_0_01_10_000_0_0; // fmadd
|
|
|
|
7'b1000111: ControlsD = `FCTRLW'b1_0_01_10_001_0_0; // fmsub
|
|
|
|
7'b1001011: ControlsD = `FCTRLW'b1_0_01_10_010_0_0; // fnmsub
|
|
|
|
7'b1001111: ControlsD = `FCTRLW'b1_0_01_10_011_0_0; // fnmadd
|
2021-06-28 22:53:58 +00:00
|
|
|
7'b1010011: casez(Funct7D)
|
2022-06-13 22:47:51 +00:00
|
|
|
7'b00000??: ControlsD = `FCTRLW'b1_0_01_10_110_0_0; // fadd
|
|
|
|
7'b00001??: ControlsD = `FCTRLW'b1_0_01_10_111_0_0; // fsub
|
|
|
|
7'b00010??: ControlsD = `FCTRLW'b1_0_01_10_100_0_0; // fmul
|
2022-06-14 23:58:39 +00:00
|
|
|
7'b00011??: ControlsD = `FCTRLW'b1_0_01_01_xx0_1_0; // fdiv
|
|
|
|
7'b01011??: ControlsD = `FCTRLW'b1_0_01_01_xx1_1_0; // fsqrt
|
2021-06-28 22:53:58 +00:00
|
|
|
7'b00100??: case(Funct3D)
|
2022-06-14 23:58:39 +00:00
|
|
|
3'b000: ControlsD = `FCTRLW'b1_0_00_xx_000_0_0; // fsgnj
|
|
|
|
3'b001: ControlsD = `FCTRLW'b1_0_00_xx_001_0_0; // fsgnjn
|
|
|
|
3'b010: ControlsD = `FCTRLW'b1_0_00_xx_010_0_0; // fsgnjx
|
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
|
|
|
7'b00101??: case(Funct3D)
|
2022-06-14 23:58:39 +00:00
|
|
|
3'b000: ControlsD = `FCTRLW'b1_0_00_xx_110_0_0; // fmin
|
|
|
|
3'b001: ControlsD = `FCTRLW'b1_0_00_xx_101_0_0; // fmax
|
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
|
|
|
7'b10100??: case(Funct3D)
|
2022-06-14 23:58:39 +00:00
|
|
|
3'b010: ControlsD = `FCTRLW'b0_1_00_xx_010_0_0; // feq
|
|
|
|
3'b001: ControlsD = `FCTRLW'b0_1_00_xx_001_0_0; // flt
|
|
|
|
3'b000: ControlsD = `FCTRLW'b0_1_00_xx_011_0_0; // fle
|
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx__0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2022-06-14 23:58:39 +00:00
|
|
|
7'b11100??: if (Funct3D == 3'b001) ControlsD = `FCTRLW'b0_1_10_xx_000_0_0; // fclass
|
|
|
|
else if (Funct3D[1:0] == 2'b00) ControlsD = `FCTRLW'b0_1_11_xx_000_0_0; // fmv.x.w to int reg
|
|
|
|
else if (Funct3D[1:0] == 2'b01) ControlsD = `FCTRLW'b0_1_11_xx_000_0_0; // fmv.x.d to int reg
|
|
|
|
else ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2022-06-13 22:47:51 +00:00
|
|
|
7'b1101000: case(Rs2D[1:0])
|
|
|
|
2'b00: ControlsD = `FCTRLW'b1_0_01_00_101_0_0; // fcvt.s.w w->s
|
|
|
|
2'b01: ControlsD = `FCTRLW'b1_0_01_00_100_0_0; // fcvt.s.wu wu->s
|
|
|
|
2'b10: ControlsD = `FCTRLW'b1_0_01_00_111_0_0; // fcvt.s.l l->s
|
|
|
|
2'b11: ControlsD = `FCTRLW'b1_0_01_00_110_0_0; // fcvt.s.lu lu->s
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2021-07-11 22:06:33 +00:00
|
|
|
7'b1100000: case(Rs2D[1:0])
|
2022-06-13 22:47:51 +00:00
|
|
|
2'b00: ControlsD = `FCTRLW'b0_1_01_00_001_0_0; // fcvt.w.s s->w
|
|
|
|
2'b01: ControlsD = `FCTRLW'b0_1_01_00_000_0_0; // fcvt.wu.s s->wu
|
|
|
|
2'b10: ControlsD = `FCTRLW'b0_1_01_00_011_0_0; // fcvt.l.s s->l
|
|
|
|
2'b11: ControlsD = `FCTRLW'b0_1_01_00_010_0_0; // fcvt.lu.s s->lu
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2022-06-14 23:58:39 +00:00
|
|
|
7'b1111000: ControlsD = `FCTRLW'b1_0_00_xx_011_0_0; // fmv.w.x to fp reg
|
2022-06-13 22:47:51 +00:00
|
|
|
7'b0100000: ControlsD = `FCTRLW'b1_0_01_00_000_0_0; // fcvt.s.d
|
2021-07-11 22:06:33 +00:00
|
|
|
7'b1101001: case(Rs2D[1:0])
|
2022-06-13 22:47:51 +00:00
|
|
|
2'b00: ControlsD = `FCTRLW'b1_0_01_00_101_0_0; // fcvt.d.w w->d
|
|
|
|
2'b01: ControlsD = `FCTRLW'b1_0_01_00_100_0_0; // fcvt.d.wu wu->d
|
|
|
|
2'b10: ControlsD = `FCTRLW'b1_0_01_00_111_0_0; // fcvt.d.l l->d
|
|
|
|
2'b11: ControlsD = `FCTRLW'b1_0_01_00_110_0_0; // fcvt.d.lu lu->d
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2021-07-11 22:06:33 +00:00
|
|
|
7'b1100001: case(Rs2D[1:0])
|
2022-06-13 22:47:51 +00:00
|
|
|
2'b00: ControlsD = `FCTRLW'b0_1_01_00_001_0_0; // fcvt.w.d d->w
|
|
|
|
2'b01: ControlsD = `FCTRLW'b0_1_01_00_000_0_0; // fcvt.wu.d d->wu
|
|
|
|
2'b10: ControlsD = `FCTRLW'b0_1_01_00_011_0_0; // fcvt.l.d d->l
|
|
|
|
2'b11: ControlsD = `FCTRLW'b0_1_01_00_010_0_0; // fcvt.lu.d d->lu
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2022-06-14 23:58:39 +00:00
|
|
|
7'b1111001: ControlsD = `FCTRLW'b1_0_00_xx_011_0_0; // fmv.d.x to fp reg
|
2022-06-13 22:47:51 +00:00
|
|
|
7'b0100001: ControlsD = `FCTRLW'b1_0_01_00_001_0_0; // fcvt.d.s
|
2022-06-14 23:58:39 +00:00
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2022-06-14 23:58:39 +00:00
|
|
|
default: ControlsD = `FCTRLW'b0_0_00_xx_0xx_0_1; // non-implemented instruction
|
2021-06-28 22:53:58 +00:00
|
|
|
endcase
|
2021-07-24 18:59:57 +00:00
|
|
|
|
2021-06-28 22:53:58 +00:00
|
|
|
// unswizzle control bits
|
2022-07-20 02:27:39 +00:00
|
|
|
assign {FRegWriteD, FWriteIntD, FResSelD, PostProcSelD, OpCtrlD, DivStartD, IllegalFPUInstrD} = ControlsD;
|
2021-04-04 18:09:13 +00:00
|
|
|
|
2021-07-24 18:59:57 +00:00
|
|
|
// rounding modes:
|
|
|
|
// 000 - round to nearest, ties to even
|
|
|
|
// 001 - round twords 0 - round to min magnitude
|
|
|
|
// 010 - round down - round twords negitive infinity
|
|
|
|
// 011 - round up - round twords positive infinity
|
|
|
|
// 100 - round to nearest, ties to max magnitude - round to nearest, ties away from zero
|
|
|
|
// 111 - dynamic - choose FRM_REGW as rounding mode
|
2021-06-28 22:53:58 +00:00
|
|
|
assign FrmD = &Funct3D ? FRM_REGW : Funct3D;
|
2021-05-01 02:18:01 +00:00
|
|
|
|
2021-06-28 22:53:58 +00:00
|
|
|
// Precision
|
2021-07-24 18:59:57 +00:00
|
|
|
// 0-single
|
|
|
|
// 1-double
|
2022-06-01 23:34:29 +00:00
|
|
|
|
2022-06-02 19:50:28 +00:00
|
|
|
if (`FPSIZES == 1)
|
|
|
|
assign FmtD = 0;
|
2022-06-01 23:34:29 +00:00
|
|
|
else if (`FPSIZES == 2)begin
|
|
|
|
logic [1:0] FmtTmp;
|
2022-06-28 21:33:31 +00:00
|
|
|
assign FmtTmp = ((Funct7D[6:3] == 4'b0100)&OpD[4]) ? Rs2D[1:0] : (~OpD[6]&(&OpD[2:0])) ? {~Funct3D[1], ~(Funct3D[1]^Funct3D[0])} : Funct7D[1:0];
|
2022-06-06 16:06:04 +00:00
|
|
|
assign FmtD = (`FMT == FmtTmp);
|
2022-06-01 23:34:29 +00:00
|
|
|
end
|
|
|
|
else if (`FPSIZES == 3|`FPSIZES == 4)
|
2022-06-20 22:53:13 +00:00
|
|
|
assign FmtD = ((Funct7D[6:3] == 4'b0100)&OpD[4]) ? Rs2D[1:0] : Funct7D[1:0];
|
2021-07-24 18:59:57 +00:00
|
|
|
|
2022-07-20 21:57:23 +00:00
|
|
|
|
|
|
|
|
2022-07-21 01:20:06 +00:00
|
|
|
// 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];
|
2022-07-20 21:57:23 +00:00
|
|
|
|
2022-06-13 22:47:51 +00:00
|
|
|
// Final Res Sel:
|
|
|
|
// fp int
|
|
|
|
// 00 other cmp
|
|
|
|
// 01 postproc cvt
|
|
|
|
// 10 store class
|
|
|
|
// 11 mv
|
2021-06-28 22:53:58 +00:00
|
|
|
|
2022-06-13 22:47:51 +00:00
|
|
|
// post processing Sel:
|
|
|
|
// 00 cvt
|
|
|
|
// 01 div
|
|
|
|
// 10 fma
|
2021-06-28 22:53:58 +00:00
|
|
|
|
2022-06-13 22:47:51 +00:00
|
|
|
// Other Sel:
|
2022-07-20 02:27:39 +00:00
|
|
|
// Ctrl signal = {OpCtrl[2], &FOpctrl[1:0]}
|
2022-06-13 22:47:51 +00:00
|
|
|
// 000 - sign 00
|
|
|
|
// 001 - negate sign 00
|
|
|
|
// 010 - xor sign 00
|
|
|
|
// 011 - mv to fp 01
|
|
|
|
// 110 - min 10
|
|
|
|
// 101 - max 10
|
2021-06-28 22:53:58 +00:00
|
|
|
|
2022-06-13 22:47:51 +00:00
|
|
|
// OpCtrl:
|
|
|
|
// Fma: {not multiply-add?, negate prod?, negate Z?}
|
|
|
|
// 000 - fmadd
|
|
|
|
// 001 - fmsub
|
|
|
|
// 010 - fnmsub
|
|
|
|
// 011 - fnmadd
|
|
|
|
// 100 - mul
|
|
|
|
// 110 - add
|
|
|
|
// 111 - sub
|
|
|
|
// Div:
|
|
|
|
// 0 - ???
|
|
|
|
// 1 - ???
|
|
|
|
// Cvt Int: {Int to Fp?, 64 bit int?, signed int?}
|
|
|
|
// Cvt Fp: output format
|
|
|
|
// 10 - to half
|
|
|
|
// 00 - to single
|
|
|
|
// 01 - to double
|
|
|
|
// 11 - to quad
|
|
|
|
// Cmp: {equal?, less than?}
|
|
|
|
// 010 - eq
|
|
|
|
// 001 - lt
|
|
|
|
// 011 - le
|
|
|
|
// 110 - min
|
|
|
|
// 101 - max
|
|
|
|
// Sgn:
|
|
|
|
// 00 - sign
|
|
|
|
// 01 - negate sign
|
|
|
|
// 10 - xor sign
|
2021-06-28 22:53:58 +00:00
|
|
|
|
2022-07-20 02:27:39 +00:00
|
|
|
// 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);
|
2022-07-20 21:57:23 +00:00
|
|
|
if(`FLEN>`XLEN)
|
|
|
|
flopenrc #(1) DEIllegalReg(clk, reset, FlushE, ~StallE, IllegalFPUInstrD, IllegalFPUInstrE);
|
2022-07-20 02:27:39 +00:00
|
|
|
// 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});
|
2022-07-20 21:57:23 +00:00
|
|
|
if(`FLEN>`XLEN)
|
|
|
|
flopenrc #(1) EMIllegalReg(clk, reset, FlushM, ~StallM, IllegalFPUInstrE, IllegalFPUInstrM);
|
2022-07-20 02:27:39 +00:00
|
|
|
// M/W pipleine register
|
|
|
|
flopenrc #(3) MWCtrlReg(clk, reset, FlushW, ~StallW,
|
|
|
|
{FRegWriteM, FResSelM},
|
|
|
|
{FRegWriteW, FResSelW});
|
2021-06-21 00:24:09 +00:00
|
|
|
|
2021-04-04 18:09:13 +00:00
|
|
|
endmodule
|