URISC 处理器设计一 URISC 处理器功能描述 URISC 处理器是只有一条指令的超级精简指令集计算机, 它是由 Mavaddat 和 Parham 提出的一种 RISC 结构 尽管 URISC 只有一条指令, 却也是一种通用计算机, 所有的复杂操作都可以由这条指令来完成 URISC 指令要完

Similar documents
Huawei Technologies Co

2. initial always initial always 0 always initial always fork module initial always 2 module clk_gen_demo(clock1,clock2); output clock1,clock2; reg cl

untitled

z x / +/- < >< >< >< >< > 3 b10x b10x 0~9,a~f,A~F, 0~9,a~f,A~F, x,x,z,z,?,_ x,x,z,z,?,_ h H 0~9,_ 0~9,_ d D 0~7,x,X,z,Z

第一章.doc

ebook122-11

图 片 展 示 : 资 源 简 介 : FPGA Altera CycloneII EP2C5T144C8 (4608 个 LE) 2 路 有 源 晶 振 (50M,25M) AS & JTAG 标 准 接 口 VGA 接 口 UART 接 口 蜂 鸣 器 8bit 并 行 DAC 8 路 按 键

Microsoft Word - FPGA的学习流程.doc

xilinx FPGA 串口设计笔记 在设计中, 需要用 FPGA 读取 GPS 内部的信息,GPS 的通信方式为串口, 所以在 FPGA 中移植了串口程序 本次移植的程序源代码是特权的串口程序, 本以为移植应该很快就能完成, 但其中还是出了一写小问题, 耽误了不少的时间, 下面将问题进行一个总结!

<4D F736F F D20B5DAC8FDCBC4D5C2D7F7D2B5B4F0B0B82E646F63>

9 什 么 是 竞 争 与 冒 险 现 象? 怎 样 判 断? 如 何 消 除?( 汉 王 笔 试 ) 在 组 合 逻 辑 中, 由 于 门 的 输 入 信 号 通 路 中 经 过 了 不 同 的 延 时, 导 致 到 达 该 门 的 时 间 不 一 致 叫 竞 争 产 生 毛 刺 叫 冒 险 如

SB 綱 領 : (1) 消 防 服 務 管 制 人 員 : 就 年 度 需 要 特 別 留 意 的 事 項 中, 當 局 提 到 年 度 內, 消 防 處 會 啟 用 啟 德 新 建 並 設 有 救 護 設 施 的 消 防 局, 請 告 知 有 關

第一章

穨R _report.PDF




除外責任修正條文對照.doc

untitled

Ps22Pdf


系统架构 - 模块划分 功能 状态机 H265 主要的模块 : 1. 顶层模块 H265ENC_top 包括 sys_ctrl,enc_core 及 fetch 三个模块 2. sys_ctrl 就是一个状态机, 控制 fetch 和 enc_core 中各子模块的工作 3. enc_core 编码

Microsoft Word 箕æ−¥ï¼‹å®ı稿;

98年度即測即評學科測試與即測即評即發證技術士技能檢定簡章

江人发2009年第49号突发事件应对法培训.doc

PowerPoint Presentation

姓名

Microsoft Word - report 4.doc

PowerPoint 演示文稿

untitled


ebook122-3

第十四章 STC单片机比较器原理及实现

CH559指令周期.doc

untitled


程式人雜誌

AT89C2051中文资料.doc

Microsoft PowerPoint - 第9讲-08.ppt [兼容模式]

untitled

廁所維護保養手冊

全国主要流域重点断面水质自动监测周报

邏輯分析儀的概念與原理-展示版


Microsoft PowerPoint - chap04.ppt

untitled

Microsoft Word - Delta Controller ASCII_RTU_SC

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

101

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

PowerPoint 演示文稿

諮 詢 / 吳 明 賢 ( 台 大 醫 院 健 康 管 理 中 心 主 任 台 大 醫 學 院 內 科 教 授 ) 撰 稿 / 伍 蓉 症 狀 多 樣 且 擾 人 胃 及 食 道 位 置 圓 胃 食 道 逆 流 分 典 型 症 狀 及 非 典 型 症 狀 典 型 症 狀 為 胃 酸 逆 流 胸 骨

标题


营养与健康

