bcm.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. MSP430 Emulator
  3. Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
  4. "MSP430 Emulator" is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. "MSP430 Emulator" is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "bcm.h"
  16. void handle_bcm (Emulator *emu)
  17. {
  18. Cpu *cpu = emu->cpu;
  19. Bcm *bcm = cpu->bcm;
  20. uint8_t DCOCTL = *bcm->DCOCTL;
  21. uint8_t BCSCTL1 = *bcm->BCSCTL1;
  22. uint8_t BCSCTL2 = *bcm->BCSCTL2;
  23. uint8_t BCSCTL3 = *bcm->BCSCTL3;
  24. // HANDLE MCLK -------------------
  25. uint8_t SELMx = BCSCTL2 >> 6;
  26. uint8_t DIVMx = (BCSCTL2 >> 4) & 0x03;
  27. if (SELMx == 0b00 || SELMx == 0b01) { // source = DCOCLK
  28. bcm->mclk_source = DCOCLK;
  29. bcm->mclk_freq = (bcm->dco_freq*1.0) / bcm->mclk_div;
  30. bcm->mclk_period = (1.0/(bcm->mclk_freq))*1000000000.0;
  31. }
  32. else if (SELMx == 0b10) { // XT2CLK
  33. bcm->mclk_source = XT2CLK;
  34. bcm->mclk_freq = 0;
  35. bcm->mclk_period = 0;
  36. }
  37. else if (SELMx == 0b11) { // VLOCLK
  38. bcm->mclk_source = VLOCLK;
  39. bcm->mclk_freq = 12000 / bcm->mclk_div;
  40. bcm->mclk_period = (1.0/(bcm->mclk_freq))*1000000000.0;
  41. }
  42. switch (DIVMx) {
  43. case 0b00: bcm->mclk_div = 1; break;
  44. case 0b01: bcm->mclk_div = 2; break;
  45. case 0b10: bcm->mclk_div = 4; break;
  46. case 0b11: bcm->mclk_div = 8; break;
  47. default: break;
  48. }
  49. // HANDLE SMCLK -------------------
  50. uint8_t SELS = (BCSCTL2 >> 3) & 0x01;
  51. uint8_t DIVSx = (BCSCTL2 >> 1) & 0x03;
  52. // HANDLE ACLK -------------------
  53. uint8_t DIVAx = (BCSCTL1 >> 4) & 0x03;
  54. // HANDLE LOW POWER MODES --------
  55. // Active Mode (CPU is active, all enabled clocks are active)
  56. if (!cpu->sr.SCG1 && !cpu->sr.SCG0 && !cpu->sr.OSCOFF && !cpu->sr.CPUOFF) {
  57. }
  58. // LPM0 (CPU, MCLK are disabled, SMCLK, ACLK are active)
  59. else if (!cpu->sr.SCG1 && !cpu->sr.SCG0 && !cpu->sr.OSCOFF && cpu->sr.CPUOFF){
  60. }
  61. /* LPM1 (CPU, MCLK are disabled. DCO and DC generator are
  62. disabled if the DCO is not used for SMCLK. ACLK is
  63. active.)
  64. */
  65. else if (!cpu->sr.SCG1 && cpu->sr.SCG0 && !cpu->sr.OSCOFF && cpu->sr.CPUOFF){
  66. }
  67. /* LPM2 (CPU, MCLK, SMCLK, DCO are disabled. DC generator remains enabled.
  68. ACLK is active.) */
  69. else if (cpu->sr.SCG1 && !cpu->sr.SCG0 && !cpu->sr.OSCOFF && cpu->sr.CPUOFF){
  70. }
  71. // LPM3 (CPU, MCLK, SMCLK, DCO are disabled. DC generatordisabled.ACLK active.
  72. else if (cpu->sr.SCG1 && cpu->sr.SCG0 && !cpu->sr.OSCOFF && cpu->sr.CPUOFF){
  73. }
  74. // LPM4 (CPU and all clocks are disabled)
  75. else if (cpu->sr.SCG1 && cpu->sr.SCG0 && cpu->sr.OSCOFF && cpu->sr.CPUOFF){
  76. }
  77. // HANDLE DCO --------------------
  78. uint8_t DCOx = DCOCTL >> 5;
  79. uint8_t MODx = DCOCTL & 0x1F;
  80. uint8_t RSELx = BCSCTL1 & 0x0F;
  81. // Default state of BCM after reset ~1.03 MHz
  82. if (DCOx == 0b011 && RSELx == 0b0111) {
  83. bcm->dco_freq = 1030000;
  84. bcm->dco_period = 971;
  85. bcm->dco_pulse_width = 485;
  86. }
  87. // 16 Mhz
  88. else if (DCOx == 0b100 && RSELx == 0b1111) {
  89. bcm->dco_freq = 16000000;
  90. bcm->dco_period = 63;
  91. bcm->dco_pulse_width = 31;
  92. }
  93. // 12 MHz
  94. else if (DCOx == 0b100 && RSELx == 0b1110) {
  95. bcm->dco_freq = 12000000;
  96. bcm->dco_period = 83;
  97. bcm->dco_pulse_width = 42;
  98. }
  99. // 8 Mhz
  100. else if (DCOx == 0b100 && RSELx == 0b1101) {
  101. bcm->dco_freq = 8000000;
  102. bcm->dco_period = 125;
  103. bcm->dco_pulse_width = 62;
  104. }
  105. // 1 MHz
  106. else if (DCOx == 0b110 && RSELx == 0b0110) {
  107. bcm->dco_freq = 1000000;
  108. bcm->dco_period = 1000;
  109. bcm->dco_pulse_width = 500;
  110. }
  111. // HANDLE LFXT1CLK -------------------
  112. uint8_t XTS = (BCSCTL1 >> 6) & 0x01; // LFXT1CLK select (high/low)
  113. }
  114. void setup_bcm (Emulator *emu)
  115. {
  116. Cpu *cpu = emu->cpu;
  117. Bcm *bcm = cpu->bcm;
  118. static const uint16_t DCOCTL_VLOC = 0x56;
  119. static const uint16_t BCSCTL1_VLOC = 0x57;
  120. static const uint16_t BCSCTL2_VLOC = 0x58;
  121. static const uint16_t BCSCTL3_VLOC = 0x53;
  122. static const uint16_t IE1_VLOC = 0x0;
  123. static const uint16_t IFG1_VLOC = 0x2;
  124. *(bcm->DCOCTL = (uint8_t *) get_addr_ptr(DCOCTL_VLOC)) = 0x60;
  125. *(bcm->BCSCTL1 = (uint8_t *) get_addr_ptr(BCSCTL1_VLOC)) = 0x87;
  126. *(bcm->BCSCTL2 = (uint8_t *) get_addr_ptr(BCSCTL2_VLOC)) = 0;
  127. *(bcm->BCSCTL3 = (uint8_t *) get_addr_ptr(BCSCTL3_VLOC)) = 0x5;
  128. *(bcm->IE1 = (uint8_t *) get_addr_ptr(IE1_VLOC)) = 0;
  129. *(bcm->IFG1 = (uint8_t *) get_addr_ptr(IFG1_VLOC)) = 0;
  130. // 1.03 MHz
  131. bcm->dco_freq = 1030000;
  132. bcm->dco_period = 971;
  133. bcm->dco_pulse_width = 970 / 2;
  134. }
  135. //uint64_t nanosec_diff(struct timespec *timeA_p, struct timespec *timeB_p)
  136. //{
  137. // return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) - ((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
  138. //}
  139. double mclk_clock_nstime(Emulator *emu) {
  140. Cpu *cpu = emu->cpu;
  141. Bcm *bcm = cpu->bcm;
  142. double nsec;
  143. nsec = (1.0/(bcm->mclk_freq))*1000000000.0;
  144. return nsec;
  145. }
  146. void mclk_wait_cycles (Emulator *emu, uint64_t cycles)
  147. {
  148. // Cpu *cpu = emu->cpu;
  149. // Bcm *bcm = cpu->bcm;
  150. //
  151. // uint64_t start = getnano();
  152. //
  153. //// uint64_t start, end;
  154. //// uint64_t i, elapsed_nsecs;
  155. // double thing = 1000;
  156. //
  157. // if (bcm->mclk_source == DCOCLK) {
  158. // thing = (1.0/(bcm->dco_freq/bcm->mclk_div))*1000000000.0;
  159. // }
  160. // thing *= cycles;
  161. //
  162. // if (last_nano > 0) {
  163. // thing -= (double)(start - last_nano);
  164. // }
  165. // if (thing > 0) {
  166. //// struct timespec tv;
  167. //// tv.tv_sec = 0;
  168. //// tv.tv_nsec = (long)thing;
  169. //// nanosleep(&tv, &tv);
  170. // usleep((long)(thing / 1000.0));
  171. // }
  172. //
  173. // last_nano = start;
  174. // return;
  175. /*
  176. for (i = 0;i < cycles;i++)
  177. {
  178. start = getnano();
  179. // clock_gettime(CLOCK_MONOTONIC, &start);
  180. while (true)
  181. {
  182. // clock_gettime(CLOCK_MONOTONIC, &end);
  183. end = getnano();
  184. elapsed_nsecs = end - start;//nanosec_diff(&end, &start);
  185. // Choose timing based on clock source
  186. if (bcm->mclk_source == DCOCLK)
  187. {
  188. double thing = (1.0/(bcm->dco_freq/bcm->mclk_div))*1000000000.0;
  189. if (elapsed_nsecs >= (uint64_t)thing)
  190. break;
  191. }
  192. else
  193. {
  194. puts("Error, clock source");
  195. }
  196. }
  197. }
  198. */
  199. }
  200. void smclk_wait_cycles (Emulator *emu, uint64_t cycles)
  201. {
  202. // Cpu *cpu = emu->cpu;
  203. // Bcm *bcm = cpu->bcm;
  204. //
  205. // uint64_t start, end;
  206. // uint64_t i, elapsed_nsecs;
  207. //
  208. // for (i = 0;i < cycles;i++) {
  209. // start = getnano();
  210. // // clock_gettime(CLOCK_MONOTONIC, &start);
  211. //
  212. // while (true) {
  213. // end = getnano();
  214. //// clock_gettime(CLOCK_MONOTONIC, &end);
  215. // elapsed_nsecs = end - start;//nanosec_diff(&end, &start);
  216. //
  217. // // Choose timing based on clock source
  218. // if (bcm->mclk_source == DCOCLK) {
  219. // //printf("div: %llu\n",
  220. // //(long long unsigned)(1/(bcm->dco_freq/bcm->mclk_div)));
  221. //
  222. // double thing = (1.0/(bcm->dco_freq/bcm->mclk_div))*1000000000.0;
  223. //
  224. // if (elapsed_nsecs >= (uint64_t)thing) {
  225. // break;
  226. // }
  227. // }
  228. // else {
  229. // puts("Error, clock source");
  230. // }
  231. //
  232. // }
  233. // }
  234. }
  235. /*
  236. /*
  237. // Start Sources DCO, etc
  238. pthread_t pp;
  239. if ( pthread_create(&pp, NULL, DCO_source, (void *)emu ) ) {
  240. printf("Error creating DCO thread\n");
  241. exit(1);
  242. }
  243. void *DCO_source (void *data)
  244. {
  245. Emulator *emu = (Emulator *)data;
  246. Bcm *bcm = emu->cpu->bcm;
  247. printf("In source thread...\n");
  248. struct timespec start, end;
  249. uint64_t elapsed_nsecs;
  250. uint64_t trimmer = 0;
  251. while (true) {
  252. clock_gettime(CLOCK_MONOTONIC, &start);
  253. while (true) {
  254. clock_gettime(CLOCK_MONOTONIC, &end);
  255. elapsed_nsecs = nanosec_diff(&end, &start);
  256. if (elapsed_nsecs >= bcm->dco_period) break;
  257. }
  258. }
  259. /*
  260. while (true) {
  261. clock_gettime(CLOCK_MONOTONIC, &start);
  262. bcm->dco_high = true;
  263. while (true) {
  264. clock_gettime(CLOCK_MONOTONIC, &end);
  265. elapsed_nsecs = nanosec_diff(&end, &start);
  266. if (elapsed_nsecs >= bcm->dco_pulse_width) {
  267. bcm->dco_high = false;
  268. }
  269. if (elapsed_nsecs >= bcm->dco_period) break;
  270. }
  271. }
  272. return NULL;
  273. }
  274. */