OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [bus_explorer/] [main.c] - Blame information for rev 68

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 68 zero_gravi
// #################################################################################################
2
// # << NEORV32 - Bus Explorer - Processor Memory Space Inspector >>                               #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6
// # Copyright (c) 2021, Stephan Nolting. All rights reserved.                                     #
7
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
33
// #################################################################################################
34
 
35
 
36
/**********************************************************************//**
37
 * @file bus_explorer/main.c
38
 * @author Stephan Nolting
39
 * @brief Interactive memory inspector.
40
 **************************************************************************/
41
 
42
#include <neorv32.h>
43
#include <string.h>
44
 
45
 
46
/**********************************************************************//**
47
 * @name User configuration
48
 **************************************************************************/
49
/**@{*/
50
/** UART BAUD rate */
51
#define BAUD_RATE 19200
52
/**@}*/
53
 
54
// Global variables
55
char access_size;
56
 
57
// Prototypes
58
void read_memory(void);
59
void setup_access(void);
60
void write_memory(void);
61
void atomic_cas(void);
62
void dump_memory(void);
63
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
64
void aux_print_hex_byte(uint8_t byte);
65
 
66
 
67
/**********************************************************************//**
68
 * This program provides an interactive console to read/write memory.
69
 *
70
 * @note This program requires the UART to be synthesized.
71
 *
72
 * @return 0 if execution was successful
73
 **************************************************************************/
74
int main() {
75
 
76
  char buffer[8];
77
  int length = 0;
78
 
79
  access_size = 0;
80
 
81
  // check if UART unit is implemented at all
82
  if (neorv32_uart0_available() == 0) {
83
    return 1;
84
  }
85
 
86
 
87
  // capture all exceptions and give debug info via UART
88
  neorv32_rte_setup();
89
 
90
  // disable global interrupts
91
  neorv32_cpu_dint();
92
 
93
  // init UART at default baud rate, no parity bits, ho hw flow control
94
  neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
95
 
96
  // check available hardware extensions and compare with compiler flags
97
  neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
98
 
99
  // intro
100
  neorv32_uart0_printf("\n<<< NEORV32 Bus Explorer >>>\n\n");
101
 
102
  // info
103
  neorv32_uart0_printf("This program allows to read/write/dump memory space by hand.\n"
104
                       "Type 'help' to see the help menu.\n\n");
105
 
106
  // Main menu
107
  for (;;) {
108
    neorv32_uart0_printf("BUS_EXPLORER:> ");
109
    length = neorv32_uart0_scan(buffer, 8, 1);
110
    neorv32_uart0_printf("\n");
111
 
112
    if (!length) // nothing to be done
113
     continue;
114
 
115
    // decode input and execute command
116
    if (!strcmp(buffer, "help")) {
117
      neorv32_uart0_printf("Available commands:\n"
118
                          " help   - show this text\n"
119
                          " setup  - configure memory access width (byte,half,word)\n"
120
                          " read   - read from address (byte,half,word)\n"
121
                          " write  - write to address (byte,half,word)\n"
122
                          " atomic - perform atomic LR/SC access (word-only)\n"
123
                          " dump   - dump several bytes/halfs/words from base address\n");
124
    }
125
 
126
    else if (!strcmp(buffer, "setup")) {
127
      setup_access();
128
    }
129
 
130
    else if (!strcmp(buffer, "read")) {
131
      read_memory();
132
    }
133
 
134
    else if (!strcmp(buffer, "atomic")) {
135
      atomic_cas();
136
    }
137
 
138
    else if (!strcmp(buffer, "write")) {
139
      write_memory();
140
    }
141
 
142
    else if (!strcmp(buffer, "dump")) {
143
      dump_memory();
144
    }
145
 
146
    else {
147
      neorv32_uart0_printf("Invalid command. Type 'help' to see all commands.\n");
148
    }
149
  }
150
 
151
  return 0;
152
}
153
 
154
 
155
/**********************************************************************//**
156
 * Configure memory access size
157
 **************************************************************************/
158
void setup_access(void) {
159
 
160
  neorv32_uart0_printf("Select data size (press 'x' to abort):\n"
161
                       " 'b' - byte, 8-bit, unsigned\n"
162
                       " 'h' - half-word, 16-bit, unsigned\n"
163
                       " 'w' - word, 32-bit, unsigned\n");
164
 
165
  while(1) {
166
    neorv32_uart0_printf("selection: ");
167
    char tmp = neorv32_uart0_getc();
168
    neorv32_uart0_putc(tmp);
169
    if ((tmp == 'b') || (tmp == 'h') || (tmp == 'w')) {
170
      access_size = tmp;
171
      neorv32_uart0_printf("\n");
172
      return;
173
    }
174
    else if (tmp == 'x') {
175
      neorv32_uart0_printf("\n");
176
      return;
177
    }
178
    else {
179
      neorv32_uart0_printf("Invalid selection!\n");
180
    }
181
  }
182
}
183
 