~50 50~25 ~ ~ 25~15 ~ ~ 15 ~ ~ ~

untitled

Transcription:

URISC 处理器设计一 URISC 处理器功能描述 URISC 处理器是只有一条指令的超级精简指令集计算机, 它是由 Mavaddat 和 Parham 提出的一种 RISC 结构 尽管 URISC 只有一条指令, 却也是一种通用计算机, 所有的复杂操作都可以由这条指令来完成 URISC 指令要完成的操作是 做减运算, 且在结果为负值时转移 URISC 的指令形式如下 : 第一个操作数地址第二个操作数地址运算结果为负时的转移地址由于只有一条指令, 故在执行时不需要译码, 其执行过程如下 : (1) 从第二个操作数中减去第一个操作数, 并把运算结果存储在第二个操作数的地址中 ; (2) 如果减法运算得到的结果为负数, 则转移到指定的地址执行, 否则执行下一个地址中的指令 ; (3) 如果转移到地址 0, 则停止 RISC 的运行 在本设计中, 假设 URISC 处理器是 8 位的, 且每一条指令都是三字节指令, 占用存储器的三个单元, 因此需要三个存储器读取周期才能将指令读出来 而且本设计采用冯诺依曼结构, 指令和数据均存在同一个存储器中 二 URISC 处理器结构设计冯诺依曼体系计算机系统框图一般如图 1 所示, 包括数据单元 控制单元和存储器 图 1 URISC 处理器系统框图 其中, 数据单元对数据进行传输和处理, 控制单元则为数据单元提供控制信号, 使数据 单元中的各个模块能够协调地工作, 以实现特定的功能 教材中提供了可参考的数据单元如图 2 所示

图 2 教材中 URISC 处理器的数据单元教材上已经对相应的控制信号做了详细的说明, 这里不再重复 需要指出的是, 完全按照教材上给出的数据单元和控制时序, 在寄存器传输级来实现是不可能的 下面以状态 0 时要完成的操作来分析原因 根据教材上的说明, 在时钟 PH2 的下降沿, 如果输入控制信号有效,PC R MDR 和 MAR 将进行更新 ; 而存储器的读 / 写操作 控制器状态的转换 控制信号的更新均在时钟 PH1 的下降沿 在状态 0, 控制信号 PCOUT ZIN MARIN 和 READ 有效 当 PCOUT 有效后,PC 中的值被传送到 BUS_A 上, 并通过加 0 操作传输到 BUS_B 上, 在 PH2 的下降沿,PC 的值写到地址寄存器 MAR 中 接着, 在 PH1 的下降沿过后, 存储器的输出有效 此后状态转入 s1 态 可见, 如果存储器是同步输出, 则其输出的数据无法写入数据寄存器 MDR 中 为了解决这一问题, 有两种可以解决的思路 :( 1) 在每一次 READ 操作后增加一个等待状态, 确保存储器中的数据能够写入数据寄存器 MDR 中 ;(2) 考虑到 MDR 寄存器最主要的功能是将加法器的输出同步锁存, 并在 WRITE 信号有效时将其写入到存储器指定的地址中, 因此, 存储器的输出可以不经过 MDR 寄存器, 而是经过一个三态门连接到 BUS_A 上, 如果三态门的控制信号为 MDROUT, 则进入状态 s1 后, 恰好可以使用存储器输出的数据, 而不需要增加额外的状态, 也不需要改变相关的控制信号 所以, 本设计选择了第二种修改方案 另外, 本设计还使用状态寄存器 Z 和 N 的输出 ZEND NNEND 作为控制单元的输入条件信号, 来决定是否动态挂起或转移到指定的地址, 省去教材中提到的控制信号 ZEND 和 NNEND 的 修改后的数据单元结构如图 3 所示

