BDOS.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /* Bart's Drive Operating System(BDOS)
  2. * A relatively simple OS that allows for some basic features including:
  3. * - Running a single user program with full hardware control
  4. * - Some system calls
  5. * - A basic shell
  6. * - Network loaders for sending data and controlling the FPGC
  7. * - HID fifo including USB keyboard driver
  8. * - BRFS Filesystem
  9. */
  10. /* List of reserved stuff:
  11. - Timer2 is used for USB keyboard polling, even when a user program is running
  12. - Socket 7 is used for netHID
  13. */
  14. /*
  15. * Defines (also might be used by included libraries below)
  16. */
  17. // As of writing, BCC assigns 4 memory addresses to ints, so we should use chars instead
  18. // However, this is confusing, so we typedef it to word, since that is what it basically is
  19. #define word char
  20. #define SYSCALL_RETVAL_ADDR 0x200000 // Address for system call communication with user program
  21. #define TEMP_ADDR 0x220000 // Address for (potentially) large temporary outputs/buffers
  22. #define RUN_ADDR 0x400000 // Address of loaded user program
  23. #define NETWORK_LOCAL_IP 213 // local IP address (last byte)
  24. #define MAX_PATH_LENGTH 127 // Max length of a file path
  25. #define BDOS_DEFAULT_BLOCKS 1024 // Default number of blocks for the BRFS filesystem
  26. #define BDOS_DEFAULT_BLOCK_SIZE 128 // Default number of words per block for the BRFS filesystem
  27. // Interrupt IDs for interrupt handler
  28. #define INTID_TIMER1 0x1
  29. #define INTID_TIMER2 0x2
  30. #define INTID_UART0 0x3
  31. #define INTID_GPU 0x4
  32. #define INTID_TIMER3 0x5
  33. #define INTID_PS2 0x6
  34. #define INTID_UART1 0x7
  35. #define INTID_UART2 0x8
  36. // System call IDs
  37. #define SYS_HID_CHECKFIFO 1
  38. #define SYS_HID_READFIFO 2
  39. #define SYS_BDOS_PRINTC 3
  40. #define SYS_BDOS_PRINT 4
  41. #define SYS_FS_OPEN 5
  42. #define SYS_FS_CLOSE 6
  43. #define SYS_FS_READ 7
  44. #define SYS_FS_WRITE 8
  45. #define SYS_FS_SETCURSOR 9
  46. #define SYS_FS_GETCURSOR 10
  47. #define SYS_FS_DELETE 11
  48. #define SYS_FS_MKDIR 12
  49. #define SYS_FS_MKFILE 13
  50. #define SYS_FS_STAT 14
  51. #define SYS_FS_READDIR 15
  52. #define SYS_FS_GETCWD 16
  53. #define SYS_FS_SYNCFLASH 17
  54. // Syscalls 17-19 are reserved for future use
  55. #define SYS_SHELL_ARGC 20
  56. #define SYS_SHELL_ARGV 21
  57. #define SYS_USB_KB_BUF 99
  58. /*
  59. * Global vars (also might be used by included libraries below)
  60. */
  61. // Flag that indicates whether a user program is running
  62. word bdos_userprogram_running = 0;
  63. /*
  64. * Included libraries
  65. */
  66. // Data includes
  67. #include "data/ASCII_BW.c"
  68. #include "data/PS2SCANCODES.c"
  69. #include "data/USBSCANCODES.c"
  70. // Code includes
  71. #include "lib/stdlib.c"
  72. #include "lib/math.c"
  73. #include "lib/gfx.c"
  74. #include "lib/hidfifo.c"
  75. #include "lib/ps2.c"
  76. #include "lib/brfs.c"
  77. #include "lib/shell.c"
  78. #include "lib/usbkeyboard.c"
  79. #include "lib/wiz5500.c"
  80. #include "lib/netloader.c"
  81. #include "lib/nethid.c"
  82. #include "lib/spiflash.c"
  83. /*
  84. * Functions
  85. */
  86. /**
  87. * Initialize the BRFS filesystem
  88. * Returns 1 if successful, 0 if not
  89. */
  90. word bdos_init_brfs()
  91. {
  92. // Initialize the SPI flash
  93. spiflash_init();
  94. // Try to read the filesystem from the SPI flash
  95. GFX_PrintConsole("Reading BRFS from SPI flash\n");
  96. if (!brfs_read_from_flash())
  97. {
  98. GFX_PrintConsole("Could not read BRFS from flash!\n");
  99. return 0;
  100. }
  101. return 1;
  102. }
  103. // Clears all VRAM
  104. // and copies the default ASCII pattern table and palette table
  105. // also resets the cursor
  106. void bdos_init_vram()
  107. {
  108. GFX_initVram();
  109. GFX_copyPaletteTable((word)DATA_PALETTE_DEFAULT);
  110. GFX_copyPatternTable((word)DATA_ASCII_DEFAULT);
  111. GFX_cursor = 0;
  112. }
  113. // Initialize the W5500
  114. void bdos_init_network()
  115. {
  116. word ip_addr[4] = {192, 168, 0, NETWORK_LOCAL_IP};
  117. word gateway_addr[4] = {192, 168, 0, 1};
  118. word mac_addr[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x24, 0x64};
  119. word sub_mask[4] = {255, 255, 255, 0};
  120. wiz_init(ip_addr, gateway_addr, mac_addr, sub_mask);
  121. }
  122. // Restores certain things when returning from a user program
  123. void bdos_restore()
  124. {
  125. // restore graphics (trying to keep text in window plane)
  126. GFX_copyPaletteTable((word)DATA_PALETTE_DEFAULT);
  127. GFX_copyPatternTable((word)DATA_ASCII_DEFAULT);
  128. GFX_clearBGtileTable();
  129. GFX_clearBGpaletteTable();
  130. GFX_clearWindowpaletteTable();
  131. GFX_clearSprites();
  132. // restore netloader
  133. NETLOADER_init(NETLOADER_SOCKET);
  134. }
  135. // Main BDOS code
  136. int main()
  137. {
  138. uprintln("BDOS_INIT");
  139. bdos_userprogram_running = 0; // Indicate that no user program is running
  140. bdos_init_vram();
  141. GFX_PrintConsole("VRAM initialized\n"); // Print to console now VRAM is initialized
  142. GFX_PrintConsole("Starting BDOS\n");
  143. GFX_PrintConsole("Initalizing network\n");
  144. bdos_init_network();
  145. GFX_PrintConsole("Initalizing netloader\n");
  146. NETLOADER_init(NETLOADER_SOCKET);
  147. GFX_PrintConsole("Initalizing netHID\n");
  148. NETHID_init(NETHID_SOCKET);
  149. GFX_PrintConsole("Initalizing USB keyboard\n");
  150. USBkeyboard_init();
  151. GFX_PrintConsole("Initalizing filesystem\n");
  152. if (!bdos_init_brfs())
  153. {
  154. GFX_PrintConsole("Error initializing FS\n");
  155. return 0;
  156. }
  157. GFX_PrintConsole("Initalizing shell\n");
  158. shell_init();
  159. // Main loop
  160. while (1)
  161. {
  162. shell_loop(); // Update shell state
  163. NETLOADER_loop(NETLOADER_SOCKET); // Update netloader state
  164. }
  165. return 1;
  166. }
  167. /**
  168. * System calls
  169. */
  170. // System call handler
  171. // Returns at the same address it reads the command from
  172. void syscall()
  173. {
  174. word *syscall_data = (word *)SYSCALL_RETVAL_ADDR;
  175. word id = syscall_data[0];
  176. // Special case for mkdir and mkfile
  177. if (id == SYS_FS_MKDIR)
  178. {
  179. char dirname_output[MAX_PATH_LENGTH];
  180. char* file_path_basename = basename((char *)syscall_data[1]);
  181. char* file_path_dirname = dirname(dirname_output, (char *)syscall_data[1]);
  182. syscall_data[0] = brfs_create_directory(file_path_dirname, file_path_basename);
  183. }
  184. else if (id == SYS_FS_MKFILE)
  185. {
  186. char dirname_output[MAX_PATH_LENGTH];
  187. char* file_path_basename = basename((char *)syscall_data[1]);
  188. char* file_path_dirname = dirname(dirname_output, (char *)syscall_data[1]);
  189. syscall_data[0] = brfs_create_file(file_path_dirname, file_path_basename);
  190. }
  191. switch (id)
  192. {
  193. case SYS_HID_CHECKFIFO:
  194. syscall_data[0] = HID_FifoAvailable();
  195. break;
  196. case SYS_HID_READFIFO:
  197. syscall_data[0] = HID_FifoRead();
  198. break;
  199. case SYS_BDOS_PRINTC:
  200. GFX_PrintcConsole(syscall_data[1]);
  201. syscall_data[0] = 0;
  202. break;
  203. case SYS_BDOS_PRINT:
  204. GFX_PrintConsole(syscall_data[1]);
  205. syscall_data[0] = 0;
  206. break;
  207. case SYS_FS_OPEN:
  208. syscall_data[0] = brfs_open_file((char *)syscall_data[1]);
  209. break;
  210. case SYS_FS_CLOSE:
  211. syscall_data[0] = brfs_close_file(syscall_data[1]);
  212. break;
  213. case SYS_FS_READ:
  214. syscall_data[0] = brfs_read(syscall_data[1], (char *)syscall_data[2], syscall_data[3]);
  215. break;
  216. case SYS_FS_WRITE:
  217. syscall_data[0] = brfs_write(syscall_data[1], (char *)syscall_data[2], syscall_data[3]);
  218. break;
  219. case SYS_FS_SETCURSOR:
  220. syscall_data[0] = brfs_set_cursor(syscall_data[1], syscall_data[2]);
  221. break;
  222. case SYS_FS_GETCURSOR:
  223. syscall_data[0] = brfs_get_cursor(syscall_data[1]);
  224. break;
  225. case SYS_FS_DELETE:
  226. syscall_data[0] = brfs_delete((char *)syscall_data[1]);
  227. break;
  228. case SYS_FS_STAT:
  229. syscall_data[0] = brfs_stat((char *)syscall_data[1]);
  230. break;
  231. case SYS_FS_READDIR:
  232. syscall_data[0] = brfs_read_directory((char *)syscall_data[1], (char *)syscall_data[2]);
  233. break;
  234. case SYS_FS_GETCWD:
  235. strcpy(syscall_data, shell_path);
  236. break;
  237. case SYS_FS_SYNCFLASH:
  238. brfs_write_to_flash();
  239. break;
  240. case SYS_SHELL_ARGC:
  241. syscall_data[0] = shell_num_tokens;
  242. break;
  243. case SYS_SHELL_ARGV:
  244. memcpy(syscall_data, shell_tokens, sizeof(shell_tokens));
  245. break;
  246. case SYS_USB_KB_BUF:
  247. syscall_data[0] = USBkeyboard_buffer_parsed;
  248. break;
  249. }
  250. }
  251. // Interrupt handler
  252. void interrupt()
  253. {
  254. // Handle BDOS interrupts
  255. int i = getIntID();
  256. switch (i)
  257. {
  258. case INTID_TIMER1:
  259. timer1Value = 1; // Notify ending of timer1
  260. break;
  261. case INTID_TIMER2:
  262. USBkeyboard_HandleInterrupt(); // Handle USB keyboard interrupt
  263. break;
  264. case INTID_UART0:
  265. break;
  266. case INTID_GPU:
  267. if (NETHID_isInitialized == 1)
  268. {
  269. // Check using CS if we are not interrupting any critical access to the W5500
  270. word *spi3ChipSelect = (word *)0xC02732; // TODO: use a define for this address
  271. if (*spi3ChipSelect == 1)
  272. {
  273. NETHID_loop(NETHID_SOCKET); // Look for an input sent to netHID
  274. }
  275. }
  276. break;
  277. case INTID_TIMER3:
  278. break;
  279. case INTID_PS2:
  280. PS2_HandleInterrupt(); // Handle PS2 interrupt
  281. break;
  282. case INTID_UART1:
  283. break;
  284. case INTID_UART2:
  285. break;
  286. }
  287. // Handle user program interrupts
  288. if (bdos_userprogram_running)
  289. {
  290. // Call interrupt() of user program
  291. asm(
  292. "; backup registers\n"
  293. "push r1\n"
  294. "push r2\n"
  295. "push r3\n"
  296. "push r4\n"
  297. "push r5\n"
  298. "push r6\n"
  299. "push r7\n"
  300. "push r8\n"
  301. "push r9\n"
  302. "push r10\n"
  303. "push r11\n"
  304. "push r12\n"
  305. "push r13\n"
  306. "push r14\n"
  307. "push r15\n"
  308. "savpc r1\n"
  309. "push r1\n"
  310. "jump 0x400001\n"
  311. "; restore registers\n"
  312. "pop r15\n"
  313. "pop r14\n"
  314. "pop r13\n"
  315. "pop r12\n"
  316. "pop r11\n"
  317. "pop r10\n"
  318. "pop r9\n"
  319. "pop r8\n"
  320. "pop r7\n"
  321. "pop r6\n"
  322. "pop r5\n"
  323. "pop r4\n"
  324. "pop r3\n"
  325. "pop r2\n"
  326. "pop r1\n");
  327. return;
  328. }
  329. else
  330. {
  331. // Code to only run when not running a user program
  332. }
  333. }