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

Subversion Repositories neorv32

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

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 69 zero_gravi
      neorv32_uart0_printf("\nInvalid selection!\n");
180 68 zero_gravi
    }
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 69 zero_gravi
  neorv32_uart0_printf("\n[0x%x] => ", mem_address);
204 68 zero_gravi
 
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 69 zero_gravi
    neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address);
262
    aux_print_hex_byte(mem_data_b);
263 68 zero_gravi
  }
264
  if (access_size == 'h') {
265
    neorv32_uart0_printf("\nEnter data (4 hex chars): 0x");
266
    neorv32_uart0_scan(terminal_buffer, 4+1, 1); // 4 hex chars for address plus '\0'
267
    mem_data_h = (uint16_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
268 69 zero_gravi
    neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address);
269
    aux_print_hex_byte((uint8_t)(mem_data_h >> 8));
270
    aux_print_hex_byte((uint8_t)(mem_data_h >> 0));
271 68 zero_gravi
  }
272
  if (access_size == 'w') {
273
    neorv32_uart0_printf("\nEnter data (8 hex chars): 0x");
274
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
275
    mem_data_w = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
276 69 zero_gravi
    neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address);
277
    aux_print_hex_byte((uint8_t)(mem_data_w >> 24));
278
    aux_print_hex_byte((uint8_t)(mem_data_w >> 16));
279
    aux_print_hex_byte((uint8_t)(mem_data_w >> 8));
280
    aux_print_hex_byte((uint8_t)(mem_data_w >> 0));
281 68 zero_gravi
  }
282
 
283
  // perform write access
284
  if (access_size == 'b') { neorv32_cpu_store_unsigned_byte(mem_address, mem_data_b); }
285
  if (access_size == 'h') { neorv32_cpu_store_unsigned_half(mem_address, mem_data_h); }
286
  if (access_size == 'w') { neorv32_cpu_store_unsigned_word(mem_address, mem_data_w); }
287
 
288
  neorv32_uart0_printf("\n");
289
}
290
 
291
 
292
/**********************************************************************//**
293
 * Perform atomic compare-and-swap operation, always 32-bit
294
 **************************************************************************/
295
void atomic_cas(void) {
296
 
297
  char terminal_buffer[16];
298
  uint32_t mem_address, rdata, wdata, status;
299
 
300
  if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
301
 
302
    // enter memory address
303
    neorv32_uart0_printf("Enter memory address (8 hex chars): 0x");
304
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
305
    mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
306
 
307
    // enter desired value
308
    neorv32_uart0_printf("\nEnter new value @0x%x (8 hex chars): 0x", mem_address);
309
    neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
310
    wdata = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
311
 
312
    rdata = neorv32_cpu_load_reservate_word(mem_address); // make reservation
313
    status = neorv32_cpu_store_conditional(mem_address, wdata);
314
 
315
    // status
316
    neorv32_uart0_printf("\nOld data: 0x%x\n", rdata);
317
    if (status == 0) {
318
      neorv32_uart0_printf("Atomic access successful!\n");
319
      neorv32_uart0_printf("New data: 0x%x\n", neorv32_cpu_load_unsigned_word(mem_address));
320
    }
321
    else {
322
      neorv32_uart0_printf("Atomic access failed!\n");
323
    }
324
  }
325
  else {
326
    neorv32_uart0_printf("Atomic operations not implemented/enabled!\n");
327
  }
328
}
329
 
330
 
331
/**********************************************************************//**
332
 * Read several bytes/halfs/word from memory base address
333
 **************************************************************************/
