Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
5.5KB

  1. ; shell
  2. ;
  3. ; Runs a shell over an block device interface.
  4. ; Status: incomplete. As it is now, it spits a welcome prompt, wait for input
  5. ; and compare the first 4 chars of the input with a command table and call the
  6. ; appropriate routine if it's found, an error if it's not.
  7. ;
  8. ; Commands, for now, are partially implemented.
  9. ;
  10. ; See constants below for error codes.
  11. ;
  12. ; All numerical values in the Collapse OS shell are represented and parsed in
  13. ; hexadecimal form, without prefix or suffix.
  14. ; *** DEFINES ***
  15. ; SHELL_GETC: Macro that calls a GetC routine
  16. ; SHELL_PUTC: Macro that calls a PutC routine
  17. ; SHELL_RAMSTART
  18. ; *** CONSTS ***
  19. ; number of entries in shellCmdTbl
  20. SHELL_CMD_COUNT .equ 2
  21. ; The command that was type isn't known to the shell
  22. SHELL_ERR_UNKNOWN_CMD .equ 0x01
  23. ; Arguments for the command weren't properly formatted
  24. SHELL_ERR_BAD_ARGS .equ 0x02
  25. ; Size of the shell command buffer. If a typed command reaches this size, the
  26. ; command is flushed immediately (same as pressing return).
  27. SHELL_BUFSIZE .equ 0x20
  28. ; *** VARIABLES ***
  29. ; Memory address that the shell is currently "pointing at" for peek and deek
  30. ; operations. Set with seek.
  31. SHELL_MEM_PTR .equ SHELL_RAMSTART
  32. ; Used to store formatted hex values just before printing it.
  33. SHELL_HEX_FMT .equ SHELL_MEM_PTR+2
  34. ; Command buffer. We read types chars into this buffer until return is pressed
  35. ; This buffer is null-terminated and we don't keep an index around: we look
  36. ; for the null-termination every time we write to it. Simpler that way.
  37. SHELL_BUF .equ SHELL_HEX_FMT+2
  38. SHELL_RAMEND .equ SHELL_BUF+SHELL_BUFSIZE
  39. ; *** CODE ***
  40. shellInit:
  41. xor a
  42. ld (SHELL_MEM_PTR), a
  43. ld (SHELL_BUF), a
  44. ; print prompt
  45. ld hl, .prompt
  46. call printstr
  47. call printcrlf
  48. ret
  49. .prompt:
  50. .db "Collapse OS", 0
  51. shellLoop:
  52. ; First, let's wait until something is typed.
  53. SHELL_GETC
  54. ; got it. Now, is it a CR or LF?
  55. cp ASCII_CR
  56. jr z, .do ; char is CR? do!
  57. cp ASCII_LF
  58. jr z, .do ; char is LF? do!
  59. ; Ok, gotta add it do the buffer
  60. ; save char for later
  61. ex af, af'
  62. ld hl, SHELL_BUF
  63. call findnull ; HL points to where we need to write
  64. ; A is the number of chars in the buf
  65. cp SHELL_BUFSIZE
  66. jr z, .do ; A == bufsize? then our buffer is full. do!
  67. ; bring the char back in A
  68. ex af, af'
  69. ; Buffer not full, not CR or LF. Let's put that char in our buffer and
  70. ; read again.
  71. ld (hl), a
  72. ; Now, write a zero to the next byte to properly terminate our string.
  73. inc hl
  74. xor a
  75. ld (hl), a
  76. jr shellLoop
  77. .do:
  78. ld hl, SHELL_BUF
  79. call shellParse
  80. ; empty our buffer by writing a zero to its first char
  81. xor a
  82. ld (hl), a
  83. jr shellLoop
  84. printcrlf:
  85. ld a, ASCII_CR
  86. SHELL_PUTC
  87. ld a, ASCII_LF
  88. SHELL_PUTC
  89. ret
  90. ; Parse command (null terminated) at HL and calls it
  91. shellParse:
  92. push af
  93. push bc
  94. push de
  95. push hl
  96. ld de, shellCmdTbl
  97. ld a, SHELL_CMD_COUNT
  98. ld b, a
  99. .loop:
  100. ld a, 4 ; 4 chars to compare
  101. call strncmp
  102. jr z, .found
  103. ld a, 6
  104. call addDE
  105. djnz .loop
  106. ; exhausted loop? not found
  107. ld a, SHELL_ERR_UNKNOWN_CMD
  108. call shellPrintErr
  109. jr .end
  110. .found:
  111. ; all right, we're almost ready to call the cmd. Let's just have DE
  112. ; point to the cmd jump line.
  113. ld a, 4
  114. call addDE
  115. ; Now, let's swap HL and DE because, welll because that's how we're set.
  116. ex hl, de ; HL = jump line, DE = cmd str pointer
  117. ; Before we call our command, we want to set up the pointer to the arg
  118. ; list. Normally, it's DE+5 (DE+4 is the space) unless DE+4 is null,
  119. ; which means no arg.
  120. ld a, 4
  121. call addDE
  122. ld a, (DE)
  123. cp 0
  124. jr z, .noarg ; char is null? we have no arg
  125. inc de
  126. .noarg:
  127. ; DE points to args, HL points to jump line. Ready to roll!
  128. call jumpHL
  129. .end:
  130. pop hl
  131. pop de
  132. pop bc
  133. pop af
  134. ret
  135. ; Print the error code set in A (in hex)
  136. shellPrintErr:
  137. push af
  138. push hl
  139. ld hl, .str
  140. call printstr
  141. ld hl, SHELL_HEX_FMT
  142. call fmtHexPair
  143. ld a, 2
  144. call printnstr
  145. call printcrlf
  146. pop hl
  147. pop af
  148. ret
  149. .str:
  150. .db "ERR ", 0
  151. ; *** COMMANDS ***
  152. ; When these commands are called, DE points to the first character of the
  153. ; command args.
  154. ; Set memory pointer to the specified address (word).
  155. ; Example: seek 01fe
  156. shellSeek:
  157. push af
  158. push de
  159. push hl
  160. ex de, hl
  161. call parseHexPair
  162. jr c, .error
  163. ; z80 is little endian. in a "ld hl, (nn)" op, L is loaded from the
  164. ; first byte, H is loaded from the second
  165. ld (SHELL_MEM_PTR+1), a
  166. inc hl
  167. inc hl
  168. call parseHexPair
  169. jr c, .error
  170. ld (SHELL_MEM_PTR), a
  171. jr .success
  172. .error:
  173. ld a, SHELL_ERR_BAD_ARGS
  174. call shellPrintErr
  175. jr .end
  176. .success:
  177. ld a, (SHELL_MEM_PTR+1)
  178. ld hl, SHELL_HEX_FMT
  179. call fmtHexPair
  180. ld a, 2
  181. call printnstr
  182. ld a, (SHELL_MEM_PTR)
  183. call fmtHexPair
  184. ld a, 2
  185. call printnstr
  186. call printcrlf
  187. .end:
  188. pop hl
  189. pop de
  190. pop af
  191. ret
  192. ; peek byte where memory pointer points to any display its value. If the
  193. ; optional numerical byte arg is supplied, this number of bytes will be printed
  194. ;
  195. ; Example: peek 2 (will print 2 bytes)
  196. shellPeek:
  197. push af
  198. push bc
  199. push de
  200. push hl
  201. ld b, 1 ; by default, we run the loop once
  202. ld a, (de)
  203. cp 0
  204. jr z, .success ; no arg? don't try to parse
  205. ex de, hl
  206. call parseHexPair
  207. jr c, .error
  208. cp 0
  209. jr z, .error ; zero isn't a good arg, error
  210. ld b, a ; loop the number of times specified in arg
  211. jr .success
  212. .error:
  213. ld a, SHELL_ERR_BAD_ARGS
  214. call shellPrintErr
  215. jr .end
  216. .success:
  217. ld hl, (SHELL_MEM_PTR)
  218. .loop: ld a, (hl)
  219. ex hl, de
  220. ld hl, SHELL_HEX_FMT
  221. call fmtHexPair
  222. ld a, 2
  223. call printnstr
  224. ex hl, de
  225. inc hl
  226. djnz .loop
  227. call printcrlf
  228. .end:
  229. pop hl
  230. pop de
  231. pop bc
  232. pop af
  233. ret
  234. ; Format: 4 bytes name followed by 2 bytes jump. fill names with zeroes
  235. shellCmdTbl:
  236. .db "seek"
  237. jr shellSeek
  238. .db "peek"
  239. jr shellPeek