Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPIO module and SubDummy tests #22

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(TOP_MODULES "")

if(TEST_AHB OR TEST_ALL)
add_subdirectory(ahb)
add_subdirectory(apb)
endif()

if(TEST_GENERIC OR TEST_ALL)
Expand Down
2 changes: 1 addition & 1 deletion dv/ahb/SimpleDecoder/SimpleDecoder_tb.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <VSimpleDecoder_tl.h>

TEST_CASE("SimpleDecoder, Dummy Test") {}
TEST_CASE("SimpleDecoder Dummy Test SimpleDecoder") {}
119 changes: 119 additions & 0 deletions dv/ahb/SubDummy/SubDummy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,122 @@ TEST_CASE("SubDummy, Single read write") {
REQUIRE(dut.resp == 0);
REQUIRE(dut.rData == 0x1234);
}

TEST_CASE("SubDummy Unslected") {
VSubDummy_tl dut;
dut.control = 0;
dut.sel = 0;
dut.nReset = 0;
dut.trans = 0;
nyu::tick(dut);
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
}

TEST_CASE("SubDummy Sequential Transfer with busy cycles") {
VSubDummy_tl dut;
//Reset
dut.control = 0;
dut.sel = 1;
dut.nReset = 0;
dut.trans = 0;
nyu::tick(dut);
//Write address 0x0
dut.nReset = 1;
dut.addr = 0x0;
dut.wData = 0x1234;
dut.write = 1;
dut.trans = 2;
nyu::tick(dut);
//Write address 0x1
REQUIRE(dut.resp == 0);
dut.addr = 0x1;
dut.wData = 0x5678;
dut.trans = 3;
nyu::tick(dut);
//Write address 0x2 with busy cycle
REQUIRE(dut.resp == 0);
dut.addr = 0x2;
dut.wData = 0x9abc;
dut.trans = 1;
nyu::tick(dut);
//Manager continues but subordinate stalls
REQUIRE(dut.resp == 0);
dut.trans = 3;
dut.control = 1;
nyu::tick(dut);
//Manager holds values as subordinate reasserts readyOut
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 0);
dut.control = 0;
nyu::tick(dut);
//Complete transferns read address 0x0
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);

dut.write = 0;
dut.addr = 0x0;
dut.trans = 2;
dut.control = 0;
nyu::tick(dut);
//Complete transferns read address 0x1
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
REQUIRE(dut.rData == 0x1234);
dut.trans = 3;
dut.addr = 0x1;
nyu::tick(dut);
//Complete transferns read address 0x2
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
REQUIRE(dut.rData == 0x5678);
dut.addr = 0x2;
nyu::tick(dut);
//Complete transferns read address 0x3
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
REQUIRE(dut.rData == 0x9abc);
}

TEST_CASE("SubDummy Idle state") {
VSubDummy_tl dut;
//Reset
dut.control = 0;
dut.sel = 1;
dut.nReset = 0;
dut.trans = 0;
nyu::tick(dut);
dut.nReset = 1;
nyu::tick(dut);
nyu::tick(dut);
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
}

TEST_CASE("SubDummy Error Resolution") {
VSubDummy_tl dut;
//Reset
dut.control = 0;
dut.sel = 1;
dut.nReset = 0;
dut.trans = 0;
nyu::tick(dut);
//Set SubDummy to trigger an error
dut.nReset = 1;
dut.trans = 2;
dut.write = 1;
dut.wData = 0x1234;
dut.addr = 0x0;
dut.control = 2;
nyu::tick(dut);
//SubDummy should respond with an error and not process anything.
//Set transfer to idle to resolve error
REQUIRE(dut.resp == 1);
REQUIRE(dut.readyOut == 0);
dut.control = 0;
dut.trans = 0;
nyu::tick(dut);
//SubDummy should be ready to process again
REQUIRE(dut.resp == 0);
REQUIRE(dut.readyOut == 1);
}
3 changes: 3 additions & 0 deletions dv/apb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_subdirectory(GPIO)