PCOUT 程序计数器 PC PCIN RIN 寄存器 R COMP ZIN NIN 加法器 ACC CIN Z N NNEND ZEND 数据寄存器 MDR MDRIN 地址寄存器 MAR MARIN MDROUT 存储器 READ WRITE BUS_A BUS_B 图 3 修改后的 URISC 处理器的数据单元 对原来的数据单元做了适当的修改后, 指令的执行仍然只需要 9 个状态, 在每个状 态控制信号的输出如表 1 所示 s0 s1 s2 s3 s4 s5 s6 s7 s8 pcin 0 0 0 1 0 0 1 1 1 pcout 1 0 0 1 0 0 1 1 0 rin 0 0 1 0 0 0 0 0 0 comp 0 0 0 0 0 1 0 0 0 cin 0 0 0 1 0 1 1 1 0 zin 1 0 0 0 0 0 0 0 0 nin 0 0 0 0 0 1 0 0 0 mdrin 0 0 0 0 0 1 0 0 0 mdrout 0 1 1 0 1 1 0 0 1 marin 1 1 0 1 1 0 1 0 0 read 1 1 0 1 1 0 1 0 0 write 0 0 0 0 0 1 0 0 0 表 1 指令执行状态对应的控制信号输出 由于 PCOUT 和 MDROUT 实际上控制的是三态门, 只要是高电平输出就即刻有效, 并不需要等待时钟沿的到来 ; 而所有寄存器的更新, 都需要相应的写入控制信号有效,

且在时钟 PH2 的下降沿才能进行 ; 存储器的读操作, 需要在时钟 PH1 的下降沿, 且 READ 信号有效时存储器的输出才有效 ; 存储器的写操作, 也需要在 PH1 的下降沿, 且 WRITE 信号有效时, 输入数据才能写入指定的地址中 根据上述的寄存器和存储器的读写操作规定, 下面详述指令的执行过程 在状态 s0,pcout 有效,PC 的值即刻输出到总线 BUS_A 上, 并被传输到加法器的一个输入端, 此时 COMP 为 0, 故加法器的另一端为 0, 且 cin 为 0, 加法器的输出依然为 PC 的值, 并被送到 BUS_B 上, 然后在 PH2 的下降沿,MARIN 有效,PC 的值写进地址寄存器 MAR 中 对于加法器, 如果输出为 0, 和 Z 寄存器相连接的输出端将被置为 1, 否则为 0; 如果输出为负值, 和 N 寄存器相连接的一端将被置为 1 否则为 0 此时由于 ZIN 也有效, 故输出 ZEND 也被更新 在时钟 PH1 的下降沿, 由于 READ 信号有效, 故 PC 地址中的值将被读出, 此时存储器输出的值为第一个操作数的地址 同时, 在时钟 PH1 的下降沿, 如果 ZEND 为 1, 说明 PC 的值为 0, 则状态依然保持为 s0, 从而实现存储器的动态挂起, 否则转入 s1 态 在 s1 态, 由于 MDROUT 控制信号有效, 存储器的输出, 即第一个操作数的地址被送到总线 BUS_A, 上, 类似地, 由于 MARIN 有效, 故在时钟 PH2 的下降沿, 第一个操作数的地址送入地址寄存器 MAR 中 在时钟 PH1 的下降沿, 由于 READ 信号为 1, 故存储器输出的值为第一个操作数, 同时,s1 态无条件转入 s2 态 在 s2 态, 由于 MDROUT 控制信号有效, 故第一个操作数被送到总线 BUS_A 上, 在时钟 PH2 的下降沿, 由于 RIN 信号有效, 故第一个操作数被送进寄存器 R 中 在时钟 PH1 的下降沿,s2 态无条件转入 s3 态 在 s3 态, 由于 PCOUT 为 1, 故 PC 的值被送到总线 BUS_A 上, 由于 COMP 为 0 而 CIN 为 1, 故 PC 加 1 后送到总线 BUS_B 上 ; 在时钟 PH2 的下降沿, 由于 MARIN 有效, 故 PC+1 被送入地址寄存器 MAR 中 在时钟 PH1 的下降沿, 由于 READ 信号有效, 故存储器输出的值为第二个操作数的地址 ; 同时,s3 态无条件转入 s4 态 在 s4 态, 由于 MDROUT 为 1, 第二个操作数的地址被送到总线 BUS_A 上, 类似地, 在时钟 PH2 的下降沿, 由于 MARIN 信号有效, 故第二个操作数的地址被送入地址寄存器 MAR 中 在时钟 PH1 的下降沿, 由于 READ 信号有效, 故存储器的输出值为第二个操作数 ; 同时 s4 态无条件转入 s5 态 在 s5 态, 由于 MDROUT 为 1, 故第二个操作数被送到总线 BUS_A 上, 由于 COMP 和 CIN 均为 1, 故加法器实现第二个数减去第一个操作数 ( 寄存器 R 的输出是第一个操作数取反后的结果 ), 并将相减的结果送到 BUS_B 上 在时钟 PH2 的下降沿, 由于 MDRIN 信号有效, 故二者相减的结果被送进数据寄存器 MDR 中 ; 同时由于 NIN 有效, 故 NNEND 的值将被更新 在时钟 PH1 的下降沿, 由于 WRITE 信号有效, 且此时 MARIN 的值为第二个个操作数的地址, 故第二个操作数减第一个操作数的结果将被写入第二个操作数的

