sectorlisp.S 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
  2. │vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
  3. ╞══════════════════════════════════════════════════════════════════════════════╡
  4. │ Copyright 2020 Justine Alexandra Roberts Tunney │
  5. │ Copyright 2021 Alain Greppin │
  6. │ Some size optimisations by Peter Ferrie │
  7. │ │
  8. │ Permission to use, copy, modify, and/or distribute this software for │
  9. │ any purpose with or without fee is hereby granted, provided that the │
  10. │ above copyright notice and this permission notice appear in all copies. │
  11. │ │
  12. │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
  13. │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
  14. │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
  15. │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
  16. │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
  17. │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
  18. │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
  19. │ PERFORMANCE OF THIS SOFTWARE. │
  20. ╚─────────────────────────────────────────────────────────────────────────────*/
  21. // LISP meta-circular evaluator in a MBR
  22. // Compatible with the original hardware
  23. .code16
  24. .set a,-2-2
  25. .globl _start # LISP: VERITAS NUMQUAM PERIT
  26. _start: .asciz "NIL" # dec %si ; dec %cx ; dec %sp
  27. kT: .asciz "T" # add %dl,(%si) boot A:\ DL=0
  28. start: ljmp $0x7c00>>4,$begin # cs = 0x7c00 is boot address
  29. .asciz ""
  30. kDefine:.asciz "DEFINE"
  31. kQuote: .asciz "QUOTE"
  32. kCond: .asciz "COND"
  33. kAtom: .asciz "ATOM" # ordering matters
  34. kCar: .asciz "CAR" # ordering matters
  35. kCdr: .asciz "CDR" # ordering matters
  36. kCons: .asciz "CONS" # ordering matters
  37. kEq: .asciz "EQ" # needs to be last
  38. Read: call GetToken
  39. call GetObject
  40. ret
  41. Define: call Read
  42. push %ax
  43. call Read
  44. pop %di
  45. call Cons
  46. xchg %ax,%di
  47. xchg %bp,%ax
  48. call Cons
  49. xchg %ax,%bp
  50. jmp main
  51. begin: mov $0x8000,%sp
  52. push %cs
  53. pop %ds
  54. push %cs
  55. pop %es
  56. push %cs
  57. pop %ss
  58. mov $2,%bx
  59. mov %sp,%cx
  60. xor %bp,%bp
  61. main: xor %dx,%dx
  62. call Read
  63. cmp $kDefine,%ax
  64. je Define
  65. mov %bp,%dx
  66. call Eval
  67. Catch: xchg %ax,%si
  68. call PrintObject
  69. mov $'\r',%al
  70. call PutChar
  71. jmp main
  72. GetToken: # GetToken():al
  73. mov %cx,%di
  74. 1: mov %dl,%al
  75. cmp $' ',%al
  76. jbe 2f
  77. stosb
  78. xchg %ax,%si
  79. 2: call GetChar # exchanges dx and ax
  80. cmp $'\b',%al
  81. je 4f
  82. cmp $' ',%al
  83. jbe 1b
  84. cmp $')',%al
  85. jbe 3f
  86. cmp $')',%dl
  87. ja 1b
  88. 3: mov %bh,(%di) # bh is zero
  89. xchg %si,%ax
  90. ret
  91. 4: dec %di
  92. jmp 2b
  93. .PrintList:
  94. mov $'(',%al
  95. 2: push (%bx,%si)
  96. mov (%si),%si
  97. call .PutObject
  98. mov $' ',%al
  99. pop %si # restore 1
  100. test %si,%si
  101. js 2b # jump if cons
  102. jz 4f # jump if nil
  103. mov $249,%al # bullet (A∙B)
  104. call .PutObject
  105. 4: mov $')',%al
  106. jmp PutChar
  107. .PutObject: # .PutObject(c:al,x:si)
  108. .PrintString: # nul-terminated in si
  109. call PutChar # preserves si
  110. PrintObject: # PrintObject(x:si,a:di)
  111. test %si,%si # set sf=1 if cons
  112. js .PrintList # jump if not cons
  113. .PrintAtom:
  114. lodsb
  115. test %al,%al # test for nul terminator
  116. jnz .PrintString # -> ret
  117. ret
  118. GetObject: # called just after GetToken
  119. cmp $'(',%al
  120. je GetList
  121. # jmp Intern
  122. Intern: push %cx # Intern(cx,di): ax
  123. sub %cx,%di
  124. inc %di
  125. push %di
  126. xor %di,%di
  127. 1: pop %cx
  128. pop %si
  129. push %si
  130. push %cx
  131. mov %di,%ax
  132. cmp %bh,(%di)
  133. je 8f
  134. rep cmpsb # memcmp(di,si,cx)
  135. je 9f
  136. xor %ax,%ax
  137. 2: scasb
  138. jne 2b
  139. jmp 1b
  140. 8: rep movsb # memcpy(di,si,cx)
  141. 9: pop %cx
  142. pop %cx
  143. ret
  144. Undef: push %ax
  145. mov $'?',%al
  146. call PutChar
  147. pop %ax
  148. jmp Catch
  149. GetChar:xor %ax,%ax # GetChar→al:dl
  150. int $0x16 # get keystroke
  151. PutChar:mov $0x0e,%ah # prints CP-437
  152. push %bp # scroll up bug
  153. int $0x10 # vidya service
  154. pop %bp # scroll up bug
  155. cmp $'\r',%al # don't clobber
  156. jne 1f # look xchg ret
  157. mov $'\n',%al
  158. jmp PutChar
  159. ////////////////////////////////////////////////////////////////////////////////
  160. Pairlis:test %di,%di # Pairlis(x:di,y:si,a:dx):ax
  161. jz 1f # jump if nil
  162. push (%bx,%di) # save 1 Cdr(x)
  163. lodsw
  164. push (%si) # save 2 Cdr(y)
  165. mov (%di),%di
  166. call Cons # preserves dx
  167. pop %si # restore 2
  168. pop %di # restore 1
  169. push %ax # save 3
  170. call Pairlis
  171. jmp xCons # can be inlined here
  172. 1: xchg %dx,%ax
  173. ret
  174. Evlis: test %di,%di # Evlis(m:di,a:dx):ax
  175. jz 1f # jump if nil
  176. push (%bx,%di) # save 1 Cdr(m)
  177. mov (%di),%ax
  178. call Eval
  179. pop %di # restore 1
  180. push %ax # save 2
  181. call Evlis
  182. # jmp xCons
  183. xCons: pop %di # restore 2
  184. Cons: xchg %di,%cx # Cons(m:di,a:ax):ax
  185. mov %cx,(%di)
  186. mov %ax,(%bx,%di)
  187. lea 4(%di),%cx
  188. 1: xchg %di,%ax
  189. ret
  190. Gc: cmp %dx,%di # Gc(x:di,A:dx,B:si):ax
  191. jb 1b # we assume immutable cells
  192. push (%bx,%di) # mark prevents negative gc
  193. mov (%di),%di
  194. call Gc
  195. pop %di
  196. push %ax
  197. call Gc
  198. pop %di
  199. call Cons
  200. sub %si,%ax # ax -= C - B
  201. add %dx,%ax
  202. ret
  203. Assoc: mov %dx,%si # Assoc(x:ax,y:dx):ax
  204. 1: test %si,%si
  205. jns Undef
  206. mov (%si),%di
  207. mov (%bx,%si),%si
  208. scasw
  209. jne 1b
  210. .byte 0xf6
  211. Cadr: mov (%bx,%di),%di # contents of decrement register
  212. .byte 0x3C # cmp §scasw,%al (nop next byte)
  213. Cdr: scasw # increments our data index by 2
  214. Car: mov (%di),%ax # contents of address register!!
  215. 2: ret
  216. GetList:call GetToken
  217. cmp $')',%al
  218. je .retF
  219. call GetObject
  220. push %ax # popped by xCons
  221. call GetList
  222. jmp xCons
  223. .dflt1: push %si # save x
  224. call Eval
  225. pop %si # restore x
  226. # jmp Apply
  227. Apply: test %ax,%ax # Apply(fn:ax,x:si:a:dx):ax
  228. jns .switch # jump if atom
  229. xchg %ax,%di # di = fn
  230. .lambda:mov (%bx,%di),%di # di = Cdr(fn)
  231. push %di # save 1
  232. mov (%di),%di # di = Cadr(fn)
  233. call Pairlis
  234. xchg %ax,%dx
  235. pop %di # restore 1
  236. jmp .EvCadr
  237. .switch:cmp $kEq,%ax # eq is last builtin atom
  238. ja .dflt1 # ah is zero if not above
  239. mov (%si),%di # di = Car(x)
  240. .ifCar: cmp $kCar,%al
  241. je Car
  242. .ifCdr: cmp $kCdr,%al
  243. je Cdr
  244. .ifAtom:cmp $kAtom,%al
  245. jne .ifCons
  246. test %di,%di # test if atom
  247. jns .retT
  248. .retF: xor %ax,%ax # ax = nil
  249. ret
  250. .ifCons:cmp $kCons,%al
  251. mov (%bx,%si),%si # si = Cdr(x)
  252. lodsw # si = Cadr(x)
  253. je Cons
  254. .isEq: xor %di,%ax # we know for certain it's eq
  255. jne .retF
  256. .retT: mov $kT,%al
  257. ret
  258. 1: mov (%bx,%di),%di # di = Cdr(c)
  259. Evcon: push %di # save c
  260. mov (%di),%si # di = Car(c)
  261. lodsw # ax = Caar(c)
  262. call Eval
  263. pop %di # restore c
  264. test %ax,%ax # nil test
  265. jz 1b
  266. mov (%di),%di # di = Car(c)
  267. .EvCadr:call Cadr # ax = Cadar(c)
  268. # jmp Eval
  269. Eval: test %ax,%ax # Eval(e:ax,a:dx):ax
  270. jz 1f
  271. jns Assoc # lookup val if atom
  272. xchg %ax,%si # di = e
  273. lodsw # ax = Car(e)
  274. cmp $kQuote,%ax # maybe CONS
  275. mov (%si),%di # di = Cdr(e)
  276. je Car
  277. cmp $kCond,%ax
  278. je Evcon # ABC Garbage Collector
  279. push %dx # save a
  280. push %cx # save A
  281. push %ax
  282. call Evlis
  283. xchg %ax,%si
  284. pop %ax
  285. call Apply
  286. pop %dx # restore A
  287. mov %cx,%si # si = B
  288. xchg %ax,%di
  289. call Gc
  290. mov %dx,%di # di = A
  291. sub %si,%cx # cx = C - B
  292. rep movsb
  293. mov %di,%cx # cx = A + (C - B)
  294. pop %dx # restore a
  295. 1: ret
  296. .sig: .fill 510 - (. - _start), 1, 0xce
  297. .word 0xAA55
  298. .type .sig,@object
  299. .type kDefine,@object
  300. .type kQuote,@object
  301. .type kCond,@object
  302. .type kAtom,@object
  303. .type kCar,@object
  304. .type kCdr,@object
  305. .type kCons,@object
  306. .type kEq,@object