|
| 1 | +module obi_timer #( |
| 2 | + parameter type obi_req_t = logic, |
| 3 | + parameter type obi_rsp_t = logic |
| 4 | +) ( |
| 5 | + input logic clk_i, |
| 6 | + input logic rst_ni, |
| 7 | + input obi_req_t obi_req_i, |
| 8 | + output obi_rsp_t obi_rsp_o, |
| 9 | + output logic expired_o, |
| 10 | + output logic overflow_o |
| 11 | +); |
| 12 | + |
| 13 | + // Registers |
| 14 | + logic [31:0] count_d, count_q; |
| 15 | + logic [31:0] compare_d, compare_q; |
| 16 | + logic enable_d, enable_q; |
| 17 | + |
| 18 | + // Internal signals |
| 19 | + obi_req_t obi_req_d, obi_req_q; |
| 20 | + logic err_d, err_q; |
| 21 | + logic [31:0] rdata_d, rdata_q; |
| 22 | + |
| 23 | + assign obi_req_d = obi_req_i; |
| 24 | + |
| 25 | + // bit enable mask: defines which bits are written to by wdata of the OBI request |
| 26 | + logic [31:0] be_mask; |
| 27 | + for (genvar i = 0; unsigned'(i) < 32/8; ++i ) begin : gen_write_mask |
| 28 | + assign be_mask[8*i +: 8] = {8{obi_req_i.a.be[i]}}; |
| 29 | + end |
| 30 | + |
| 31 | + // Output assignment |
| 32 | + assign expired_o = (compare_q != 32'h0 && compare_q == count_q) ? 1'b1 1'b0; |
| 33 | + assign overflow_o = (count_q == 32'hffff_ffff) ? 1'b1 : 1'b0; |
| 34 | + |
| 35 | + always_comb begin : obi_response |
| 36 | + obi_rsp_o = '0; |
| 37 | + obi_rsp_o.gnt = 1'b1; |
| 38 | + obi_rsp_o.rvalid = obi_req_q.req; |
| 39 | + obi_rsp_o.r.err = err_q; |
| 40 | + obi_rsp_o.r.rid = obi_req_q.a.aid; |
| 41 | + obi_rsp_o.r.rdata = rdata_q; |
| 42 | + end |
| 43 | + |
| 44 | + always_comb begin |
| 45 | + err_d = '0; |
| 46 | + rdata_d = '0; |
| 47 | + count_d = count_q; |
| 48 | + compare_d = compare_q; |
| 49 | + enable_d = enable_q; |
| 50 | + |
| 51 | + if (expired_o) |
| 52 | + count_d = '0; |
| 53 | + else if (enable_q) |
| 54 | + count_d = count_q + 1; |
| 55 | + |
| 56 | + if (obi_req_i.req) begin |
| 57 | + |
| 58 | + if (obi_req_i.a.we) begin : write |
| 59 | + automatic logic [31:0] wdata = obi_req_i.a.wdata & be_mask; |
| 60 | + unique case ({obi_req_i.a.addr[IntAddrWidth-1:2], 2'b00}) |
| 61 | + OBI_TIMER_COUNT_OFFSET: begin |
| 62 | + count_d = wdata; |
| 63 | + end |
| 64 | + OBI_TIMER_COMPARE_OFFSET: begin |
| 65 | + compare_d = wdata; |
| 66 | + count_d = '0; |
| 67 | + end |
| 68 | + OBI_TIMER_ENABLE_OFFSET: begin |
| 69 | + enable_d = wdata[0]; |
| 70 | + end |
| 71 | + default: begin |
| 72 | + err_d = 1'b1; |
| 73 | + end |
| 74 | + endcase |
| 75 | + |
| 76 | + end else begin : read |
| 77 | + unique case ({obi_req_i.a.addr[IntAddrWidth-1:2], 2'b00}) |
| 78 | + OBI_TIMER_COUNT_OFFSET: begin |
| 79 | + rdata_d = count_q; |
| 80 | + end |
| 81 | + OBI_TIMER_COMPARE_OFFSET: begin |
| 82 | + rdata_d = compare_q; |
| 83 | + end |
| 84 | + OBI_TIMER_ENABLE_OFFSET: begin |
| 85 | + rdata_d = {31'h0, enable_q}; |
| 86 | + end |
| 87 | + default: begin |
| 88 | + rdata_d = 32'hBADCAB1E; |
| 89 | + err_d = 1'b1; |
| 90 | + end |
| 91 | + endcase |
| 92 | + end |
| 93 | + |
| 94 | + end |
| 95 | + end |
| 96 | + |
| 97 | + always_ff @(posedge clk_i or negedge rst_ni) begin |
| 98 | + if (~rst_ni) begin |
| 99 | + count_q <= '0; |
| 100 | + compare_q <= '0; |
| 101 | + enable_q <= '0; |
| 102 | + end else begin |
| 103 | + count_q <= count_d; |
| 104 | + compare_q <= compare_d; |
| 105 | + enable_q <= enable_d; |
| 106 | + end |
| 107 | + end |
| 108 | + |
| 109 | + |
| 110 | +endmodule |
0 commit comments