地址中 ; 同时 s5 态无条件转入 s6 态 在 s6 态, 由于 PCOUT 为 1, 故 PC 的值被送到总线 BUS_A 上, 由于 COMP 为 0, CIN 为 1, 故 PC 加 1 后被送到总线 BUS_B 上 在时钟 PH2 的下降沿, 由于 MARIN 和 PCIN 均为 1, 故 PC 加 1 的值同时被送进 PC 寄存器和 MAR 寄存器中 在时钟 PH1 的下降沿, 由于 READ 信号有效, 故存储器的输出值为相减结果为负值时的跳转地址 ; 同时 s6 态无条件转入 s7 态 在 s7 态, 由于 PCOUT 为 1, 故 PC 的值被送到 BUS_A 上, 由于 COMP 为 0,CIN 为 1, 故 PC 加 1 后被送到总线 BUS_B 上 在时钟 PH2 的下降沿, 由于 PCIN 为 1, 故 PC 加 1 的值被送入 PC 寄存器中 在 PH1 的下降沿, 由于 READ 和 WRITE 信号均无效, 故存储器无操作, 输出值依然是相减结果为负值时的跳转地址 在时钟 PH1 的下降沿, 如果条件信号 NNEND 的值为 1, 说明需要跳转到指定的地址, 则 s7 态转入 s8 态 ; 否则转入 s0 态, 开始执行新的指令 在 s8 态, 由于 MDROUT 有效, 故跳转地址被送到 BUS_A 上, 由于 COMP 为 0,CIN 为 0, 故跳转地址被送到 BUS_B 上 在时钟 PH2 的下降沿, 由于 PCIN 为 1, 故跳转地址送被入 PC 寄存器中 在时钟 PH1 的下降沿 s8 态无条件转入 s0 态, 从跳转地址处开始执行新的指令 根据上述的指令执行过程, 可以得到控制器的状态转移图如图 4 所示 ZEND=1 s0 ZEND=0 s1 NNEND=1 s8 NNEND=0 s2 s7 s3 s6 s5 s4 图 4 控制单元状态转移图 最后需要指出的是, 为了保证 URISC 能够正常地运行, 还需要一个全局复位信号

reset 当 reset 为高电平时, 控制器则无条件地转入 s0 态, 同时程序计数器 PC 的值被复位到初始运行地址 1 三 URISC 处理器仿真结果及分析根据修改后的数据单元 控制单元和存储器, 可以用 Verilog HDL 语言在寄存器传输级进行描述, 详细的代码见第四部分 接着对所涉及的 URISC 进行功能仿真 为了验证指令是否能够正确地执行, 首先让 URISC 处理器作减法运算 2-1=1, 为负时跳转到地址 0; 接着让 URISC 处理器做减法运算 1-2=-1, 为负时跳转到地址 0 这样第一条指令执行完后不进行跳转, 接着执行第二条指令, 第二条指令执行完成后跳转到地址 0, 并动态挂起, 不再执行指令 为了实现上述操作, 初始化 RAM 如下 : mem[0]=8'b0000_0000; mem[1]=8'b0000_0111; mem[2]=8'b0000_1000; mem[3]=8'b0000_0000;// 7 8 0 mem[4]=8'b0000_1001; mem[5]=8'b0000_1010; mem[6]=8'b0000_0000;//9 10 0 mem[7]=8'b0000_0001; mem[8]=8'b0000_0010; mem[9]=8'b0000_0010; mem[10]=8'b0000_0001; 利用 nclaunch 工具进行功能仿真, 得到的输出结果如图 5 所示 图 5 URISC 处理器功能仿真结果

