|
| 1 | +// Copyright 2023 The XLS Authors |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +import std |
| 16 | +import xls.modules.axi4.dma.config as config |
| 17 | +import xls.modules.axi4.dma.axi_pkg as axi_pkg |
| 18 | +import xls.modules.axi4.dma.csr as csr |
| 19 | + |
| 20 | +// FIXME: casting imported types is a workaround |
| 21 | +// https://github.com/google/xls/issues/1030 |
| 22 | +const ID_W = config::AXI_0_ID_W; |
| 23 | +const ADDR_W = config::AXI_0_ADDR_W; |
| 24 | +const DATA_W = config::AXI_0_DATA_W; |
| 25 | +const STRB_W = config::AXI_0_STRB_W; |
| 26 | + |
| 27 | +type axi_aw_t = axi_pkg::axi_aw_t<ID_W, ADDR_W>; |
| 28 | +type axi_w_t = axi_pkg::axi_w_t<DATA_W, STRB_W>; |
| 29 | +type axi_b_t = axi_pkg::axi_b_t<ID_W>; |
| 30 | + |
| 31 | +// AXI4 Manager behavioral model |
| 32 | +// Request new AXI transaction by sending a message on the ctrl_data channel. |
| 33 | +// Model responds on channel ctrl_done channel once done. |
| 34 | +proc axi_manager_beh<ID_W: u32, ADDR_W: u32, DATA_W: u32, STRB_W: u32> { |
| 35 | + aw_req: chan<axi_aw_t> out; |
| 36 | + aw_rsp: chan<()> in; |
| 37 | + w_req: chan<axi_w_t> out; |
| 38 | + w_rsp: chan<()> in; |
| 39 | + b_req: chan<axi_b_t> in; |
| 40 | + b_rsp: chan<()> out; |
| 41 | + ctrl_done: chan<()> out; |
| 42 | + ctrl_data: chan<(uN[ADDR_W], uN[DATA_W])> in; |
| 43 | + |
| 44 | + config(aw_req: chan<axi_aw_t> out, aw_rsp: chan<()> in, w_req: chan<axi_w_t> out, w_rsp |
| 45 | + : |
| 46 | + chan<()> in, |
| 47 | + b_req: chan<axi_b_t> in, b_rsp: chan<()> out, ctrl_done: chan<()> out, ctrl_data |
| 48 | + : |
| 49 | + chan<(uN[ADDR_W], uN[DATA_W])> in) { |
| 50 | + (aw_req, aw_rsp, w_req, w_rsp, b_req, b_rsp, ctrl_done, ctrl_data) |
| 51 | + } |
| 52 | + |
| 53 | + init { () } |
| 54 | + |
| 55 | + next(tok: token, state:()) { |
| 56 | + // Wait for data to write to registers |
| 57 | + let (tok, payload) = recv(tok, ctrl_data); |
| 58 | + let (addr, data) = payload; |
| 59 | + let req = axi_aw_t { |
| 60 | + awid: uN[ID_W]:0x0, |
| 61 | + awaddr: addr, |
| 62 | + awsize: axi_pkg::AXI_AXSIZE_ENCODING::MAX_8B_TRANSFER, |
| 63 | + awprot: u3:0 |
| 64 | + }; |
| 65 | + // AW Handshake |
| 66 | + let tok = send(tok, aw_req, req); |
| 67 | + let (tok, _) = recv(tok, aw_rsp); |
| 68 | + |
| 69 | + // Write channel handler |
| 70 | + let w_data = axi_w_t { wdata: data, wstrb: std::unsigned_max_value<STRB_W>(), wlast: u1:1 }; |
| 71 | + let tok = send(tok, w_req, w_data); |
| 72 | + let (tok, _) = recv(tok, w_rsp); |
| 73 | + |
| 74 | + // Response channel handler |
| 75 | + let (tok, bresp) = recv(tok, b_req); |
| 76 | + let tok = send(tok, b_rsp, ()); |
| 77 | + |
| 78 | + let tok = send(tok, ctrl_done, ()); |
| 79 | + state |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +// AXI4 subordinate receives AXI4 transactions and translates them into simple |
| 84 | +// read/Writes for CSR |
| 85 | +proc axi_subordinate_beh<ID_W: u32, ADDR_W: u32, DATA_W: u32, STRB_W: u32> { |
| 86 | + aw_req: chan<axi_aw_t> in; |
| 87 | + aw_rsp: chan<()> out; |
| 88 | + w_req: chan<axi_w_t> in; |
| 89 | + w_rsp: chan<()> out; |
| 90 | + b_req: chan<axi_b_t> out; |
| 91 | + b_rsp: chan<()> in; |
| 92 | + read_req: chan<csr::ReadReq> out; |
| 93 | + read_resp: chan<csr::ReadResp> in; |
| 94 | + write_req: chan<csr::WriteReq> out; |
| 95 | + write_resp: chan<csr::WriteResp> in; |
| 96 | + |
| 97 | + config(aw_req: chan<axi_aw_t> in, aw_rsp: chan<()> out, w_req: chan<axi_w_t> in, w_rsp |
| 98 | + : |
| 99 | + chan<()> out, |
| 100 | + b_req: chan<axi_b_t> out, b_rsp: chan<()> in) { |
| 101 | + let (read_req_s, read_req_r) = chan<csr::ReadReq>; |
| 102 | + let (read_resp_s, read_resp_r) = chan<csr::ReadResp>; |
| 103 | + let (write_req_s, write_req_r) = chan<csr::WriteReq>; |
| 104 | + let (write_resp_s, write_resp_r) = chan<csr::WriteResp>; |
| 105 | + spawn csr::CSR(read_req_r, read_resp_s, write_req_r, write_resp_s); |
| 106 | + |
| 107 | + ( |
| 108 | + aw_req, aw_rsp, w_req, w_rsp, b_req, b_rsp, read_req_s, read_resp_r, write_req_s, |
| 109 | + write_resp_r, |
| 110 | + ) |
| 111 | + } |
| 112 | + |
| 113 | + init { (u32:0) } |
| 114 | + |
| 115 | + next(tok: token, state: u32) { |
| 116 | + // AW Channel Handler |
| 117 | + let (tok, req) = recv(tok, aw_req); |
| 118 | + let tok = send(tok, aw_rsp, ()); |
| 119 | + |
| 120 | + // W channel Handler |
| 121 | + let (tok, w_data) = recv(tok, w_req); |
| 122 | + let tok = send(tok, w_rsp, ()); |
| 123 | + |
| 124 | + // Handle write to CSR |
| 125 | + let tok = send(tok, write_req, csr::WriteWordReq(req.awaddr, w_data.wdata)); |
| 126 | + let (tok, _) = recv(tok, write_resp); |
| 127 | + |
| 128 | + // B Channel Handlers |
| 129 | + let req = axi_b_t { bresp: axi_pkg::AXI_WRITE_RESPONSE_CODES::OKAY, bid: uN[ID_W]:0 }; |
| 130 | + let tok = send(tok, b_req, req); |
| 131 | + let (tok, rsp) = recv(tok, b_rsp); |
| 132 | + state |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +const TEST_0_OP_NUM = u32:512; |
| 137 | + |
| 138 | +#[test_proc] |
| 139 | +proc test_axi_beh { |
| 140 | + ctrl_done: chan<()> in; |
| 141 | + ctrl_data: chan<(uN[ADDR_W], uN[DATA_W])> out; |
| 142 | + terminator: chan<bool> out; |
| 143 | + |
| 144 | + config(terminator: chan<bool> out) { |
| 145 | + let (aw_req_s, aw_req_r) = chan<axi_aw_t>; |
| 146 | + let (aw_rsp_s, aw_rsp_r) = chan<()>; |
| 147 | + let (w_req_s, w_req_r) = chan<axi_w_t>; |
| 148 | + let (w_rsp_s, w_rsp_r) = chan<()>; |
| 149 | + let (b_req_s, b_req_r) = chan<axi_b_t>; |
| 150 | + let (b_rsp_s, b_rsp_r) = chan<()>; |
| 151 | + let (ctrl_done_s, ctrl_done_r) = chan<()>; |
| 152 | + let (ctrl_data_s, ctrl_data_r) = chan<(uN[ADDR_W], uN[DATA_W])>; |
| 153 | + spawn axi_manager_beh<ID_W, ADDR_W, DATA_W, STRB_W>( |
| 154 | + aw_req_s, aw_rsp_r, w_req_s, w_rsp_r, b_req_r, b_rsp_s, ctrl_done_s, ctrl_data_r); |
| 155 | + spawn axi_subordinate_beh<ID_W, ADDR_W, DATA_W, STRB_W>( |
| 156 | + aw_req_r, aw_rsp_s, w_req_r, w_rsp_s, b_req_s, b_rsp_r); |
| 157 | + (ctrl_done_r, ctrl_data_s, terminator) |
| 158 | + } |
| 159 | + |
| 160 | + init { () } |
| 161 | + |
| 162 | + next(tok: token, state: ()) { |
| 163 | + for (i, tok): (u32, token) in u32:0..TEST_0_OP_NUM { |
| 164 | + let addr = i as uN[ADDR_W]; |
| 165 | + let data = (u32:0x4000 + i) as uN[DATA_W]; |
| 166 | + trace_fmt!("TEST_{}: ADDR=[{}] DATA=[{}]", i, addr, data); |
| 167 | + let tok = send(tok, ctrl_data, (addr, data)); |
| 168 | + let (tok, _) = recv(tok, ctrl_done); |
| 169 | + (tok) |
| 170 | + }(tok); |
| 171 | + let tok = send(tok, terminator, true); |
| 172 | + } |
| 173 | +} |
0 commit comments