远程FPGA虚拟实验平台用SystemVerilog HDL实现数据通路
前言:本次实验要交多周期数据通路的rbf,单周期数据通路的sALU,RegFile,sv和rbf。然后上次ALU的参考设计还没给,这次又要在单周期数据通路里用。
原理
参考材料(多周期数据通路)
参考材料其实就只给了多周期数据通路的sv,它的ALU,GRS,DataReg,SevenSegDecode要自己写,要写的四个里面DataReg和SevenSegDecode是以前已经写成模块了的,ALU和GRS要根据之前的代码写。
这个面板有够复杂的,大致就是DATA:数据信号;GRS:寄存器R0~R3;RX:运算数X的寄存器;ALU:运算电路;RF:结果F的寄存器;PSW:标志寄存器。
单周期数据通路
是把多周期数据通路里的一堆寄存器删掉了,需要注意的是在这里要向寄存器输入值需要通过:RD1向X输入0,MUX向Y输入DATA,二者作加法运算后的结果F输入WD。
源代码
两个实验都有需要注意的点就是模块的数据改变是否要根据CLK信号来进行,而不能直接简单地用always_comb,容易出问题。
参考材料(多周期数据通路)
VirtalBoard模块
`default_nettype none
module VirtualBoard (
input logic CLOCK, // 10 MHz Input Clock
input logic [19:0] PB, // 20 Push Buttons, logical 1 when pressed
input logic [35:0] S, // 36 Switches
output logic [35:0] L, // 36 LEDs, drive logical 1 to light up
output logic [7:0] SD7, // 8 common anode Seven-segment Display
output 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 [3:0] DATA = S[3:0];
wire [1:0] INDEX = S[5:4];
wire RFoe = S[6];
wire GRSoe = S[7];
wire DATAoe= S[8];
wire [3:0] ALUop = S[12:9];
// wire = S[13];
wire RFce = S[14];
wire PSWce= S[15];
wire GRSce= S[16];
wire RXce = S[17];
/************* The logic of this experiment *************/
//各模块间连线信号
wire [3:0] BUS, RX_Q, F, RF_Q, GRS_Q;
wire [3:0] FLAG, PSW_Q;
//模块实例
ALU #(4) ALU_inst(.iOp(ALUop), .iX(RX_Q), .iY(BUS), .oF(F), .oFlag(FLAG), .Cin(PSW_Q[0]));//这里Y是BUS给的
GRS #(4) GRS_inst(.iD(BUS), .oQ (GRS_Q), .Load(GRSce), .Clk(clk), .Index(INDEX));
DataReg #(4) RX_inst(.oQ(RX_Q), .iD(BUS), .Clk(clk), .Load(RXce), .Reset(reset));
DataReg #(4) RF_inst(.oQ(RF_Q), .iD(F), .Clk(clk), .Load(RFce), .Reset(reset));
DataReg #(4) PSW_inst(.oQ(PSW_Q), .iD(FLAG), .Clk(clk), .Load(PSWce ), .Reset(reset));
//三态缓冲器逻辑描述
assign BUS = RFoe ? RF_Q : 4'bzzzz;//这三个的优先度是如果三个oe都为1,就输出RF,如果GRS和DATA的oe是1,就输出GRS
assign BUS = GRSoe ? GRS_Q : 4'bzzzz;
assign BUS = DATAoe ? DATA : 4'bzzzz;//代码写出来不管DATAoe是不是1都会输出到BUS,不是代码问题,不要在意
/****** Internal signal assignment to output port *******/
assign L[25:22] = PSW_Q;
assign L[21:18] = FLAG;
assign HD[5] = RX_Q;//SD5
assign HD[4] = BUS;//SD4
assign HD[3] = GRS_Q;//SD3
assign HD[1] = RF_Q;//SD1
assign HD[0] = F;//SD0
endmodule
ALU模块
ALU是根据上次自己做的算术逻辑单元改的,改法是根据sv的实例化信号来删删改改,蛮快的。
module ALU
#(parameter N = 4)
(
input logic [N-1:0] iX, iY,
input logic [3:0] iOp,
input logic Cin,
output logic [N-1:0] oF,
output logic [3:0] oFlag
);
wire [N-1:0] A,B;
wire C0;
wire [N:0] result;
wire SR, SV, SL, M3, M2, M1, M0, S1, S0;
always @ iOp
begin
case(iOp)
4'b0000: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010000000;
end
4'b0001: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010000100;
end
4'b0010: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010011000;
end
4'b0011: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010000101;
end
4'b0100: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010000110;
end
4'b0101: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010000111;
end
4'b0110: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b100000000;
end
4'b0111: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b001000000;
end
4'b1000: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010001111;
end
4'b1001: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010010000;
end
4'b1010: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010001100;
end
4'b1011: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010100100;
end
4'b1100: begin
{SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b010101000;
end
default: {SR, SV, SL, M3, M2, M1, M0, S1, S0}=9'b000000000;
endcase
end
assign A[3] = (iX[3] & SR) | (iX[3] & SV ) | (iX[2] & SL);
assign A[2] = (iX[3] & SR) | (iX[2] & SV ) | (iX[1] & SL);
assign A[1] = (iX[2] & SR) | (iX[1] & SV ) | (iX[0] & SL);
assign A[0] = (iX[1] & SR) | (iX[0] & SV ) | (0 & SL);
assign B[3] = (iY[3] & M0) | (~iY[3] & M1);
assign B[2] = (iY[2] & M0) | (~iY[2] & M1);
assign B[1] = (iY[1] & M0) | (~iY[1] & M1);
assign B[0] = (iY[0] & M0) | (~iY[0] & M1);
/*assign C0 = (Cin & M3) | M2;//这个是Cin=0时带借位减法有借位,而Cin=1时带借位减法无借位*/
assign C0 = ((~Cin) & M3 & M1)| (Cin & M3 & M0) | M2;//这个是Cin=1时带借位减法有借位,而Cin=0时带借位减法无借位
always_comb
begin
case({S1,S0})
2'b00: result = A + B + C0;
2'b01: result = iX & B;
2'b10: result = iX | B;
2'b11: result = iX ^ B;
default: result = {(N+1){1'bx}};
endcase
end
assign oF = result[N-1:0];
assign oFlag[3] = oF[N-1];
assign oFlag[2] = (oF==0) ? 1 : 0; // ~|F;
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
GRS模块
GRS是根据单端口寄存器改的,改法是根据sv的实例化信号来删删改改,为了信号准确点所以我还改了always的部分。
module GRS
#(parameter N = 4)
(
input logic [N-1:0] iD,
output logic [N-1:0] oQ,
input logic Load,
input logic Clk,
input logic [1:0] Index
);
logic load3, load2, load1, load0;
always@(posedge Clk or posedge Load)
begin
if (Load)
case (Index)
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;
endcase
else
{load3, load2, load1, load0} = 4'b0000;
end
logic [N-1:0] R0_Q, R1_Q, R2_Q, R3_Q;
DataReg #(N) R0(.oQ(R0_Q), .iD(iD), .Clk(Clk), .Load(load0), .Reset(1'b0));
DataReg #(N) R1(.oQ(R1_Q), .iD(iD), .Clk(Clk), .Load(load1), .Reset(1'b0));
DataReg #(N) R2(.oQ(R2_Q), .iD(iD), .Clk(Clk), .Load(load2), .Reset(1'b0));
DataReg #(N) R3(.oQ(R3_Q), .iD(iD), .Clk(Clk), .Load(load3), .Reset(1'b0));
always@(posedge Clk or posedge Load)
begin
case (Index)
2'b00: oQ = R0_Q;
2'b01: oQ = R1_Q;
2'b10: oQ = R2_Q;
2'b11: oQ = R3_Q;
endcase
end
endmodule
写完记得加入工程,具体在寄存器那章的博客。
DataReg模块
由于我非常懒,所有模块代码其实是在一个工程里的,就不用写DataReg和SevenSegDecode然后再加入这个工程,但是我还是把这个部分放一下。
module DataReg
#(parameter N = 4)
( output reg [N-1:0] oQ,
input wire [N-1:0] iD,
input wire Clk,
input wire Load,
input wire Reset
);
always @(posedge Clk or posedge Reset)
begin
if (Reset)
oQ <= 0;
else if (Load)
oQ <= iD;
end
endmodule
SevenSegDecode模块
module SevenSegDecode(
input logic [4:0]iData,
output logic [7:0]oSeg
);
always_comb
case(iData)
4'b0000: oSeg = 8'b11000000;
4'b0001: oSeg = 8'b11111001;
4'b0010: oSeg = 8'b10100100;
4'b0011: oSeg = 8'b10110000;
4'b0100: oSeg = 8'b10011001;
4'b0101: oSeg = 8'b10010010;
4'b0110: oSeg = 8'b10000010;
4'b0111: oSeg = 8'b11111000;
4'b1000: oSeg = 8'b10000000;
4'b1001: oSeg = 8'b10010000;
4'b1010: oSeg = 8'b10001000;
4'b1011: oSeg = 8'b10000011;
4'b1100: oSeg = 8'b11000110;
4'b1101: oSeg = 8'b10100001;
4'b1110: oSeg = 8'b10000110;
4'b1111: oSeg = 8'b10001110;
default: oSeg = 8'b11111111;
endcase
endmodule
单周期数据通路
单周期数据通路的VirtualBoard根据多周期的来改;RegFile用三端口寄存器来改;sALU要用上个实验的参考设计来改,没给,我就自己捏一个,我感觉我说这句话,我在,我在无中生有,之后如果给了的话记得dd我,我改一下。
VirtalBoard模块
`default_nettype none
module VirtualBoard (
input logic CLOCK, // 10 MHz Input Clock
input logic [19:0] PB, // 20 Push Buttons, logical 1 when pressed
input logic [35:0] S, // 36 Switches
output logic [35:0] L, // 36 LEDs, drive logical 1 to light up
output logic [7:0] SD7, // 8 common anode Seven-segment Display
output 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));
wire clk = PB[1];
wire M0 = S[14];
wire S1 = S[13];
wire S0 = S[12];
wire [3:0] DATA = S[11:8];
wire Mux = S[7];
wire WE = S[6];
wire [1:0] WA = S[5:4];
wire [1:0] RA2 = S[3:2];
wire [1:0] RA1 = S[1:0];
wire [3:0] WD, RD1, RD2;//实例化RegFile需要的数据
wire [3:0] X, Y, F, FLAG;//实例化sALU需要的数据
assign X = RD1;
assign Y = Mux ? DATA : RD2;//选择Mux给Y哪个值
assign WD = F;//ALU的输出结果F返回给WD
RegFile #(4) RegFile_inst(.Data(WD), .GRS_Q1(RD1), .GRS_Q2(RD2), .Load(WE), .clk(clk), .WIndex(WA), .RIndex1(RA1), .RIndex2(RA2));
sALU #(4) sALU_inst(.iX(X), .iY(Y), .M0(M0), .S1(S1), .S0(S0), .oF(F), .oFlag(FLAG));
assign L[21:18] = FLAG;
assign HD[3] = F;//SD3
assign HD[2] = RD2;//SD2
assign HD[1] = RD1;//SD1
assign HD[0] = Y;//SD0
endmodule
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_comb
begin
case({S1,S0})
2'b00: result = A + B + C0;
2'b01: result = iX & iY;
2'b10: result = iX | iY;
2'b11: result = iX ^ iY;
endcase
end
assign 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
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)
begin
if (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;
endcase
else
{load3, load2, load1, load0} = 4'b0000;
end
logic [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 @ *
begin
case (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;
endcase
case (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;
endcase
end
endmodule
其他模块
从多周期数据通路里拽过来用。
测试/保存/提交
两个都要测试和提交,老麻烦了。多周期数据通路的测试结果一直是22.22分,没关系,自信提交,等老师给我打一百,单周期数据通路的测试结果没什么毛病。