从图中可以看出, 当两条指令执行完成后, 控制单元一直处于 0 状态,urisc 处理器已经动态挂起 ; 而且第二个操作数的地址 8 和 10 中的内容在状态 5 之后分别变为 1 和 -1, 可见, 第二个数减第一个数的结果写入了第二个操作数的地址中, 指令功能执行正确 相关的控制信号和条件信号 (ZEND 和 NNEND) 也已经在图中给出,bus_a 信号为存储器的输出 可以看到, 这些信号的值都和预想的相符合, 从而验证了 URISC 处理器功能的正确性 四 URISC 处理器寄存器传输级 Verilog HDL 源代码 urisc_datapath.v module PC_reg(clk2,reset,pcin,pcout,bus_b,bus_a); input clk2,reset,pcin,pcout; input[7:0] bus_b; output reg[7:0] bus_a; reg[7:0] data; always@(negedge clk2 or posedge reset) if (reset) data<=8'b0000_0001; if (pcin) data<=bus_b; always@(*) if (pcout) bus_a=data; bus_a=8'bzzzz_zzzz; module module R_reg(clk2,rin,comp,bus_a,dout); input clk2,rin,comp; input[7:0] bus_a; output reg[7:0] dout; reg[7:0] data; always@(negedge clk2) if (rin) data<=bus_a; always@(*)