334
void dump_memory(void) {
335
 
336
  char terminal_buffer[16];
337
 
338
  if (access_size == 0) {
339
    neorv32_uart0_printf("Configure data size using 'setup' first.\n");
340
    return;
341
  }
342
 
343
  // enter base address
344
  neorv32_uart0_printf("Enter base address (8 hex chars): 0x");
345
  neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
346
  uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
347
 
348
  neorv32_uart0_printf("\nPress key to start dumping. Press any key to abort.\n");
349
 
350
  neorv32_uart0_getc(); // wait for key
351
 
352
  // perform read accesses
353
  while(neorv32_uart0_char_received() == 0) {
354
 
355
    neorv32_uart0_printf("[0x%x] = ", mem_address);
356
 
357
    neorv32_cpu_csr_write(CSR_MCAUSE, 0);
358
 
359
    uint8_t mem_data_b = 0;
360
    uint16_t mem_data_h = 0;
361
    uint32_t mem_data_w = 0;
362
    if (access_size == 'b') { mem_data_b = (uint32_t)neorv32_cpu_load_unsigned_byte(mem_address); }
363
    if (access_size == 'h') { mem_data_h = (uint32_t)neorv32_cpu_load_unsigned_half(mem_address); }
364
    if (access_size == 'w') { mem_data_w = (uint32_t)neorv32_cpu_load_unsigned_word(mem_address); }
365
 
366
    // show memory content if there was no exception
367
    if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
368
      neorv32_uart0_printf("0x");
369
      if (access_size == 'b') {
370
        aux_print_hex_byte(mem_data_b);
371
      }
372
      if (access_size == 'h') {
373
        aux_print_hex_byte((uint8_t)(mem_data_h >>  8));
374
        aux_print_hex_byte((uint8_t)(mem_data_h >>  0));
375
      }
376
      if (access_size == 'w') {
377
        aux_print_hex_byte((uint8_t)(mem_data_w >> 24));
378
        aux_print_hex_byte((uint8_t)(mem_data_w >> 16));
379
        aux_print_hex_byte((uint8_t)(mem_data_w >>  8));
380
        aux_print_hex_byte((uint8_t)(mem_data_w >>  0));
381
      }
382
      neorv32_uart0_printf("\n");
383
    }
384
    else {
385
     break;
386
    }
387
 
388
    if (access_size == 'b') {
389
      mem_address += 1;
390
    }
391
    else if (access_size == 'h') {
392
      mem_address += 2;
393
    }
394
    else if (access_size == 'w') {
395
      mem_address += 4;
396
    }
397
 
398
  }
399
  neorv32_uart0_char_received_get(); // clear UART rx buffer
400
  neorv32_uart0_printf("\n");
401
}
402
 
403
 
404
/**********************************************************************//**
405
 * Helper function to convert N hex chars string into uint32_T
406
 *
407
 * @param[in,out] buffer Pointer to array of chars to convert into number.
408
 * @param[in,out] length Length of the conversion string.
409
 * @return Converted number.
410
 **************************************************************************/
411
uint32_t hexstr_to_uint(char *buffer, uint8_t length) {
412
 
413
  uint32_t res = 0, d = 0;
414
  char c = 0;
415
 
416
  while (length--) {
417
    c = *buffer++;
418
 
419
    if ((c >= '0') && (c <= '9'))
420
      d = (uint32_t)(c - '0');
421
    else if ((c >= 'a') && (c <= 'f'))
422
      d = (uint32_t)((c - 'a') + 10);
423
    else if ((c >= 'A') && (c <= 'F'))
424
      d = (uint32_t)((c - 'A') + 10);
425
    else
426
      d = 0;
427
 
428
    res = res + (d << (length*4));
429
  }
430
 
431
  return res;
432
}
433
 
434
 
435
/**********************************************************************//**
436
 * Print HEX byte.
437
 *
438
 * @param[in] byte Byte to be printed as 2-cahr hex value.
439
 **************************************************************************/
440
void aux_print_hex_byte(uint8_t byte) {
441
 
442
  static const char symbols[] = "0123456789abcdef";
443
 
444
  neorv32_uart0_putc(symbols[(byte >> 4) & 0x0f]);
445
  neorv32_uart0_putc(symbols[(byte >> 0) & 0x0f]);
446
}

powered by: WebSVN 2.1.0

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