远程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分,没关系,自信提交,等老师给我打一百,单周期数据通路的测试结果没什么毛病。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值