远程FPGA虚拟实验平台用SystemVerilog HDL实现硬布线控制器
原理参考材料实验内容源代码参考材料VirtalBoard实验内容RegFile模块sALU模块测试/保存/提交前言:上次微程序有错呜呜呜 传送的地方有错已经改了 老板们去康康!!疯狂鞠躬.gif->是更新博客的时候写的前言,现在抄的话不用管,已经是对的了
这个实验做完了之后差不多课设了,课设不让外传,除了我们学校应该没人学这些,所以我不是很敢发。
有问题可以联系我qq,CSDN经常看不见消息。
找到我的方式参考这里。
我人超好的,请找我玩!(请带我打王者,我课设除了数据结构之外都是A,暗示.jpg)
感谢您一路以来的阅读!鞠躬.gif
原理
参考材料
这次和前两次一样也是直接套用参考材料,所以没有原理直接看实验内容。
实验内容
先看实验平台有个大概思路。
从慕课里的表来看,就是有两种指令,一种用俩寄存器运算,一种用一个寄存器和一个直接数据运算,由OPCODE[3]决定用哪种。
源代码
参考材料
VirtalBoard
写这个主要先回顾一下sALU的功能,M0=0做加法,M0=1做减法,S1S0=00正常加减,01与,10或,11异或。然后把OPCODE译码一下,RegFile和sALU实例化一下。
`default_nettype none module VirtualBoard (input logic CLOCK,// 10 MHz Input Clock input logic [19:0] PB, // 20 Push Buttons, logical 1 when pressedinput logic [35:0] S, // 36 Switchesoutput logic [35:0] L, // 36 LEDs, drive logical 1 to light upoutput logic [7:0] SD7, // 8 common anode Seven-segment Displayoutput logic [7:0] SD6,output logic [7:0] SD5,output logic [7:0] SD4,output logic [7:0] SD3,output logic [7:0] SD2,output logic [7:0] SD1,output logic [7:0] SD0);/********* Seven-segment decoder instantiation **********/logic [3:0] HD[7:0]; // 8 hexadecimal display SevenSegDecode ssdecode_inst7(.iData(HD[7]), .oSeg(SD7));SevenSegDecode ssdecode_inst6(.iData(HD[6]), .oSeg(SD6));SevenSegDecode ssdecode_inst5(.iData(HD[5]), .oSeg(SD5));SevenSegDecode ssdecode_inst4(.iData(HD[4]), .oSeg(SD4));SevenSegDecode ssdecode_inst3(.iData(HD[3]), .oSeg(SD3));SevenSegDecode ssdecode_inst2(.iData(HD[2]), .oSeg(SD2));SevenSegDecode ssdecode_inst1(.iData(HD[1]), .oSeg(SD1));SevenSegDecode ssdecode_inst0(.iData(HD[0]), .oSeg(SD0));/** The input port is replaced with an internal signal **/wire reset = PB[0];wire clk = PB[1];wire [1:0] write_addr = S[13:12];wire [1:0] read_addr1 = S[11:10];wire [1:0] read_addr2 = S[9:8];wire [3:0] imm_data = S[7:4];wire [3:0] opcode = S[3:0];//各模块间连线信号wire [3:0] alu_result, alu_y, read_data1, read_data2;wire [3:0] flag;wire write_enable;wire immToALU;wire [3:0] ALUctrl;//用来控制alu的/************* The logic of this experiment *************/assign write_enable = 1'b1;//老师的要求说要寄存器一直可读,那就一直可读assign immToALU = opcode[3];//其实就是opcode的最高位,特地写出来给多路器用看着比较好看assign ALUctrl[3] = opcode[3];//写在译码器里也可以的,但是这样写好看always @ *begincase(opcode[2:0])3'b001:ALUctrl[2:0] = 3'b000;//alu的三位分别是M0,S1,S0所以不能简单地用opcode的代码,要自己写译码部分3'b010:ALUctrl[2:0] = 3'b100;3'b011:ALUctrl[2:0] = 3'b001;3'b100:ALUctrl[2:0] = 3'b010;3'b101:ALUctrl[2:0] = 3'b011;default:ALUctrl[2:0] = 3'bx;endcaseendassign alu_y = immToALU ? imm_data : read_data2;//多路器,决定用直接给的data还是rs2的dataRegFile #(4) RegFile_inst(.Data(alu_result), .GRS_Q1(read_data1), .GRS_Q2(read_data2), .Load(write_enable), .clk(clk), .WIndex(write_addr), .RIndex1(read_addr1), .RIndex2(read_addr2));//写入寄存器的DATA由ALU结果给出,两个GRS分别读两个RS寄存器,Windex是写地址,Rindex是俩读地址sALU #(4) sALU_inst(.iX(read_data1), .iY(alu_y), .M0(ALUctrl[2]), .S1(ALUctrl[1]), .S0(ALUctrl[0]), .oF(alu_result), .oFlag(flag));//参与运算的是RS1给的DATA还有多路器选择之后的IY,MO~S0三个值是自己谢的译码部分给出的/****** Internal signal assignment to output port *******/assign HD[0] = alu_y;assign HD[1] = read_data1;assign HD[2] = read_data2;assign HD[3] = alu_result;assign L[21:18] = flag;assign L[5] = write_enable;assign L[4] = immToALU;assign L[3:0] = ALUctrl;endmodule
实验内容
这次用到的模块就是单周期数据通路的模块,再放一下。
RegFile模块
module RegFile#(parameter N = 4)(input logic [N-1:0] Data,output logic [N-1:0] GRS_Q1,output logic [N-1:0] GRS_Q2,input logic Load,input logic clk,input logic [1:0] WIndex,input logic [1:0] RIndex1,input logic [1:0] RIndex2);logic load3, load2, load1, load0;always @ (posedge clk or posedge Load)beginif (Load)case (WIndex)2'b00: {load3, load2, load1, load0} = 4'b0001;2'b01: {load3, load2, load1, load0} = 4'b0010;2'b10: {load3, load2, load1, load0} = 4'b0100;2'b11: {load3, load2, load1, load0} = 4'b1000;default: {load3, load2, load1, load0} = 4'bx;endcaseelse{load3, load2, load1, load0} = 4'b0000;endlogic [N-1:0] R0_Q, R1_Q, R2_Q, R3_Q;DataReg #(N) R0(.oQ(R0_Q), .iD(Data), .Clk(clk), .Load(load0), .Reset(1'b1));DataReg #(N) R1(.oQ(R1_Q), .iD(Data), .Clk(clk), .Load(load1), .Reset(1'b0));DataReg #(N) R2(.oQ(R2_Q), .iD(Data), .Clk(clk), .Load(load2), .Reset(1'b0));DataReg #(N) R3(.oQ(R3_Q), .iD(Data), .Clk(clk), .Load(load3), .Reset(1'b0));always @ *begincase (RIndex1)2'b00: GRS_Q1 = R0_Q;2'b01: GRS_Q1 = R1_Q;2'b10: GRS_Q1 = R2_Q;2'b11: GRS_Q1 = R3_Q;endcasecase (RIndex2)2'b00: GRS_Q2 = R0_Q;2'b01: GRS_Q2 = R1_Q;2'b10: GRS_Q2 = R2_Q;2'b11: GRS_Q2 = R3_Q;endcaseendendmodule
sALU模块
module sALU#(parameter N = 4)(input logic [N-1:0] iX, iY,input logic M0, S1, S0,output logic [N-1:0] oF,output logic [3:0] oFlag);wire [N-1:0] A, B;logic [N:0] result;logic C0;assign A = iX;assign B = (M0==0) ? iY : (~iY); assign C0 = (M0==0) ? 0 : 1; always_combbegincase({S1,S0})2'b00: result = A + B + C0;2'b01: result = iX & iY;2'b10: result = iX | iY;2'b11: result = iX ^ iY;endcaseendassign oF = result[N-1:0];assign oFlag[3] = oF[N-1];assign oFlag[2] = (oF==0) ? 1 : 0; assign oFlag[1] = (~A[N-1]) & ~B[N-1] & oF[N-1] | (A[N-1]) & B[N-1] & ~oF[N-1] ;assign oFlag[0] = result[N];endmodule
测试/保存/提交
这次测试的赋值方法和单周期数据通路差不多(说实话整个实验思路都和单周期数据通路差不多),就很温柔地写完了。