Skip to content
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
5 changes: 4 additions & 1 deletion hw/ip_templates/rv_plic/rtl/rv_plic.sv.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #(
.src_i (intr_src_synced),
.le_i (LevelEdgeTrig),

.claim_i (claim),
// Clear the lowest bit of `claim`. This represents interrupt 0 ("no interrupt")
// which is "claimed" if no interrupts are pending. This isn't strictly necessary
// but it satisfies the OnlyClaimPending_A assertion in rv_plic_gateway.
.claim_i ({ claim[NumSrc-1:1], 1'b0 }),
.complete_i (complete),

.ip_o (ip)
Expand Down
52 changes: 35 additions & 17 deletions hw/ip_templates/rv_plic/rtl/rv_plic_gateway.sv.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,32 @@ module ${module_instance_name}_gateway #(
input [N_SOURCE-1:0] src_i,
input [N_SOURCE-1:0] le_i, // Level0 Edge1

// Clear IP and keep it low until `complete_i`. This is non-zero when
// the CC CSR is read. If no interrupts are pending it will be set to 1,
// corresponding to the "no interrupt" input.
//
// Except for the "no interrupt" value, this must not claim an interrupt
// that is not pending. This is verified with an assertion.
input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i)
// Allow IP to be set again. Ignored for interrupts that aren't already claimed.
input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i)

// Interrupt Pending output which is is set when an interrupt is first received.
// It is cleared and held low when claimed, and then allowed to go high
// again after completion.
output logic [N_SOURCE-1:0] ip_o
);

logic [N_SOURCE-1:0] ia; // Interrupt Active
// True if an interrupt has been claimed so that IP should be held at 0.
logic [N_SOURCE-1:0] claimed;

// The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered
// (because le_i[i]=0) then this just asks that src_i[i] is true. If the interrupt is edge
// triggered (because le_i[i]=1) then we also ask that src_i[i] was false on the previous cycle
// (which is registered with src_q).
logic [N_SOURCE-1:0] set;

// Registered interrupt input so we can detect edges.
logic [N_SOURCE-1:0] src_q;

always_ff @(posedge clk_i or negedge rst_ni) begin
Expand All @@ -35,28 +48,33 @@ module ${module_instance_name}_gateway #(

assign set = src_i & ~(src_q & le_i);

// Interrupt pending is set by source (depends on le_i), cleared by claim_i.
// Until interrupt is claimed, set doesn't affect ip_o.
// RISC-V PLIC spec mentioned it can have counter for edge triggered
// But skipped the feature as counter consumes substantial logic size.
// "Depending on the design of the device and the interrupt handler, in
// between sending an interrupt request and receiving notice of its handler’s completion, the gateway
// might either ignore additional matching edges or increment a counter of pending interrupts."
//
// This implementation ignores the additional matches as the counters
// consume substantial logic size.

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ip_o <= '0;
claimed <= '0;
end else begin
ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i));
end
end
// Claim/complete process. It is impossible for a claim and
// complete to happen in the same cycle because only one CSR access is
// allowed per cycle. This is verified below.
claimed <= (claimed | claim_i) & ~complete_i;

// Interrupt active is to control ip_o. If ip_o is set then until completed
// by target, ip_o shouldn't be set by source even claim_i can clear ip_o.
// ia can be cleared only when ia was set. If `set` and `complete_i` happen
// at the same time, always `set` wins.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ia <= '0;
end else begin
ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o));
// IP is set if there's an interrupt and cleared if it is claimed.
// The '| claim_i' is to avoid an extra cycle delay.
ip_o <= (ip_o | set) & ~(claimed | claim_i);
end
end