184
 
185
/**********************************************************************//**
186
 * Read from memory address
187
 **************************************************************************/
188
void read_memory(void) {
189
 
190
  char terminal_buffer[16];
191
 
192
  if (access_size == 0) {
193
    neorv32_uart0_printf("Configure data size using 'setup' first.\n");
194
    return;
195
  }
196
 
197
  // enter address
198
  neorv32_uart0_printf("Enter address (8 hex chars): 0x");
199
  neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
200
  register uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
201
 
202
  // perform read access
203
  neorv32_uart0_printf("\n[0x%x] = ", mem_address);
204
 
205
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
206
 
207
  uint8_t mem_data_b = 0;
208
  uint16_t mem_data_h = 0;
209
  uint32_t mem_data_w = 0;
210
  if (access_size == 'b') { mem_data_b = (uint32_t)neorv32_cpu_load_unsigned_byte(mem_address); }
211
  if (access_size == 'h') { mem_data_h = (uint32_t)neorv32_cpu_load_unsigned_half(mem_address); }
212
  if (access_size == 'w') { mem_data_w = (uint32_t)neorv32_cpu_load_unsigned_word(mem_address); }
213
 
214
  // show memory content if there was no exception
215
  if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
216
    neorv32_uart0_printf("0x");
217
    if (access_size == 'b') {
218
      aux_print_hex_byte(mem_data_b);
219
    }
220
    if (access_size == 'h') {
221
      aux_print_hex_byte((uint8_t)(mem_data_h >>  8));
222
      aux_print_hex_byte((uint8_t)(mem_data_h >>  0));
223
    }
224
    if (access_size == 'w') {
225
      aux_print_hex_byte((uint8_t)(mem_data_w >> 24));
226
      aux_print_hex_byte((uint8_t)(mem_data_w >> 16));
227
      aux_print_hex_byte((uint8_t)(mem_data_w >>  8));
228
      aux_print_hex_byte((uint8_t)(mem_data_w >>  0));
229
    }
230
  }
231
 
232
  neorv32_uart0_printf("\n");
233
}
234
 
235
 
236
/**********************************************************************//**
237
 * Write to memory address
238
 **************************************************************************/
