main.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <stdio.h>
  2. #include "nuclei_sdk_soc.h"
  3. #if !defined(__riscv_atomic)
  4. #error "RVA(atomic) extension is required for SMP"
  5. #endif
  6. #if !defined(SMP_CPU_CNT)
  7. #warning "This example require CPU SMP feature!"
  8. #error "SMP_CPU_CNT macro is not defined, please set SMP_CPU_CNT to integer value > 1"
  9. #endif
  10. typedef struct {
  11. uint32_t state;
  12. } spinlock;
  13. // volatile required
  14. volatile spinlock lock;
  15. volatile uint32_t lock_ready = 0;
  16. volatile uint32_t cpu_count = 0;
  17. volatile uint32_t finished = 0;
  18. // comment SPINLOCK_CAS to use AMOSWAP as spinlock
  19. #define SPINLOCK_CAS
  20. __STATIC_FORCEINLINE void spinlock_init(spinlock *lock)
  21. {
  22. lock->state = 0;
  23. }
  24. __STATIC_FORCEINLINE void spinlock_lock(spinlock *lock)
  25. {
  26. uint32_t old;
  27. uint32_t backoff = 10;
  28. do {
  29. #ifndef SPINLOCK_CAS
  30. // Use amoswap as spinlock
  31. old = __AMOSWAP_W((&(lock->state)), 1);
  32. #else
  33. // use lr.w & sc.w to do CAS as spinlock
  34. old = __CAS_W((&(lock->state)), 0, 1);
  35. #endif
  36. if (old == 0) {
  37. break;
  38. }
  39. for (volatile int i = 0; i < backoff; i ++) {
  40. __NOP();
  41. }
  42. backoff += 10;
  43. } while (1);
  44. }
  45. __STATIC_FORCEINLINE void spinlock_unlock(spinlock *lock)
  46. {
  47. lock->state = 0;
  48. }
  49. int boot_hart_main(unsigned long hartid);
  50. int other_harts_main(unsigned long hartid);
  51. int main(void);
  52. /* Reimplementation of smp_main for multi-harts */
  53. int smp_main(void)
  54. {
  55. return main();
  56. }
  57. int main(void)
  58. {
  59. int ret;
  60. // get hart id in current cluster
  61. unsigned long hartid = __get_hart_id();
  62. if (hartid == BOOT_HARTID) { // boot hart
  63. spinlock_init((spinlock *)&lock);
  64. lock_ready = 1;
  65. finished = 0;
  66. __SMP_RWMB();
  67. ret = boot_hart_main(hartid);
  68. } else { // other harts
  69. // wait for lock initialized
  70. while (lock_ready == 0);
  71. ret = other_harts_main(hartid);
  72. }
  73. return ret;
  74. }
  75. int boot_hart_main(unsigned long hartid)
  76. {
  77. volatile unsigned long waitcnt = 0;
  78. spinlock_lock((spinlock *)&lock);
  79. printf("Hello world from hart %lu\n", hartid);
  80. cpu_count += 1;
  81. spinlock_unlock((spinlock *)&lock);
  82. // wait for all harts boot and print hello
  83. while (cpu_count < SMP_CPU_CNT) {
  84. waitcnt ++;
  85. __NOP();
  86. // The waitcnt compare value need to be adjust according
  87. // to cpu frequency
  88. if (waitcnt >= SystemCoreClock) {
  89. break;
  90. }
  91. }
  92. if (cpu_count == SMP_CPU_CNT) {
  93. printf("All harts boot successfully!\n");
  94. finished = 1;
  95. return 0;
  96. } else {
  97. printf("Some harts boot failed, only %d/%d booted!\n", cpu_count, SMP_CPU_CNT);
  98. return -1;
  99. }
  100. }
  101. int other_harts_main(unsigned long hartid)
  102. {
  103. spinlock_lock((spinlock *)&lock);
  104. printf("Hello world from hart %lu\n", hartid);
  105. cpu_count += 1;
  106. spinlock_unlock((spinlock *)&lock);
  107. // wait for all harts boot and print hello
  108. while (cpu_count < SMP_CPU_CNT);
  109. // wait for boot hart to set finished flag
  110. // Attention: must wait until all the harts stop print,
  111. // because the _postmain_fini will print some dummy '\0', which has no lock-protecting
  112. while (finished == 0);
  113. return 0;
  114. }