File:  [Research Unix] / researchv10no / cmd / sml / src / mips / emitters.nw
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

\section{Emitters}
We have an odd problem---we need to be able to emit either a 32-bit
integer or a string.
The order in which the bytes of the integer are emitted depends on
whether the target machine is BigEndian or LittleEndian, but the
bytes of the string should be emitted in the same order on both machines.
This means that the two emission functions depend on each other, but
in a machine-dependent way, so we bundle them up.
We also have to be able to emit two words for floating point constants.
The way to do this can be derived from [[emit_word]], and this
code seems to be the sensible place to do that.
So we define a type [[emitter_triple]] 
and pass them around that way.

@ Eventually we want to take all the words and strings that have been
emitted and bundle them up into a single string using [[implode]].
We'll take the following tack with that:
each emitter will squirrel some info away in a reference variable.
A function [[emitted_string: unit -> string]] will take the
squirreled information and return a string that represents
everything emitted so far.
As a side effect, it will reset the emitter system to its initial 
state, where ``everything emitted so far'' is the empty string.

The actual implementation will be a list of strings which is reversed 
and imploded.
<<signature>>=
signature EMITTERS = sig
    type emitter_triple
    val LittleEndian : emitter_triple
    val BigEndian : emitter_triple
    val emitted_string : unit -> string
    val MipsAsm : outstream -> emitter_triple
    val address : int ref
end

@ First something that's capable of emitting real code, then
something that can print assembly code.
We emit the assembly code to output right away, without any fooling.
<<*>>=
structure Emitters : EMITTERS = struct
    type emitter_triple = (int * int -> unit) * (int -> string -> unit)
					* (string -> unit)
    local 
        <<memory and basic services>>
    in
        <<string emitter>>
        <<little-endian emitter>>
        <<big-endian emitter>>
	fun emitted_string () =
	    let val s = implode (rev (!so_far))
	    in  so_far := nil; s
	    end
    end
    structure BigReal = MipsReal(struct val emit_word = emit_pair_big end)
    structure LittleReal =MipsReal(struct val emit_word = emit_pair_little end)
    val LittleEndian = (emit_pair_little,emit_string,LittleReal.realconst)
    val BigEndian = (emit_pair_big,emit_string,BigReal.realconst)
    <<assembly-code emitters>>
end


@ Here is a variable to remember what's been emitted so far
<<memory and basic services>>=
val so_far = ref nil : string list ref
fun squirrel s = so_far := s :: !so_far
fun emit_byte n = squirrel (chr n)
<<string emitter>>=
fun emit_string n s = squirrel (substring(s,0,n))
        	handle e =>
        		(print "?exception "; print (System.exn_name e);
        		 print (" in emitters.emit_string "^
				(Integer.makestring n) ^ " \""^s^"\"\n");
        		 raise e)

@ Little-endian means the little (least significant) end first,
like the VAX.
 We parameterize the real emitters by a function that emits a byte.
<<little-endian emitter>>=
fun emit_pair_little(hi,lo) =
    let open Bits
        fun emit_word(n) =
          (emit_byte(andb(n,255));emit_byte(andb(rshift(n,8),255)))
    in  (emit_word(lo);emit_word(hi))
    end

<<big-endian emitter>>=
fun emit_pair_big(hi,lo) =
     let open Bits
        fun emit_word(n) =
          (emit_byte(andb(rshift(n,8),255));emit_byte(andb(n,255)))
    in  (emit_word(hi);emit_word(lo))
    end


@ Now the assembly code.
to make it easier to debug, we print out addresses in the same format
as {\tt dbx}: we use the byte address and we print it in hex.

We have to bend over backwards to handle real numbers

<<assembly-code emitters>>=
val address = ref 0		(* address of next instruction in words *)
<<real number state info and [[decode_real_ptr]]>>
fun MipsAsm stream =
    let fun say s = (output stream s; flush_out stream)
        fun printaddr addrref = 
           let val n = !addrref
           in  (if n<10 then "  " else if n < 100 then " " else "") 
                ^ (Integer.makestring n) 
           end
        local 
            open Bits
            fun hexdigit n = 
                let val d = andb(n,15)
                in  if d <= 9 then chr(d+ord("0"))
                              else chr(d-10+ord("a"))
                end
            fun hex1 n = hexdigit(rshift(n,4))^hexdigit(n)
            fun hex2 n = hex1(rshift(n,8))^hex1(n)
	    fun hex4 n = hex2(rshift(n,16))^hex2(n)
        in
            fun hex(hi,lo) = hex2(hi) ^ hex2(lo)
	    fun printaddr addrref = 
           	let val n = 4 * (!addrref)	(* address in bytes *)
           	in "0x" ^ (hex4 n) 
           end
        end
        fun decode x = (
                say ((printaddr address) ^ ": (" ^ (hex x) ^") " 
                 ^ (MipsDecode.decode x));
           address := !address + 1; ()
           )
	fun do_decode_real(w,s) = (
                say ((printaddr address) ^ ": (" ^ (hex w) ^") " 
                 ^ s ^ "\n");
           address := !address + 1; ()
           )
	fun decode_real s = (real_string := s; AsmReal.realconst s)
        fun decode_string n s =
            if n > 0 then
                (say ((printaddr address) 
                            ^ ": \"" ^substring(s,0,4) ^"\"\n");
                   address := !address + 1;
                   decode_string (n-4) (substring(s,4,String.length(s)-4))
                   )
            else ()
    in
	decode_real_ptr := SOME do_decode_real;
        (decode,decode_string,decode_real) : emitter_triple
    end
<<real number state info and [[decode_real_ptr]]>>=
val decode_real_ptr = ref NONE : ((int * int) * string -> unit) option ref
				   (* used to emit asm code for a real word *)
    
val real_least = ref NONE : (int * int) option ref
				   (* least significant word of real *)
val real_string = ref ""
fun emit_real_word w =
    let val decode_real = case !decode_real_ptr of 
		  SOME f => f 
		| NONE => ErrorMsg.impossible "missed real decoder in mips asm"
    in
        case !real_least of 
    	    NONE => real_least := SOME w
          | SOME least => 
		(decode_real(least,"[low  word of "^(!real_string)^"]");
		 decode_real(w,"[high word of "^(!real_string)^"]"))
    end

structure AsmReal = MipsReal(struct val emit_word = emit_real_word end)


unix.superglobalmegacorp.com

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