SatCat5
cfgbus_core.cc
1 // Copyright 2021-2023 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 // ConfigBus core definitions
6 //
7 // Define a memory-mapped "ConfigBus" interface, based on a base address.
8 // All registers in this interface correspond to volatile pointers.
9 //
10 
11 #include <satcat5/cfgbus_core.h>
12 #include <satcat5/cfgbus_interrupt.h>
13 #include <satcat5/log.h>
14 
22 namespace log = satcat5::log;
23 
24 // By default, check for duplicate interrupt handlers.
25 #ifndef SATCAT5_CHECK_DUPIRQ
26 #define SATCAT5_CHECK_DUPIRQ 1
27 #endif
28 
29 WrappedRegister::WrappedRegister(ConfigBus* cfg, unsigned reg)
30  : m_cfg(cfg)
31  , m_reg(reg)
32 {
33  // Nothing else to initialize.
34 }
35 
36 WrappedRegister::operator u32()
37 {
38  u32 tmp;
39  m_cfg->read(m_reg, tmp);
40  return tmp;
41 }
42 
43 void WrappedRegister::operator=(u32 wrval)
44 {
45  m_cfg->write(m_reg, wrval);
46 }
47 
48 void WrappedRegister::write_repeat(unsigned count, const u32* data)
49 {
50  m_cfg->write_repeat(m_reg, count, data);
51 }
52 
53 WrappedRegisterPtr::WrappedRegisterPtr(ConfigBus* cfg, unsigned reg)
54  : m_cfg(cfg)
55  , m_reg(reg)
56 {
57  // Nothing else to initialize.
58 }
59 
60 bool WrappedRegisterPtr::operator!() const
61 {
62  return !m_cfg;
63 }
64 
65 WrappedRegister WrappedRegisterPtr::operator*()
66 {
67  return WrappedRegister(m_cfg, m_reg);
68 }
69 
70 WrappedRegister WrappedRegisterPtr::operator[](unsigned idx)
71 {
72  return WrappedRegister(m_cfg, m_reg + idx);
73 }
74 
75 WrappedRegisterPtr WrappedRegisterPtr::operator+(unsigned idx)
76 {
77  return WrappedRegisterPtr(m_cfg, m_reg + idx);
78 }
79 
81 {
82  // Traverse the linked list to confirm this entry isn't a duplicate.
83  // (Otherwise, this action will create an infinite loop.)
84  if (SATCAT5_CHECK_DUPIRQ && m_irq_list.contains(obj)) {
85  log::Log(log::ERROR, "ConfigBus IRQ duplicate");
86  } else {
87  m_irq_list.add(obj);
88  }
89 }
90 
92 {
93  m_irq_list.remove(obj);
94 }
95 
96 unsigned ConfigBus::count_irq() const
97 {
98  return m_irq_list.len();
99 }
100 
101 Register ConfigBus::get_register(unsigned dev, unsigned reg)
102 {
103  unsigned idx = get_regaddr(dev, reg);
104 #if SATCAT5_CFGBUS_DIRECT
105  return (volatile u32*)(m_base_ptr + idx);
106 #else
107  return WrappedRegisterPtr(this, idx);
108 #endif
109 }
110 
112 {
113  // Traverse the linked list and poll each handler.
114  Interrupt* ptr = m_irq_list.head();
115  while (ptr != 0) {
116  ptr->irq_check();
117  ptr = ptr->m_next;
118  }
119 }
120 
121 ConfigBus::ConfigBus(void* base_ptr)
122  : m_base_ptr((volatile u32*)base_ptr)
123 {
124  // Nothing else to initialize at this time.
125 }
126 
128  unsigned regaddr, unsigned count, u32* result)
129 {
130  IoStatus status = IoStatus::OK;
131  for (unsigned a = 0 ; a < count ; ++a) {
132  IoStatus tmp = read(regaddr+a, result[a]);
133  if (tmp != IoStatus::OK) status = tmp;
134  }
135  return status;
136 }
137 
139  unsigned regaddr, unsigned count, u32* result)
140 {
141  IoStatus status = IoStatus::OK;
142  for (unsigned a = 0 ; a < count ; ++a) {
143  IoStatus tmp = read(regaddr, result[a]);
144  if (tmp != IoStatus::OK) status = tmp;
145  }
146  return status;
147 }
148 
150  unsigned regaddr, unsigned count, const u32* data)
151 {
152  IoStatus status = IoStatus::OK;
153  for (unsigned a = 0 ; a < count ; ++a) {
154  IoStatus tmp = write(regaddr+a, data[a]);
155  if (tmp != IoStatus::OK) status = tmp;
156  }
157  return status;
158 }
159 
161  unsigned regaddr, unsigned count, const u32* data)
162 {
163  IoStatus status = IoStatus::OK;
164  for (unsigned a = 0 ; a < count ; ++a) {
165  IoStatus tmp = write(regaddr, data[a]);
166  if (tmp != IoStatus::OK) status = tmp;
167  }
168  return status;
169 }
170 
171 IoStatus ConfigBusMmap::read(unsigned regaddr, u32& val) {
172  val = m_base_ptr[regaddr];
173  return IoStatus::OK;
174 }
175 
176 IoStatus ConfigBusMmap::write(unsigned regaddr, u32 val) {
177  m_base_ptr[regaddr] = val;
178  return IoStatus::OK;
179 }
180 
181 ConfigBusMmap::ConfigBusMmap(void* base_ptr, int irq)
182  : ConfigBus(base_ptr)
183  , irq::Handler("ConfigBus", irq)
184 {
185  // Nothing else to initialize at this time.
186 }
187 
188 void* ConfigBusMmap::get_device_mmap(unsigned dev) const
189 {
190  return (void*)(m_base_ptr + get_regaddr(dev,0));
191 }
192 
194  // Forward interrupt events to parent.
195  irq_poll();
196 }
197 
ConfigBus core definitions.
IoStatus
Status codes for ConfigBus read/write operations.
Definition: cfgbus_core.h:99
Generic ConfigBus API.
Definition: cfgbus_core.h:124
virtual satcat5::cfg::IoStatus read(unsigned regaddr, u32 &rdval)=0
Basic single-register read operation.
satcat5::cfg::Register get_register(unsigned dev, unsigned reg=0)
Create register-map object for the given device address.
Definition: cfgbus_core.cc:101
void irq_poll()
Poll all registered ConfigBus interrupt handlers.
Definition: cfgbus_core.cc:111
virtual satcat5::cfg::IoStatus write(unsigned regaddr, u32 wrval)=0
Basic single-register write operation.
virtual satcat5::cfg::IoStatus read_repeat(unsigned regaddr, unsigned count, u32 *result)
Bulk-read the same register N times.
Definition: cfgbus_core.cc:138
unsigned get_regaddr(unsigned dev, unsigned reg) const
Convert device + register to combined address.
Definition: cfgbus_core.h:147
virtual satcat5::cfg::IoStatus write_repeat(unsigned regaddr, unsigned count, const u32 *data)
Bulk-write the same register N times.
Definition: cfgbus_core.cc:160
void unregister_irq(satcat5::cfg::Interrupt *obj)
Remove an interrupt handler.
Definition: cfgbus_core.cc:91
virtual satcat5::cfg::IoStatus write_array(unsigned regaddr, unsigned count, const u32 *data)
Bulk-write with auto-increment (regaddr, regaddr+1, ...)
Definition: cfgbus_core.cc:149
void register_irq(satcat5::cfg::Interrupt *obj)
Add an interrupt handler.
Definition: cfgbus_core.cc:80
unsigned count_irq() const
Count attached interrupt handlers.
Definition: cfgbus_core.cc:96
virtual satcat5::cfg::IoStatus read_array(unsigned regaddr, unsigned count, u32 *result)
Bulk-read with auto-increment (regaddr, regaddr+1, ...) Bulk read/write operations are more efficient...
Definition: cfgbus_core.cc:127
Memory-mapped local ConfigBus.
Definition: cfgbus_core.h:199
satcat5::cfg::IoStatus write(unsigned regaddr, u32 val) override
Basic single-register write operation.
Definition: cfgbus_core.cc:176
void * get_device_mmap(unsigned dev) const
Get a raw pointer to the designated device-address.
Definition: cfgbus_core.cc:188
void irq_event() override
Method called whenever an interrupt is triggered.
Definition: cfgbus_core.cc:193
satcat5::cfg::IoStatus read(unsigned regaddr, u32 &val) override
Basic single-register read operation.
Definition: cfgbus_core.cc:171
ConfigBusMmap(void *base_ptr, int irq)
Constructor accepts the base pointer for the memory-map interface, and the interrupt-index for the sh...
Definition: cfgbus_core.cc:181
Event-handler for individual ConfigBus interrupts.
void irq_check()
Check if this interrupt may need service.
Generic wrapper for a specific ConfigBus register.
Definition: cfgbus_core.h:59
Pointer-like wrapper for one or more ConfigBus registers.
Definition: cfgbus_core.h:76
The Log class creates and formats one log message.
Definition: log.h:195
unsigned len() const
Traverse the linked list to count its length.
Definition: list.h:257
bool contains(const T *item) const
Scan the list, looking for the item in question.
Definition: list.h:235
void add(T *item)
Add new item to front or back, whichever is simpler.
Definition: list.h:221
void remove(T *item)
Remove the designated item from the list.
Definition: list.h:277
Diagnostic logging to UART and/or Ethernet ports.