Skip to content

Commit

Permalink
add(apb): manager and subordinate (#28)
Browse files Browse the repository at this point in the history
* (fix): Attempted to implement APB Manager (4/19)

* (fix): Rewrote APB manager module; Partially wrote associated test bench

* build: add apb subdir to dv CML

Signed-off-by: rishyak <hello@rishyak.com>

* fix: loop variable

Signed-off-by: rishyak <hello@rishyak.com>

* (fix): Added APB sub module

* (fix): Implemented APB sub module and test bench

---------

Signed-off-by: rishyak <hello@rishyak.com>
  • Loading branch information
Auryny268 authored May 29, 2024
1 parent fabbe2d commit 0158140
Show file tree
Hide file tree
Showing 14 changed files with 432 additions and 1 deletion.
4 changes: 4 additions & 0 deletions dv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ if(TEST_GENERIC OR TEST_ALL)
add_subdirectory(generic)
endif()

if(TEST_APB OR TEST_ALL)
add_subdirectory(apb)
endif()

nyu_link_sv(tests PRIVATE amba)
nyu_target_verilate(tests
TOP_MODULES ${TOP_MODULES}
Expand Down
64 changes: 64 additions & 0 deletions dv/apb/APBManager/APBManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <catch2/catch_test_macros.hpp>
#include <NyuTestUtil.hpp>

#include <VAPBManager_tl.h>

// Verify all pass-thrus into bus
TEST_CASE("APBManager, bus-to-device pass-thru") {
VAPBManager_tl& bm {nyu::getDUT<VAPBManager_tl>()};
nyu::reset(bm);
for (std::uint8_t i {0}; i < 2; ++i) {
bm.localSel = i;
nyu::eval(bm);
REQUIRE(bm.bus_selectors == i);
}
for (std::uint8_t i {0}; i < 16; ++i) {
bm.mgr_prot = i;
bm.mgr_wStrb = i;
nyu::eval(bm);
REQUIRE(bm.bus_prot == i);
REQUIRE(bm.bus_strb == i);
}
for (std::uint32_t i {1}; i; i <<= 1) {
bm.mgr_wData = i;
bm.mgr_addr = i;
nyu::eval(bm);
REQUIRE(bm.bus_wData == i);
REQUIRE(bm.bus_addr == i);
REQUIRE(bm.localAddr == i);
}
// Double-check how to handle localSel & localAddr here
}

// Verify all pass-thrus from bus
TEST_CASE("APBManager, device-to-bus pass-thru") {
VAPBManager_tl& bm {nyu::getDUT<VAPBManager_tl>()};
nyu::reset(bm);
for (std::uint8_t i {0}; i < 2; ++i) {
bm.bus_ready = i;
bm.bus_subError = i;
nyu::eval(bm);
REQUIRE(bm.mgr_busy == !i);
REQUIRE(bm.mgr_error == i);
}
for (std::uint32_t i {1}; i; i <<= 1) {
bm.bus_rData = i;
nyu::eval(bm);
REQUIRE(bm.mgr_rData == i);
}
}

// Verify all logic implemented
TEST_CASE("APBManager, logical assigns"){
VAPBManager_tl& bm {nyu::getDUT<VAPBManager_tl>()};
nyu::reset(bm);
for (std::uint8_t i {0}; i < 2; ++i) {
for (std::uint8_t j {0}; j < 2; ++j) {
bm.mgr_wEn = i;
bm.mgr_rEn = j;
nyu::eval(bm);
REQUIRE(bm.bus_write == (i && !j));
REQUIRE(bm.bus_enable == (i ^ j));
}
}
}
89 changes: 89 additions & 0 deletions dv/apb/APBManager/APBManager_tl.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
module APBManager_tl #(
DataWidth = 32,
AddrWidth = 32,
ProtWidth = 4,
PrphNum = 1
) (
input clk,
input nReset,

// Managing Device signals
input mgr_wEn,
input mgr_rEn,
input [AddrWidth - 1:0] mgr_addr,
input [DataWidth - 1:0] mgr_wData,
input [DataWidth/8 - 1:0] mgr_wStrb,
input [ProtWidth - 1:0] mgr_prot,

output logic [DataWidth - 1:0] mgr_rData,
output logic mgr_error,
output logic mgr_busy,

// Bus signals
// assigns values to it c++ - input to sv model
// read values from it c++ - output to sv model


input bus_ready,
input [DataWidth - 1:0] bus_rData,
input bus_subError,

output logic [PrphNum - 1:0] bus_selectors,
output [ProtWidth - 1:0] bus_prot,
output logic bus_enable,
output logic bus_write,
output [AddrWidth - 1:0] bus_addr,
output logic [DataWidth - 1:0] bus_wData,
output logic [DataWidth/8 - 1:0] bus_strb,

// Extraneous signals (source unknown)
// Adjust localSel and localAddr -> Ask Vito
input [PrphNum - 1:0] localSel,
output [AddrWidth-1:0] localAddr
);

GenericBus_if #(DataWidth, AddrWidth, ProtWidth) mgr (
clk,
nReset
);

