Annotation of researchv10no/cmd/sml/src/mips/emitters.nw, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.