A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
2.7 KiB

  1. import type { SSA } from "./ir"
  2. const reg8 = ["B", "C", "D", "E"] as const
  3. type R8 = typeof reg8[number]
  4. class ASMState {
  5. regs: { [r in R8]: string | null }
  6. syms: { [s: string]: R8 }
  7. stack_offsets: { [s: string]: number }
  8. cur_offset: number
  9. insns: Array<string>
  10. constructor() {
  11. this.regs = { "B": null, "C": null, "D": null, "E": null }
  12. this.syms = {}
  13. this.stack_offsets = {}
  14. this.cur_offset = 0
  15. this.insns = []
  16. }
  17. // TODO: Generalize for u16
  18. get_sym_loc(sym: string): R8 | number | null {
  19. // return register if already allocated
  20. if (typeof this.syms[sym] !== "undefined") {
  21. return this.syms[sym]
  22. }
  23. // return stack offset if already allocated
  24. if (typeof this.stack_offsets[sym] !== "undefined") {
  25. return this.cur_offset - this.stack_offsets[sym]
  26. }
  27. return null
  28. }
  29. alloc_sym_loc(sym: string): R8 | number {
  30. const existing_loc = this.get_sym_loc(sym)
  31. if (existing_loc !== null) {
  32. return existing_loc
  33. }
  34. // look for free register
  35. for (const r8 of reg8) {
  36. if (this.regs[r8] === null) {
  37. this.regs[r8] = sym
  38. this.syms[sym] = r8
  39. return r8
  40. }
  41. }
  42. // allocate space on stack
  43. this.cur_offset++
  44. this.stack_offsets[sym] = this.cur_offset
  45. this.insns.push("ADD SP, -1")
  46. return this.stack_offsets[sym]
  47. }
  48. }
  49. export const convertASM = (ir: Array<SSA>): Array<string> => {
  50. const state = new ASMState()
  51. ir.forEach(ssa => convertASM_SSA(state, ssa))
  52. return state.insns
  53. }
  54. const convertASM_SSA = (state: ASMState, ssa: SSA): void => {
  55. const dest = state.alloc_sym_loc(ssa.dest)
  56. if ("source1" in ssa) { // Binary
  57. } else if ("op" in ssa) { // Unary
  58. } else { // Copy
  59. let source = ""
  60. if (typeof ssa.source == "number") {
  61. source = ssa.source.toString()
  62. } else {
  63. const loc = state.get_sym_loc(ssa.source)
  64. if (loc === null) {
  65. state.insns.push(`LD A, (${ssa.source})`)
  66. source = "A"
  67. } else if (typeof loc === "string") {
  68. source = loc
  69. } else {
  70. state.insns.push(
  71. `LD HL, SP + (${loc})`,
  72. `LD A, (HL)`
  73. )
  74. source = "A"
  75. }
  76. }
  77. if (typeof dest === "string") {
  78. state.insns.push(`LD ${dest}, ${source}`)
  79. } else {
  80. state.insns.push(
  81. `LD HL, SP + (${dest})`,
  82. `LD (HL), ${source}`
  83. )
  84. }
  85. }
  86. }