|
|
1.1 ! root 1: \section{Emitters} ! 2: We have an odd problem---we need to be able to emit either a 32-bit ! 3: integer or a string. ! 4: The order in which the bytes of the integer are emitted depends on ! 5: whether the target machine is BigEndian or LittleEndian, but the ! 6: bytes of the string should be emitted in the same order on both machines. ! 7: This means that the two emission functions depend on each other, but ! 8: in a machine-dependent way, so we bundle them up. ! 9: We also have to be able to emit two words for floating point constants. ! 10: The way to do this can be derived from [[emit_word]], and this ! 11: code seems to be the sensible place to do that. ! 12: So we define a type [[emitter_triple]] ! 13: and pass them around that way. ! 14: ! 15: @ Eventually we want to take all the words and strings that have been ! 16: emitted and bundle them up into a single string using [[implode]]. ! 17: We'll take the following tack with that: ! 18: each emitter will squirrel some info away in a reference variable. ! 19: A function [[emitted_string: unit -> string]] will take the ! 20: squirreled information and return a string that represents ! 21: everything emitted so far. ! 22: As a side effect, it will reset the emitter system to its initial ! 23: state, where ``everything emitted so far'' is the empty string. ! 24: ! 25: The actual implementation will be a list of strings which is reversed ! 26: and imploded. ! 27: <<signature>>= ! 28: signature EMITTERS = sig ! 29: type emitter_triple ! 30: val LittleEndian : emitter_triple ! 31: val BigEndian : emitter_triple ! 32: val emitted_string : unit -> string ! 33: val MipsAsm : outstream -> emitter_triple ! 34: val address : int ref ! 35: end ! 36: ! 37: @ First something that's capable of emitting real code, then ! 38: something that can print assembly code. ! 39: We emit the assembly code to output right away, without any fooling. ! 40: <<*>>= ! 41: structure Emitters : EMITTERS = struct ! 42: type emitter_triple = (int * int -> unit) * (int -> string -> unit) ! 43: * (string -> unit) ! 44: local ! 45: <<memory and basic services>> ! 46: in ! 47: <<string emitter>> ! 48: <<little-endian emitter>> ! 49: <<big-endian emitter>> ! 50: fun emitted_string () = ! 51: let val s = implode (rev (!so_far)) ! 52: in so_far := nil; s ! 53: end ! 54: end ! 55: structure BigReal = MipsReal(struct val emit_word = emit_pair_big end) ! 56: structure LittleReal =MipsReal(struct val emit_word = emit_pair_little end) ! 57: val LittleEndian = (emit_pair_little,emit_string,LittleReal.realconst) ! 58: val BigEndian = (emit_pair_big,emit_string,BigReal.realconst) ! 59: <<assembly-code emitters>> ! 60: end ! 61: ! 62: ! 63: @ Here is a variable to remember what's been emitted so far ! 64: <<memory and basic services>>= ! 65: val so_far = ref nil : string list ref ! 66: fun squirrel s = so_far := s :: !so_far ! 67: fun emit_byte n = squirrel (chr n) ! 68: <<string emitter>>= ! 69: fun emit_string n s = squirrel (substring(s,0,n)) ! 70: handle e => ! 71: (print "?exception "; print (System.exn_name e); ! 72: print (" in emitters.emit_string "^ ! 73: (Integer.makestring n) ^ " \""^s^"\"\n"); ! 74: raise e) ! 75: ! 76: @ Little-endian means the little (least significant) end first, ! 77: like the VAX. ! 78: We parameterize the real emitters by a function that emits a byte. ! 79: <<little-endian emitter>>= ! 80: fun emit_pair_little(hi,lo) = ! 81: let open Bits ! 82: fun emit_word(n) = ! 83: (emit_byte(andb(n,255));emit_byte(andb(rshift(n,8),255))) ! 84: in (emit_word(lo);emit_word(hi)) ! 85: end ! 86: ! 87: <<big-endian emitter>>= ! 88: fun emit_pair_big(hi,lo) = ! 89: let open Bits ! 90: fun emit_word(n) = ! 91: (emit_byte(andb(rshift(n,8),255));emit_byte(andb(n,255))) ! 92: in (emit_word(hi);emit_word(lo)) ! 93: end ! 94: ! 95: ! 96: @ Now the assembly code. ! 97: to make it easier to debug, we print out addresses in the same format ! 98: as {\tt dbx}: we use the byte address and we print it in hex. ! 99: ! 100: We have to bend over backwards to handle real numbers ! 101: ! 102: <<assembly-code emitters>>= ! 103: val address = ref 0 (* address of next instruction in words *) ! 104: <<real number state info and [[decode_real_ptr]]>> ! 105: fun MipsAsm stream = ! 106: let fun say s = (output stream s; flush_out stream) ! 107: fun printaddr addrref = ! 108: let val n = !addrref ! 109: in (if n<10 then " " else if n < 100 then " " else "") ! 110: ^ (Integer.makestring n) ! 111: end ! 112: local ! 113: open Bits ! 114: fun hexdigit n = ! 115: let val d = andb(n,15) ! 116: in if d <= 9 then chr(d+ord("0")) ! 117: else chr(d-10+ord("a")) ! 118: end ! 119: fun hex1 n = hexdigit(rshift(n,4))^hexdigit(n) ! 120: fun hex2 n = hex1(rshift(n,8))^hex1(n) ! 121: fun hex4 n = hex2(rshift(n,16))^hex2(n) ! 122: in ! 123: fun hex(hi,lo) = hex2(hi) ^ hex2(lo) ! 124: fun printaddr addrref = ! 125: let val n = 4 * (!addrref) (* address in bytes *) ! 126: in "0x" ^ (hex4 n) ! 127: end ! 128: end ! 129: fun decode x = ( ! 130: say ((printaddr address) ^ ": (" ^ (hex x) ^") " ! 131: ^ (MipsDecode.decode x)); ! 132: address := !address + 1; () ! 133: ) ! 134: fun do_decode_real(w,s) = ( ! 135: say ((printaddr address) ^ ": (" ^ (hex w) ^") " ! 136: ^ s ^ "\n"); ! 137: address := !address + 1; () ! 138: ) ! 139: fun decode_real s = (real_string := s; AsmReal.realconst s) ! 140: fun decode_string n s = ! 141: if n > 0 then ! 142: (say ((printaddr address) ! 143: ^ ": \"" ^substring(s,0,4) ^"\"\n"); ! 144: address := !address + 1; ! 145: decode_string (n-4) (substring(s,4,String.length(s)-4)) ! 146: ) ! 147: else () ! 148: in ! 149: decode_real_ptr := SOME do_decode_real; ! 150: (decode,decode_string,decode_real) : emitter_triple ! 151: end ! 152: <<real number state info and [[decode_real_ptr]]>>= ! 153: val decode_real_ptr = ref NONE : ((int * int) * string -> unit) option ref ! 154: (* used to emit asm code for a real word *) ! 155: ! 156: val real_least = ref NONE : (int * int) option ref ! 157: (* least significant word of real *) ! 158: val real_string = ref "" ! 159: fun emit_real_word w = ! 160: let val decode_real = case !decode_real_ptr of ! 161: SOME f => f ! 162: | NONE => ErrorMsg.impossible "missed real decoder in mips asm" ! 163: in ! 164: case !real_least of ! 165: NONE => real_least := SOME w ! 166: | SOME least => ! 167: (decode_real(least,"[low word of "^(!real_string)^"]"); ! 168: decode_real(w,"[high word of "^(!real_string)^"]")) ! 169: end ! 170: ! 171: structure AsmReal = MipsReal(struct val emit_word = emit_real_word end) ! 172:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.