// `claim_i` and `complete_i` cannot both be non-zero.
`ASSERT(NoSimulateneousClaimComplete_A, !(claim_i != '0 && complete_i != '0));

// We shouldn't see a claim for an interrupt that isn't pending.
`ASSERT(OnlyClaimPending_A, (claim_i & ~ip_o) == '0);

endmodule
5 changes: 4 additions & 1 deletion hw/top_darjeeling/ip_autogen/rv_plic/rtl/rv_plic.sv
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,10 @@ module rv_plic import rv_plic_reg_pkg::*; #(
.src_i (intr_src_synced),
.le_i (LevelEdgeTrig),

.claim_i (claim),
// Clear the lowest bit of `claim`. This represents interrupt 0 ("no interrupt")
// which is "claimed" if no interrupts are pending. This isn't strictly necessary
// but it satisfies the OnlyClaimPending_A assertion in rv_plic_gateway.
.claim_i ({ claim[NumSrc-1:1], 1'b0 }),
.complete_i (complete),

.ip_o (ip)
Expand Down
52 changes: 35 additions & 17 deletions hw/top_darjeeling/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,32 @@ module rv_plic_gateway #(
input [N_SOURCE-1:0] src_i,
input [N_SOURCE-1:0] le_i, // Level0 Edge1

// Clear IP and keep it low until `complete_i`. This is non-zero when
// the CC CSR is read. If no interrupts are pending it will be set to 1,
// corresponding to the "no interrupt" input.
//
// Except for the "no interrupt" value, this must not claim an interrupt
// that is not pending. This is verified with an assertion.
input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i)
// Allow IP to be set again. Ignored for interrupts that aren't already claimed.
input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i)

// Interrupt Pending output which is is set when an interrupt is first received.
// It is cleared and held low when claimed, and then allowed to go high
// again after completion.
output logic [N_SOURCE-1:0] ip_o
);

logic [N_SOURCE-1:0] ia; // Interrupt Active
// True if an interrupt has been claimed so that IP should be held at 0.
logic [N_SOURCE-1:0] claimed;

// The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered
// (because le_i[i]=0) then this just asks that src_i[i] is true. If the interrupt is edge
// triggered (because le_i[i]=1) then we also ask that src_i[i] was false on the previous cycle
// (which is registered with src_q).
logic [N_SOURCE-1:0] set;

// Registered interrupt input so we can detect edges.
logic [N_SOURCE-1:0] src_q;

always_ff @(posedge clk_i or negedge rst_ni) begin
Expand All @@ -35,28 +48,33 @@ module rv_plic_gateway #(

assign set = src_i & ~(src_q & le_i);

// Interrupt pending is set by source (depends on le_i), cleared by claim_i.
// Until interrupt is claimed, set doesn't affect ip_o.
// RISC-V PLIC spec mentioned it can have counter for edge triggered
// But skipped the feature as counter consumes substantial logic size.
// "Depending on the design of the device and the interrupt handler, in
// between sending an interrupt request and receiving notice of its handler’s completion, the gateway
// might either ignore additional matching edges or increment a counter of pending interrupts."
//
// This implementation ignores the additional matches as the counters
// consume substantial logic size.

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ip_o <= '0;
claimed <= '0;
end else begin
ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i));
end
end
// Claim/complete process. It is impossible for a claim and
// complete to happen in the same cycle because only one CSR access is
// allowed per cycle. This is verified below.
claimed <= (claimed | claim_i) & ~complete_i;

// Interrupt active is to control ip_o. If ip_o is set then until completed
// by target, ip_o shouldn't be set by source even claim_i can clear ip_o.
// ia can be cleared only when ia was set. If `set` and `complete_i` happen
// at the same time, always `set` wins.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ia <= '0;
end else begin
ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o));
// IP is set if there's an interrupt and cleared if it is claimed.
// The '| claim_i' is to avoid an extra cycle delay.
ip_o <= (ip_o | set) & ~(claimed | claim_i);
end
end