always_comb begin
mgr.wEn = mgr_wEn;
mgr.rEn = mgr_rEn;
mgr.addr = mgr_addr;
mgr.wData = mgr_wData;
mgr.wStrb = mgr_wStrb;
mgr.prot = mgr_prot;

mgr_rData = mgr.rData;
mgr_error = mgr.error;
mgr_busy = mgr.busy;
end

APBCommon_if #(DataWidth, AddrWidth, PrphNum) bus (
clk,
nReset
);

always_comb begin
bus_write = bus.write;
bus_enable = bus.enable;
bus_wData = bus.wData;
bus_strb = bus.strb;
bus_selectors = bus.selectors;
bus_prot = bus.prot;
bus_addr = bus.addr;

bus.rData = bus_rData;
bus.subError = bus_subError;
bus.ready = bus_ready;
end

APBManager bus_mgr (
mgr,
bus,
localSel,
localAddr
);

endmodule
6 changes: 6 additions & 0 deletions dv/apb/APBManager/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target_sources(tests PRIVATE APBManager.cpp)
nyu_add_sv(tests
APBManager_tl.sv
)
list(APPEND TOP_MODULES APBManager_tl)
set(TOP_MODULES ${TOP_MODULES} PARENT_SCOPE)
68 changes: 68 additions & 0 deletions dv/apb/APBSubordinate/APBSubordinate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <catch2/catch_test_macros.hpp>
#include <NyuTestUtil.hpp>

#include <VAPBSubordinate_tl.h>


void logical_test(VAPBSubordinate_tl& bs, uint8_t sel) {
nyu::reset(bs);
const std::uint32_t base_addr {0x100};
bs.bus_selectors = sel;
for (std::uint8_t i {0}; i < 2; ++i) {
for (std::uint8_t j {0}; j < 2; ++j) {
bs.bus_write = i;
bs.bus_enable = j;
nyu::eval(bs);
REQUIRE(bs.sub_wEn == (sel ? (i && j) : 0));
REQUIRE(bs.sub_rEn == (sel ? (!i && j) : 0));
}
}
for (std::uint32_t i {1}; i; i <<= 1) {
bs.bus_addr = base_addr + i;
nyu::eval(bs);
REQUIRE(bs.sub_addr == (sel ? i : 0));
}
}

// bus-to-device pass-thru
TEST_CASE("APBSubordinate, bus-to-device pass-thru") {
VAPBSubordinate_tl& bs {nyu::getDUT<VAPBSubordinate_tl>()};
nyu::reset(bs);
for (std::uint8_t i {0}; i < 16; ++i) {
bs.bus_prot = i;
bs.bus_strb = i;
nyu::eval(bs);
REQUIRE(bs.sub_prot == i);
REQUIRE(bs.sub_wStrb == i);
}
for (std::uint32_t i {1}; i; i <<= 1) {
bs.bus_wData = i;
nyu::eval(bs);
REQUIRE(bs.sub_wData == i);
}
}

// device-to-bus pass-thru
TEST_CASE("APBSubordinate, device-to-bus pass-thru") {
VAPBSubordinate_tl& bs {nyu::getDUT<VAPBSubordinate_tl>()};
nyu::reset(bs);
for (std::uint8_t i{0}; i < 2; ++i) {
bs.sub_error = i;
bs.sub_busy = i;
nyu::eval(bs);
REQUIRE(bs.bus_subError == i);
REQUIRE(bs.bus_ready == !i);
}
for (std::uint32_t i{1}; i; i <<= 1) {
bs.sub_rData = i;
nyu::eval(bs);
REQUIRE(bs.bus_rData == i);
}
}