239
void write_memory(void) {
240
 
241
  char terminal_buffer[16];
242
 
243
  if (access_size == 0) {
244
    neorv32_uart0_printf("Configure data size using 'setup' first.\n");
245
    return;
246
  }
247
 
248
  // enter address
249
  neorv32_uart0_printf("Enter address (8 hex chars): 0x");
250
  neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
251
  uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
252
 
253
  // enter data
254
  uint8_t mem_data_b = 0;
255
  uint16_t mem_data_h = 0;
256
  uint32_t mem_data_w = 0;
257
  if (access_size == 'b') {
258
    neorv32_uart0_printf("\nEnter data (2 hex chars): 0x");
259
    neorv32_uart0_scan(terminal_buffer, 2+1, 1); // 2 hex chars for address plus '\0'
260
    mem_data_b = (uint8_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
261
  }
262
  if (access_size == 'h') {
263
    neorv32_uart0_printf("\nEnter data (4 hex chars): 0x");
264
    neorv32_uart0_scan(terminal_buffer, 4+1, 1); // 4 hex chars for address plus '\0'
265
    mem_data_h = (uint16_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
266
  }
267
  if (access_size == 'w') {
268
    neorv32_uart0_printf("\nEnter data (8 hex chars): 0x");
269
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
270
    mem_data_w = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
271
  }
272
 
273
  // perform write access
274
  if (access_size == 'b') { neorv32_cpu_store_unsigned_byte(mem_address, mem_data_b); }
275
  if (access_size == 'h') { neorv32_cpu_store_unsigned_half(mem_address, mem_data_h); }
276
  if (access_size == 'w') { neorv32_cpu_store_unsigned_word(mem_address, mem_data_w); }
277
 
278
  neorv32_uart0_printf("\n");
279
}
280
 
281
 
282
/**********************************************************************//**
283
 * Perform atomic compare-and-swap operation, always 32-bit
284
 **************************************************************************/
285
void atomic_cas(void) {
286
 
287
  char terminal_buffer[16];
288
  uint32_t mem_address, rdata, wdata, status;
289
 
290
  if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
291
 
292
    // enter memory address
293
    neorv32_uart0_printf("Enter memory address (8 hex chars): 0x");
294
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
295
    mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
296
 
297
    // enter desired value
298
    neorv32_uart0_printf("\nEnter new value @0x%x (8 hex chars): 0x", mem_address);
299
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
300
    wdata = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
301
 
302
    rdata = neorv32_cpu_load_reservate_word(mem_address); // make reservation
303
    status = neorv32_cpu_store_conditional(mem_address, wdata);
304
 
305
    // status
306
    neorv32_uart0_printf("\nOld data: 0x%x\n", rdata);
307
    if (status == 0) {
308
      neorv32_uart0_printf("Atomic access successful!\n");
309
      neorv32_uart0_printf("New data: 0x%x\n", neorv32_cpu_load_unsigned_word(mem_address));
310
    }
311
    else {
312
      neorv32_uart0_printf("Atomic access failed!\n");
313
    }
314
  }
315
  else {
316
    neorv32_uart0_printf("Atomic operations not implemented/enabled!\n");
317
  }
318
}
319
 
320
 
321
/**********************************************************************//**
322
 * Read several bytes/halfs/word from memory base address
323
 **************************************************************************/
324
void dump_memory(void) {
325
 
326
  char terminal_buffer[16];
327
 
328
  if (access_size == 0) {
329
    neorv32_uart0_printf("Configure data size using 'setup' first.\n");
330
    return;
331
  }
332
 
333
  // enter base address
334
  neorv32_uart0_printf("Enter base address (8 hex chars): 0x");
335
  neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
336
  uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
337
 
338
  neorv32_uart0_printf("\nPress key to start dumping. Press any key to abort.\n");
339
 
340
  neorv32_uart0_getc(); // wait for key
341
 
342
  // perform read accesses
343
  while(neorv32_uart0_char_received() == 0) {
344
 
345
    neorv32_uart0_printf("[0x%x] = ", mem_address);
346
 
347
    neorv32_cpu_csr_write(CSR_MCAUSE, 0);
348
 
349
    uint8_t mem_data_b = 0;
350
    uint16_t mem_data_h = 0;
351
    uint32_t mem_data_w = 0;
352
    if (access_size == 'b') { mem_data_b = (uint32_t)neorv32_cpu_load_unsigned_byte(mem_address); }
353
    if (access_size == 'h') { mem_data_h = (uint32_t)neorv32_cpu_load_unsigned_half(mem_address); }
354
    if (access_size == 'w') { mem_data_w = (uint32_t)neorv32_cpu_load_unsigned_word(mem_address); }
355
 
356
    // show memory content if there was no exception
357
    if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
358
      neorv32_uart0_printf("0x");
359
      if (access_size == 'b') {
360
        aux_print_hex_byte(mem_data_b);
361
      }
362
      if (access_size == 'h') {
363
        aux_print_hex_byte((uint8_t)(mem_data_h >>  8));
364
        aux_print_hex_byte((uint8_t)(mem_data_h >>  0));
365
      }
366
      if (access_size == 'w') {
367
        aux_print_hex_byte((uint8_t)(mem_data_w >> 24));
368
        aux_print_hex_byte((uint8_t)(mem_data_w >> 16));
369
        aux_print_hex_byte((uint8_t)(mem_data_w >>  8));
370
        aux_print_hex_byte((uint8_t)(mem_data_w >>  0));
371
      }
372
      neorv32_uart0_printf("\n");
373
    }
374
    else {
375
     break;
376
    }
377
 
378
    if (access_size == 'b') {
379
      mem_address += 1;
380
    }
381
    else if (access_size == 'h') {
382
      mem_address += 2;
383
    }
384
    else if (access_size == 'w') {
385
      mem_address += 4;
386
    }
387
 
388
  }
389
  neorv32_uart0_char_received_get(); // clear UART rx buffer
390
  neorv32_uart0_printf("\n");
391
}
392
 
393
 
394
/**********************************************************************//**
395
 * Helper function to convert N hex chars string into uint32_T
396
 *
397
 * @param[in,out] buffer Pointer to array of chars to convert into number.
398
 * @param[in,out] length Length of the conversion string.
399
 * @return Converted number.
400
 **************************************************************************/
401
uint32_t hexstr_to_uint(char *buffer, uint8_t length) {
402
 
403
  uint32_t res = 0, d = 0;
404
  char c = 0;
405
 
406
  while (length--) {
407
    c = *buffer++;
408
 
409
    if ((c >= '0') && (c <= '9'))
410
      d = (uint32_t)(c - '0');
411
    else if ((c >= 'a') && (c <= 'f'))
412
      d = (uint32_t)((c - 'a') + 10);
413
    else if ((c >= 'A') && (c <= 'F'))
414
      d = (uint32_t)((c - 'A') + 10);
415
    else
416
      d = 0;
417
 
418
    res = res + (d << (length*4));
419
  }
420
 
421
  return res;
422
}
423
 
424
 
425
/**********************************************************************//**
426
 * Print HEX byte.
427
 *
428
 * @param[in] byte Byte to be printed as 2-cahr hex value.
429
 **************************************************************************/
430
void aux_print_hex_byte(uint8_t byte) {
431
 
432
  static const char symbols[] = "0123456789abcdef";
433
 
434
  neorv32_uart0_putc(symbols[(byte >> 4) & 0x0f]);
435
  neorv32_uart0_putc(symbols[(byte >> 0) & 0x0f]);
436
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.