// `claim_i` and `complete_i` cannot both be non-zero.
`ASSERT(NoSimulateneousClaimComplete_A, !(claim_i != '0 && complete_i != '0));

// We shouldn't see a claim for an interrupt that isn't pending.
`ASSERT(OnlyClaimPending_A, (claim_i & ~ip_o) == '0);

endmodule
5 changes: 4 additions & 1 deletion hw/top_earlgrey/ip_autogen/rv_plic/rtl/rv_plic.sv
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,10 @@ module rv_plic import rv_plic_reg_pkg::*; #(
.src_i (intr_src_synced),
.le_i (LevelEdgeTrig),

.claim_i (claim),
// Clear the lowest bit of `claim`. This represents interrupt 0 ("no interrupt")
// which is "claimed" if no interrupts are pending. This isn't strictly necessary
// but it satisfies the OnlyClaimPending_A assertion in rv_plic_gateway.
.claim_i ({ claim[NumSrc-1:1], 1'b0 }),
.complete_i (complete),

.ip_o (ip)
Expand Down
52 changes: 35 additions & 17 deletions hw/top_earlgrey/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,32 @@ module rv_plic_gateway #(
input [N_SOURCE-1:0] src_i,
input [N_SOURCE-1:0] le_i, // Level0 Edge1

// Clear IP and keep it low until `complete_i`. This is non-zero when
// the CC CSR is read. If no interrupts are pending it will be set to 1,
// corresponding to the "no interrupt" input.
//
// Except for the "no interrupt" value, this must not claim an interrupt
// that is not pending. This is verified with an assertion.
input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i)
// Allow IP to be set again. Ignored for interrupts that aren't already claimed.
input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i)

// Interrupt Pending output which is is set when an interrupt is first received.
// It is cleared and held low when claimed, and then allowed to go high
// again after completion.
output logic [N_SOURCE-1:0] ip_o
);

logic [N_SOURCE-1:0] ia; // Interrupt Active
// True if an interrupt has been claimed so that IP should be held at 0.
logic [N_SOURCE-1:0] claimed;

// The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered
// (because le_i[i]=0) then this just asks that src_i[i] is true. If the interrupt is edge
// triggered (because le_i[i]=1) then we also ask that src_i[i] was false on the previous cycle
// (which is registered with src_q).
logic [N_SOURCE-1:0] set;

// Registered interrupt input so we can detect edges.
logic [N_SOURCE-1:0] src_q;

always_ff @(posedge clk_i or negedge rst_ni) begin
Expand All @@ -35,28 +48,33 @@ module rv_plic_gateway #(

assign set = src_i & ~(src_q & le_i);

// Interrupt pending is set by source (depends on le_i), cleared by claim_i.
// Until interrupt is claimed, set doesn't affect ip_o.
// RISC-V PLIC spec mentioned it can have counter for edge triggered
// But skipped the feature as counter consumes substantial logic size.
// "Depending on the design of the device and the interrupt handler, in
// between sending an interrupt request and receiving notice of its handler’s completion, the gateway
// might either ignore additional matching edges or increment a counter of pending interrupts."
//
// This implementation ignores the additional matches as the counters
// consume substantial logic size.

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ip_o <= '0;
claimed <= '0;
end else begin
ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i));
end
end
// Claim/complete process. It is impossible for a claim and
// complete to happen in the same cycle because only one CSR access is
// allowed per cycle. This is verified below.
claimed <= (claimed | claim_i) & ~complete_i;

// Interrupt active is to control ip_o. If ip_o is set then until completed
// by target, ip_o shouldn't be set by source even claim_i can clear ip_o.
// ia can be cleared only when ia was set. If `set` and `complete_i` happen
// at the same time, always `set` wins.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ia <= '0;
end else begin
ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o));
// IP is set if there's an interrupt and cleared if it is claimed.
// The '| claim_i' is to avoid an extra cycle delay.
ip_o <= (ip_o | set) & ~(claimed | claim_i);
end
end