set(TOP_MODULES ${TOP_MODULES} PARENT_SCOPE)
6 changes: 6 additions & 0 deletions dv/apb/GPIO/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target_sources(tests PRIVATE GPIO.cpp)
nyu_add_sv(amba
GPIO_tb.sv
)
list(APPEND TOP_MODULES GPIO_tb)
set(TOP_MODULES ${TOP_MODULES} PARENT_SCOPE)
76 changes: 76 additions & 0 deletions dv/apb/GPIO/GPIO.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <VGPIO_tb.h>
#include <catch2/catch_test_macros.hpp>

TEST_CASE("GPIO Write") {
VGPIO_tb dut;
dut.eval();
dut.nReset = 1;
dut.addr = 0x0;
dut.wData = 0xAA;
dut.enable = 1;
dut.sel = 1;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

std::cout << dut.PORTA_out << std::endl;
REQUIRE(1 == 1);
}

TEST_CASE("GPIO Read") {
VGPIO_tb dut;
dut.eval();
dut.PINA = 0xFFFF; //Set the input from GPIO pins to 0xFFFF
dut.nReset = 1; //Reset is active low
dut.enable = 1;
dut.sel = 1;
dut.write = 1;
dut.wData = 0xABCD; //Write to PORTA pins
dut.addr = 0x0;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

dut.wData = 0xAAAA; //Write to DDR pins to set every other pin as output
dut.addr = 0x1;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

REQUIRE(dut.PORTA_PINS & 0x5555 == 0x5555); //Since every other pin is set as output, the input pins should be 0x5555

dut.write = 0;
dut.addr = 0x2;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

REQUIRE(dut.rData & 0x5555 == 0x5555); //Verify that read operation has the same result.
//Since write pins also show up in reads, they are excluded

dut.addr = 0x1;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

REQUIRE(dut.rData == 0xAAAA);

dut.addr = 0x0;

dut.clk = 0;
dut.eval();
dut.clk = 1;
dut.eval();

REQUIRE(dut.rData == 0xABCD);
}
39 changes: 39 additions & 0 deletions dv/apb/GPIO/GPIO_tb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module GPIO_tb #(
AddrWidth = 32,
DataWidth = 32
) (
input clk, //PCLK
input nReset, //PRESETn
input [AddrWidth-1:0] addr, //PADDR
input [DataWidth-1:0] wData, //PWDATA
input write, //PWRITE
input sel, //PSEL
input enable, //PENABLE
input [15:0] PINA,
inout [15:0] PORTA_PINS,

output [DataWidth-1:0] rData, //PRDATA
output subErr, //PsubErr
output readyOut, //PREADY
output [15:0] PORTA_out,
output [15:0] DDRA_out
);

APBCommon_if #(DataWidth, AddrWidth) apb (clk, nReset);

GPIO #(16) sub (.*);

assign PORTA_out = sub.PORTA;
assign DDRA_out = sub.DDRA;

assign apb.sel = sel;
assign apb.addr = addr;
assign apb.wData = wData;
assign apb.write = write;
assign apb.enable = enable;

assign subErr = apb.subErr;
assign rData = apb.rData;
assign readyOut = apb.readyOut;

endmodule
113 changes: 63 additions & 50 deletions rtl/ahb/devices/SubDummy.sv
Original file line number Diff line number Diff line change
Expand Up @@ -33,58 +33,71 @@ module SubDummy (
} Control; // Dummy control signal for testing


