Pavona Software APIs
dif_acc.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
6
7#include <assert.h>
8
12
13#include "hw/top/acc_regs.h" // Generated.
14
15static_assert(kDifAccErrBitsBadDataAddr ==
16 (1 << ACC_ERR_BITS_BAD_DATA_ADDR_BIT),
17 "Layout of error bits changed.");
18static_assert(kDifAccErrBitsBadInsnAddr ==
19 (1 << ACC_ERR_BITS_BAD_INSN_ADDR_BIT),
20 "Layout of error bits changed.");
21static_assert(kDifAccErrBitsCallStack == (1 << ACC_ERR_BITS_CALL_STACK_BIT),
22 "Layout of error bits changed.");
23static_assert(kDifAccErrBitsIllegalInsn == (1 << ACC_ERR_BITS_ILLEGAL_INSN_BIT),
24 "Layout of error bits changed.");
25static_assert(kDifAccErrBitsLoop == (1 << ACC_ERR_BITS_LOOP_BIT),
26 "Layout of error bits changed.");
28 (1 << ACC_ERR_BITS_IMEM_INTG_VIOLATION_BIT),
29 "Layout of error bits changed.");
31 (1 << ACC_ERR_BITS_DMEM_INTG_VIOLATION_BIT),
32 "Layout of error bits changed.");
33static_assert(kDifAccErrBitsRegIntgViolation ==
34 (1 << ACC_ERR_BITS_REG_INTG_VIOLATION_BIT),
35 "Layout of error bits changed.");
36static_assert(kDifAccErrBitsBusIntgViolation ==
37 (1 << ACC_ERR_BITS_BUS_INTG_VIOLATION_BIT),
38 "Layout of error bits changed.");
39static_assert(kDifAccErrBitsIllegalBusAccess ==
40 (1 << ACC_ERR_BITS_ILLEGAL_BUS_ACCESS_BIT),
41 "Layout of error bits changed.");
43 (1 << ACC_ERR_BITS_LIFECYCLE_ESCALATION_BIT),
44 "Layout of error bits changed.");
45static_assert(kDifAccErrBitsFatalSoftware ==
46 (1 << ACC_ERR_BITS_FATAL_SOFTWARE_BIT),
47 "Layout of error bits changed.");
48
49/**
50 * Data width of big number subset, in bytes.
51 */
52const int kDifAccWlenBytes = 256 / 8;
53
54/**
55 * Ensures that `offset` and `size` are valid for a given `mem_size`.
56 *
57 * Valid are 32b word accesses to 32b-aligned memory locations within
58 * `mem_size`.
59 */
60static bool check_offset_len(uint32_t offset_bytes, size_t len_bytes,
61 size_t mem_size) {
62 // The overflow check below assumes/requires two unsigned inputs.
63 return (len_bytes % sizeof(uint32_t) == 0 &&
64 offset_bytes % sizeof(uint32_t) == 0 &&
65 offset_bytes + len_bytes >= len_bytes &&
66 offset_bytes + len_bytes <= mem_size);
67}
68
69dif_result_t dif_acc_reset(const dif_acc_t *acc) {
70 if (acc == NULL) {
71 return kDifBadArg;
72 }
73
74 mmio_region_write32(acc->base_addr, ACC_INTR_ENABLE_REG_OFFSET, 0);
75
76 // Clear all pending interrupts.
77 mmio_region_write32(acc->base_addr, ACC_INTR_STATE_REG_OFFSET, 0xFFFFFFFF);
78
79 return kDifOk;
80}
81
82dif_result_t dif_acc_write_cmd(const dif_acc_t *acc, dif_acc_cmd_t cmd) {
83 if (acc == NULL) {
84 return kDifBadArg;
85 }
86
87 mmio_region_write32(acc->base_addr, ACC_CMD_REG_OFFSET, cmd);
88
89 return kDifOk;
90}
91
92dif_result_t dif_acc_get_status(const dif_acc_t *acc,
94 if (acc == NULL || status == NULL) {
95 return kDifBadArg;
96 }
97
98 *status = mmio_region_read32(acc->base_addr, ACC_STATUS_REG_OFFSET);
99
100 return kDifOk;
101}
102
103dif_result_t dif_acc_get_err_bits(const dif_acc_t *acc,
104 dif_acc_err_bits_t *err_bits) {
105 if (acc == NULL || err_bits == NULL) {
106 return kDifBadArg;
107 }
108
109 uint32_t err_bits_raw =
110 mmio_region_read32(acc->base_addr, ACC_ERR_BITS_REG_OFFSET);
111
112 *err_bits = err_bits_raw;
113 return kDifOk;
114}
115
116dif_result_t dif_acc_get_insn_cnt(const dif_acc_t *acc, uint32_t *insn_cnt) {
117 if (acc == NULL || insn_cnt == NULL) {
118 return kDifBadArg;
119 }
120
121 *insn_cnt = mmio_region_read32(acc->base_addr, ACC_INSN_CNT_REG_OFFSET);
122 return kDifOk;
123}
124
125dif_result_t dif_acc_get_load_checksum(const dif_acc_t *acc,
126 uint32_t *checksum) {
127 if (acc == NULL || checksum == NULL) {
128 return kDifBadArg;
129 }
130
131 *checksum = mmio_region_read32(acc->base_addr, ACC_LOAD_CHECKSUM_REG_OFFSET);
132 return kDifOk;
133}
134
135dif_result_t dif_acc_clear_load_checksum(const dif_acc_t *acc) {
136 if (acc == NULL) {
137 return kDifBadArg;
138 }
139
140 mmio_region_write32(acc->base_addr, ACC_LOAD_CHECKSUM_REG_OFFSET, 0);
141
142 return kDifOk;
143}
144
145dif_result_t dif_acc_imem_write(const dif_acc_t *acc, uint32_t offset_bytes,
146 const void *src, size_t len_bytes) {
147 if (acc == NULL || src == NULL ||
148 !check_offset_len(offset_bytes, len_bytes, ACC_IMEM_SIZE_BYTES)) {
149 return kDifBadArg;
150 }
151
152 mmio_region_memcpy_to_mmio32(
153 acc->base_addr, ACC_IMEM_REG_OFFSET + offset_bytes, src, len_bytes);
154
155 return kDifOk;
156}
157
158dif_result_t dif_acc_imem_read(const dif_acc_t *acc, uint32_t offset_bytes,
159 void *dest, size_t len_bytes) {
160 if (acc == NULL || dest == NULL ||
161 !check_offset_len(offset_bytes, len_bytes, ACC_IMEM_SIZE_BYTES)) {
162 return kDifBadArg;
163 }
164
165 mmio_region_memcpy_from_mmio32(
166 acc->base_addr, ACC_IMEM_REG_OFFSET + offset_bytes, dest, len_bytes);
167
168 return kDifOk;
169}
170
171dif_result_t dif_acc_dmem_write(const dif_acc_t *acc, uint32_t offset_bytes,
172 const void *src, size_t len_bytes) {
173 if (acc == NULL || src == NULL ||
174 !check_offset_len(offset_bytes, len_bytes, ACC_DMEM_SIZE_BYTES)) {
175 return kDifBadArg;
176 }
177
178 mmio_region_memcpy_to_mmio32(
179 acc->base_addr, ACC_DMEM_REG_OFFSET + offset_bytes, src, len_bytes);
180
181 return kDifOk;
182}
183
184dif_result_t dif_acc_dmem_read(const dif_acc_t *acc, uint32_t offset_bytes,
185 void *dest, size_t len_bytes) {
186 if (acc == NULL || dest == NULL ||
187 !check_offset_len(offset_bytes, len_bytes, ACC_DMEM_SIZE_BYTES)) {
188 return kDifBadArg;
189 }
190
191 mmio_region_memcpy_from_mmio32(
192 acc->base_addr, ACC_DMEM_REG_OFFSET + offset_bytes, dest, len_bytes);
193
194 return kDifOk;
195}
196
197dif_result_t dif_acc_set_ctrl_software_errs_fatal(const dif_acc_t *acc,
198 bool enable) {
199 if (acc == NULL) {
200 return kDifBadArg;
201 }
202
203 // Only one bit in the CTRL register so no need to read current value.
204 uint32_t new_ctrl;
205
206 if (enable) {
207 new_ctrl = 1;
208 } else {
209 new_ctrl = 0;
210 }
211
212 mmio_region_write32(acc->base_addr, ACC_CTRL_REG_OFFSET, new_ctrl);
213 if (mmio_region_read32(acc->base_addr, ACC_CTRL_REG_OFFSET) != new_ctrl) {
214 return kDifUnavailable;
215 }
216
217 return kDifOk;
218}
219
220size_t dif_acc_get_dmem_size_bytes(const dif_acc_t *acc) {
221 return ACC_DMEM_SIZE_BYTES;
222}
223
224size_t dif_acc_get_imem_size_bytes(const dif_acc_t *acc) {
225 return ACC_IMEM_SIZE_BYTES;
226}