scc  2022.4.0
SystemC components library
initiator.cpp
1 /*******************************************************************************
2  * Copyright 2019-2022 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
18 #define SC_INCLUDE_DYNAMIC_PROCESSES
19 #endif
20 #include "initiator.h"
21 #include <ahb/ahb_tlm.h>
22 #include <scc/report.h>
23 #include <scc/utilities.h>
24 
25 using namespace ahb::pin;
26 using namespace sc_core;
27 
28 template <unsigned WIDTH>
29 initiator<WIDTH>::initiator(const sc_module_name& nm)
30 : sc_module(nm) {
31  SC_HAS_PROCESS(initiator);
32  SC_THREAD(bus_addr_task);
33  SC_THREAD(bus_data_task);
34 
35  tsckt.register_nb_transport_fw(
36  [this](tlm::tlm_generic_payload& payload, tlm::tlm_phase& phase, sc_core::sc_time& delay) -> tlm::tlm_sync_enum {
37  if(phase == tlm::BEGIN_REQ) {
38  if(payload.has_mm())
39  payload.acquire();
40  auto* ext = payload.get_extension<ahb_extension>();
41  if(!ext) {
42  ext = new ahb_extension();
43  payload.set_extension(ext);
44  }
45  this->inqueue.notify(payload);
46  }
47  return tlm::TLM_ACCEPTED;
48  });
49 }
50 
51 template <unsigned WIDTH> inline void initiator<WIDTH>::bus_addr_task() {
52  auto& hready = HREADY_i.read();
53  while(true) {
54  wait(inqueue.get_event());
55  while(auto trans = inqueue.get_next_transaction()) {
56  sc_assert(trans->get_data_length() * 8 <= WIDTH && "Transaction length larger than bus width, this is not supported");
57  SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address();
58  auto bytes_exp = scc::ilog2(trans->get_data_length());
59  auto width_exp = scc::ilog2(WIDTH / 8);
60  size_t size = 0;
61  for(; size < bytes_exp; ++size)
62  if(trans->get_address() & (1 << size))
63  break; // i contains the first bit not being 0
64  auto* ext = trans->template get_extension<ahb_extension>();
65  HADDR_o.write(trans->get_address());
66  HWRITE_o.write(trans->is_write());
67  HMASTLOCK_o.write(ext->is_locked());
68  HPROT_o.write(ext->get_protection());
69  HBURST_o.write(static_cast<unsigned>(ext->get_burst()));
70  HSIZE_o.write(size);
71  HTRANS_o.write(static_cast<unsigned>(ext->is_seq() ? trans_e::SEQ : trans_e::NONSEQ));
72  do {
73  wait(HCLK_i.posedge_event());
74  } while(!hready);
75  SCCDEBUG(SCMOD) << "Send end req for read to addr 0x" << std::hex << trans->get_address();
76  tlm::tlm_phase phase{tlm::END_REQ};
77  sc_time delay;
78  auto res = tsckt->nb_transport_bw(*trans, phase, delay);
79  tx_in_flight.notify(*trans);
80  HTRANS_o.write(static_cast<unsigned>(trans_e::IDLE));
81  }
82  }
83 }
84 
85 template <unsigned WIDTH> inline void initiator<WIDTH>::bus_data_task() {
86  auto const width = WIDTH / 8;
87  auto& hready = HREADY_i.read();
88  auto& rdata = HRDATA_i.read();
89  while(true) {
90  wait(tx_in_flight.get_event());
91  while(auto trans = tx_in_flight.get_next_transaction()) {
92  auto bytes_exp = scc::ilog2(trans->get_data_length());
93  auto width_exp = scc::ilog2(WIDTH / 8);
94  size_t size = 0;
95  for(; size < width_exp; ++size)
96  if(trans->get_address() & (1 << size))
97  break; // i contains the first bit not being 0
98  auto beats = bytes_exp < size ? 1 : 1 << (bytes_exp - size);
99  auto start_offs = trans->get_address() & (width - 1);
100  auto len = trans->get_data_length();
101  if(trans->is_write()) {
102  data_t data{0};
103  for(size_t i = start_offs * 8, j = 0; i < WIDTH; i += 8, ++j)
104  data.range(i + 7, i) = *(uint8_t*)(trans->get_data_ptr() + j);
105  HWDATA_o.write(data);
106  trans->set_response_status(tlm::TLM_OK_RESPONSE);
107  tlm::tlm_phase phase{tlm::BEGIN_RESP};
108  sc_time delay;
109  tsckt->nb_transport_bw(*trans, phase, delay);
110  }
111  do {
112  wait(HCLK_i.posedge_event());
113  } while(!hready);
114  if(trans->is_read()) {
115  for(size_t i = start_offs * 8, j = 0; i < WIDTH; i += 8, ++j)
116  *(uint8_t*)(trans->get_data_ptr() + j) = rdata.range(i + 7, i).to_uint();
117  trans->set_response_status(tlm::TLM_OK_RESPONSE);
118  tlm::tlm_phase phase{tlm::BEGIN_RESP};
119  sc_time delay;
120  tsckt->nb_transport_bw(*trans, phase, delay);
121  }
122  if(trans->has_mm())
123  trans->release();
124  }
125  }
126 }
127 
128 template class ahb::pin::initiator<32>;
129 template class ahb::pin::initiator<64>;
130 template class ahb::pin::initiator<128>;
131 template class ahb::pin::initiator<256>;
132 template class ahb::pin::initiator<512>;
133 template class ahb::pin::initiator<1024>;
pin level adapters
Definition: initiator.h:26