diff --git a/doc/spec/SPI.md b/doc/spec/SPI.md new file mode 100644 index 0000000..b83ed2f --- /dev/null +++ b/doc/spec/SPI.md @@ -0,0 +1,19 @@ +# SPI特性 + + +## 同步采样SPI/QSPI + +同步采样SPI通过使用系统驱动的时钟,将输入的spi/QSPI信号全部当作异步数据信号,通过观测CSN,以及其余信号和SCK的关系,采样SPI/QSPI的输入,并给出输出 + +使用这种方法允许的QSPI传输速度会受到限制,使用慢模式时,允许的SCK速率为无穷小到1/2主时钟频率,当使用快模式时,允许的SCK速度为1/2主时钟频率到1倍主时钟频率 + + +## 异步采样SPI/QSPI + +异步采样设计的SPI/QSPI端直接使用SCK作为敏感源,因此允许更高的传输速度,但是SPI数据测和主时钟域需要精确地进行跨时钟域处理 + + + + + + diff --git a/doc/spec/SlaveParser.md b/doc/spec/SlaveParser.md new file mode 100644 index 0000000..180b170 --- /dev/null +++ b/doc/spec/SlaveParser.md @@ -0,0 +1,113 @@ +# SlaveParser + +---------------------------- + +以下为用户区域 + +--------------------------- + +* 该模块例化在`MstSlvSwith`模块内,负责从站接收功能实现 +* 内部例化了两个`SlaveRecParser`(`downRecParser`和`upRecParser`)和两个`SlaveSendGen`(`downSendGen`和`upSendGen`) + + +## 接口 + +* `downIn`以`Decoupled`封装的axis格式的lvds下行串行数据输入 +* `downOut`以`Decoupled`封装的axis格式的lvds下行串行数据输出 +* `upIn`以`Decoupled`封装的axis格式的lvds上行串行数据输入 +* `upOut`以`Decoupled`封装的axis格式的lvds上行串行数据输出 +* `sram_w`接入到4个`SmUnit`的SRAM写接口 +* `sram_r`接入到4个`SmUnit`的SRAM读接口 +* `dSMenq`接入到4个`SmUnit`的下行写入压栈Bool信号 +* `uSMdeq`接入到4个`SmUnit`的上行读出弹出Bool信号 +* `localDevIndex`输出本地设备的索引16bits +* `isDevOnRight`表示设备的“右边”(下行方向下一级)是否还有设备2bits,实际只使用了1bits +* `isDevOnRightModify`表示设备的“右边”(下行方向下一级)是否改变过 +* `indexOfRightDev`表示设备的“右边”(下行方向下一级)设备的索引号 +* `mstDeltaTimeStamp`输出32bits的时间戳信息 +* `slvDeltaTime`输出32bits的时间戳信息 +* `deltaFinal`输出64bits的时间戳信息 +* `isLoop`是否回环Bool +* `cReg`以结构体输入通用寄存器组 +* `sReg`以结构体输入从站寄存器组 +* `lvds`一个类似sram的访问接口,用于允许从lvds总线的访问读写寄存器区域 +* `intHWTrig`输出两个Bool硬件中断信号 +* `intHWClr`输入两个Bool硬件清除中断信号 +* `downRecStat`输出下行接收方向信息 +* `upRecStat`输出上行接收方向信息 + + +--------------------------------------------------------- + +## 主报文转发处理 + +* 下行发送模块`downSendGen`的帧头请求`frameReq`来自于下行接收`downRecParser`的报文头同步握手,同时`frameInfo`会被更改为本地设备的索引号`lcalDevIndex` + +* 上行发送模块`upSendGen`的帧头请求`frameReq` + - 上行接收`upRecParser`的报文头同步握手,此时`frameStyle`需要为普通包`FRAME_STYLE_COMMON`,转发完全相同的上行接收报文头 + - 下行接收到的是嗅探包而进入`isAckProbe`状态,发送(回复)嗅探包,`frameLenAim`为0,`frameStyle`为`FRAME_STYLE_PROBE`,`frameInfo`为`localDevIndex` + +## 子报文处理 + +* 子报文接收在上、下行各有2个位宽8bits,深度20的FIFO`downRecFifo`/`upRecFifo`,以乒乓方式工作,子报文负载信息先进入`RecFifo`,再由发送模块`SendGen`发送 +* 子报文接收在上、下行各有2组寄存器分别保存子报文头,子报文尾信息,以乒乓方式工作,发送模块发送时从寄存器中提取和修改信息 + + +## 索引特质 + +* 当子报文的`operator`为`SUBMSG_OPERATOR_INDEX`,为索引模式,从站按顺序更新自己的索引 +* 更新索引时 + - 本设备索引`localDevIndex`更新为子报文尾工作计数`workCnt`加1 + - 下行转发的`workCnt`计数也加1,即`localDevIndex` + - 右边(下行方向)设备索引`indexOfRightDev` + + 当是最后一个设备,记录为0 + + 不是最后一个设备,更新为子报文尾工作计数`workCnt`计数加2 + + +## 读写特质 + + +* 写操作发生在下行阶段 +* 读操作发生在上行阶段 +* 单独读(和/或)写操作是否执行需要根据子报文头的报文类型`style`进行判定 + - 当为顺序索引`SeqIndex`,只需要子报文头的设备索引`devIndex`匹配上本设备的索引`localDevIndex`,则需要进行操作 + - 当为逻辑索引`LgcIndex`, 则需要进一步根据EBMMU的配置进行判定 +* 广播读(和/或)写操作则均会被执行 +* 如果从站对该子报文进行了操作,则转发到下一级从站时,子报文的工作计数`workCnt`需要加1 +* lvds的写操作根据地址可以访问 + - 寄存器 + - SMUnit0 + - SMUnit2 + - SMUnit4 + - SMUnit6 +* lvds的写操作根据地址可以访问 + - 寄存器 + - SMUnit1 + - SMUnit3 + - SMUnit5 + - SMUnit7 +* 当lvds的读、写操作到特定地址时,触发SMUnit对应的写压入或者读弹出操作 + + + +### ebmmu + + +## 同步特质 + + + + + +## 嗅探特质 + +## + + + + +--------------------------------------- + +以下是大模型补充区域 + +--------------------------------------- \ No newline at end of file diff --git a/doc/spec/SlaveRecParser.md b/doc/spec/SlaveRecParser.md new file mode 100644 index 0000000..ca0e1a3 --- /dev/null +++ b/doc/spec/SlaveRecParser.md @@ -0,0 +1,147 @@ +# SlaveRecParser + +---------------------------- + +以下为用户区域 + +--------------------------- + +* 从站接收解析器使用状态机,将输入的数据流解析,获取到帧头,子报文头,负载数据,子报文尾,CRC校验等部分 +* `SlaveRecParser`在`SlaveParser`模块中例化2个,分别解析上行和下行方向接收到的数据 + +## 接口 + +* `rec`数据流输入接口,以axis协议传输 +* `data`以`decoupledIO`握手协议下的8bits数据传输,将负载数据传输到下一级逻辑 +* `stateNext` 组合逻辑输出下一拍状态机状态输出 +* `stateCurr` 当前状态机状态寄存器输出 +* `frameReq`以``validIO`握手协议输出帧头的信息,完整帧头信息以结构体打包 +* `subMsgHeadReq`以``validIO`握手协议输出子报文头的信息,完整子报文头信息以结构体打包 +* `subMsgTailReq`以``validIO`握手协议输出子报文尾的信息,完整子报文尾信息以结构体打包 +* `isError` 输出Bool下的错误状态,当状态机进入错误状态,则为真 +* `stat`输出传输状态 + - `isHeaderError `帧头错误 + - `isSubHeaderError`子报文头错误 + - `isPayloadError `负载错误 + - `isSubTailError `子报文尾错误 + - `isCRCError `CRC错误 + - `isFinish `传输正确完成 + - `isRecByteAck `接收到一个字节 +* `flush`软件复位 + +--------------------------------------- + + +## 状态机 +状态机有如下状态 +* `STATE_IDLE`空闲 +* `STATE_HEADER`解析帧头 +* `STATE_SUBMSG_HEADER`解析子报文头 +* `STATE_PAYLOAD_DATA`解析负载 +* `STATE_SUBMSG_TAIL`解析子报文尾 +* `STATE_CRC`CRC校验 +* `STATE_ERROR`传输错误 + +* 上电复位或者软件复位后,状态机应该处在空闲状态 +* 在`STATE_IDLE` + - 当输入的`rec`的`valid`从0跳1,则进入`STATE_HEADER` + - 其余状况保持 +* 在`STATE_HEADER` + - 当`rec`fire时,`tlast`为1(传输结束),进入`STATE_ERROR`状态 + - 当`rec`fire,`tlast`为0,接收帧头长度到达3(4byte),判断解析的帧类型 + + 如果为常规包`FRAME_STYLE_COMMON`,进入解析子报文头`STATE_SUBMSG_HEADER`,此时为***时刻1*** + + 如果为探测包`FRAME_STYLE_PROBE`,进入CRC校验`STATE_CRC`,此时为***时刻1*** + + 以上均不是则是错误,进入`STATE_ERROR` + - 其余状况保持 +* 在`STATE_SUBMSG_HEADER` + - 当`rec`fire时,`tlast`为1(传输结束),进入`STATE_ERROR`状态 + - 当`rec`fire,`tlast`为0,接收子报文头长度到达5(6byte),进入解析负载`STATE_PAYLOAD_DATA`,此时为***时刻2*** + - 其余状况保持 +* 在`STATE_PAYLOAD_DATA` + - 当`rec`fire时,`tlast`为1(传输结束)或者`data`端口上溢出`isDataRejErr`(valid为1而ready为0),进入`STATE_ERROR`状态 + - 当`rec`fire,`tlast`为0,接收子报文长度到达子报文头信息标示的长度-1,进入子报文尾解析`STATE_SUBMSG_TAIL` + - 其余状况保持 +* 在`STATE_SUBMSG_TAIL` + - 当`rec`fire时,`tlast`为1(传输结束),进入`STATE_ERROR`状态 + - 当`rec`fire,`tlast`为0,接收子报文尾长度到达1(2byte) + + 若已接受帧长度到达帧头标示的长度-1,进入`STATE_CRC`,此时为***时刻3*** + + 若未达到,进入`STATE_SUBMSG_HEADER`接收下一个子报文,此时为***时刻3*** + - 其余状况保持 +* 在`STATE_CRC` + - 当`rec`fire时,`tlast`为1(传输结束), + + 传输长度达到3(4byte)且CRC校验通过,返回`STATE_IDLE`,解析正确完成 + + 否则,进入`STATE_ERROR`,长度不一致或者CRC校验失败 + - 其余状况保持 +* 在`STATE_ERROR` + - 保持`STATE_ERROR`,只能通过软复位或者全局复位清除错误 + + + +-------------------------------------- + +## 帧结构 + +* 帧头4byte + - frameLenAim(12bits)帧长度目标 + - Null(2bits) 留空 + - frameStyle (2bits) 包类型 + + `FRAME_STYLE_COMMON` 普通包 0 + + `FRAME_STYLE_PROBE` 嗅探包 1 + - frameInfo (16bits)其它信息 + +* 子报文头 6byte + - devIndex (14bits) 子报文中设备索引 + - style (2bits) 子报文类型 + + SeqIndex 0 顺序索引 + + LgcIndex 2 逻辑索引 + - address (16bits) 子报文地址 + - operator (4bits) 子报文命令类型 + + `SUBMSG_OPERATOR_UNIREAD ` 单独读 0 + + `SUBMSG_OPERATOR_UNIWRITE ` 单独写 1 + + `SUBMSG_OPERATOR_UNIRDWR ` 单独读写 2 + + `SUBMSG_OPERATOR_SYNCA ` 时间同步操作A 0xa + + `SUBMSG_OPERATOR_INDEX ` 索引 0xb + + `SUBMSG_OPERATOR_SYNCC ` 时间同步操作C 0xc + + `SUBMSG_OPERATOR_BOARDREAD ` 广播读 0xd + + `SUBMSG_OPERATOR_BOARDWRITE` 广播写 0xe + + `SUBMSG_OPERATOR_BOARDRDWR ` 广播读写 0xf + - length (12bits) 子报文负载长度 + +* 子报文尾 2byte + - 包含`workCnt`工作计数 + + + +------------------------------------------- + +## 信息交换 + +* 在***时刻1***,`frameReq`的`valid`为高,将帧头信息使用结构体传输到`SlaveParser`模块 +* 在***时刻2***,`subMsgHeadReq`的`valid`为高,将子报文头信息使用结构体传输到`SlaveParser`模块 +* 在***时刻3***,`subMsgTailReq`的`valid`为高,将子报文尾信息使用结构体传输到`SlaveParser`模块 +* 在`STATE_PAYLOAD_DATA`状态,`data`的`valid`始终为高,将负载数据传输到`SlaveParser`模块 + - `SlaveParser`模块需要保证`data`的`ready`在`valid`为高是也为高,否则触发上溢出`isDataRejErr` + +----------------------- + +## CRC + +* `SlaveRecParser`内部例化一个CRC32的8比特输入模块 +* 当`rec`fire时,且状态机处于`STATE_HEADER` `STATE_SUBMSG_HEADER` `STATE_PAYLOAD_DATA` `STATE_SUBMSG_TAIL`时,将数据输入模块进行计算 +* 当状态机处于`STATE_IDLE`时,或者软件复位时,清空CRC模块状态 +* 当接收的最后4byte和CRC模块计算值匹配时,CRC通过 + + + + + + + + + + +--------------------------------------- + +以下是大模型补充区域 + +--------------------------------------- diff --git a/doc/spec/SmUnit.md b/doc/spec/SmUnit.md new file mode 100644 index 0000000..8d49cfa --- /dev/null +++ b/doc/spec/SmUnit.md @@ -0,0 +1,52 @@ +# SMUnit + +--------------------------------------------- + +以下是用户区域 + +--------------------------------------------- + + +SMUnit本质是一个SRAM队列(FIFO)的维护模块 + +## 接口 +对外接口包括: +* sram对外写接口 +* sram对外读接口 +* enq 输入Bool 压栈 +* deq 输入Bool 弹出 +* SRAM对内接口(接入实际例化的多个SRAM) +* cnt 输出当前fifo内有多少个数据 +* flush 输入软件复位整个SMUnit +* isComf 输入Bool,确认正式写入 +* isAbrt 输入Bool,放弃写入 + +----------------------------------------- + +## 指针 +* FIFO内部除了常见的读指针`rPtr`和写指针`wPtr`,额外增加了一个提交指针`cPtr` +* 提交指针是为了在系统错误写入时进行撤销而设计的,当eb01从站接收数据过程中,有可能收到了部分数据进而写入fifo并进行压栈,但是本次传输并没有完全完成,例如后续数据错误,crc校验失败。这时,我们需要回滚fifo的状态抛弃掉之前写入的数据 + +------------------------- + +* 三个指针的位宽比fifo实际需要位宽多1bits用于指示空满`log2Ceil(depth)+1` +* 当读指针`rPtr`和提交指针`cPtr`相等时fifo为空 +* 当读指针`rPtr`和写指针`wPtr`最高位不同,其余比特相同,fifo为满 +* 复位或者使用`flush`软复位时,所有指针归零 +* 当`enq`时且fifo不为满,写指针加1 +* 当`isAbrt`了,写指针`wPtr`回退到提交指针`cPtr`的位置 +* **对于写指针`wPtr`,当`enq`和`isAbrt`同时到来,`enq`的优先级更高,对整个大系统工作功能会不会产生问题需要测,或者系统正常运行时不会发生这种情况** +* 当`deq`且fifo不为空,读指针加1 +* 当`isComf`时提交指针`cPtr`前进到写指针`wPtr`的位置 +* 根据写指针`wPtr`的有效比特位的值,sram对外写接口连接到内部实际例化特定SRAM的写接口,其余未指向的接口保持为0不活动或者悬空 +* 根据读指针`rPtr`的有效比特位的值,sram对外读接口连接到内部实际例化特定SRAM的读接口,其余未指向的接口保持为0不活动或者悬空 + + + +--------------------------------------- + +以下是大模型补充区域 + +--------------------------------------- + + diff --git a/doc/spec/物理层优化.md b/doc/spec/物理层优化.md new file mode 100644 index 0000000..2b5fabb --- /dev/null +++ b/doc/spec/物理层优化.md @@ -0,0 +1,44 @@ +# 物理层优化 + + +---------------------------- + +以下为用户区域 + +--------------------------- + +## 8b10b模块 + +* 停用4b5b特性 + - 删除选择寄存器器 h4c寄存器不再有效 +* 增加部分控制码 + - 所有控制码都有极性 + - 控制码有对应原始码 + - 额外增加一条控制线 + - 控制线由发送状态机控制 + - 解码不需要极性控制 + +* 增加6个控制码 + - 同时将`in(4,0)b11100".U`在`isCtrl`时映射为 `"b001111".U(6.W), "b110000".U(6.W)` + - 3个必选 `in(7,5)`保持不变 + val isK28_0 = Output(Bool()) //0x1c + val isK28_3 = Output(Bool()) //0x7c + val isK28_4 = Output(Bool()) //0x9c + - 3个备选使用宏定义控制 `in(7,5)`平衡但需要增加翻转 + * val isK28_1 = Output(Bool()) //0x3c IS_ENABLE_K28_1 + * val isK28_2 = Output(Bool()) //0x5c IS_ENABLE_K28_2 + * val isK28_6 = Output(Bool()) //0xdc IS_ENABLE_K28_6 + + + + + +--------------------------------------- + +以下是大模型补充区域 + +--------------------------------------- + + + + diff --git a/src/main/scala/backBoard/shin/b8b10.scala b/src/main/scala/backBoard/shin/b8b10.scala index 7d451ae..9509d66 100644 --- a/src/main/scala/backBoard/shin/b8b10.scala +++ b/src/main/scala/backBoard/shin/b8b10.scala @@ -6,15 +6,31 @@ import chisel3.util._ class Encode_Bundle extends Bundle{ val dataIn = Input(UInt(8.W)) val isEnable = Input(Bool()) + val isCtrl = Input(Bool()) val dataOut = Output(UInt(10.W)) } class Decode_Bundle extends Bundle{ val dataIn = Input(UInt(10.W)) val dataOut = Output(UInt(8.W)) + + val isK28_0 = Output(Bool()) //0x1c + val isK28_1 = Output(Bool()) //0x3c + val isK28_2 = Output(Bool()) //0x5c + val isK28_3 = Output(Bool()) //0x7c + val isK28_4 = Output(Bool()) //0x9c + val isK28_6 = Output(Bool()) //0xdc + } -class b8b10Encode extends Module with RequireAsyncReset{ +trait b8b10Config{ this: RawModule => + val IS_ENABLE_K28_1 = false + val IS_ENABLE_K28_2 = false + val IS_ENABLE_K28_6 = false +} + + +class b8b10Encode extends Module with RequireAsyncReset with b8b10Config{ val io = IO(new Encode_Bundle) val rdTest = IO(Output(Bool())) //测试使用 @@ -51,7 +67,8 @@ class b8b10Encode extends Module with RequireAsyncReset{ (io.dataIn(4,0) === "b11001".U) -> "b100110".U(6.W), (io.dataIn(4,0) === "b11010".U) -> "b010110".U(6.W), (io.dataIn(4,0) === "b11011".U) -> Mux( ~rd, "b110110".U(6.W), "b001001".U(6.W) ), - (io.dataIn(4,0) === "b11100".U) -> "b001110".U(6.W), + (io.dataIn(4,0) === "b11100".U & ~io.isCtrl) -> "b001110".U(6.W), + (io.dataIn(4,0) === "b11100".U & io.isCtrl) -> Mux( ~rd, "b001111".U(6.W), "b110000".U(6.W) ), (io.dataIn(4,0) === "b11101".U) -> Mux( ~rd, "b101110".U(6.W), "b010001".U(6.W) ), (io.dataIn(4,0) === "b11110".U) -> Mux( ~rd, "b011110".U(6.W), "b100001".U(6.W) ), (io.dataIn(4,0) === "b11111".U) -> Mux( ~rd, "b101011".U(6.W), "b010100".U(6.W) ) @@ -87,20 +104,35 @@ class b8b10Encode extends Module with RequireAsyncReset{ (io.dataIn(4,0) === "b11001".U) -> rd, (io.dataIn(4,0) === "b11010".U) -> rd, (io.dataIn(4,0) === "b11011".U) -> ~rd, - (io.dataIn(4,0) === "b11100".U) -> rd, + (io.dataIn(4,0) === "b11100".U & ~io.isCtrl) -> rd, + (io.dataIn(4,0) === "b11100".U & io.isCtrl) -> ~rd, (io.dataIn(4,0) === "b11101".U) -> ~rd, (io.dataIn(4,0) === "b11110".U) -> ~rd, (io.dataIn(4,0) === "b11111".U) -> ~rd, )) val b3b4LookUp = Mux1H(Seq( - (io.dataIn(7,5) === "b000".U) -> Mux( ~b5b6RD, "b1011".U(4.W), "b0100".U(4.W) ), - (io.dataIn(7,5) === "b001".U) -> "b1001".U(4.W), - (io.dataIn(7,5) === "b010".U) -> "b0101".U(4.W), - (io.dataIn(7,5) === "b011".U) -> Mux( ~b5b6RD, "b1100".U(4.W), "b0011".U(4.W) ), - (io.dataIn(7,5) === "b100".U) -> Mux( ~b5b6RD, "b1101".U(4.W), "b0010".U(4.W) ), + (io.dataIn(7,5) === "b000".U) -> Mux( ~b5b6RD, "b1011".U(4.W), "b0100".U(4.W) ),//控制位与否保持相同情况 + + (io.dataIn(7,5) === "b001".U) -> Mux( (if(IS_ENABLE_K28_1) {~io.isCtrl} else { true.B }), + "b1001".U(4.W), + Mux( ~b5b6RD, "b0110".U(4.W), "b1001".U(4.W) ), //控制位 + ), + + (io.dataIn(7,5) === "b010".U) -> Mux( (if(IS_ENABLE_K28_2) {~io.isCtrl} else { true.B }), + "b0101".U(4.W), + Mux( ~b5b6RD, "b1010".U(4.W), "b0101".U(4.W)), //控制位 + ), + + (io.dataIn(7,5) === "b011".U) -> Mux( ~b5b6RD, "b1100".U(4.W), "b0011".U(4.W) ),//控制位与否保持相同情况 + (io.dataIn(7,5) === "b100".U) -> Mux( ~b5b6RD, "b1101".U(4.W), "b0010".U(4.W) ),//控制位与否保持相同情况 (io.dataIn(7,5) === "b101".U) -> "b1010".U(4.W), - (io.dataIn(7,5) === "b110".U) -> "b0110".U(4.W), + + (io.dataIn(7,5) === "b110".U) -> Mux( (if(IS_ENABLE_K28_6) {~io.isCtrl} else { true.B }), + "b0110".U(4.W), + Mux( ~b5b6RD, "b1001".U(4.W), "b0110".U(4.W)), //控制位 + ), + (io.dataIn(7,5) === "b111".U) -> MuxCase( Mux( ~b5b6RD, "b1110".U(4.W), "b0001".U(4.W) ), Array( ((io.dataIn(4,0) === 17.U || io.dataIn(4,0) === 18.U || io.dataIn(4,0) === 20.U) & ~b5b6RD) -> "b0111".U(4.W), // 17, 18, 20 are special cases ((io.dataIn(4,0) === 11.U || io.dataIn(4,0) === 13.U || io.dataIn(4,0) === 14.U) & b5b6RD) -> "b1000".U(4.W), // 11, 13, 14 are special cases @@ -131,10 +163,11 @@ class b8b10Encode extends Module with RequireAsyncReset{ } + } -class b8b10Decode extends Module with RequireAsyncReset{ +class b8b10Decode extends Module with RequireAsyncReset with b8b10Config{ val io = IO(new Decode_Bundle) @@ -189,4 +222,11 @@ class b8b10Decode extends Module with RequireAsyncReset{ io.dataOut := Cat(b3b4LookUp, b5b6LookUp) + io.isK28_0 := (io.dataIn === "b0011110100".U) || (io.dataIn === "b1100001011".U) + io.isK28_1 := (if(IS_ENABLE_K28_1) { (io.dataIn === "b0011111001".U) || (io.dataIn === "b1100000110".U) } else { false.B }) + io.isK28_2 := (if(IS_ENABLE_K28_2) { (io.dataIn === "b0011110101".U) || (io.dataIn === "b1100001010".U) } else { false.B }) + io.isK28_3 := (io.dataIn === "b0011110011".U) || (io.dataIn === "b1100001100".U) + io.isK28_4 := (io.dataIn === "b0011110010".U) || (io.dataIn === "b1100001101".U) + io.isK28_6 := (if(IS_ENABLE_K28_6) { (io.dataIn === "b0011110110".U) || (io.dataIn === "b1100001001".U) } else { false.B }) + }