PageRenderTime 26ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/samples/Forth/asm.fr

https://gitlab.com/Aaeinstein54/linguist
Forth | 244 lines | 211 code | 33 blank | 0 comment | 15 complexity | e73486fee8eb35367259b368f8429243 MD5 | raw file
  1. \ Copyright 2013-2014 Lars Brinkhoff
  2. \ Assembler for x86.
  3. \ Adds to FORTH vocabulary: ASSEMBLER CODE ;CODE.
  4. \ Creates ASSEMBLER vocabulary with: END-CODE and x86 opcodes.
  5. \ Conventional prefix syntax: "<source> <destination> <opcode>,".
  6. \ Addressing modes:
  7. \ - immediate: "n #"
  8. \ - direct: n
  9. \ - register: <reg>
  10. \ - indirect: "<reg> )"
  11. \ - indirect with displacement: "n <reg> )#"
  12. \ - indexed: not supported yet
  13. require lib/common.fth
  14. require search.fth
  15. vocabulary assembler
  16. also assembler definitions
  17. \ Access to the target image.
  18. ' header, defer header, is header,
  19. ' cell defer cell is cell
  20. ' dp defer dp is dp
  21. 0 value delta
  22. : aligned cell + 1 - cell negate nand invert ;
  23. : align dp @ aligned dp ! ;
  24. : allot dp +! ;
  25. : here dp @ ;
  26. : cells cell * ;
  27. : c! delta + c! ;
  28. : c, here c! 1 allot ;
  29. : h, dup c, 8 rshift c, ;
  30. : , dup h, 16 rshift h, ;
  31. base @ hex
  32. \ This constant signals that an operand is not a direct address.
  33. deadbeef constant -addr
  34. \ Assembler state.
  35. variable opcode
  36. variable d
  37. variable s
  38. variable dir?
  39. variable mrrm defer ?mrrm,
  40. variable sib defer ?sib,
  41. variable disp defer ?disp,
  42. variable imm defer ?imm,
  43. defer imm,
  44. defer immediate-opcode
  45. defer reg
  46. defer ?opsize
  47. \ Set opcode. And destination: register or memory.
  48. : opcode! 3@ is immediate-opcode >r opcode ! ;
  49. : !reg dir? @ if 2 d ! then dir? off ;
  50. : !mem dir? off ;
  51. \ Set bits in mod/reg/rm byte.
  52. : -mrrm ['] nop is ?mrrm, ;
  53. : mod! mrrm c0 !bits ;
  54. : reg@ mrrm 38 @bits ;
  55. : reg! mrrm 38 !bits ;
  56. : rm@ mrrm 7 @bits ;
  57. : rm! rm@ 3 lshift reg! mrrm 7 !bits ;
  58. : reg>opcode rm@ opcode 07 !bits ;
  59. : opcode>reg opcode @ dup 3 rshift rm! 8 rshift opcode ! ;
  60. \ Write parts of instruction to memory.
  61. : ds d @ s @ + ;
  62. : ?twobyte dup FF > if dup 8 rshift c, then ;
  63. : opcode, opcode @ ?twobyte ds + c, ;
  64. : mrrm, mrrm @ c, ;
  65. : sib, sib @ c, ;
  66. : imm8, imm @ c, ;
  67. : imm16, imm @ h, ;
  68. : imm32, imm @ , ;
  69. : disp8, disp @ c, ;
  70. : disp32, disp @ , ;
  71. \ Set operand size.
  72. : -opsize 2drop r> drop ;
  73. : opsize! is imm, s ! ['] -opsize is ?opsize ;
  74. : !op8 0 ['] imm8, ?opsize ;
  75. : !op32 1 ['] imm32, ?opsize ;
  76. : !op16 1 ['] imm16, ?opsize 66 c, ;
  77. \ Set SIB byte.
  78. : !sib ['] sib, is ?sib, ;
  79. : sib! 3 lshift + sib ! !sib ;
  80. \ Set displacement.
  81. : byte? -80 80 within ;
  82. : disp! is ?disp, disp ! ;
  83. : !disp8 ['] disp8, disp! ;
  84. : !disp32 ['] disp32, disp! ;
  85. : !disp ( a -- u ) dup byte? if !disp8 40 else !disp32 80 then ;
  86. : -pc here 5 + negate ;
  87. : relative -pc disp +! ;
  88. \ Set immediate operand.
  89. : imm! imm ! ['] imm, is ?imm, ;
  90. \ Implements addressing modes: register, indirect, indexed, and direct.
  91. : reg1 rm! !reg ;
  92. : reg2 3 lshift reg! ;
  93. : !reg2 ['] reg2 is reg ;
  94. : ind dup mod! rm! !mem !reg2 ;
  95. : ind# swap !disp + ind ;
  96. : idx 04 ind sib! ;
  97. : idx# rot !disp 04 + ind sib! ;
  98. : addr !disp32 05 ind ;
  99. \ Reset assembler state.
  100. : 0opsize ['] opsize! is ?opsize ;
  101. : 0ds d off s off ;
  102. : 0reg ['] reg1 is reg ;
  103. : 0mrrm c0 mrrm ! ['] mrrm, is ?mrrm, ;
  104. : 0sib ['] nop is ?sib, ;
  105. : 0disp ['] nop is ?disp, ;
  106. : 0imm imm off ['] nop is ?imm, 0 is imm, ;
  107. : 0asm 0imm 0disp 0reg 0ds 0mrrm 0sib 0opsize dir? on ;
  108. \ Enter and exit assembler mode.
  109. : start-code also assembler 0asm ;
  110. : end-code align previous ;
  111. \ Implements addressing mode: immediate.
  112. : imm8? imm @ byte? ;
  113. : ?sign-extend d off imm8? if 2 d ! ['] imm8, is ?imm, then ;
  114. : alu# opcode @ reg! 80 opcode ! ?sign-extend ;
  115. : mov# B0 s @ 3 lshift + rm@ + opcode ! 0ds -mrrm ;
  116. : push# imm8? if ['] imm8, 6A else ['] imm32, 68 then dup opcode ! rm! is ?imm, ;
  117. : test# F6 opcode ! ;
  118. : imm-op imm! immediate-opcode ;
  119. \ Process one operand. All operands except a direct address
  120. \ have the stack picture ( n*x xt -addr ).
  121. : addr? dup -addr <> ;
  122. : op addr? if addr else drop execute then ;
  123. \ Define instruction formats.
  124. : instruction, opcode! opcode, ?mrrm, ?sib, ?disp, ?imm, 0asm ;
  125. : mnemonic ( u a "name" -- ) create ['] nop 3, does> instruction, ;
  126. : format: create ] !csp does> mnemonic ;
  127. : immediate: ' latestxt >body ! ;
  128. \ Instruction formats.
  129. format: 0op -mrrm ;
  130. format: 1reg op reg>opcode 0ds -mrrm ;
  131. format: 1op opcode>reg op d off ;
  132. format: 2op op op ;
  133. format: 2op-d op op d off ;
  134. format: 2op-ds op op 0ds ;
  135. format: 1addr op relative -mrrm ;
  136. format: 1imm8 !op8 op -mrrm ;
  137. \ Instruction mnemonics.
  138. 00 2op add, immediate: alu#
  139. 08 2op or, immediate: alu#
  140. 0F44 2op-ds cmove, \ Todo: other condition codes.
  141. 0FB6 2op-ds movzx,
  142. 0FBE 2op-ds movsx,
  143. 10 2op adc, immediate: alu#
  144. 18 2op sbb, immediate: alu#
  145. 20 2op and, immediate: alu#
  146. 26 0op es,
  147. 28 2op sub, immediate: alu#
  148. 2E 0op cs,
  149. 30 2op xor, immediate: alu#
  150. 36 0op ss,
  151. 38 2op cmp, immediate: alu#
  152. 3E 0op ds,
  153. 50 1reg push, immediate: push#
  154. 58 1reg pop,
  155. 64 0op fs,
  156. 65 0op gs,
  157. \ 70 jcc
  158. 84 2op-d test, immediate: test#
  159. 86 2op-d xchg,
  160. 88 2op mov, immediate: mov#
  161. 8D 2op-ds lea,
  162. \ 8F/0 pop, rm
  163. 90 0op nop,
  164. C3 0op ret,
  165. \ C6/0 immediate mov to r/m
  166. \ C7/0 immediate mov to r/m
  167. CD 1imm8 int,
  168. E8 1addr call,
  169. E9 1addr jmp,
  170. \ EB jmp rel8
  171. F0 0op lock,
  172. F2 0op rep,
  173. F3 0op repz,
  174. F4 0op hlt,
  175. F5 0op cmc,
  176. F610 1op not,
  177. F618 1op neg,
  178. F8 0op clc,
  179. F9 0op stc,
  180. FA 0op cli,
  181. FB 0op sti,
  182. FC 0op cld,
  183. FD 0op std,
  184. \ FE 0 inc rm
  185. \ FF 1 dec rm
  186. \ FF 2 call rm
  187. \ FF 4 jmp rm
  188. \ FF 6 push rm
  189. : sp? dup 4 = ;
  190. \ Addressing mode syntax: immediate, indirect, and displaced indirect.
  191. : # ['] imm-op -addr ;
  192. : ) 2drop sp? if 4 ['] idx else ['] ind then -addr 0reg 0opsize ;
  193. : )# 2drop sp? if 4 ['] idx# else ['] ind# then -addr 0reg 0opsize ;
  194. \ Define registers.
  195. : reg8 create , does> @ ['] reg -addr !op8 ;
  196. : reg16 create , does> @ ['] reg -addr !op16 ;
  197. : reg32 create , does> @ ['] reg -addr !op32 ;
  198. : reg: dup reg8 dup reg16 dup reg32 1+ ;
  199. \ Register names.
  200. 0
  201. reg: al ax eax reg: cl cx ecx reg: dl dx edx reg: bl bx ebx
  202. reg: ah sp esp reg: ch bp ebp reg: dh si esi reg: bh di edi
  203. drop
  204. \ Runtime for ;CODE. CODE! is defined elsewhere.
  205. : (;code) r> code! ;
  206. base ! only forth definitions also assembler
  207. \ Standard assembler entry points.
  208. : code parse-name header, ?code, start-code ;
  209. : ;code postpone (;code) reveal postpone [ ?csp start-code ; immediate
  210. 0asm
  211. previous