// `claim_i` and `complete_i` cannot both be non-zero.
`ASSERT(NoSimulateneousClaimComplete_A, !(claim_i != '0 && complete_i != '0));

// We shouldn't see a claim for an interrupt that isn't pending.
`ASSERT(OnlyClaimPending_A, (claim_i & ~ip_o) == '0);

endmodule
5 changes: 4 additions & 1 deletion hw/top_englishbreakfast/ip_autogen/rv_plic/rtl/rv_plic.sv
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,10 @@ module rv_plic import rv_plic_reg_pkg::*; #(
.src_i (intr_src_synced),
.le_i (LevelEdgeTrig),

.claim_i (claim),
// Clear the lowest bit of `claim`. This represents interrupt 0 ("no interrupt")
// which is "claimed" if no interrupts are pending. This isn't strictly necessary
// but it satisfies the OnlyClaimPending_A assertion in rv_plic_gateway.
.claim_i ({ claim[NumSrc-1:1], 1'b0 }),
.complete_i (complete),

.ip_o (ip)
Expand Down
52 changes: 35 additions & 17 deletions hw/top_englishbreakfast/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,32 @@ module rv_plic_gateway #(
input [N_SOURCE-1:0] src_i,
input [N_SOURCE-1:0] le_i, // Level0 Edge1

// Clear IP and keep it low until `complete_i`. This is non-zero when
// the CC CSR is read. If no interrupts are pending it will be set to 1,
// corresponding to the "no interrupt" input.
//
// Except for the "no interrupt" value, this must not claim an interrupt
// that is not pending. This is verified with an assertion.
input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i)
// Allow IP to be set again. Ignored for interrupts that aren't already claimed.
input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i)

// Interrupt Pending output which is is set when an interrupt is first received.
// It is cleared and held low when claimed, and then allowed to go high
// again after completion.
output logic [N_SOURCE-1:0] ip_o
);

logic [N_SOURCE-1:0] ia; // Interrupt Active
// True if an interrupt has been claimed so that IP should be held at 0.
logic [N_SOURCE-1:0] claimed;

// The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered
// (because le_i[i]=0) then this just asks that src_i[i] is true. If the interrupt is edge
// triggered (because le_i[i]=1) then we also ask that src_i[i] was false on the previous cycle
// (which is registered with src_q).
logic [N_SOURCE-1:0] set;

// Registered interrupt input so we can detect edges.
logic [N_SOURCE-1:0] src_q;

always_ff @(posedge clk_i or negedge rst_ni) begin
Expand All @@ -35,28 +48,33 @@ module rv_plic_gateway #(

assign set = src_i & ~(src_q & le_i);

// Interrupt pending is set by source (depends on le_i), cleared by claim_i.
// Until interrupt is claimed, set doesn't affect ip_o.
// RISC-V PLIC spec mentioned it can have counter for edge triggered
// But skipped the feature as counter consumes substantial logic size.
// "Depending on the design of the device and the interrupt handler, in
// between sending an interrupt request and receiving notice of its handler’s completion, the gateway
// might either ignore additional matching edges or increment a counter of pending interrupts."
//
// This implementation ignores the additional matches as the counters
// consume substantial logic size.

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ip_o <= '0;
claimed <= '0;
end else begin
ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i));
end
end
// Claim/complete process. It is impossible for a claim and
// complete to happen in the same cycle because only one CSR access is
// allowed per cycle. This is verified below.
claimed <= (claimed | claim_i) & ~complete_i;

// Interrupt active is to control ip_o. If ip_o is set then until completed
// by target, ip_o shouldn't be set by source even claim_i can clear ip_o.
// ia can be cleared only when ia was set. If `set` and `complete_i` happen
// at the same time, always `set` wins.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ia <= '0;
end else begin
ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o));
// IP is set if there's an interrupt and cleared if it is claimed.
// The '| claim_i' is to avoid an extra cycle delay.
ip_o <= (ip_o | set) & ~(claimed | claim_i);
end
end

// `claim_i` and `complete_i` cannot both be non-zero.
`ASSERT(NoSimulateneousClaimComplete_A, !(claim_i != '0 && complete_i != '0));

// We shouldn't see a claim for an interrupt that isn't pending.
`ASSERT(OnlyClaimPending_A, (claim_i & ~ip_o) == '0);

endmodule
Loading