Mirror of CollapseOS
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

334 строки
6.3KB

  1. ; shell
  2. ;
  3. ; Runs a shell over a 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 3
  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 welcome
  45. ld hl, .welcome
  46. call printstr
  47. ret
  48. .welcome:
  49. .db "Collapse OS", ASCII_CR, ASCII_LF, "> ", 0
  50. shellLoop:
  51. ; First, let's wait until something is typed.
  52. SHELL_GETC
  53. ; got it. Now, is it a CR or LF?
  54. cp ASCII_CR
  55. jr z, .do ; char is CR? do!
  56. cp ASCII_LF
  57. jr z, .do ; char is LF? do!
  58. ; Echo the received character right away so that we see what we type
  59. SHELL_PUTC
  60. ; Ok, gotta add it do the buffer
  61. ; save char for later
  62. ex af, af'
  63. ld hl, SHELL_BUF
  64. call findnull ; HL points to where we need to write
  65. ; A is the number of chars in the buf
  66. cp SHELL_BUFSIZE
  67. jr z, .do ; A == bufsize? then our buffer is full. do!
  68. ; bring the char back in A
  69. ex af, af'
  70. ; Buffer not full, not CR or LF. Let's put that char in our buffer and
  71. ; read again.
  72. ld (hl), a
  73. ; Now, write a zero to the next byte to properly terminate our string.
  74. inc hl
  75. xor a
  76. ld (hl), a
  77. jr shellLoop
  78. .do:
  79. call printcrlf
  80. ld hl, SHELL_BUF
  81. call shellParse
  82. ; empty our buffer by writing a zero to its first char
  83. xor a
  84. ld (hl), a
  85. ld hl, .prompt
  86. call printstr
  87. jr shellLoop
  88. .prompt:
  89. .db "> ", 0
  90. printcrlf:
  91. ld a, ASCII_CR
  92. SHELL_PUTC
  93. ld a, ASCII_LF
  94. SHELL_PUTC
  95. ret
  96. ; Parse command (null terminated) at HL and calls it
  97. shellParse:
  98. push af
  99. push bc
  100. push de
  101. push hl
  102. ld de, shellCmdTbl
  103. ld a, SHELL_CMD_COUNT
  104. ld b, a
  105. .loop:
  106. ld a, 4 ; 4 chars to compare
  107. call strncmp
  108. jr z, .found
  109. ld a, 7
  110. call addDE
  111. djnz .loop
  112. ; exhausted loop? not found
  113. ld a, SHELL_ERR_UNKNOWN_CMD
  114. call shellPrintErr
  115. jr .end
  116. .found:
  117. ; all right, we're almost ready to call the cmd. Let's just have DE
  118. ; point to the cmd jump line.
  119. ld a, 4
  120. call addDE
  121. ; Now, let's swap HL and DE because, welll because that's how we're set.
  122. ex hl, de ; HL = jump line, DE = cmd str pointer
  123. ; Before we call our command, we want to set up the pointer to the arg
  124. ; list. Normally, it's DE+5 (DE+4 is the space) unless DE+4 is null,
  125. ; which means no arg.
  126. ld a, 4
  127. call addDE
  128. ld a, (DE)
  129. cp 0
  130. jr z, .noarg ; char is null? we have no arg
  131. inc de
  132. .noarg:
  133. ; DE points to args, HL points to jump line. Ready to roll!
  134. call jumpHL
  135. .end:
  136. pop hl
  137. pop de
  138. pop bc
  139. pop af
  140. ret
  141. ; Print the error code set in A (in hex)
  142. shellPrintErr:
  143. push af
  144. push hl
  145. ld hl, .str
  146. call printstr
  147. ld hl, SHELL_HEX_FMT
  148. call fmtHexPair
  149. ld a, 2
  150. call printnstr
  151. call printcrlf
  152. pop hl
  153. pop af
  154. ret
  155. .str:
  156. .db "ERR ", 0
  157. ; *** COMMANDS ***
  158. ; When these commands are called, DE points to the first character of the
  159. ; command args.
  160. ; Set memory pointer to the specified address (word).
  161. ; Example: seek 01fe
  162. shellSeek:
  163. push af
  164. push de
  165. push hl
  166. ex de, hl
  167. call parseHexPair
  168. jr c, .error
  169. ; z80 is little endian. in a "ld hl, (nn)" op, L is loaded from the
  170. ; first byte, H is loaded from the second
  171. ld (SHELL_MEM_PTR+1), a
  172. inc hl
  173. inc hl
  174. call parseHexPair
  175. jr c, .error
  176. ld (SHELL_MEM_PTR), a
  177. jr .success
  178. .error:
  179. ld a, SHELL_ERR_BAD_ARGS
  180. call shellPrintErr
  181. jr .end
  182. .success:
  183. ld a, (SHELL_MEM_PTR+1)
  184. ld hl, SHELL_HEX_FMT
  185. call fmtHexPair
  186. ld a, 2
  187. call printnstr
  188. ld a, (SHELL_MEM_PTR)
  189. call fmtHexPair
  190. ld a, 2
  191. call printnstr
  192. call printcrlf
  193. .end:
  194. pop hl
  195. pop de
  196. pop af
  197. ret
  198. ; peek byte where memory pointer points to any display its value. If the
  199. ; optional numerical byte arg is supplied, this number of bytes will be printed
  200. ;
  201. ; Example: peek 2 (will print 2 bytes)
  202. shellPeek:
  203. push af
  204. push bc
  205. push de
  206. push hl
  207. ld b, 1 ; by default, we run the loop once
  208. ld a, (de)
  209. cp 0
  210. jr z, .success ; no arg? don't try to parse
  211. ex de, hl
  212. call parseHexPair
  213. jr c, .error
  214. cp 0
  215. jr z, .error ; zero isn't a good arg, error
  216. ld b, a ; loop the number of times specified in arg
  217. jr .success
  218. .error:
  219. ld a, SHELL_ERR_BAD_ARGS
  220. call shellPrintErr
  221. jr .end
  222. .success:
  223. ld hl, (SHELL_MEM_PTR)
  224. .loop: ld a, (hl)
  225. ex hl, de
  226. ld hl, SHELL_HEX_FMT
  227. call fmtHexPair
  228. ld a, 2
  229. call printnstr
  230. ex hl, de
  231. inc hl
  232. djnz .loop
  233. call printcrlf
  234. .end:
  235. pop hl
  236. pop de
  237. pop bc
  238. pop af
  239. ret
  240. ; Load the specified number of bytes (max 0xff) from IO and write them in the
  241. ; current memory pointer (which doesn't change). For now, we can only load from
  242. ; SHELL_GETC, but a method of selecting IO sources is coming, making this
  243. ; command much more useful.
  244. ; Control is returned to the shell only after all bytes are read.
  245. ;
  246. ; Example: load 42
  247. shellLoad:
  248. push af
  249. push bc
  250. push hl
  251. ld a, (de)
  252. call parseHex
  253. jr c, .error
  254. jr .success
  255. .error:
  256. ld a, SHELL_ERR_BAD_ARGS
  257. call shellPrintErr
  258. jr .end
  259. .success:
  260. ld b, a
  261. ld hl, (SHELL_MEM_PTR)
  262. .loop: SHELL_GETC
  263. ld (hl), a
  264. inc hl
  265. djnz .loop
  266. .end:
  267. pop hl
  268. pop bc
  269. pop af
  270. ret
  271. ; Format: 4 bytes name followed by 3 bytes jump. fill names with zeroes
  272. shellCmdTbl:
  273. .db "seek"
  274. jp shellSeek
  275. .db "peek"
  276. jp shellPeek
  277. .db "load"
  278. jp shellLoad