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

312 строки
6.7KB

  1. ; codegen.s - documented scalar instruction emitter (E04-S03).
  2. ;
  3. ; The emitter writes into cg_code, a 256-byte RAM buffer. cg_len is the byte
  4. ; count (0-254); every failure sets cg_err and returns C=1. It does not emit a
  5. ; whole function yet: parser/codegen integration is E04-S04.
  6. ;
  7. ; API:
  8. ; cg_init
  9. ; cg_put A = byte
  10. ; cg_lda_imm A = value
  11. ; cg_ldx_imm A = value
  12. ; cg_ora_imm A = value
  13. ; cg_ldy_imm A = value
  14. ; cg_lda_zp A = zero-page address
  15. ; cg_ldx_zp A = zero-page address
  16. ; cg_sta_zp A = zero-page address
  17. ; cg_stx_zp A = zero-page address
  18. ; cg_lda_zpy A = zero-page pointer address, indexed by Y
  19. ; cg_sta_zpy A = zero-page pointer address, indexed by Y
  20. ; cg_adc_imm A = value (ADC #value)
  21. ; cg_adc_zp A = zero-page address (CLC/ADC (zp))
  22. ; cg_sbc_zp A = zero-page address (SEC/SBC (zp))
  23. ; (there is no LDX (zp),Y: use LDA/TAX for a high byte)
  24. ; cg_lda_abs A/X = address
  25. ; cg_ldx_abs A/X = address
  26. ; cg_sta_abs A/X = address
  27. ; cg_stx_abs A/X = address
  28. ; cg_adc_abs A/X = address
  29. ; cg_sbc_abs A/X = address
  30. ; cg_cmp_abs A/X = address
  31. ; cg_cmp_zp A = zero-page address (CMP zp)
  32. ; cg_jsr_abs A/X = address
  33. ; cg_clc, cg_sec, cg_rts
  34. ; cg_branch_fwd A = branch opcode; emits opcode + placeholder, returns
  35. ; C=0 and A = fixup index
  36. ; cg_patch_here A = fixup index; target is the current end of buffer
  37. ; cg_here returns A = current length
  38. ; cg_set_count A != 0: count bytes only (no stores); 0: emit bytes
  39. ;
  40. ; Only forward relative branches within +0..+127 bytes are accepted. This is
  41. ; enough for the scalar shapes and gives E04-S04 the checked primitive it
  42. ; needs for a later long-branch expansion.
  43. ;
  44. ; Count mode (E04-S04) lets a sizing pass measure a routine without writing
  45. ; the code buffer. cg_len advances exactly as in emit mode, so label offsets
  46. ; and lengths match by construction.
  47. .setcpu "6502"
  48. .include "../common/codegen.inc"
  49. .export cg_init, cg_put, cg_here, cg_branch_fwd, cg_patch_here
  50. .export cg_set_count, cg_count
  51. .export cg_lda_imm, cg_ldx_imm, cg_ora_imm, cg_ldy_imm, cg_lda_abs, cg_ldx_abs
  52. .export cg_lda_zp, cg_ldx_zp, cg_sta_zp, cg_stx_zp, cg_lda_zpy, cg_sta_zpy
  53. .export cg_adc_zp, cg_sbc_zp, cg_adc_imm
  54. .export cg_sta_abs, cg_stx_abs, cg_adc_abs, cg_sbc_abs, cg_cmp_abs, cg_cmp_zp
  55. .export cg_jsr_abs, cg_clc, cg_sec, cg_rts
  56. .export cg_code, cg_len, cg_err
  57. .segment "CODE"
  58. cg_init:
  59. lda #$00
  60. sta cg_len
  61. sta cg_err
  62. sta cg_fix_count
  63. sta cg_count
  64. clc
  65. rts
  66. cg_here:
  67. lda cg_len
  68. rts
  69. ; A != 0: count bytes only. A = 0: emit them (the default).
  70. cg_set_count:
  71. sta cg_count
  72. rts
  73. ; A = byte to append. C=1 on overflow.
  74. cg_put:
  75. ldy cg_len
  76. cpy #CG_MAX
  77. bcs @full
  78. pha
  79. lda cg_count
  80. bne @count
  81. pla
  82. sta cg_code,y
  83. jmp @bump
  84. @count: pla
  85. @bump: inc cg_len
  86. clc
  87. rts
  88. @full: lda #CG_ERR_FULL
  89. sta cg_err
  90. sec
  91. rts
  92. ; Immediate forms.
  93. cg_lda_imm:
  94. pha
  95. lda #$A9
  96. jsr cg_put
  97. bcs @out
  98. pla
  99. jmp cg_put
  100. @out: pla
  101. sec
  102. rts
  103. cg_ldx_imm:
  104. pha
  105. lda #$A2
  106. jsr cg_put
  107. bcs @out
  108. pla
  109. jmp cg_put
  110. @out: pla
  111. sec
  112. rts
  113. cg_ora_imm:
  114. pha
  115. lda #$09
  116. jsr cg_put
  117. bcs @out
  118. pla
  119. jmp cg_put
  120. @out: pla
  121. sec
  122. rts
  123. cg_ldy_imm:
  124. pha
  125. lda #$A0
  126. jsr cg_put
  127. bcs @out
  128. pla
  129. jmp cg_put
  130. @out: pla
  131. sec
  132. rts
  133. ; Zero-page forms (E05-S04). Each wrapper supplies the opcode in Y; the
  134. ; shared routine stores the address before Y is reused by cg_put.
  135. cg_lda_zp:
  136. ldy #$A5
  137. jmp cg_emit_zp
  138. cg_ldx_zp:
  139. ldy #$A6
  140. jmp cg_emit_zp
  141. cg_sta_zp:
  142. ldy #$85
  143. jmp cg_emit_zp
  144. cg_stx_zp:
  145. ldy #$86
  146. jmp cg_emit_zp
  147. cg_adc_zp:
  148. ldy #$65
  149. jmp cg_emit_zp
  150. cg_sbc_zp:
  151. ldy #$E5
  152. jmp cg_emit_zp
  153. cg_cmp_zp:
  154. ldy #$C5
  155. jmp cg_emit_zp
  156. cg_lda_zpy:
  157. ldy #$B1
  158. jmp cg_emit_zp
  159. cg_sta_zpy:
  160. ldy #$91
  161. jmp cg_emit_zp
  162. cg_emit_zp:
  163. sta cg_addr
  164. tya
  165. jsr cg_put
  166. bcs @out
  167. lda cg_addr
  168. jmp cg_put
  169. @out: sec
  170. rts
  171. ; Absolute-address forms. Each wrapper supplies the opcode in Y; the shared
  172. ; routine stores the address before Y is reused by cg_put.
  173. cg_lda_abs:
  174. ldy #$AD
  175. jmp cg_emit_addr
  176. cg_ldx_abs:
  177. ldy #$AE
  178. jmp cg_emit_addr
  179. cg_sta_abs:
  180. ldy #$8D
  181. jmp cg_emit_addr
  182. cg_stx_abs:
  183. ldy #$8E
  184. jmp cg_emit_addr
  185. cg_adc_imm:
  186. pha
  187. lda #$69
  188. jsr cg_put
  189. bcs @out
  190. pla
  191. jmp cg_put
  192. @out: pla
  193. sec
  194. rts
  195. cg_adc_abs:
  196. ldy #$6D
  197. jmp cg_emit_addr
  198. cg_sbc_abs:
  199. ldy #$ED
  200. jmp cg_emit_addr
  201. cg_cmp_abs:
  202. ldy #$CD
  203. jmp cg_emit_addr
  204. cg_jsr_abs:
  205. ldy #$20
  206. jmp cg_emit_addr
  207. cg_emit_addr:
  208. sta cg_addr
  209. stx cg_addr+1
  210. tya
  211. jsr cg_put
  212. bcs @out
  213. lda cg_addr
  214. jsr cg_put
  215. bcs @out
  216. lda cg_addr+1
  217. jmp cg_put
  218. @out: sec
  219. rts
  220. cg_clc:
  221. lda #$18
  222. jmp cg_put
  223. cg_sec:
  224. lda #$38
  225. jmp cg_put
  226. cg_rts:
  227. lda #$60
  228. jmp cg_put
  229. ; A = branch opcode; forward target must be patched later.
  230. cg_branch_fwd:
  231. sta cg_op
  232. lda cg_fix_count
  233. cmp #CG_FIX_MAX
  234. bcs @fix_full
  235. sta cg_idx
  236. lda cg_op
  237. jsr cg_put
  238. bcs @out
  239. lda cg_len
  240. sta cg_pos
  241. ldy cg_idx
  242. sta cg_fixpos,y
  243. inc cg_fix_count
  244. lda #$00
  245. jsr cg_put
  246. bcs @out
  247. lda cg_idx
  248. clc
  249. rts
  250. @fix_full:
  251. lda #CG_ERR_FIX
  252. sta cg_err
  253. sec
  254. rts
  255. @out: sec
  256. rts
  257. ; A = fixup index. Patch its placeholder so the branch targets cg_len.
  258. cg_patch_here:
  259. cmp cg_fix_count
  260. bcs @bad
  261. tax
  262. lda cg_len
  263. sec
  264. sbc cg_fixpos,x
  265. sec
  266. sbc #1
  267. cmp #128
  268. bcs @range
  269. ldy cg_fixpos,x
  270. sta cg_code,y
  271. clc
  272. rts
  273. @bad: lda #CG_ERR_FIX
  274. sta cg_err
  275. sec
  276. rts
  277. @range: lda #CG_ERR_RANGE
  278. sta cg_err
  279. sec
  280. rts
  281. .segment "BSS"
  282. cg_code: .res 256
  283. cg_len: .res 1
  284. cg_err: .res 1
  285. cg_count: .res 1
  286. cg_fix_count: .res 1
  287. cg_fixpos: .res CG_FIX_MAX
  288. cg_addr: .res 2
  289. cg_op: .res 1
  290. cg_idx: .res 1
  291. cg_pos: .res 1

Powered by TurnKey Linux.