if (comp) dout=~data; dout=8'b0000_0000; module module adder(clk2,bus_a,rout,cin,zin,nin,z,nn,bus_b); input clk2,cin,zin,nin; input[7:0] bus_a,rout; output[7:0] bus_b; output reg z,nn; reg Z_temp,N_temp; wire[7:0] data; assign bus_b=data; assign data=rout+bus_a+cin; always@(*) if (data==8'b0000_0000) Z_temp=1'b1; Z_temp=1'b0; always@(*) if (bus_a[7]==1'b0 && rout[7]==1'b0 && data[7]==1'b1) N_temp=1'b0; N_temp=data[7]; always@(negedge clk2) if (zin) z<=z_temp; always@(negedge clk2) if (nin) nn<=n_temp; module module MDR(clk2,mdrin,bus_b,ram_in); input clk2,mdrin; input[7:0] bus_b;

output reg[7:0] ram_in; always@(negedge clk2) if(mdrin) ram_in<=bus_b; module module MAR(clk2,marin,bus_b,marout); input clk2,marin; input[7:0] bus_b; output reg[7:0] marout; always@(negedge clk2) if (marin) marout<=bus_b; module module urisc_datapath(clk2, reset, pcin, pcout, rin, comp, cin, zin, nin, mdrin, marin, read, write, z, nn, marout, ram_in, bus_a); input clk2; input reset; input pcin; input pcout; input rin; input comp; input cin; input zin;

input nin; input mdrin; input marin; input read; input write; output z; output nn; output[7:0] marout; output[7:0] ram_in; output[7:0] bus_a; wire[7:0] bus_b; wire[7:0] dout; PC_reg u_pc_reg(.clk2(clk2),.reset(reset),.pcin(pcin),.pcout(pcout),.bus_b(bus_b),.bus_a(bus_a)); R_reg u_r_reg(.clk2(clk2),.rin(rin),.comp(comp),.bus_a(bus_a),.dout(dout)); adder u_adder(.clk2(clk2),.bus_a(bus_a),.rout(dout),.cin(cin),.zin(zin),.nin(nin),.z(z),.nn(nn),.bus_b(bus_b)); MDR u_mdr(.clk2(clk2),.mdrin(mdrin),.bus_b(bus_b),.ram_in(ram_in)); MAR u_mar(.clk2(clk2),.marin(marin),.bus_b(bus_b),.marout(marout)); module urisc_controller.v module urisc_controller(clk1, reset, z, nn, pcin, pcout, rin, comp, cin, zin, nin, mdrin, mdrout, marin, read, write); input clk1; input reset; input z; input nn; output reg pcin;

output reg pcout; output reg rin; output reg comp; output reg cin; output reg zin; output reg nin; output reg mdrin; output reg mdrout; output reg marin; output reg read; output reg write; reg[3:0] state; parameter s0=4'b0000, s1=4'b0001, s2=4'b0010, s3=4'b0011, s4=4'b0100, s5=4'b0101, s6=4'b0110, s7=4'b0111, s8=4'b1000; always@(negedge clk1 or posedge reset) if (reset) state<=s0; case(state) s0: if (z) state<=s0; state<=s1; s1:state<=s2; s2:state<=s3; s3:state<=s4; s4:state<=s5; s5:state<=s6; s6:state<=s7; s7: if(nn) state<=s8;

state<=s0; s8:state<=s0; default:state<=s0; case // output of pcin if (state==s3 state==s6 state==s7 state==s8) pcin=1'b1; pcin=1'b0; // output of pcout if (state==s0 state==s3 state==s6 state==s7) pcout=1'b1; pcout=1'b0; // output of rin if (state==s2) rin=1'b1; rin=1'b0; // output of comp if (state==s5) comp=1'b1; comp=1'b0; // output of cin if (state==s3 state==s5 state==s6 state==s7) cin=1'b1;

cin=1'b0; // output of zin if (state==s0) zin=1'b1; zin=1'b0; // output of nin if (state==s5) nin=1'b1; nin=1'b0; // output of mdrin if (state==s5) mdrin=1'b1; mdrin=1'b0; // output of mdrout if (state==s1 state==s2 state==s4 state==s5 state==s8) mdrout=1'b1; mdrout=1'b0; // output of marin if (state==s0 state==s1 state==s3 state==s4 state==s6) marin=1'b1; marin=1'b0; // output of read

if (state==s0 state==s1 state==s3 state==s4 state==s6) read=1'b1; read=1'b0; // output of write if (state==s5) write=1'b1; write=1'b0; module urisc_ram.v module urisc_ram(clk1,read,write,mdrout,addr,ram_in,bus_a); input clk1,read,write,mdrout; input[7:0] addr; input[7:0] ram_in; output reg[7:0] bus_a; reg[7:0] mem[255:0]; reg[7:0] data; initial mem[0]=8'b0000_0000; mem[1]=8'b0000_0111; mem[2]=8'b0000_1000; mem[3]=8'b0000_0000; mem[4]=8'b0000_1001; mem[5]=8'b0000_1010; mem[6]=8'b0000_0000; mem[7]=8'b0000_0001; mem[8]=8'b0000_0010; mem[9]=8'b0000_0010; mem[10]=8'b0000_0001; always@(negedge clk1) if (read) data<=mem[addr];

always@(negedge clk1) if (write) mem[addr]<=ram_in; always@(*) if(mdrout) bus_a=data; bus_a=8'bzzzz_zzzz; module urisc.v `include "urisc_datapath.v" `include "urisc_controller.v" `include "urisc_ram.v" module urisc(clk1,clk2,reset); input clk1,clk2,reset; wire pcin; wire pcout; wire rin; wire comp; wire cin; wire zin; wire nin; wire mdrin; wire mdrout; wire marin; wire read; wire write; wire z; wire nn; wire[7:0] marout; wire[7:0] ram_in; wire[7:0] bus_a; urisc_datapath datapath(.clk2(clk2),.reset(reset),.pcin(pcin),.pcout(pcout),.rin(rin),

.comp(comp),.cin(cin),.zin(zin),.nin(nin),.mdrin(mdrin),.marin(marin),.read(read),.write(write),.z(z),.nn(nn),.marout(marout),.ram_in(ram_in),.bus_a(bus_a)); urisc_controller controller(.clk1(clk1),.reset(reset),.z(z),.nn(nn),.pcin(pcin),.pcout(pcout),.rin(rin),.comp(comp),.cin(cin),.zin(zin),.nin(nin),.mdrin(mdrin),.mdrout(mdrout),.marin(marin),.read(read),.write(write)); urisc_ram ram(.clk1(clk1),.read(read),.write(write),.mdrout(mdrout),.addr(marout),.ram_in(ram_in),.bus_a(b us_a)); module urisc_test.v `include "urisc.v" module urisc_test(); reg clk1,clk2,reset; initial clk1=1'b1; forever

#100 clk1=~clk1; initial clk2=1'b0; forever #100 clk2=~clk2; initial reset=0; #10 reset=1'b1; #250 reset=1'b0; urisc u_urisc(.clk1(clk1),.clk2(clk2),.reset(reset)); module