Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

634 lines
14KB

  1. ; E04-S04: control-flow emitter fixture in x128.
  2. ;
  3. ; The fixture generates the same routine twice with flow.s: first in counting
  4. ; mode (a sizing pass that writes no bytes), then in emitting mode. Both
  5. ; passes must produce identical label offsets and total lengths. The emitted
  6. ; routine is then executed and must compute:
  7. ;
  8. ; a = 0; while a < 5: a = a + 1 -> a = 5
  9. ; if a = 5 then path = 10 else path = 20 -> path = 10
  10. ; for i = 1 to 3: sum = sum + i -> sum = 16, i = 4
  11. ; sum = add(sum) -> sum = 17 (call + return)
  12. ; return sum -> A = 17
  13. ;
  14. ; A separate routine takes a long conditional branch (distance >= 128) over
  15. ; 125 bytes of filler and must reach its target. The fixture also checks the
  16. ; five-byte branch encoding: short form has the distance byte plus three NOPs,
  17. ; long form has +3 and a live JMP.
  18. ;
  19. ; Mailbox data:
  20. ; +0 program result (17)
  21. ; +1 a (5)
  22. ; +2 if/else path marker (10)
  23. ; +3 i after the for loop (4)
  24. ; +4 long-branch result (5A)
  25. ; +5 long-branch wrong-path marker (0)
  26. ; +6 label/length mismatches between the sizing and emission passes (0)
  27. ; +7 branch-form bits: 1 short form verified, 2 long form verified (3)
  28. ; Failure bits: 1 sizing, 2 program result, 4 if/else, 8 for loop,
  29. ; 16 call/return, 32 long branch, 64 branch bytes, 128 emitter error.
  30. .setcpu "6502"
  31. .include "../../src/common/c128.inc"
  32. .include "../../src/common/mailbox.inc"
  33. .include "../../src/common/codegen.inc"
  34. .include "../../src/common/flow.inc"
  35. .include "../../src/common/frames.inc"
  36. .import cg_init, cg_len, cg_err, cg_code, cg_here
  37. .import cg_lda_imm, cg_ldx_imm, cg_lda_abs, cg_sta_abs
  38. .import cg_adc_abs, cg_cmp_abs, cg_jsr_abs
  39. .import cg_clc, cg_sec, cg_rts
  40. .import fl_init, fl_label, fl_jmp, fl_branch, fl_finish, fl_get_label
  41. .import fl_branch_true, fl_call_byte, fl_prologue, fl_ret_byte
  42. .import fl_err, fl_enter, fl_leave, fl_discard
  43. .import frame_init, frame_enter, frame_leave, frame_discard, frame_push_word
  44. ; Label ids (reset by every fl_init).
  45. L_WHILE = 0
  46. L_ENDWHILE = 1
  47. L_ELSE = 2
  48. L_ENDIF = 3
  49. L_FOR = 4
  50. L_ENDFOR = 5
  51. L_ERR = 6
  52. L_LONG = 7
  53. LABEL_IDS = 7 ; ids 0..6 belong to the main routine
  54. .macro EMIT_LDA addr
  55. lda #<(addr)
  56. ldx #>(addr)
  57. jsr cg_lda_abs
  58. .endmacro
  59. .macro EMIT_STA addr
  60. lda #<(addr)
  61. ldx #>(addr)
  62. jsr cg_sta_abs
  63. .endmacro
  64. .macro EMIT_ADC addr
  65. lda #<(addr)
  66. ldx #>(addr)
  67. jsr cg_adc_abs
  68. .endmacro
  69. .macro EMIT_CMP addr
  70. lda #<(addr)
  71. ldx #>(addr)
  72. jsr cg_cmp_abs
  73. .endmacro
  74. .macro EMIT_LDA_IMM value
  75. lda #value
  76. jsr cg_lda_imm
  77. .endmacro
  78. .macro EMIT_LDX_IMM value
  79. lda #value
  80. jsr cg_ldx_imm
  81. .endmacro
  82. .macro EMIT_JSR addr
  83. lda #<(addr)
  84. ldx #>(addr)
  85. jsr cg_jsr_abs
  86. .endmacro
  87. ; Branch to a global error label even when it is out of relative range.
  88. .macro ON_CARRY target
  89. bcc :+
  90. jmp target
  91. :
  92. .endmacro
  93. .segment "LOADADDR"
  94. .word $1C01
  95. .segment "EXEHDR"
  96. .word basic_end
  97. .word 10
  98. .byte $9E
  99. .byte "7181"
  100. .byte $00
  101. basic_end:
  102. .word $0000
  103. .segment "MAILBOX"
  104. .res MB_SIZE
  105. .segment "STARTUP"
  106. .export test_entry
  107. test_entry:
  108. php
  109. sei
  110. ldx #MB_SIZE - 1
  111. lda #$00
  112. @clr: sta MB_BASE,x
  113. dex
  114. bpl @clr
  115. lda #MB_MAGIC0_VALUE
  116. sta MB_MAGIC0
  117. lda #MB_MAGIC1_VALUE
  118. sta MB_MAGIC1
  119. lda #MB_PROD_PROGRAM
  120. sta MB_PRODUCER
  121. lda #MB_ST_RUNNING
  122. sta MB_STATUS
  123. lda #$00
  124. sta fail_mask
  125. sta mismatch
  126. sta form_mask
  127. sta MB_CODE
  128. sta MB_CODE+1
  129. jsr init_vars
  130. ; Runtime addresses for the emitted prologue/call/epilogue.
  131. lda #<frame_enter
  132. sta fl_enter
  133. lda #>frame_enter
  134. sta fl_enter+1
  135. lda #<frame_leave
  136. sta fl_leave
  137. lda #>frame_leave
  138. sta fl_leave+1
  139. lda #<frame_discard
  140. sta fl_discard
  141. lda #>frame_discard
  142. sta fl_discard+1
  143. lda MMU_CR
  144. sta saved_cr
  145. lda #CR_RAM0_KERNAL
  146. sta MMU_CR
  147. ; ------------------------------------------- main routine: sizing pass
  148. lda #FL_MODE_COUNT
  149. jsr fl_init
  150. jsr gen_main
  151. ON_CARRY emitter_error
  152. jsr fl_finish
  153. ON_CARRY emitter_error
  154. lda cg_len
  155. sta main_size
  156. jsr save_labels
  157. ; ------------------------------------------ main routine: emit pass 2
  158. jsr frame_init
  159. lda #FL_MODE_EMIT
  160. jsr fl_init
  161. jsr gen_main
  162. ON_CARRY emitter_error
  163. jsr fl_finish
  164. ON_CARRY emitter_error
  165. lda cg_len
  166. cmp main_size
  167. beq @len_ok
  168. inc mismatch
  169. lda #$01
  170. jsr fail
  171. @len_ok:
  172. jsr compare_labels
  173. ; short branch: distance byte plus three NOPs
  174. ldy pos_while
  175. lda cg_code,y
  176. cmp #128
  177. bcs @short_bad
  178. iny
  179. lda cg_code,y
  180. cmp #$EA
  181. bne @short_bad
  182. iny
  183. lda cg_code,y
  184. cmp #$EA
  185. bne @short_bad
  186. iny
  187. lda cg_code,y
  188. cmp #$EA
  189. bne @short_bad
  190. lda #$01
  191. sta form_mask
  192. jmp @run_main
  193. @short_bad:
  194. lda #$40
  195. jsr fail
  196. ; ------------------------------------------------ execute the routine
  197. @run_main:
  198. jsr frame_init
  199. lda #$00
  200. jsr run_code
  201. sta prog_result
  202. lda prog_result
  203. cmp #17
  204. beq @check_a
  205. lda #$02
  206. jsr fail
  207. @check_a:
  208. lda v_a
  209. cmp #5
  210. beq @check_if
  211. lda #$04
  212. jsr fail
  213. @check_if:
  214. lda v_ifpath
  215. cmp #10
  216. beq @check_for
  217. lda #$04
  218. jsr fail
  219. @check_for:
  220. lda v_i
  221. cmp #4
  222. beq @check_call
  223. lda #$08
  224. jsr fail
  225. @check_call:
  226. lda v_sum
  227. cmp #17
  228. beq @long_begin
  229. lda #$10
  230. jsr fail
  231. ; ------------------------------- long branch routine: sizing + emit
  232. @long_begin:
  233. lda #FL_MODE_COUNT
  234. jsr fl_init
  235. jsr gen_long
  236. ON_CARRY emitter_error
  237. jsr fl_finish
  238. ON_CARRY emitter_error
  239. lda cg_len
  240. sta long_size
  241. lda #FL_MODE_EMIT
  242. jsr fl_init
  243. jsr gen_long
  244. ON_CARRY emitter_error
  245. jsr fl_finish
  246. ON_CARRY emitter_error
  247. lda cg_len
  248. cmp long_size
  249. beq @long_len_ok
  250. inc mismatch
  251. lda #$01
  252. jsr fail
  253. @long_len_ok:
  254. ; long form: +3 then JMP, and the target is at least 128 bytes away
  255. ldy pos_long
  256. lda cg_code,y
  257. cmp #$03
  258. bne @long_bad
  259. iny
  260. lda cg_code,y
  261. cmp #$4C
  262. bne @long_bad
  263. ldy pos_long
  264. dey
  265. lda cg_code,y
  266. cmp #$F0 ; BNE was inverted to BEQ
  267. bne @long_bad
  268. lda #L_LONG
  269. jsr fl_get_label
  270. bcs @long_bad
  271. txa
  272. sec
  273. sbc pos_long
  274. sec
  275. sbc #$01
  276. cmp #128
  277. bcc @long_bad
  278. lda form_mask
  279. ora #$02
  280. sta form_mask
  281. jmp @run_long
  282. @long_bad:
  283. lda #$40
  284. jsr fail
  285. @run_long:
  286. lda #$00
  287. jsr run_code
  288. lda v_long
  289. cmp #$5A
  290. beq @check_bad
  291. lda #$20
  292. jsr fail
  293. @check_bad:
  294. lda v_bad
  295. beq report
  296. lda #$20
  297. jsr fail
  298. jmp report
  299. ; ---------------------------------------------------------- report
  300. report:
  301. lda saved_cr
  302. sta MMU_CR
  303. lda prog_result
  304. sta MB_DATA+0
  305. lda v_a
  306. sta MB_DATA+1
  307. lda v_ifpath
  308. sta MB_DATA+2
  309. lda v_i
  310. sta MB_DATA+3
  311. lda v_long
  312. sta MB_DATA+4
  313. lda v_bad
  314. sta MB_DATA+5
  315. lda mismatch
  316. sta MB_DATA+6
  317. lda form_mask
  318. sta MB_DATA+7
  319. lda fail_mask
  320. sta MB_CODE
  321. lda #$00
  322. sta MB_CODE+1
  323. lda #MB_ST_FAIL
  324. ldx fail_mask
  325. bne @status
  326. lda #MB_ST_PASS
  327. @status:
  328. sta MB_STATUS
  329. ldy #$00
  330. @print: lda message,y
  331. beq @end
  332. sty print_y
  333. jsr CHROUT
  334. ldy print_y
  335. iny
  336. bne @print
  337. @end: plp
  338. rts
  339. emitter_error:
  340. lda #$80
  341. jsr fail
  342. jmp report
  343. ; ------------------------------------------------------------- generators
  344. ; if/else/while/for, one call, and a value return.
  345. gen_main:
  346. lda #$00 ; prologue: no locals
  347. ldx #$00
  348. ldy #L_ERR
  349. jsr fl_prologue
  350. ON_CARRY gen_out
  351. EMIT_LDA_IMM $00 ; a = 0
  352. EMIT_STA v_a
  353. EMIT_LDA_IMM $00 ; sum = 0
  354. EMIT_STA v_sum
  355. lda #L_WHILE ; while a < 5
  356. jsr fl_label
  357. EMIT_LDA v_a
  358. EMIT_CMP v_five
  359. jsr cg_here ; the exit branch's distance byte
  360. clc
  361. adc #$01
  362. sta pos_while
  363. lda #$B0 ; BCS: a >= 5 leaves the loop
  364. ldx #L_ENDWHILE
  365. jsr fl_branch
  366. ON_CARRY gen_out
  367. EMIT_LDA v_a ; a = a + 1
  368. jsr cg_clc
  369. EMIT_ADC v_one
  370. EMIT_STA v_a
  371. lda #L_WHILE ; back edge: absolute jump
  372. jsr fl_jmp
  373. ON_CARRY gen_out
  374. lda #L_ENDWHILE
  375. jsr fl_label
  376. EMIT_LDA v_a ; if a = 5
  377. EMIT_CMP v_five
  378. lda #$D0 ; BNE: else
  379. ldx #L_ELSE
  380. jsr fl_branch
  381. ON_CARRY gen_out
  382. EMIT_LDA_IMM 10
  383. EMIT_STA v_ifpath
  384. EMIT_STA v_sum
  385. lda #L_ENDIF
  386. jsr fl_jmp
  387. ON_CARRY gen_out
  388. lda #L_ELSE
  389. jsr fl_label
  390. EMIT_LDA_IMM 20
  391. EMIT_STA v_ifpath
  392. EMIT_STA v_sum
  393. lda #L_ENDIF
  394. jsr fl_label
  395. EMIT_LDA_IMM 1 ; for i = 1 to 3
  396. EMIT_STA v_i
  397. lda #L_FOR
  398. jsr fl_label
  399. EMIT_LDA v_i
  400. EMIT_CMP v_four
  401. lda #$B0 ; BCS: i >= 4 leaves the loop
  402. ldx #L_ENDFOR
  403. jsr fl_branch
  404. ON_CARRY gen_out
  405. EMIT_LDA v_sum ; sum = sum + i
  406. jsr cg_clc
  407. EMIT_ADC v_i
  408. EMIT_STA v_sum
  409. EMIT_LDA v_i ; i = i + 1
  410. jsr cg_clc
  411. EMIT_ADC v_one
  412. EMIT_STA v_i
  413. lda #L_FOR
  414. jsr fl_jmp
  415. ON_CARRY gen_out
  416. lda #L_ENDFOR
  417. jsr fl_label
  418. EMIT_LDA v_sum ; push(sum) for add()
  419. EMIT_LDX_IMM 0
  420. EMIT_JSR frame_push_word
  421. ON_CARRY gen_out
  422. lda #$B0 ; push refused a frame
  423. ldx #L_ERR
  424. jsr fl_branch
  425. ON_CARRY gen_out
  426. lda #<add ; sum = add(sum)
  427. ldx #>add
  428. ldy #2
  429. jsr fl_call_byte
  430. ON_CARRY gen_out
  431. EMIT_STA v_sum
  432. EMIT_LDA v_sum ; return sum
  433. jsr fl_ret_byte
  434. ON_CARRY gen_out
  435. lda #L_ERR ; frame or argument-push failure
  436. jsr fl_label
  437. lda #$00
  438. jsr cg_sec
  439. jmp cg_rts
  440. ; A long taken branch over 125 bytes of filler.
  441. gen_long:
  442. EMIT_LDA_IMM $00
  443. EMIT_STA v_bad
  444. EMIT_LDA_IMM $01
  445. jsr cg_here ; remember the branch's distance byte
  446. clc
  447. adc #$01
  448. sta pos_long
  449. lda #L_LONG
  450. jsr fl_branch_true
  451. ON_CARRY gen_out
  452. EMIT_LDA_IMM $AA ; wrong path if the branch fails
  453. EMIT_STA v_bad
  454. lda #25 ; X is clobbered by the emit macros
  455. sta fill_count
  456. @fill: EMIT_LDA_IMM $11
  457. EMIT_STA v_filler
  458. dec fill_count
  459. bne @fill
  460. lda #L_LONG
  461. jsr fl_label
  462. EMIT_LDA_IMM $5A
  463. EMIT_STA v_long
  464. jmp cg_rts
  465. ; Shared early exit for both generators: C=1 from the failing call.
  466. gen_out:
  467. rts
  468. ; ---------------------------------------------------------------- helpers
  469. ; A = code-buffer offset. Run the snippet and return its A.
  470. run_code:
  471. clc
  472. adc #<cg_code
  473. sta @target+1
  474. lda #>cg_code
  475. adc #$00
  476. sta @target+2
  477. @target:
  478. jsr $FFFF
  479. rts
  480. save_labels:
  481. lda #$00
  482. sta label_id
  483. @loop: lda label_id
  484. cmp #LABEL_IDS
  485. beq @done
  486. jsr fl_get_label
  487. bcs @missing
  488. ldy label_id
  489. txa
  490. sta saved_labels,y
  491. inc label_id
  492. jmp @loop
  493. @missing:
  494. inc mismatch
  495. lda #$01
  496. jsr fail
  497. inc label_id
  498. jmp @loop
  499. @done: rts
  500. compare_labels:
  501. lda #$00
  502. sta label_id
  503. @loop: lda label_id
  504. cmp #LABEL_IDS
  505. beq @done
  506. jsr fl_get_label
  507. bcs @bad
  508. ldy label_id
  509. txa
  510. cmp saved_labels,y
  511. beq @next
  512. @bad: inc mismatch
  513. lda #$01
  514. jsr fail
  515. @next: inc label_id
  516. jmp @loop
  517. @done: rts
  518. init_vars:
  519. lda #$01
  520. sta v_one
  521. lda #$03
  522. sta v_three
  523. lda #$04
  524. sta v_four
  525. lda #$05
  526. sta v_five
  527. lda #$00
  528. sta v_a
  529. sta v_sum
  530. sta v_i
  531. sta v_ifpath
  532. sta v_bad
  533. sta v_long
  534. sta v_filler
  535. sta prog_result
  536. rts
  537. ; add(value as word) as byte: returns value + 1.
  538. add:
  539. lda #$00
  540. ldx #$00
  541. jsr frame_enter
  542. bcs @fault
  543. ldy #2
  544. lda (FRAME_FP),y
  545. clc
  546. adc #$01
  547. sta add_result
  548. jsr frame_leave
  549. lda add_result
  550. clc
  551. rts
  552. @fault: lda #$00
  553. sec
  554. rts
  555. .segment "CODE"
  556. fail:
  557. ora fail_mask
  558. sta fail_mask
  559. rts
  560. .segment "RODATA"
  561. message: .byte "NOVA128 CONTROL TEST DONE", $0D, $00
  562. .segment "BSS"
  563. fail_mask: .res 1
  564. print_y: .res 1
  565. saved_cr: .res 1
  566. label_id: .res 1
  567. mismatch: .res 1
  568. form_mask: .res 1
  569. main_size: .res 1
  570. long_size: .res 1
  571. pos_while: .res 1
  572. pos_long: .res 1
  573. prog_result: .res 1
  574. v_one: .res 1
  575. v_three: .res 1
  576. v_four: .res 1
  577. v_five: .res 1
  578. v_a: .res 1
  579. v_sum: .res 1
  580. v_i: .res 1
  581. v_ifpath: .res 1
  582. v_bad: .res 1
  583. v_long: .res 1
  584. v_filler: .res 1
  585. add_result: .res 1
  586. saved_labels: .res LABEL_IDS
  587. fill_count: .res 1

Powered by TurnKey Linux.