always_ff @(posedge ahb.clk or negedge ahb.nReset) begin
if (~ahb.nReset) begin
ahb.readyOut <= 1'b1;
end else begin
//If subordinate is not selected, respond with okay and idle
if (~ahb.sel) begin
ahb.resp <= AHBCommon_pkg::RESP_OKAY;
ahb.readyOut <= 1'b1;
state <= AHBCommon_pkg::STATE_IDLE;
end else begin
case (ahb.trans)
//Manager is idle or busy
AHBCommon_pkg::TRANS_IDLE: begin
case (state)
//Wait until transfer continues or ends
AHBCommon_pkg::STATE_IDLE, AHBCommon_pkg::STATE_READ, AHBCommon_pkg::STATE_WRITE: begin
always_ff @(posedge ahb.clk or negedge ahb.nReset) begin
if (~ahb.nReset) begin
ahb.readyOut <= 1'b1;
end else begin
//If subordinate is not selected, respond with okay and idle
if (~ahb.sel) begin
ahb.resp <= AHBCommon_pkg::RESP_OKAY;
ahb.readyOut <= 1'b1;
end
AHBCommon_pkg::STATE_ERROR: begin
//Only set readyOut to 1 if the manager returns to Idle
ahb.readyOut <= 1'b0;
state <= AHBCommon_pkg::STATE_IDLE;
end
endcase
end
AHBCommon_pkg::TRANS_BUSY: begin
//Doesn't do anything yet
ahb.readyOut <= 1'b1;
end
//Manager is starting a new transfer
AHBCommon_pkg::TRANS_NONSEQ: begin
case (state)
AHBCommon_pkg::STATE_IDLE, AHBCommon_pkg::STATE_READ, AHBCommon_pkg::STATE_WRITE: begin
//Perform read and writes to modules
if (ahb.write && control == CONTROL_OK) begin
mem[ahb.addr] <= ahb.wData;
state <= AHBCommon_pkg::STATE_WRITE;
end else begin
ahb.rData <= mem[ahb.addr];
state <= AHBCommon_pkg::STATE_READ;
end
end
AHBCommon_pkg::STATE_ERROR: begin
state <= AHBCommon_pkg::STATE_ERROR;
end
endcase
end
AHBCommon_pkg::TRANS_SEQ: begin
//Doesn't do anything yet
state <= AHBCommon_pkg::STATE_IDLE;
end
endcase
end else begin
case (ahb.trans)
//Manager is idle or busy
AHBCommon_pkg::TRANS_IDLE: begin
case (state)
//Wait until transfer continues or ends
AHBCommon_pkg::STATE_IDLE, AHBCommon_pkg::STATE_READ, AHBCommon_pkg::STATE_WRITE: begin
ahb.readyOut <= 1'b1;
end
AHBCommon_pkg::STATE_ERROR: begin
//Only set readyOut to 1 if the manager returns to Idle
ahb.readyOut <= 1'b0;
state <= AHBCommon_pkg::STATE_IDLE;
end
endcase
end
AHBCommon_pkg::TRANS_BUSY: begin
//Doesn't do anything yet
ahb.readyOut <= 1'b1;
end
//Manager is starting a new transfer
AHBCommon_pkg::TRANS_NONSEQ: begin
case (state)
AHBCommon_pkg::STATE_IDLE, AHBCommon_pkg::STATE_READ, AHBCommon_pkg::STATE_WRITE: begin
//Perform read and writes to modules
if (ahb.write && control == CONTROL_OK) begin
mem[ahb.addr] <= ahb.wData;
state <= AHBCommon_pkg::STATE_WRITE;
end else begin
ahb.rData <= mem[ahb.addr];
state <= AHBCommon_pkg::STATE_READ;
end
end
AHBCommon_pkg::STATE_ERROR: begin
state <= AHBCommon_pkg::STATE_ERROR;
end
endcase
end
AHBCommon_pkg::TRANS_SEQ: begin
case (state)
AHBCommon_pkg::STATE_READ, AHBCommon_pkg::STATE_WRITE: begin
//Perform read and writes to modules
if (ahb.write && control == CONTROL_OK) begin
mem[ahb.addr] <= ahb.wData;
state <= AHBCommon_pkg::STATE_WRITE;
end else begin
ahb.rData <= mem[ahb.addr];
state <= AHBCommon_pkg::STATE_READ;
end
end
default: begin
state <= AHBCommon_pkg::STATE_ERROR;
end
endcase
end
endcase

//Set reponse based on control signals
case (control)
Expand Down
1 change: 1 addition & 0 deletions rtl/apb/devices/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(GPIO)
3 changes: 3 additions & 0 deletions rtl/apb/devices/GPIO/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
nyu_add_sv(amba
GPIO.sv
)
Loading