// logical
TEST_CASE("APBSubordinate, logical") {
VAPBSubordinate_tl& bs {nyu::getDUT<VAPBSubordinate_tl>()};
logical_test(bs, 0);
logical_test(bs, 1);
}
77 changes: 77 additions & 0 deletions dv/apb/APBSubordinate/APBSubordinate_tl.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module APBSubordinate_tl #(
DataWidth = 32,
AddrWidth = 32,
ProtWidth = 4,
PrphNum = 1
) (
input clk,
input nReset,

output logic sub_wEn,
output logic sub_rEn,
output logic [AddrWidth - 1:0] sub_addr,
output logic [DataWidth - 1:0] sub_wData,
output logic [DataWidth/8 - 1:0] sub_wStrb,
output logic [ProtWidth - 1:0] sub_prot,

input [DataWidth - 1:0] sub_rData,
input sub_error,
input sub_busy,

input bus_write,
input bus_enable,
input [AddrWidth - 1:0] bus_addr,
input [DataWidth - 1:0] bus_wData,
input [DataWidth/8 - 1:0] bus_strb,
input [ProtWidth - 1:0] bus_prot,
input [PrphNum - 1:0] bus_selectors,

output logic [DataWidth - 1:0] bus_rData,
output logic bus_subError,
output logic bus_ready

);

GenericBus_if #(DataWidth, AddrWidth, ProtWidth) sub (
clk,
nReset
);

always_comb begin
sub_wEn = sub.wEn;
sub_rEn = sub.rEn;
sub_addr = sub.addr;
sub_wData = sub.wData;
sub_wStrb = sub.wStrb;
sub_prot = sub.prot;

sub.rData = sub_rData;
sub.error = sub_error;
sub.busy = sub_busy;
end

APBCommon_if #(DataWidth, AddrWidth, PrphNum) bus (
clk,
nReset
);

always_comb begin
bus.write = bus_write;
bus.enable = bus_enable;
bus.addr = bus_addr;
bus.wData = bus_wData;
bus.strb = bus_strb;
bus.prot = bus_prot;
bus.selectors = bus_selectors;

bus_rData = bus.rData;
bus_subError = bus.subError;
bus_ready = bus.ready;
end

APBSubordinate #(32'h100, 32'hFFFFFF00) bus_sub (
sub,
bus
);

endmodule
6 changes: 6 additions & 0 deletions dv/apb/APBSubordinate/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target_sources(tests PRIVATE APBSubordinate.cpp)
nyu_add_sv(tests
APBSubordinate_tl.sv
)
list(APPEND TOP_MODULES APBSubordinate_tl)
set(TOP_MODULES ${TOP_MODULES} PARENT_SCOPE)
4 changes: 4 additions & 0 deletions dv/apb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_subdirectory(APBManager)
add_subdirectory(APBSubordinate)

set(TOP_MODULES ${TOP_MODULES} PARENT_SCOPE)
36 changes: 36 additions & 0 deletions rtl/apb/devices/APBManager.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
@brief Manager that uses the AMBA APB protocol directly as the transmission
protocol
@input device managing device
@input bus bus to managed
*/

module APBManager (
GenericBus_if device,
APBCommon_if bus,
input [bus.PrphNum - 1:0] localSel,
output [bus.AddrWidth-1:0] localAddr
);
always_comb begin
device.rData = bus.rData;
bus.wData = device.wData;
bus.addr = device.addr;
localAddr = device.addr;
bus.selectors = localSel;
end
// Always_comb must have something for every situation
always_comb begin
bus.prot = device.prot;
bus.strb = device.wStrb;
bus.write = device.wEn && !device.rEn;
bus.enable = device.wEn ^ device.rEn;
end
// wEn and rEn both being high is meaningless in generic -> check this in test bench
// Generic pov -> device tells you it's done by wEn going low -> done writing
// Assume for generic, rEn goes up for single cycle
always_comb begin
device.busy = !bus.ready;
device.error = bus.subError;
end
endmodule
Loading

0 comments on commit 0158140

Please sign in to comment.